[Compil Games] Game Develop : le nouveau logiciel de création ?

Démarré par yoshi04, 28 Janvier 2009 à 23:52

0 Membres et 1 Invité sur ce sujet

La version 2.2.11127 vient de sortir  :)

Voici quelques uns des changements depuis la dernière fois que je suis passé donner des nouvelles :

-Amélioration de l'éditeur de scènes ( Propriétés affichées dans une grille, avec édition de multiples objets possibles, verrouillage des objets, redimensionnement facilité avec des vraies poignées ).
-L'éditeur de la banque d'images profite également d'une grille de propriétés pour faciliter l'édition de la liste.
-La compilation en interne a été légèrement revu, ce qui a fait baisser un peu le poids des jeux et a amélioré la vitesse.
-L'aide s'affiche dans un navigateur integré à GD.
-En parlant d'aide, celle ci est maintenant intégralement en ligne ( et librement améliorable par tous ) sur le wiki : http://wiki.compilgames.net/doku.php/game_develop/documentation
-Des modèles de jeux sont proposés à la création d'un nouveau jeu.
-L'interface de certaines boites de dialogue a été épurée.
-Corrections de crashs avec les cartes graphiques Intel.
-Les projets font maintenant référence aux ressources ( notamment les images ) grâce à des chemins relatifs au dossier du jeu. En bref, il est possible de déplacer facilement un projet d'un ordinateur à l'autre en copiant simplement le dossier de celui ci avec les images.
-Les masques de collisions peuvent maintenant être des polygones convexes quelconques.

Téléchargement

Game Develop est disponible comme d'habitude sur http://www.compilgames.net, pour Windows et Ubuntu.

La version Ubuntu nécessite quelques dépendances qui sont maintenant rappelées quand on lance le logiciel si jamais on ne les a pas d'installées.
Normalement, GD devrait tourner sur les Ubuntu et derivées pas trop anciennes, on m'a rapporté que ça tournait sur quelques autres distrib aussi. Un exemple sur Linux Mint 64 bits :

4ian

www.compilgames.net

La version 3 de Game Develop est disponible :)

La principale nouveauté est la possibilité de créer des jeux HTML5 avec la nouvelle plateforme Web. Il est également toujours possible de créer des jeux natifs, voir des jeux qui peuvent être exportés sur les deux plateformes.
Des parties de l'interface ont été revues ( Grille de propriété pour les objets ) et de nouveaux automatismes sont disponibles pour accélerer la création de jeux

Quelques exemples de jeux Web

Pour les curieux, voici quelques exemples de jeux :

http://www.compilgames.net/games/WebShoot
http://www.compilgames.net/games/WebSoldier
http://www.compilgames.net/games/EnhancedTutorial

Comme pour tous les jeux en HTML5, assurez vous d'avoir un navigateur récent avec WebGL d'activé  :)
Les jeux tournent aussi sur les smartphones récents, plus d'optimisations pour les mobiles sont à venir, ainsi que la gestion du tactile ;)
De même, de nombreuses extensions seront bientôt portée vers la plateforme Web pour un maximum de fonctionnalités et de compatibilité avec les jeux natifs déjà existants.

Extensions officielles et platforme Web open source

Les extensions officielles sont disponibles librement : https://github.com/4ian/GD-Extensions
De même, la plateforme web peut profiter de vos contributions : https://github.com/4ian/GDJS

Téléchargement

Game Develop est disponible comme d'habitude sur www.compilgames.net, pour Windows et Ubuntu.
A noté que Game Develop est toujours disponible gratuitement, mais que vous pouvez également donner ce que vous souhaitez si vous trouvez le logiciel utile.

Pour les débutants, un tutoriel tout en français est disponible sur le wiki : Tutoriel pas à pas pour débuter avec Game Develop
4ian

www.compilgames.net

En 4 ans, je n'avais pas du tout vu ce topic. Je m'auto-congratule.
J'ai épluché le step by step français, histoire de voir comment ça se manie.
Y a beaucoup de potentiel! Joli travail. :)
Signé : Un mec relou

Bonjour,

Je passe présenter quelques ajouts dans les dernières versions de Game Develop  :)

Un nouvel automatisme "Plateforme" est disponible : Il permet de créer rapidement et efficacement un jeu de plateforme en désignant un ( ou plusieurs ) objets comme pouvant se déplacer sur les plateformes, et d'autres objets comme étant les dites plateformes.
Vous pouvez tester le modèle "Web platformer" ( fourni avec GD ) directement ici : http://compilgames.net/games/WebPlatformer/

L'automatisme Moteur physique est également présent pour les jeux HTML5. Là aussi, vous pouvez le tester directement en ligne sur ce petit jeu d'exemple fourni avec Game Develop : http://www.compilgames.net/games/AngryPeasExample/

D'autres objets ont également été rendus disponibles pour les jeux HTML5 ( Objets TiledSprite ( Mosaïques )... ), ainsi que des automatismes ( Drag'n'drop, destruction automatique à la sortie de l'écran... ), des nouvelles actions pour envoyer par exemple des requêtes HTTP ou parser du JSON, pas mal de bugs corrigés, le support complet de l'audio pour les jeux HTML5 et il y a même des nouveaux thèmes visuels pour l'éditeur ( Dans le style "Metro" de Windows 8 ).

GD est toujours téléchargeable sur le site officiel : http://compilgames.net/
Vous pouvez également aimer la page facebook pour donner un petit coup de pouce au logiciel :) : https://www.facebook.com/GameDevelop
4ian

www.compilgames.net

Toujours très impressionné par ton travail :)
Est-ce que le moteur physique est fait maison? Ou est-ce une bibliothèque comme Box2D? (ils ont des implémentations web aussi)

De même, il faudrait vraiment que je l'essaie un peu plus :)

Sinon, as-tu déjà envisagé d'intégrer un module d'animation ? Avec possibilité de gérer une timeline et de poser des clefs sur les différents paramètres inhérents aux sprites. Ainsi qu'une gestion plus précise via les courbes :P
C'est courant dans le domaine de la 3D, mais j'ai eu l'occasion de voir tout ça appliqué à la 2D sous After Effect.

D'autre part, j'ai l'impression que la programmation nodale (comme le kismet sous UDK) prend de plus en plus d'ampleur. J'en ai utilisé en début d'année et j'admets que ça passe plutôt bien pour la programmation Click&Create (pour les textures/shaders aussi).
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!

Le moteur physique est Box2DWeb, ce qui va parfaitement avec Box2D qui est déjà utilisé pour les jeux natifs  :)

Il y a eu une extension développée par un autre développeur qui permettait de dessiner des objets sous formes de squelettes auquels on fixait des images, ça permettait de créer des animations de ce genre. Après, la demande est assez peu élevée pour le moment pour ce genre de chose, je crois que l'extension n'a pas été mise à jour pour les dernières versions : Le plus dur étant de faire quelque chose d'ergonomique pour que chacun puisse l'utiliser de façon efficace.
4ian

www.compilgames.net

Citation de: 4ian le 10 Novembre 2013 à 11:29
Le plus dur étant de faire quelque chose d'ergonomique pour que chacun puisse l'utiliser de façon efficace.
C'est le plus important, c'est sûr :)
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!

C'est vraiment pas mal. Toujours pas au niveau d'un Multimedia Fusion (ou Fusion 2.5) qui reste pour moi la référence dans le domaine des logiciels de type CASE, mais c'est un bon challenger.


Une campagne de financement participatif a été mise en place pour Game Develop sur Indiegogo  :D
Il s'agit de trouver des fonds pour porter Game Develop sur MacOS, améliorer le support Ubuntu et aussi de permettre l'export des jeux HTML5 vers iOS et Android !
Les contributeurs pourront avoir accès aux version bêta avant leur mise en ligne officielle pour avoir les nouvelles fonctionnalités dès qu'elles sont prêtes !

La page Indiegogo est ici : http://igg.me/at/gdevelop/x/6586688 (C'est en anglais, mais posez moi toute question si quelque chose n'est pas clair évidemment  ;))

N'hésitez pas à partager les posts de la page https://www.facebook.com/GameDevelop ou du Twitter officiel https://twitter.com/Game_Develop  :D
4ian

www.compilgames.net

Pas mal, le montant visé n'est pas exorbitant, ça ne semble pas trop mal parti, et les fonctionnalités que vous proposez sont également réalistes mais pratiques ; bon choix et compromis je trouve. L'interface semble plus propre qu'auparavant, y'a eu du neuf de ce côté-ci ?

En tout cas (comme d'habitude mais bon), ravi de voir que GD se porte bien et ne cesse d'évoluer de manière positive... :).

    







Merci, le montant n'est en effet pas exorbitant au regard des fonctionnalités qui pourraient être developpées, ça me semble intéressant et juste pour tout le monde  :)
N'hésitez pas à partager avec les options de partage sur la page Indiegogo ou suivre Game Develop sur twitter : https://twitter.com/Game_Develop

Oui un graphiste a refait toutes les icones du logiciel  :lol: J'ai de mon coté adapté le ruban et quelques élements de l'interface pour obtenir un look "flat" et clean plus à la mode.
Rien que ça, ça donne un bon feeling lors de l'utilisation du logiciel  :)
4ian

www.compilgames.net

Avec les récents changements (Unreal, Crytek), il va devenir de plus en plus dur pour des indépendants de fournir un éditeur avec autant de features. Je pense que votre force réside dans le "prototyping" : tester et ajuster rapidement les mécaniques d'un gameplay sans se perdre dans les détails de l'implémentation :)

Je pense qu'il est dans votre intérêt de mettre ça en avant, et d'allouer moins de moyens sur le développement "release". En ce sens, j'approuve le portage de l'éditeur sur d'autre plateformes, bien plus que la production de jeux exécutables sur platformes mobiles/web.

Bon courage pour la suite ;)
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!

@4ian:
Bon courage pour la campagne de financement! Le montant visé n'est pas très haut et j'ose espérer que le projet pourra se conclure dans le positif! Il sera également intéressant de voir comment se déroule le port sur OSX ;)

@Wouf:
Pouvoir publier le jeu au format web, c'est tout de même un grand avantage:
- Web: Le jeu se lance via un navigateur web avec un simple clic (ou au touché si compatible mobile)
- OS classique: Télécharger le binaire compatible du jeu, potentiellement l'installer et ensuite clic / touch pour y jouer.

Bien sûr il y a des désavantages nombreux avec la version web (performances, limites de la sandbox, etc.), mais c'est probablement le média le plus simple pour le partage.

Pense qu'en web et mobile, tu as des plateformes qui proposent énormément de features à prix réduit, en ce compris la 3D, les shaders, ... Des logiciels tels que Game Develop ne pourront rivaliser éternellement. C'est ça que je veux dire. Le "target" ou dev "release" deviendra de plus en plus dérisoire face à la concurrence de studios avec plus de 100 ingénieurs à temps plein. En revanche, pour développer un prototype rapidement, en quelques clics et tester/équilibrer les mécaniques d'un gameplay, les logiciels tels que game develop et game maker ont un avantage crucial. Pas pour le développement final.

Edit: le partage n'a pas sa place durant la phase de prototypage, en revanche, un support mobile permettrait de tester l'ergonomie des capteurs sur le gameplay : accéléromètres, gyroscopes, ... J'avais négligé ce point.
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!

Tu peux avoir les avantages des 2. Entre WebGL et des outils du genre Emscripten, on commence à faire sauter les plus grosses barrières web vs binaires, notamment au niveau de l'exploitation du gpu ( Unreal 3 sur firefox , et glxGears pour voir les perfs ).
Pour des grosses appli ça reste bien sur lourd de se taper le download à chaque cache vidé, mais sinon c'est clairement négligeable vu l'avancée dans le domaine ;)
Faudra tenter de porter solarus sur un serveur et faire un twitchplayspokemon-like à l'occas ^^

Bonne chance pour les ports en tout cas :)

Là n'est pas la question, je ne parlais pas de perfs ;)

Sinon, je vous encourage à visionner ces courtes vidéos qui illustrent le fonctionnement de Game Develop :

Un berf apperçu du système d'événements, pas à pas (anglais)
Mise en place accélérée d'un jeu de plateforme (avec anims et scrolling)

Ca me rappelle mes débuts avec TGF/MMF et Game Maker :)
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!

Quelques nouvelles, la version 3.4 de Game Develop est en ligne ! :sourire3

Dans les nouveautés, on compte un nouveau mouvement pour bouger un objet dans 4 ou 8 directions avec le clavier, une traduction russe en plus de la française/anglaise/espagnole, des améliorations de performances (rendu 400% plus rapide des jeux HTML5, mise à jour de SFML coté natif), ajout du support de Intel XDK pour exporter les jeux HTML5 vers Android et iOS.

Pour rappel, Game Develop est maintenant entièrement open source et sur GitHub: https://github.com/4ian/GD

Un objet TileMap pour créer des cartes à base de tiles est en cours d'écriture par un autre développeur, ça promet de faciliter radicalement la création de map ou de jeux à base de tiles. :)

Le téléchargement se fait toujours sur http://www.compilgames.net (ou sur GitHub, dans l'onglet "Releases" !).
N'hésitez pas à liker la page Facebook: http://facebook.com/GameDevelop
et followez le compte Twitter: http://twitter.com/Game_Develop :sourit
4ian

www.compilgames.net

Citation de: 4ian le 29 Août 2014 à 21:57
Pour rappel, Game Develop est maintenant entièrement open source et sur GitHub: https://github.com/4ian/GD

\o/ Hurray \o/

Content que tu ais pris cette décision :)

En passant j'ai fait un peu de pub pour toi sur: http://forums.tigsource.com/index.php?topic=42292.30

Je viens d'utiliser ce logiciel le temps d'une mini gamejam pour gagner du temps ... Et au final j'en ai encore plus perdu :ninja:

Dans l'ensemble, je trouve ce logiciel bien foutu. Il souffre de plusieurs limitations par rapport à du code, mais y a tjs bien moyen de bidouiller ^_^

En revanche, il y a un quelque chose que je n'ai pas aimé du tout et qui m'a fait perdre une quinzaine d'heures !
--> La signification des identificateurs qui change en cours de code :ninja:

Je m'explique. Lorsqu'on crée une entité, on lui donne un nom. Admettons que je l'appelle Spider. Je peux à présent poser plusieurs instances de Spider sur ma scène. Mais dans l'event-script, il n'y a pas de notion de pointeur, de référence ou d'id. Ainsi Spider peut tantôt faire référence à toutes les instances de la "classe" Spider, tantôt faire référence à une instance en particulier, voire à un sous-ensemble. Par exemple, si je teste une collision entre Spider et Player, Spider fera reférence aux instances de type Spider qui sont en collision avec le joueur, soit un sous-ensemble des instances de Spider ; les actions s'exécuteront dès lors pour chaque élément de ce sous-ensemble. Dans une boucle foreach sur Spider, Spider fait référence à l'instance de l'itération courante. Bref, les actions impliquant Spider seront exécutées pour chaque élément de la classe.

Mais il y a des situations plus problématiques : si je crée dynamiquement une instance de Spider, Spider désignera désormais la nouvelle instance pour toutes les actions qui suivent ... Ainsi que dans celles des sous-événements.

Et voici un cas vraiment problématique :
[event] Si machin, [action] alors crée une instance de type Spider à une position aléatoire.
[sub-event] Foreach Spider, [action] mettre la variable d'instance bidule à 0.


A votre avis, combien d'araignées auront leur variable réinitialisée ?
Je vous le donne en mille : 1, à savoir la nouvelle ! :linkXD:

Ben oui, tout semble se passer comme si un identificateur (p.ex. Spider) désignait un ensemble d'instances. Par défaut, il contiendrait toutes les instances. Mais après certaines instructions, ce sous-ensemble se réduirait par intersections successives. Dès lors, toutes les actions qui suivent ou qui font partie de sous-événements ne seront appliquées qu'au dernier sous-ensemble d'instances (Spider).

Alors certes, il y a parfois moyen d'y remédier en changeant l'ordre des instructions ou en les séparant en différents sous-events. Néanmoins, je pense que ce mécanisme génère plus de bugs et d'énervement qu'autre chose :(


Edit : En plus, je vois mal comment faire des jeux plus complexes sans conteneurs (tableaux, listes, ...) :unsure:
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!

C'est embêtant ça. Et du coup, on ne peut pas non plus faire quelque chose du genre : "si deux Spider se rencontrent, déplacer l'une à gauche et l'autre à droite" ?

On avait un problème très similaire avec The Games Factory et Multimedia Fusion. Pas moyen de distinguer les instances entre elles. Au final, pour s'en sortir, il faut ruser mais ça devient très compliqué. Je pense qu'on ne peut pas cacher à l'utilisateur la différence entre une classe et une instance. Pour s'en sortir, il faut finalement connaître la programmation objet (classes, instances) alors que le but de ces logiciels est censé être l'inverse : soi-disant, pas besoin de s'y connaître en programmation.
Chaîne Twitch : diffusion en direct de sessions de développement de Solarus, de création de jeux, de parties de jeux vidéo.
Chaîne YouTube : replays des diffusions en direct, tutos Solarus
Compte Twitter : pour être au courant des nouveautés
Chat Discord : pour discuter en direct avec la communauté Solarus

CitationPar exemple, si je teste une collision entre Spider et Player, Spider fera reférence aux instances de type Spider qui sont en collision avec le joueur, soit un sous-ensemble des instances de Spider ; les actions s'exécuteront dès lors pour chaque élément de ce sous-ensemble.

Mais c'est exactement le principe fondateur qui fait que la création avec les évènements ça marche !  :lol:
Sans ça, impossible de créer des conditions pour modifier par exemple la vie d'un objet qui vient de rentrer en collision avec un ennemi ou ce genre de chose  :)
C'est expliqué dans les concepts dans le guide de démarrage du logiciel : http://www.wiki.compilgames.net/doku.php/game_develop/documentation/manual/pres_concepts

(Partie "La sélection des objets par les évènements").
C'est le même fonctionnement dans MMF ou Construct 2/Construct Classic : les conditions d'un évènement permettent de "filtrer" les objets sur lesquels on va effectuer les actions (tels des "if" de programmation tout simplement). Et donc d'effectuer les actions uniquement sur un sous ensemble d'objets.

Sans ça, aucun jeu ne peut être créé  :)

CitationMais il y a des situations plus problématiques : si je crée dynamiquement une instance de Spider, Spider désignera désormais la nouvelle instance pour toutes les actions qui suivent ... Ainsi que dans celles des sous-événements.

Là aussi, c'est le même principe : les seuls instructions qui changent les objets "filtrés" sont les conditions logiquement, et cette action. Ca va permettre de faire ceci :

Conditions : Aucune
Action 1 : Créer un objet Spider
Action 2 : Tourner Spider vers sa cible
Action 3 : Mettre la vie de Spider à 100
Action 4 : et ainsi de suite  :)

CitationEt voici un cas vraiment problématique :
[event] Si machin, [action] alors crée une instance de type Spider à une position aléatoire.
[sub-event] Foreach Spider, [action] mettre la variable d'instance bidule à 0.

Ca se règle en une action :

[event] Si machin,
[action] alors crée une instance de type Spider à une position aléatoire.
[action2] Considérer toutes les objets Spider
[sub-event] Foreach Spider, [action] mettre la variable d'instance bidule à 0.

L'action Considérer tous les objets XXX est (avec les conditions et l'action de création) une des dernières actions qui permettent de filtrer les objets (il reste l'action qui choisit une entité au hasard, très pratique d'ailleurs).
Elle permet tout simplement de recommencer à filtrer tous les objets de la scène  :)

CitationPas moyen de distinguer les instances entre elles.

Si tu as besoin absolument de distinguer deux instances, tu peux leur affecter une variable aléatoire ou différente du moins qui servira à les identifier (grâce à une condition qui filtrera une ou l'autre en testant la variable).

C'est vraiment le coeur de ce genre de logiciel : traduire les phrases du genre "Si Spider est en collision avec Laser Alors Détruire Spider". Dans ma phrase vous comprenez bien que je veux détruire uniquement les spider en collision avec Laser et non pas toutes ? Et bien dans GD (MMF et Construct), c'est pareil !  :lol:
Le seul moment où ça peut être chaud et j'en conviens, c'est dans le cas posté par Christopho "si deux Spider se rencontrent, déplacer l'une à gauche et l'autre à droite".
Mais sinon, tout ce fait très bien.  :)
EDIT : Remarque, en utilisant l'évènement "Pour chaque objet", on peut très bien faire partir à gauche ou à droite les Spider en collision. (Et là aussi quand je dit "les Spider en collision", j'exprime le fait que je n'applique mon évènement qu'a les Spider que j'ai "selectionné" avant : c'est ce que ma condition de test de collision fait  :)
(Je me répète un peu mais bon  ^_^)

CitationEdit : En plus, je vois mal comment faire des jeux plus complexes sans conteneurs (tableaux, listes, ...) hésite

Exact ! C'est pour ça que GDevelop est le seul logiciel à gérer les variables qui contiennent des variables enfants (i.e: des structures) qui permettent de faire des manipulations avancer (on peut même traduire du JSON en structure avec une action). Notamment garder en mémoire des listes ou des tableaux !
Voir la fin de cette page : http://www.wiki.compilgames.net/doku.php/game_develop/tutoriels/commentutiliserlesvariables
4ian

www.compilgames.net

Ok, merci pour les explications très détaillées :)
Ça me semble beaucoup plus clair, et effectivement l'action "Considérer toutes les objets Spider" règle le problème de Wouf.
Citation de: 4ian le 24 Novembre 2014 à 09:06
CitationPas moyen de distinguer les instances entre elles.

Si tu as besoin absolument de distinguer deux instances, tu peux leur affecter une variable aléatoire ou différente du moins qui servira à les identifier (grâce à une condition qui filtrera une ou l'autre en testant la variable).
Ok, c'est un moyen de contourner le problème. Mais ça me semble très lourd : si je comprends bien, pour pouvoir identifier un objet, il faut les parcourir tous linéairement. Il faudrait un système d'index pour pouvoir accéder en temps constant à un objet précis selon son id. Je crois qu'il y a ça dans MMF : une variable spéciale qui sert d'identifiant unique dans chaque objet. En gros, l'équivalent d'un pointeur finalement.
Chaîne Twitch : diffusion en direct de sessions de développement de Solarus, de création de jeux, de parties de jeux vidéo.
Chaîne YouTube : replays des diffusions en direct, tutos Solarus
Compte Twitter : pour être au courant des nouveautés
Chat Discord : pour discuter en direct avec la communauté Solarus

CitationConsidérer toutes les objets Spider
Effectivement, je n'avais pas vu cette action. C'est assez chaud à deviner quand on l'ignore ... Particulièrement avec des réflexes de programmeur :P Ca simplifiera ma solution, c'est sûr ^^

Citation de: Christopho le 24 Novembre 2014 à 10:04
Mais ça me semble très lourd : si je comprends bien, pour pouvoir identifier un objet, il faut les parcourir tous linéairement. Il faudrait un système d'index pour pouvoir accéder en temps constant à un objet précis selon son id. Je crois qu'il y a ça dans MMF : une variable spéciale qui sert d'identifiant unique dans chaque objet. En gros, l'équivalent d'un pointeur finalement.
J'allais y venir justement. Multiplier les accès linéaires alors qu'un temps constant suffirait, ça risque de poser des problèmes de performances sur certains jeux. En particulier pour les plateformes mobiles. Pour un gars qui vient du dev console, c'est inimaginable :ninja:
Et oui, pouvoir référencer des instances par id, ce serait déjà mieux :)

Sinon, j'admets que c'est un système astucieux ^^
J'aime beaucoup la programmation, qu'elle soit au clic and create, visuelle, par script, système et même assembleur. En fait, tant que j'évite la jvm, tout me va :D Je me suis bien amusé avec ce logiciel !

Mais pour le moment, je flirte avec le blueprint d'ue4 :coeur:

Edit :
En fait, ma frustration venait aussi du fait que le moteur physique plante si deux instances se retrouvent au même endroit (sûrement une division par la distance entre 2 objets). Ca me ralentissait beaucoup de devoir relancer le logiciel à chaque test, fermer l'autosave, ouvrir le projet et tester un nouveau truc.

Edit2 : Il semblerait que n'aie même plus besoin du foreach en subcondition à partir du moment où je fais un consider Spiders :)
Marre des pavés ? Marchez dans la boue!
ハハ、あなたは私の罠に落ちた!