intro

Bienvenue à 3D GameStudio ! Si vous venez juste d'avoir acheté cet étonnant de logiciel, prenez garde : vous avez un jouet puissant entre les mains. Mais pourquoi l'appelons-nous un studio de jeux ? Et bien... principalement parce que c'est un studio complet de développement de jeux. 3DGS est fourni avec tout les logiciels qui sont nécessaires pour créer un jeu de qualité commerciale : il inclut le moteur puissant d'Acknex, un grand éditeur de niveau, un constructeur de modèles et un éditeur de scripts.

Peut-être vous voulez créer vos modèles dans 3D Studio Max ou vous voudriez utiliser un outil de conception de niveau différent. Nous respectons cela et nous sommes heureux de vous dire que 3dgs peut importer et employer beaucoup d'autres formats de fichier ; visitez notre page de "téléchargement" sur www.conitec.net/a4update.htm et vous verrez que nous avons des connexions qui vous permettent d'importer tous les dossiers auquels vous pouvez penser.

Bien qu'il soit possible de créer un jeu sans écrire une seule ligne de code, nous vous encourageons à apprendre comment programmer au moins une partie du jeu par vous-même ; de cette façon vous pouvez être sûr que votre jeu sera différent et original. Ce manuel vous enseignera le C-Script, le langage de programmation employé par 3DGS. Nous l'appelons C-Script parce qu'il ressemble à C mais il est beaucoup plus facile à apprendre ; lisez simplement les premiers ateliers et vous vous en rendrez compte pour vous-même.

Ce manuel se compose de cinq parties:
1. Ateliers : accompagnez-moi à travers 27 ateliers et vous deviendrez un utilisateur 3DGS chevronné. Les bonnes nouvelles sont que chaque atelier inclut du code entièrement fonctionnel qui peut être employé dans tous vos futurs projets de jeu.
2. Mots-clés de C-Script : chaque mot-clé du moteur est expliqué avec des images et du code prêt à être utilisé.
3. Des scripts préfabriqués
4. Des exemples de jeux : apprennez à créer un jeu de l'espace 3D à partir de zéro. Transformez une idée en un projet réalisable prêt à être vendu.
5. Annexe: trucs et pièges, questions les plus fréquemment posées, vos obligations légales etc.

Ce manuel utilise les fonctions de base de l'éditeur de niveau de 3DGS appelé WED. Aussi ce serait vraiment une très bonne idée que vous ayez fait le tutoriel WED avant de démarrer ce manuel.

Pour terminer quelques mots à mon sujet, mon nom est George Pirvu et je suis le CEO pour Randombyte, une compagnie de développement de logiciel - www.randombyte.com. J'ai commencé à utiliser Acknex3 en 1997 ; c'était un bon moteur mais ce que vous tenez dans des vos mains maintenant - Acknex6 - est cent fois mieux, faites moi confiance ! Je suis le rédacteur du magazine d'utilisateur d'Acknex (AUM), un magasine gratuit qui présente un calibre de jeu et de nombreux tutoriels de C-Script et de code. Si vous pensez qu'3dgs est seulement un bon outil dédié au développement de jeu, détrompez-vous : AUM contient des exemples pour des synthétiseurs, réveille-matin, visionneuses de bilan, des outils qui produisent des visionneuses de code de C-Script et des modèles, des calculatrices et plus encore! J'ai travaillé avec plusieurs moteurs de jeu mais 3DGS est le meilleur outil en rapport qualoté / prix, : il est puissant, facile d'utilisation et a une grande (pour ne pas dire énorme) communauté d'utilisateur.

Les fichiers exemples se trouvent ici.

Suite: Découvrons le moteur

Traduction française : alain Brégeon alainbregeon@hotmail.com

communauté française de développement de jeux sur www.bregeon.net


workshop01

Précédent: Introduction

Atelier 01: découvrons le moteur

Si vous lisez ce document c'estque vous avez installé 3DGS sur votre ordinateur, ce programme doit avoir une entrée dans le menu démarrer de windowson comme sur l'image ci-dessous:

Vous pouvez voir des raccourcis pour "Level editor" (l'éditeur de niveau ou WED), "Model editor" (l'éditeur de modèle ou MED), "Manual" (ce manuel) et "Script editor" (l'éditeur de Script ou SED). Voyons ce que chacun fait :
- L'éditeur de niveau (Wed) estutilisé pour créer les niveaux de notre jeu, le monde 3D qui contieis used to create the levels for our games, les mondes 3D qui seront peuplés d'humains, de monstres, etc;
- L'éditeur de modèle (Med) est utile si vous voulez créer des objets 3D (modèles).Vous avez besoin d'une torche dans votre niveau? Créez la dans Med. Besoin d'un modèle de joueur? Créez le dans Med.
- Le manuel(ce manuel) vous apprendra C-Script, le langage de programmation utilisé par le moteur Acknex. Si vous jetez un coup d'oeil à quelques ateliers, vous verrez que C-Script est un langage puissant : vous pouvez créer des choses intéressantes avec seulement quelques lignes de code;
- L'éditeur de Script(Sed) est le programme qui vous aidera à écrire vos lignes de code. Sed est un grand éditeur de script avec de nombreuses fonctionnalités.

Démarrons l'éditeur de niveau ( level editor - Wed):

C'est la fenêtre principale, ça ne paraît pas très intéressant pour le moment mais cela va bientôt changer, soyez rassurés. Cliquez l'icône d'ouverture [image] et vous verrez la fenêtre windows "ouvrir" comme sur l'image ci-dessous:

Vous voyez les dossiers qui se trouvent dans votre répertoire GStudio6; double-cliquez sur le dossier nommé workshops:

Il y a quelques ateliers ! Ne vous inquiétez pas, la plupart d'entre eux peuvent être accomplis en moins de 30 minutes ; mieux que cela, toutes les nouvelles choses à l'intérieur sont expliquées point par point. Double-cliquez sur workshop01 pour l'ouvrir :

A présent double-cliquez sur le niveau nommé pour le charger:

Vous pouvez voir une maison et différentes choses dans ce niveau.

A ce point, j'estime qu'il est temps de vous fournir des informations utile sur l'utilisation de windows. Je ne vous blâme pas si vous voulez lire ce manuel et exécuter le moteur d'Acknex en même temps. Windows nous permet de commuter d'une tâche (programme) à l'autre par la pression alt + tab ; c'est ce ce que je vais faire dorénavant tandis que j'écris ce manuel. Je vous encourage à faire la même chose tant que vous travaillez avec ces ateliers.

Revenons à notre travail, pressez l'icône de compilation (build) [image] et vous verrez la fenêtre suivante:

Assurez-vous que "Level Map", "Preview" et "Enable" soient sélectionnés, tapez work01.wmb dans le champ texte "Engine options" et cliquez sur OK pour compiler le niveau:

Maintenant retenez votre souffle et pressez OK, vous devriez obtenir ceci:

C'est notre niveau dans le "vrai" monde 3D ; vous pouvez voir la maison et une créature minuscule qui bouge sans interruption... qu'est-ce donc? un moine, un guerrier...?

Ce niveau est déjà compilé, nous n'avons pas besoin de le compiler de nouveau tant que nous ne changeons rien dans ce niveau. Si nous quittons le moteur, nous pouvons exécuter de nouveau le niveau sans le recompiler. C'est ce que nous allons faire à présent: pressez Echap ou F10 pour quitter le moteur et exécuter de nouveau le niveau en pressant l'icône de lancement (Run) [image] :

Assurez-vous que le champ texte des options du moteur contient bien work01.wmb puis pressez le bouton OK pour exécuter le niveau. Je ne sais pas pour vous mais moi je suis vraiment curieux de savoir ce qu'est cette chose qui bouge au loin. Nous allons taper notre premier programme C-Script aussi suivez ces étapes :

1. Pressez la touche Tab de votre clavier. Vous voyez appraître un curseur clignotant en bas à gauche de votre écran;
2. Tapez camera.arc = 5; et pressez la touche Entrée.

Savez-vous ce qui vient de se passer? Avec une simple ligne de code (et courte en plus) nous avons écrit un effet de longue vue! Maintenant nous pouvons voir le modèle de magicien dans toute sa splendeur.!

Remettons la bonne valeur du zoom:
1. Pressez la touche Tab de votre clavier. Vous voyez appraître le même curseur clignotant en bas à gauche de votre écran;
2. Effacez le "5" en utilisant la touche effacement arrière et remplacez le par "60". La ligne de code doit être celle-ci: camera.arc = 60;
3. Pressez la touche "Entrée" et les choses sont redevenues normales.

Découvrez le niveau, utilisez les touches de directions et la souris pour vous déplacer; (pressez la touche zéro 1 fois si vous ne pouvez pas vous déplacer au début). Si vous vous éloignez trop de la maison vous pouvez sortir du niveau. Si cela se produit vous pouvez soit essayer de revenir d'où vous venez soit quitter le niveau en utilisant la touche "Echap" et redémarrez le niveau de nouveau. Approchons-nous à présent de la maison et plaçons-nous devant le magicien. Il se présente plutôt pas mal mais pourquoi passe-t-il par toutes ses animations ?

La raison est simple: il n'a aucune espèce de code qui lui est attachée. Le moteur utilise le code C-Script pour tous les objets qui ont besoin de faire quelque chose "d'intelligent" dans le niveau. J'ai créé un fichier C-Script pour ce projet; son nom est script01.wdl aussi arrêtez l'exécution du niveau en pressant la touche "Echap" puis cliquez sur l'icône de lancement (Run) [image] pour l'exécuter de nouveau mais changez le nom dans la fenêtre de lancement du niveau (Run Leve) comme suit :

Il y a pas mal de changement dans le niveau. Je peux voir de jolis effets de feux, le vieil homme se tient tranquille un moment puis il lance quelques balles énergétiques qui diffuse une lumière bleue sur le sol. Mon pauvre niveau s'est bien enrichi, non?

Pressez la touche zéro et vous pourrez de nouveau vous déplacer dans le niveau en utilisant les les mêmes touches de direction et la souris.

Le code qui est utilisé pour cet exemple est placé dans le fichier script01.wdl. Vous pouvez ouvrir le fichier du script (avec Sed) si vous êtes curieux de voir le code mais nous n'en parlerons pas pour l'instant mais sachez qu'il m'a fallu environ 70 petites lignes de code C-Script pour faire tout ce que vous avez vu.

Chaque niveau a besoin d'un fichier C-Script qui lui soit associé. Assurez-vous que WED s'exécute, ouvrez le même niveau (work01) puis choisissez File -> Map Properties.

Vous pouvez voir que j'ai associé le fichier C-Script nommé script01.wdl avec le niveau utilisé pour cet atelier. Pressez le bouton "choisir un script (Choose Script) [image] et vous serez en mesure d'associer n'importe quel fichier C-Script file à ce niveau. Je sais que je ne vous ai pas encore appris à en créer mais ne vous inquiétez pas, cela ne va pas tarder!

Suivant: Les variables


workshop02

Précédent: Découvrons le moteur

Atelier 02: les variables

Une variable n'est rien d'autre qu'un emplacement dans la mémoire de votre ordinateur (un contenant) qui peut être utilisé pour stocker des nombres. Regardons quelques exemples de variables C-Script :

var
balles = 7;
var sante;
var vies = 3; // le joueur à 3 vies

Ce sont des petites lignes de codes mais qui peuvent nous servir pour apprendre de nouvelles choses:

1. Chaque variable doit être définie avant d'être utilisée en utilisant le mot clé appelé var . Si vous écrivez cette ligne de code:

health = 100;

et que vous n'ayez pas défini une variable nommée health avant de l'utiliser vous obtiendrez un message d'erreur.

2. Chaque variable peut recevoir une valeur unitiale (balles = 7, vies = 3) au démarrage du jeu mais ce n'est pas obligatoire.

3. Nous pouvons ajouter nos propres commentaires pour n'importe quelle définition de variable. A chaque fois qu'il rencontre 2 slashs (//) le moteur ignorera les mots, expressions, symboles, etc qui les suivent. De cette façon nous pouvons facilement commenter notre code:

var car_speed; // la vitesse de la voiture qui poursuit le joueur
// @%$%&^& Ha Ha Ha! %^&** I règles!

4. Chaque ligne C-Script doit se terminer par un point virgule. Beaucoup de débutants oublie d'ajouter ";" à la fin de leurs lignes de code C-Script et cela génère de nombreux messages d'erreur.

5. C-Script n'utilise qu'un type de variable (var) qui peut contenir des nombres de 6 chiffres plus 3 décimales soit de -999999,999 à 999999,999;. Vous pouvez combiner 2 (ou plus) variables si vous avez besoin de nombres plus grands.

6. Chaque nom de variable doit commencer par une lettre ou le caractère souligné _. Voic quelques npmns de variables autorisés :

var
AlohA;
var _me_too;
var go42;
var
Iamb19;
var _12345;

Maintenant voici des noms de variables qui ne sont pas bons:

var
#ItoldYou;
var 1_for_all;
var 12345;

Je vous laisse découvrir ce qui n'est pas bon dans les définitions de variable ci-dessus..

7. Le nom des variables n'est pas sensible à la casse (majuscule / minuscule). De cette façon on peut définir une variable comme:

var MyHeadShots;

et nous l'utiliserons plus loin dans notre code comme :

myheadshots = 5; // ou
mYheadSHots = 5; // ou
MYHEADSHOTS = 5;

le moteur l'acceptera. Ceci étant il est toujours bien de se fixer une convention de nommage et de s'y tenir.

8. Pour terminer, les variables doivent avoir un nom significatif. Bien qu'il soit possible de définir des variables comme celles-ci:

var x32;
var a125;
var h_34_5;
var _z34187;

ce n'est pas la meilleure façon de procéder. Vous aurez des problèmes pour essayer de vous souvenir à quoi correspondent ces variables lorsque vous jetterez un oeil sur votre code quelques semaines plus tard. Si vous avez besoin de montrer votre code à quelqu'un d'autre, il passera beaucoup de temps à essayer de comprendre ce que vous avez voulu faire avec votre code. Les définitions suivantes sont quand même plus parlantes non?

var position_actuelle;
// position actuelle de l'ennemi
var
nombre_de_buts;
var high_score;
var armure_du_joueur; // sera mis à
100 au démarrage du jeu

Assez de théorie! Utilisons ces variables! Démarrez Wed, cliquez sur l'icône d'ouverture (Open) [image] puis choississez le dossier nommé workshop02 et ouvrez le:

Double cliquez sur le fichier work02 pour le charger dans Wed puis compilez le niveau et exécutez le (lisez le premier atelier si vous n'avez aucune idée sur la manière de procéder pour cela)

Votre écran deviendra bleu (oui c'est ma couleur favorite). Cela se produit tout simplement parce que le niveau consiste en un simple cube qui a été texturé avec une texture bleue uni sur toutes ses faces et la caméra (vos yeux dans un monde 3D) se trouve à l'intérieur de mon cube bleu. N'ayez pas peur on peut faire apparaître la caméra n'importe ou dans votre niveau, y compris à l'extérieur de votre niveau mais elle apparaîtra toujours à l'origine de WED si vous n'utilisez aucun code pour la contrôler.

Revenons à notre écran, il doit ressembler à ceci:

Cet écran ne parait pas très excitant, n'est-ce pas? Pressez la touche Tab de votre clavier pour montrer la console (vous savez le curseur clignotant) puis tapez :

a = 5;

et pressez la touche "Entrée". Vous noterez qu'il s'affiche a = 5 et c = 5 ! Merveilleux, ce qui se passe ici...

Pressez la touche Tab de nouveau, effacez le texte actuel et remplacez le par la ligne de code suivante:

b = 3;

L'écran doit rassembler à ceci:

Commencez-vous à comprendre? Il semblerait que c soit la somme de a et de b; essayez différentes valeurs pour a et pour b, cela devrait se confirmer. Maintenant jetons un oeil sur ce merveilleux code qui transforme notre extraordinaire moteur Acknex en une simple calculatrice:

var video_mode = 7; // 800x600 pixels
var video_depth = 32; // 32 bit mode
var a = 0;
var b = 0;
var c = 0;

string work02_wmb = <work02.wmb>;

text
collision_txt
{
pos_x = 10;
pos_y = 10;
font = _a4font;
string = "a = \nb = \nc = ";
flags = d3d, visible;
}

panel display_pan
{
pos_x = 0;
pos_y = 0;
layer = 15;
digits = 35, 10, 3, _a4font, 1, a;
digits = 35, 19, 3, _a4font, 1, b;
digits = 35, 28, 3, _a4font, 1, c;
flags = overlay, refresh, visible;
}

function main()
{
level_load (work02_wmb);
while (1)
{
c = a + b;
wait (1);
}
}

Si vous pensez que ce code est déjà trop compliqué, ne vous désolez pas, nous nous intéressons uniquement qu'aux lignes bleues de ce code dans cet atelier. J'entends comme un soupir de soulagement ou je rêve?

var a = 0;
var b = 0;
var c = 0;

Ce sont 3 simples définitions de variable. Maintenant je sais qu'on à besoin de définir une variable de cette façon si je veux l'utiliser plus tard dans mon jeu.

c = a + b;

Cette ligne de code C-Script semble être très simple également; elle fait que c soit égal à la somme de a et de b. Faisons une petite expérience, démarrez l'éditeur de script (Script Editor - Sed ) puis pressez son icône d'ouverture (Open) [image] :

Double cliquez sur le dossier workshop02 puis sur le fichier script02 qui se trouve dans ce dossier pour ouvrir le fichier C-Script:

Si vous ne pouvez pas voir les numéros des lignes, allez dans le menu "Options" et sélectionnezt "Show Line Numbers", comme sur l'image ci-dessous

Ne soyez pas troublé par ces grandes lignes de slashs, je les utilises pour séparer les différentes zones de mon code mais vous n'avez pas à les utiliser si vous n'aimez pas.

Revenons à notre code; la 45ème ligne du code est notre c = a + b; effacez le signe "+" et remplacez le par le signe "-" ce qui donnera ceci:

c = a - b;

A présent pressez l'icône de l'exécution Test [image] et... rien ne se passe. si vous êtes un utilisateur avancé vous avez déjà configuré SED correctement mais il faut aussi penser au débutant, ce que je fais actuellement:

1) Cliquez le menu nommé Options puis selectionnez Configuration; vous devriez voir la fenêtre suivante:

Nous devons renseigner les 2 chemins: le répertoire 3D GameStudio et les fichiers CSC/WDL a exécuter. Click gauche sur le premier bouton navigateur [image] :

Trouvez le répertoire où vous avez installé 3DGS sur votre ordinateur (le mien est C:\Program files\GStudio6) puis cliquez sur le dossier bin \ folder qui se trouve à l'intérieur, comme sur l'image ci-dessus. Que se passe-t-il avec ce dossier bin? Bien, il contient acknex.exe, le moteur qui exécute nos niveaux. Cliquez sur le second bouton de navigation [image] et selectionnez le fichier script que nous voulons exécuter lorsque nous pressons sur le bouton test. Ici ma configuration C-Script après avoir trouvé les bons chemins:

N'oubliez pas que si vous avez installé 3DGS dans un autre dossier, votre fenêtre de configuration doit différer de celle-ci. Pressez OK et nous pouvons tenter de nouveau notre chance avec le bouton exécution Test [image] :

Cette fois-ci ça fonctionne! Je revois ce bon vieil écran bleu qui me manquait déjà! Tapez quelques valeurs (n'oubliez pas de presser la touche Tab):

a = 2;
b = 5;

et le résultat est c = -3! ça fonctionne vraiment!

Vous voici à présent passé maître dans les bases de C-Script, vous ne trouvez pas? Faisons une petite expérience, vous vous souvenez que nous avons dit qu'une variable (var à partir de maintenant ) pouvez recevoir une valeur initiale.Est-ce vrai? Nous allons vérifier cela tout de suite : éditez les valeurs pour a et b dans votre fichier C-Script pour qu'il ressemble à ceci:

Testons [image] notre niveau de nouveau!

Le moteur a lu les nouvelles valeurs, a soustrait 5 de 20, affiché le résultat correct : 15. Je reconnais que ce n'est pas un jeu que nous avons fait ici mais c'est déjà sympa! A présent nous savons ajouter et soustraire des valeurs; nous pouvons aussi utiliser * pour multiplier 2 nombres ou / pour les diviser. Nous pouvons remplacer la 45ème ligne (celle ou se passe le calcul) par des expressions beaucoup plus complexes mais comme je hais les mathématiques parlons d'autre chose...

Vous vous souvenez de ces deux lignes de code? J'ai oublié de vous en parler:

var video_mode = 7; // 800x600 pixels
var video_depth = 32; // 32 bit mode

Acknex sait traiter 2 types de variables: les variables prédéfinies et les variables définies par l'utilisateur. Quelques variables sont déjà définies à l'intérieur du moteur par ses créateurs; ce sont les variables prédéfinies et elles contrôlent différentes fonctionnalités du moteur. Les 2 variables ci dessus sont des variables prédéfinies; elles sont utilisées par le moteur pour gérer la résolution de l'écran (800x600 pixels dans mon exemple) et le nombre de couleurs qui seront utilisées dans le jeu (32 bits). Notez s'il vous plait que la variable prédéfinie video_mode peut avoir une valeur comprise entre 1 et 11 et que la variable video_depth peut être mise à 16 ou 32. Pour une liste exhaustive des variables prédéfinies, reportez-vous à la seconde partie de ce manuel : mots clés C-Script.

Si vous projetez de réaliser le prochain Quake c'est bien de savoir comment les grandes personnes change la résolution vidéo dans leur menu "options", ils donnent simplement une nouvelle valeur à une variable qui ressemble à notre variable video_mode. Vous semblez fatigué? Moi aussi. Faisons une pause.

Suivant: Les fonctions


workshop03

Précédent: les variables

Atelier 03: les fonctions

J'espère que vous avez lu l'atelier précédent, au sujet des variables. Je ne sais pas pour vous, mais moi j'ai appris pas mal de choses à propos de ces variables. Si tout va bien, ce chapitre vous apprendra de nouvelles et intéressantes choses à propos des fonctions.

Mais quoiqu'il en soit, qu'est-ce qu'une fonction? Regardons un petit exemple :

function ajoute_nombres( )
{
a = 3;
b = 5;
c = a + b;
}

Vous voyez ce que je vois ? Une fonction n'est rien d'autre qu'une suite de phrases qui sont en l'occurence des instructions C-script qui utilisent des variables et qui leurs donnent à manger. Voyons quelques propriétés pour ces fonctions:

1. Une fonction est définie en utilisant le mot clé "function" suivit par le nom de la fonction et une paire de parenthèses ( ).

2. Le corps de la fonction (son contenu) doit être écrit à l'intérieur d'une paire d'accolades { }.

3. Le corps de la fonction consiste en une ou plusieurs lignes de code C-Script terminée(s) par un point virgule.

4. Il y a peu de restrictions pour le nom donné à vos fonctions mais vous devez appliquer les mêmes conventions que pour le nom donné aux variables.

5. Vous ne devez pas utiliser le même nom pour une variable et une fonction; ceci génèrera des erreurs.

Si vous pouvez lire ce tutoriel je suppose que vous connaissez votre âge également. Pas en années mais en jours ! Quoi, vous ne le connaissez-pas ? Vous aimeriez écrire une fonction qui calcule le nombre de jours ? Ok, nous allons essayer d'écrire une fonction qui calcule le nombre de jours écoulés pour moi (ou vous) sur cette terre depuis votre naissance. Elle utilisera quelques variables aussi nous devons les définir auparavant:

var
mon_age = 33; // ici vous donnez votre âge en année
var jours_dans_une_annee = 365;
var nombre_de_jours;

Rien de bien nouveau ici, n'est-ce pas? Nous avons défini 3 variables dont 2 qui reçoivent une valeur initiale parce que je connais mon âge en années et que je sais que pratiquement toutes les années ont 365 jours. Je suis un peu nerveux - est-ce que cette fonction fonctionne?

Je sais comment démarrer! J'écris le mot clé function et le nom de la fonction, nommons là calcule_jours:

function calcule_jours()
{

Je n'ai pas oublié les parenthèses après le nom de la fonction et j'ai ajouté ma première accolade!

Maintenant arrive la partie ardue de la chose, comment suis-je capable de dire au moteur de calculer le nombre de jours? Attendez...Comment ferais-je si je devais utiliser une calculatrice de poche ? Je ferais quelques chose qui ressemble à ça:

nombre_de_jours = 33 x 365 // nombre_de_jours estjuste un nom pour le résultat

Maintenant regardons nos variables, si je remplace 33 par mon_age et 365 par jours_dans_une_annee mon calcul peut s'écrire comme ça:

nombre_de_jours = mon_age x jours_dans_une_annee

Cette ligne commence à ressemble à du code C-Script mais nous avons tout d'abord 2 petits problèmes à régler:
- C-Script utilise * pour multiplier et non pas x
- Chaque ligne de code C-Script doit se terminer par un point virgule.

Ok, donc notre fonction doit ressembler à cela:

function calcule_jours()
{
nombre_de_jours = mon_age *jours_dans_une_annee;
}

J'ai pensé à ajouter la deuxième accolade aussi à présent le corps de la fonction est bien enfermé entre les 2 accolades requises. Je suis vraiment curieux de voir si cette fonction fonctionne bien aussi j'ai préparé un petit fichier script pour nos tests. Démarrez Sed, choisissez Options -> Configurations puis choisissez script03 comme fichier CSC/WDL à exécuter:

Ouvrez le fichier script03 qui se trouve dans le répertoire nommé workshop03:

Le code paraît très simple, n'est-ce pas? Nous savons déjà comment travailler avec ces variables, nous savons comment ajouter des commentaires...il ne nous reste plus qu'à copier notre fonction calcule_jour de ce document et la coller avant la "function main(): sélectionnez l'intégralité du script de la fonction avec votre souris, clic droit, choisissez copier, basculez vers SED, clic droit à hauteur de la ligne 26 puis choisissez Coller pour coller la nouvelle fonction:

Exécutons le Test [image] de notre fichier script:

Il fonctionne...mais rien ne se passe Je peux voir l'écran bleu et un zéro... Je suis âgé de 0 jour? Je me croyais un peu plus vieux!

Il doit y avoir quelque chose de mauvais dans ce code...Je suis pourtant sur d'avoir copié correctement la fonction! Que dois-je faire?

Bien, nous avons écrit une fonction qui est censée bien fonctionner, mais nous ne l'avons pas "appelée", nous ne l'avons pas fait fonctionner. Imaginons que vous voulez célébrer votre anniversaire et vous louez une bande de musiciens. Ils arrivent chez vous et ils se reposent dans un coin sans rien faire, attendant que vous leur donniez l'ordre de jouer. Et vous vous tenez là, vous ne leur dites pas que de commencer à jouer et vous vous demandez pourquoi vous ne pouvez pas entendre leur musique... La même chose se produit avec notre fonction : nous l'écrivons mais nous devons aussi lui dire de fonctionner.

Très bien mais comment demander à ma fonction de s'exécuter? N'oubliez pas que nous avons une amie fidèle - la console. Démarrez le test de nouveau puis pressez la touche Tab pour arriver en mode console (le curseur en bas de votre écran) puis tapez le texte suivant:

calcule_jours( );

Miracle! ça fonctionne, je suis âgé de 12045 jours! Vous devez voir une autre valeur si vous avez remplacé 33 par votre âge.

Ok, maintenant que l'enthousiasme est retombé je ressens comme un malaise : il va falloir que je tape le nom de la fonction à la console à chaque fois que j'exécute un script? La réponse est non, nous pouvons appeler n'importe quelle fonction depuis notre script. Tapez la ligne qui appelle la fonction à l'intérieur de 'function main' comme sur l'image ci-dessous:

Il est temps de tester notre niveau de nouveau...

Ok, cette fois ci ça fonctionne mais je ne suis pas sur de ce qui se passe, est-ce que la fonction 'main' est une fonction spéciale ou bien? Oui 'main' (main signifiant principal) est le nom d'une fonction prédéfinie, donc n'essayez pas de créer une autre fonction appelée main(). Cette fonction spéciale s'auto exécute à chaque fois que le niveau est lancé. Jetons un oeil au contenu de la fonction main:

function
main()
{
level_load (work03_wmb);
calcule_jours(); // j'ai ajouté cette ligne dans main
}

D'après ce que je peux voir, le code charge un niveau nommé work03_wmb puis il appelle (il exécute) notre fonction. Bien, maintenant si je résume ce que nous avons vu pour appeler une fonction nous devons écrire son nom suivi d'une paire de parenthèsest puis nous terminons la ligne de code C-Script par un point virgule. Tout cela semble logique, n'est-ce pas?

Truc Important: Ecrivez les lignes de codes de votre fonction en premier puis appelez-la ensuite. Le moteur lit le code de la même façon que vous lisez un livre, il démarre au début de la page de script pour terminer à la fin en lisant le code ligne par ligne. Si j'avais écrit mon script de cette façon

function main()
{
level_load (work03_wmb);
compute_days();
}

function
compute_days()
{
number_of_days = my_age * days_a_year;
}

le moteur va se dire : oh, c'est la fonction main. je connais la fonction main; j'ai besoin de l'exécuter à chaque fois. Que dit-elle à présent? Je dois charger un niveau nommé work03_wmb... Est-ce que je connais ce niveau? Bien entendu que je connais, sa définition se trouve à la ligne 12 du fichier script script03, une ligne qui est placée avant la fonction main( ). Ok, qu'y -a-t-il après? Compute_days( ). Qu'est-ce que cette fonction? Je ne la connais pas! Je ne sais pas ce qu'elle attend de moi. Je vais afficher un message d'erreur et je vais en rester là.:

N'oubliez pas de définir votre fonction en premier, autrement le moteur se plaindra lorsque vous l'utiliserez. Petite note au passage, vous pouvez voir pourquoi aucune personne sensée voudra partager sa copie de 3DGS avec ses amis ou partenaires, chaque moteur est personnalisé nominativement donc si je partage mon moteur avec une autre personne, Conitec me tombera dessus et me punira pour piratage!

Peut-être vous demandez-vous pourquoi nous n'avons pas compilé de niveau cette fois. J'ai décidé de compiler le niveau pour vous, le moteur l'a trouvé dans le répertoire workshop03 et l'a chargé. Si vous voulez créer vous-même le fichier de niveau wmb démarrez Wed, ouvrez work03 et compilez-le.

N'êtes-vous pas anxieux d'en apprendre encore plus? Notre journée en compagnie du merveilleux monde du C-Script s'avère assez facile, n'est-ce pas? Le prochain atelier nous apprendra comment créer des panneaux : des éléments qui peuvent afficher différentes formes, de figures, de barres, etc. A chaque fois que vous voyez une image ou une figure à l'écran, il y a une définition de panneau à l'origine.

Suivant: Images bitmaps et panneaux


workshop04

Précédent: Les fonctions

Atelier 04: images bitmaps et panneaux

Images bititmaps

Une image bitmap n'est rien d'autre qu'un fichier image créé avec un logiciel de dessin. Le fichier peut être au format pcx, bmp ou tga, en couleur vraie (fortement recommandé) ou 8 bits (fortement déconseillé). D'ailleurs je ne peux pas imaginer ce qui vous pousserez à vouloir utiliser des images 8 bits c'est à dire en 256 couleurs...attendez, si, je sais pourquoi!
a) Votre jeu paraît trop beau et vous voulez qu'il paraîsse plus moche;
b) Tous vos clients ont des vieilles cartes 3D (comme S3 Trio 3D ou Voodoo1) et vous savez que votre jeu s'exécutera plus vite sur leurs PC si vous utilisez des images 8 bits.

Vous devez utiliser des images et des textures en couleurs vraies tout le temps, croyez-moi! Personnellement je ne voudrais pas acheter un jeu qui utilise uniquement 256 couleurs dans ses niveaux. Par ailleurs, les images Targa 32 Bits (TGA) contienne en plus un canal alpha qui permet de donner une valeur de transparence à chaque pixel. Vous pouvez dessiner le canal alpha en utilisant votre programme de dessin favori (Photoshop, Paint Shop Pro, etc).

Comment définit-on une image bitmap? Regardons l'exemple ci-dessous:

bmap sante_pcx = <sante.pcx>;

Bien, ainsi nous avons le mot clé bmap suivi d'un nom et nous écrivons le nom du fichier correspondant dans des parenthèses angulaires. Nous terminons notre ligne de code C-Script avec un point virgule, comme d'habitude. J'ai nommé mon bitmap 'sante_pcx' mais il peut avoir un tout autre nom comme par exemple:

bmap test = <sante.pcx>;

Voyez-vous ce que je vois? Lorsque je voudrais utiliser l'image bitmap dans mon jeu (peut-être dans quelques jours ou quelques semaines) test ne sera pas un nom très significatif pour moi. Il faudra que je me réferre de nouveau à l'instruction pour voir à quoi correspond "test". Alors pourquoi se compliquer la vie, définissons tout simplement notre bitmap de cette façon:

bmap sante = <sante.pcx>;

Pensez-vous vous souvenir de ce qu'est sante dans quelques semaines? Oui j'entends les mauvais esprit me dire mais je ne sais pas si c'est une variable, une bitmap ou tout autre chose? Alors pour éviter d'avoir une erreur en nommant une variable avec un nom identique à une bitmap...je vous encourage vivement à utiliser des noms "parlants" pour les ressources utilisées dans vos projets. C'est pour cela que j'utilise sante_pcx et lorsque je rencontre ce nom je sais que je parle d'une ressource bitmap qui utilise un fichier pcx. Les définitons pour des fichiers bmp et tga sont identiques:

bmap munition_bmp = <munition.bmp>;
bmap armure_tga = <armure.tga>;

Les images bitmaps sont des ressources importantes pour nos jeux; lorsque vous voyez une image à l'écran c'est qu'il y a une définition bmap derrière elle. Alors qu'est-ce qu'on attend ? Découvrons toute la puissance des images bitmap! J'ai créé une image sympa et je veux l'afficher à l'écran, là, maintenant, tout de suite! Du calme, on peut le faire, mais avant tout il ya quelques petites choses à connaître...

Panneaux

Chaque jeu nécessite l'utilisation de panneaux! Si votre jeu utilise un tableau de bord, un cockpit, un bouton, un écran de démarrage, un inventaire etc vous avez besoin d'utiliser un panneau, une image bitmap rectangulaire qui sera placée "par dessus" l'écran. Chaque jeu utilise un moteur 2D pour dessinner tout ce qui est 2D, Acknex n'échappe pas à la règle, en plus d'un moteur 3D, il a son moteur 2D également.

Avant que nous commencions je veux vous montrer quelques exemples de panneaux d'une de mes démos:

Que pouvons-nous faire avec ces panneaux? Ou plus exactement, que pouvons-nous faire avec le moteur 2D inclus dans Acknex?
a) Des panneaux et images standards pouvant être appliqués par dessus notre écran, couvrant une partie de notre monde 3D;
b) Des chiffres (digit), éléments d'un panneau pour afficher des nombres;
c) Des fenêtres (window), éléments d'un panneau pouvant être utilisé pour une boussole ou un joueur 2D animé, barre d'énergie etc;
b) Des boutons (button), éléments cliquables d'un panneau qui peuvent démarrer des des fonctions;
e) Des curseurs (slider), éléments d'un panneau qui peuvent servir à donner une valeur par glissement d'un curseur de la même façon que vous modifiez le volume sonore dans un jeu;
.

Maintenant vous comprenez pourquoi ces panneaux sont aussi fantastiques - ils peuvent nous permettre de faire pas mal de choses intéressantes dans notre jeu. Relisez a)... f) ci dessus et jetez un oeil sur l'image qui suit pour retrouver chacun des éléments énoncés:

N'allez pas croire que j'utilise ce panneau et ses éléments dans un de mes jeux! Plusieurs éléments ont été ajoutés artificiellement avec mon programme de dessin parce que je voulais vous montrer tous les éléments sur une même image. A présent au travail!

Démarrez Sed et ouvrez le fichier nommé script04 à l'intérieur du répertoire workshop04:

Pas beaucoup de code, n'est-ce pas? Testons l'exécution de notre script:

Si vous ne pouvez pas démarrer le moteur c'est que vous avez oublié de choisir script04 dans Option -> Configuration de SED. Ce panneau est plutôt pas mal aussi vous pouvez être sur que ce n'est pas moi qui l'ai créé; j'ai utilisé un panneaud'exemple trouvé par ailleurs. La bonne nouvelle est qu'un panneau peut avoir des formes irrégulières alors que nous avions parlé d'image bitmap rectangulaires ? Attendez une minute...une image bitmap est obligatoirement une image rectangulaire!

En fait le moteur déclare comme étant transparents les pixels dont les valeurs de Rouge (R), Vert (V) et bleu (B) sont égales à 0. De cette façon je peux créer des panneaux qui ont n'importe quelle forme comme celui utilisé dans mon exemple. Voyons un autre exemple, l'image bitmap rectangulaire de gauche ne laisse appraître que le triangle jaune lorsqu'elle est affichée à l'écran:

Il est temps d'examiner la définition de notre panneau en détail:

panel
first_pan
{
bmap = first_pcx;
pos_x = 0;
pos_y = 0;
layer = 1;
flags = overlay, refresh, visible;
}

Qu'avons-nous ici? En premier le mot clé panel suivi par le nom du panneau. Suivant le même principe de nom facile à retrouver je le termine par _pan afin de me rappeler que l'on parle d'un panneau. Mais vous pouvez, bien entendu, choisir un tout autre nom. Rien de bien nouveau jusque là, je parie que la partie la plus intéressante se trouve dans les accolades.

1) bmap = first_pcx dit au moteur d'utiliser la bitmap nommé first_pcx définie auparavant. Si vous voulez revoir cette définition, je l'écris encore une fois pour vous, souvenez-vous simplement de définir la bitmap en premier et de créer ensuite le panneau qui l'utilisera.

bmap first_pcx = <first.pcx>;

2) pos_x = 0 et pos_y = 0 signifie que le panneau sera affiché aux positions x = 0 et y = 0 de votre écran.Levez les yeux vers le coin supérieur gauche de votre écran, c'est là que se trouve la position pos_x = 0 et pos_y = 0.

Donc si vous choisissez une valeur plus grande pour pos_x le panneau sera positionné plus vers la droite. Que se passe-t-il si je choisis pos_x = 200 et pos_y = 300? Si nous modifiions le script dès maintenant pour voir!

Exécutons notre niveau...que se passe-t-il?

Une image vaut mieux qu'un long discours, n'est-ce pas? Notez que le moteur ne vous dira rien si vous donnez de mauvaises valeurs à pos_x et à pos_y values; si ces nombres sont trop petits (négatifs) ou trop grand, vous serez incapables de voir votre panneau tout simplement parcequ'il sera placé en dehors de l'écran!

Jouons à un peit jeu, je vous donne une image de 150 x 130 pixels et vous demande de la placer sur l'écran, dans le coin inférieur droit sachant que nous utilisons video_mode = 7. Quelles valeurs devons-nous donner à pos_x et pos_y ?

Solution (ne regardez pas avant d'avoir cherché un peu): Video_mode = 7 signifie que l'écran est en résolution 800 x 600 pixels, donc nous avons 800 pixels en x et 600 pixels en y. Notre panneau a 150 pixels en x et 130 pixels en y il doit donc démarrer en 800 - 150 pixels en x et 600 - 130 pixels en y, si vous voulez qu'il se termine bien en (800, 600) pixels. La bonne réponse est donc pos_x = 650 et pos_y = 470.

3) le nombre associé à layer (couche) détermine l'ordre dans lequel sera affiché le panneau (on peut afficher plusieurs panneaux les uns par dessus les autres). Les éléments avec une valeur plus forte de layer seront placés par dessus les éléments d'une valeur inférieure. Si vous définissez un deuxième panneau et que vous lui mettez layer = 2; dans sa définition vous le verrez apparaître juste au dessus du panneau qui a layer = 1; comme sur l'image ci-dessous:

4) Bien, nous apprenons plein de choses intéressantes...

flags = overlay, refresh, visible;

Cette ligne permet de mettre diiférents drapeaux (flags) à 1 pour le panneau. Voyons ces drapeaux maintenant:

- overlay c'est ce drapeau qui demande au moteur de mettre en transparent les pixels qui ont pour valeur RVB (0,0,0). Si nous n'utilisons pas le drapeau overlay l'intégralité de l'image sera visible à l'écran, y compris les parties noires;

- refresh demande au moteur de dessiner le panneau à chaque cycle d'affichage. Beaucoup de jeux nécessite le redessinnage du panneau à chaque frame aussi n'oubliez pas de mettre ce drapeau.

- visible demande au moteur d'afficher le panneau dés le démarrage du jeu. Si vous avez le drapeau visible de mis et que vous ne voyez pas votre panneau à l'écran vérifiez vos valeurs de pos_x et pos_y values -elles sont certaienement trop petites ou trop grandes.

Le prochain atelier vous apprendra à créer tous les éléments d'un panneau : chiffres (digits), fenêtre (windows), boutons, curseurs (sliders) et barres.

Suivant: Chiffres (Digits) et fenêtres (windows)


workshop05

Précédent: Images bitmaps et panneaux

Atelier 05: chiffres (digits) et fenêtres (windows)

Chiffres (Digits)

Bien maintenant que nous savons créer des panneaux, que nous reste-il à étudier? Nous allons nous amuser avec les chiffres (digits) un élément de panneau qui peut afficher des valeurs numériques. Démarrez SED et ouvrez le fichier nommé script05:

J'aime les exemples courts mais je vois quelque chose d'étrange ici, ça n'a pas du vous échapper, j'avais compris que dans la définition d'un panneau il devait y avoir une instruction du genre bmap = une_bitmap; ! Oui mais, si vous n'avez pas besoin d'images pour votre panneau, vous n'avez pas besoin d'ajouter cette ligne de code. Nous voulons afficher quelques nombres ici, nous n'avons donc pas besoin d'image pour cela.

A priori la définition pour digits ne paraît pas trop compliqué, voyons là en détail:

digits = 410, 200, 2, _a4font, 1, sys_seconds;

- "digits" est le mot clé que nous devons utiliser à chaque fois que l'on veut afficher des nombres à l'écran;

- les 2 premiers nombres (x = 410 et y = 200) montre la position du digit par rapport au panneau. Si le panneau est à la position pos_x = 20 et pos_y = 30 et que la définition du digit est x = 410 et y = 200 nous verrons le résultat à l'écran à t x = 430 et y = 230, OK?

- deux (2) est le nombre de chiffres que l'on souhaite afficher pour notre nombre Dans mon exemple digits je peux afficher des nombres jusqu'à 99 (2 chiffres) mais si je remplace le 2 par 5 je permet l'affichage d'un nombre jusqu'à 99 999;

- _a4font est une fonte interne, un jeu de caractères qui sera utilisé pour afficher nos figures (j'utilise le mot figure est non nombre car la police peut contenir autre chose que des chiffres, cela peut être des symboles). Nous pouvons donc définir et utiliser n'importe quelles fontes mais celle-ci à le mérite d'être dans le moteur, aussi nous n'avons pas besoin de la définir au préalable;

- un (1) est le facteur par lequel sera multiplié la valeur que nous voulons afficher. Ne soyez pas inquiet à ce sujet pour l'instant, nous employons souvent 1 même si ce n'est pas toujours le cas;

- pour terminer, sys_seconds est le nom de la variable que nous voulons afficher. Vous pouvez la remplacer par n'importe quelle autre variable.

Ok, maintenant que nous avons expliqué toutes ces choses, nous pouvons écrire une définition plus générale pour digit:

digits = x, y, number_of_digits, font, factor, variable;

Exécutons le test de notre fichier script:

Je peux voir mon nombre à l'écran et sa valeur change toutes les secondes.(donc si vous n'avez pas 24 comme sur l'image ce n'est pas grave) pile poil comme une horloge! Je suis sur que "sys_seconds" est une variable prédéfinie, tout comme video_mode, parce que je n'ai pas écrit sa définition du tout. Vous pouvez jouer avec les valeurs "410" et "200" pour changer la position du digit à l'écran. Si vous voulez changer également pos_x et pos_y vous verrez que le panneau change sa position mais que le digit garde sa position à l'intérieur du panneau.

Ces digits sont plutôt sympas, je les utilise pour afficher la santé du joueur, son armure, le nombre de balles, de vies ...chaque fois que j'ai besoin d'afficher une valeur j'utilise un digit! Mais attendez... comment j'affiche plusieurs valeurs ? Simplement en ajoutnt autant de digits que de valeurs à afficher dans ma définition de panneau:

digits = 370, 200, 2, _a4font, 1, sys_hours;
digits = 390, 200, 2, _a4font, 1, sys_minutes;
digits = 410, 200, 2, _a4font, 1, sys_seconds;

Si vous avez un peu de courage, remplacer la simple ligne digits dans script05 avec les 3 lignes ci-dessus pour obtenir une simple (mais fonctionnelle) horloge:

Fenêtre (Windows)

NDT : J'ai parfois du mal à traduire Windows car je ne sais pas toujours s'il s'agit du système d'exploitation de Microsoft ou si on parle de fenêtre ! Dans notre cas c'est bien de fenêtre qu'il s'agit; Je veux vous montrer comment créer une fenêtre, nous entendons par fenêtre une partie d'une image que l'on souhaite afficher. La fenêtre étant un élément du panneau. Si vous n'êtes pas encore très sur de ce que peut vous apporter l'élément fenêtre, imaginez que vous vouliez créer une boussole ou une barre (horizontale ou verticale) qui changerait sa longueur ou hauteur, par exemple des barres d'énergie pour votre jeu de combat:

Laissez-moi vous montrer comment winfows fonctionne et vous serez à même de savoir quand et où vous les utiliserez.

Imaginons que nous voulions utiliser une lampe torche dans notre jeu. Nous aimerions avoir un indicateur d'usure de piles: lorsqu'elles sont neuves, nous aimerions avoir une petite image verte, lorsqu'elles commencent à être usées, une image orange et lorsqu'elles sont déchargées, une image rouge.

Bien entendu cet indicateur serait mieux si les transitions d'une couleur vers une autre se faisaient en douceur comme sur l'image ci-dessous...

Pas de soucis, tout ceci peut être créer avec une simple définition de fenêtre (window. En premier nous devons créer une longue image bitmap qui ressemblera à celle-ci:

Ensuite nous utiliserons une définition de fenêtre qui fera coulisser cette image à l'intérieur du petit cadre, comme sur cette image:

La partie de l'image bitmap qui se trouve en dehors du petit cadre est invisible, donc le joueur ne voit que l'image à l'intérieur du cadre. Vous changerez simplement une variable qui déplacera l'image vers la gauche ou vers la droite Ceci se fait également avec la définition de la fenêtre (window).

Maintenant que vous avez compris les bases, nous allons créer un altimètre pour notre avion:

Il est clair que nous avons besoin d'une image bitmap qui ressemble à ceci:

Le problème est le suivant : comment pouvons-nous afficher qu'une partie de l'image, celle correspondant à l'altitude actuelle de notre avion? Nous devons définir une fenêtre : éditez votre code jusqu'à ce qu'il ressemble à celui ci-dessous, copier / coller les lignes bleues dans le fichier script05.wdl mais n'oubliez pas de changer les valeurs pour pos_x et pos_y.

var video_mode = 7; // 800x600 pixels
var video_depth = 32; // 32 bit mode

var altitude = 0; // height of the plane

bmap metter_pcx = <metter.pcx>; // used for the frame
bmap height_pcx = <height.pcx>; // used for the altitude metter

string work05_wmb = <work05.wmb>;

panel first_pan
{
bmap = frame_pcx;
pos_x = 0;
pos_y = 0;
window = 40, 10, 178, 160, height_pcx, 0, altitude;
flags = overlay, refresh, visible;
}

function main()
{
level_load (work05_wmb);
}

et
voici l'image du fichier modifié:

Regardons ce qui a changé, nous avons une variable nommée altitude qui a une valeur initiale de 0, 2 définitions d'image, l'une sera utilisée pour le cadre de l'altimètre (nous n'en n'avons pas réellement besoin, mais c'est plus sympa) et l'autre est utilisé dans la définition de la fenêtre et bien entendu nous avons la définition de la fenêtre (window)!

Il est temps d'exécuter notre script! Pressez Test run et vous devriez obtenir l'image suivante:

Pressez la touche Tab de votre clavier pour passer en mode console puis tapez la ligne de code suivante et pressez la touche "entrée":

altitude = 150;

Vous pouvez voir que l'image a changé et qu'elle s'approche des 185 pieds / miles. Vous pouvez essayer avec la valeur de votre choix mais vous constaterez qu'avec des grandes valeurs telles que :

altitude = 1000;

l'affichage ne se fait pas pas correctement, ceci est du au fait que l'image bitmap utilisée pour l'instruction windows a une haiteur de 780 pixels seulement. Utilisez des valeursplus petites ou une image plus grande si nécessaire.

Regardons une image typique du mode fenêtre et étudions sa définition étape par étape:

window = x, y, taille_en_x, taille_en_y, bitmap, variable_x, variable_y

- "window" est le mot clé que nous utilisons à chaque fois que nous définissons une fenêtre;

- x et y donne la position de la fenêtre sur le panneau. Si le panneau a pos_x = 200 et pos_y = 100 et notre fenêtre a x = 30 et y = 20, l'image utilisée pour la fenêtre sera placée à x = 230 et y = 120 sur l'écran.

- taille_en_x et taille_en_y donne la taille de la découpe de fenêtre en x et en y. Souvenez-vous que l'image de la fenêtre elle-même est énorme, ce que nous donnons ce sont les dimensions de la partie visible de l'image en x et y;

- bitmap est le nom de l'image utilisée pour la fenêtre;

- variable_x donne le décalage horizontal de l'image utilisée pour la fenêtre. Si nous n'avons pas à bouger l'image vers la gauche ou la droite nous mettrons cette valeur à zéro;

- variable_y donne le décalage vertical de l'image utilisée pour la fenêtre. Si nous n'avons pas à bouger l'image vers le haut ou le bas nous mettrons cette valeur à zéro;

Conclusion
Lorsque vous créez une fenêtre, vous voyez seulement une partie de l'image utilisée pour cela. Changez variable_x ou variable_y (altitude dans notre script) et la grande image glissera selon ses axes x ou y, affichant d'autres parties de l'image à l'écran. La taille de la fenêtre découpée, ce que vous voyez à l'écran, est donnée par taille_en_x et taille_en_y.

Suivant: Boutons et curseurs


workshop06

Précédent: Chiffres (Digits) et fenêtres(windows )

Atelier 06: boutons, curseurs (sliders) et barres

Boutons

Un bouton est un autre élément du panneau qui peut être cliqué. Bien entendu vous cliquez sur des centaines de boutons à longueur de journées vous savez donc ce que c'est. Regardons la définition standard pour un bouton:

button = x, y, bitmap_si_clic, bitmap_pour_normal, bitmap_pour_par_dessus, fonction_si_clic, fonction_si_relache_bouton, fonction_si_par_dessus;

C'est une longue définition. Expliquons chaque terme en images:

- x et y donne la position du bouton sur le panneau. Vous pouvez voir que x = 70 et y = 60 dans l'image ci-dessous. Les coordonnées fonctionnent pour le bouton de la même façon qu'elles fonctionnent pour digits et windows;

- bitmap_si_clic est l'image qui apparait sur le bouton lorsqu'on le clique avec le bouton gauche de la souris;

- bitmap_pour_normal est l'image qui apparait sur le bouton au démarrage du jeu, sans qu'on le clique;

- bitmap_pour_par_dessus est l'image qui apparait sur le bouton si vous déplacez la souris par dessus, sans le cliquer;

- fonction_si_clic est le nom de la fonction, sans les parenthèses, qui sera exécutée lorsque nous cliquerons le bouton;

- fonction_si_relache_bouton est le nom de la fonction, sans les parenthèses ,qui sera exécutée lorsque nous relacherons le clic du bouton en restant au dessus de lui;

- fonction_si_par_dessus est le nom de la fonction, sans les parenthèses, qui sera exécutée lorsque nous survolerons le bouton sans cliquer dessus.

Prêt pour voir un petit exemple sur le fonctionnement des boutons ? Démarrons notre fichier script06:

Je cherche à faire le code le plus court possible mais nous pouvons voir quelques petites choses intéressantes:
a) Un panneau;
b) Un pointeur de souris (l'image d'un Smiley vert)) que l'on peut déplacer dans le niveau;
c) Un boton qui change son image bitmap du bleu vers le rouge lorsque le pointeur de la souris est au dessus de lui;
d) Le même bouton change son image bitmap du bleu vers le vert si on presse et qu'on maintient le bouton gauche de la souris sur lui;
e) Si nous cliquons sur le bouton "Quit" le moteur s'arrêtera de lui même au bout de 3 secondes.

quitnormal_pcx [image] quitover_pcx [image] quitclicked_pcx

Regardons le code:

Bien, nous avons défini 5 images bitmap (3 d'entre elles étant pour le bouton "quit") et nous avons placé le code de la souris dans la fonction main . Nous ignorons le code de la souris dans cet atelier mais nous parlerons un peu de la fonction qui permet au moteur de s'arrêter lorsque nous cliquons sur le bouton.

Si nous revenons au début de l'atelier et à la définition de "button" nous voyons que quit_program est notre fonction_si_clic, aussi elle sera exécutée lorsque nous cliquerons le bouton "Quit",ce qui est bien. La première ligne de code dit au moteur d'attendre 3 secondes et la seconde ligne arrête le moteur. Si vous désirez connaître tous les mots clés du moteur, consultez la deuxième partie du manuel : mots clés C-Script; vous trouverez tous les mots clés ainsi que des exemples pour vous aider dans cette section.

J'ai placé la fonction quit_program avant la définition du panneau car (vous devez vous souvenir de ceci) nous avons besoin de définir chaque chose avant de s'en servir..Il est temps de voir le code pour la définition de notre bouton:

button = 250, 134, quitclicked_pcx, quitnormal_pcx, quitover_pcx, quit_program, null, null;

Vous pouvez voir que je paramètre les habituels positions x et y et je paramètre les 3 images bitmap qui seront utilisées pour le bouton. Les 2 dernières fonctions (fonction_si_relache_bouton et fonction_si_par_dessus )sont remplacées par null, ce qui fait qu'il ne se passera rien. Nous utilisons uniquement la première fonction ici, celle qui sera exécutée lorsque nous cliquerons le bouton, la plupart du temps nous n'utiliserons pas les 2 autres fonctions mais peut-être aurez-vous l'occasion de vous en servir dans un de vos projets.

Si vous voulez créer plusieurs boutons sur un panneau ajoutez simplement plusieurs définitions de bouton. Je vous encourage vivement à créer 3 images pour chaque nouveau bouton, assurez-vous qu'elles aient la même taille, définissez bmaps ajoutez le nouveau code pour le bouton. Utilisez null pour toutes les fonctions associées à ce bouton. Pourquoi n'essayerez-vous pas pendant que prépare la suite de cet atelier ?...

Curseurs (Sliders)

Un curseur est un élément de panneau qui peut être déplacé avec la souris et qui sert à donner une valeur à une certaine variable. Nous pouvons avoir des curseurs horizontaux ou verticaux et nous pouvons paramétrer leur rayon d'action. La plupart du temps les curseurs sont utilisés pour régler le volume du son ou de la musique, le facteur gamma etc.

Voici l'illustration de nos curseurs en action:

Ok, je vous entend! Ces curseurs ne ressemblent pas à des curseurs et pour couronner le tout vous ne pouvez pas leur donner une valeur de début et de fin. Bien mais qu'est-ce qui vous empêche de peindre ce dont vous avez besoin sur le panneau existant? Faites le ressembler à ceci:

Maintenant ajoutons les mêmes curseurs à notre panneau:

Cela ressemble plus à l'image que l'on se fait d'un curseur, n'est-ce pas? Vous ne serez pas surpris d'apprendre que le code pour définir un curseur se résume en une seule ligne; une définition classique pour un curseur ressemble à ceci ::

hslider = x, y,taille_en_pixels, image_du_curseur, valeur_minimale, valeur_maximale, variable;
vslider = x, y, taille_en_pixels, image_du_curseur, valeur_minimale, valeur_maximale, variable;

Les deux types de curseur utilisent la même définition. Regardons un curseur en action, démarrez SED et ouvrez le fichier script06_2:

Vous savez que je suis un gentil garçon, c'est pourquoi j'ai créé un panneau avec un curseur de dessiné par dessus rien que pour vous son nom est main2.pcx. Nous utiliserons une nouvelle variable nommée speed; sa valeur initiale est 50 et nous pouvons utiliser n'importe quel autre nom pour elle. Nous allons également utilisé une définition de "digits" pour afficher la valeur de la variable.

Mais qu'est-ce que vous attendez, démarrez et testez le script!

Si vous ne pouvez pas exécuter le fichier script06_2, vous avez oublié de choisir son nom dans Sed -> Options -> Configuration. Maintenant cliquez et déplacez le curseur et regardez comment sa valeur, affichée par le digit, change de 0 à 100. C'est une jolie et rapide façon d'entrer une valeur numérique lorsque nous connaissons ses 2 extrémités.

Regardons notre définition du curseur:

vslider = 16, 71, 90, slider_pcx, 0, 100, speed;

Bien, nous paramétrons ses coordonées x et y pour montrer son image sur le panneau, taille_en_pixels est 90 pour le curseur vertical, nous utilsons une image nommée slider_pcx et nous changeons la valeur de la variable nommée speed de 0 à 100. Si vous voulez voir tous ce que nous venons d'apprendre au sujet des curseurs, essayez d'ajouter la définition d'un curseur horizontal sur le même panneau.

Suivant: Chaînes de caractères, textes et fontes


workshop07

Précédent : Boutons et curseurs

Atelier 07: Chaînes de caractères, textes et fontes

Nous avons appris comment afficher des panneaux, des chiffres et denombreux éléments de panneau. Si nousavons besoin d'afficher un texte (le nom du joeur, un message, etc)nous avons besoin de chaînes et de textes. Et si nous voulons qu enotre texte sorte de l'ordinaire, nous avons besoin d'utiliser une fonte sympa.

Strings

Une chaine (string) est une séquence de caractères, lettres, nombres, symboles. Voic quelques exemples de chaînes:

string player_str = "Johny Bravo";
string my_very_own_string = "je suis le meilleur!"
string player_meets_monster = "Die now! I won't have time for that later!";
string crypto1234 = "a#45@123--//";
string test_string; // vide, chaîne illimitée
string riddle[100]; // chaîne vide, peut contenir jusqu'à 100 caractères

Nous pouvons apprendre quelques trucs juste en regardant les définitions ci-dessus:

1. Chaque chaîne doit être définie avant d'être utilisée, en utilisant le mot clé "string".

2. Le contenu d'une chaîne, s'il existe, doit être entre guillemets "".

3. Nous pouvons assigner une séquence de caractères à la chaîne qu'on est en train de définir ou nous pouvons créer une chaîne vide et la remplir plus tard.

4. Une chaîne peut avoir une longueur illimitée ou une longueur spécifiée; string riddle[100]; crée une chaîne nommée riddle qui peut contenir jusqu'à 100 caractères.

5. Chaque ligne C-Script devant se terminer par un point virgule, n'oubliez pas le point virgule à la fin de votre définition de chaînes.

6. La convention de nom qui s'applique au x variables s'appliquent également aux noms des chaînes. J'aime ajouter _str aux noms de mes chaînes mais ce n'est pas une obligation.

Les chaînes n'affichent rien à l'écran par elles-mêm, elles ont besoin d'être placées dans une définition de texte.

Textes

Un texte est un objet qui peut afficher des chaînes à l'écran Voici une simple définition de texte:

text
first_txt
{
pos_x = 300;
pos_y = 250;
font = some_font; // previously defined font
string = player_str;
flags = visible;
}

Cela ressemble beaucoup à la définition d'un panneau, n'est-ce pas? La bonne nouvelle est que sa définition est vraiment simple:
- pos_x et pos_y donne la distance (en pixels) par rapport au coin supérieur gauche de l'écran;
- font donne le nom de la fonte (définie auparavant) qui sera utilisée pour le texte;
- string donne le nom de la chaîne qui sera affichée;
- flags = visible rend le texte visible.

C'est vraiment très simple! Je ne peux attendre pluspour voir un texte à l'écran!

Ouvrez script07 - Il doit ressembler à ceci:

Attendez une minute! Nous avons déjà défini un string pour notre niveau depuis le début?

string work07_wmb = <work07.wmb>;

Oui, nous pouvons utiliser des strings pour toute sorte de chose, nous avons défini une chaîne (utilisée pour le nom de notre niveau) avec chaque fichier script.

Revenons à notre code; vous pouvez voir que nous avons défini une chaîne nommée aloha_str:

string aloha_str = "Welcome to Paradise Island!";

N'oubliez pas que vous pouvez mettre tout ce que vous voulez (caractères, nombres, symboles) à l'intérieur des guillemets. Notre définition de texte est vraiment simple. Exécutons le test de notre fichier script!

Il est temps d'apprendre quelque chose de nouveau, ajouter la ligne ci-dessous à notre fichier script script07:

string pockets_str = "We will try to empty your pockets!";

et changez la fonction main() pour qu'elle ressemble à ceci:

function
main()
{
level_load (work07_wmb);
sleep (3);
greetings_txt.string
= pockets_str;
sleep (3);
greetings_txt.visible
= off;
}

Votre script doit ressembler à ceci (en vert = nouvelles lignes de code):

Exécutez le fichier script07 de nouveau et vous devriez avoir la séquence suivante:

Le code qui fait toutes ces choses est à l'intérieur de la fonction main(),aussi voyons de plus près ce qu'il fait:

function main()
{
level_load (work07_wmb);
sleep (3);
greetings_txt.string = pockets_str;
sleep (3);
greetings_txt.visible
= off;
}

Nous savons que level_load (work07_wmb); un niveau défini au préalable; sleep(3); demande au moteur d'attendre 3 secondes puis nous avons ceci en ligne de code:

greetings_txt.string = pockets_str;

Faites très attention car c'est la phrase la plus importante que j'ai écrite jusque là, nous pouvons accéder à (presque) n'importe quelle propriété / dispositif d'un objet en utilisant la méthode dite "du point" comme montrée ci-dessous:

objet.propriété

Nous avions utilisé cette méthode du point dans le premier atelier lorsque nous avions écrit camera.arc = ... avec camera comme étant l'objet et arc étant une de ses propriétés. Vous pouvez voir les objets prédéfinis et leurs propriétés dans la seconde partie du manuel. Maintenant que nous connaissons la méthode du point, la ligne de code ne nous paraît plus si compliquée, n'est-ce pas? Nous avons un objet nommé greetings_txt et nous avons une de ses propriétés (sa chaine string) qui est égale à la chaine définie auparavant nommée pockets_str. De cette façon on peut afficher différentes chaînes en utilisant toujours la même définition de texte.

Si vous vous demandez ce qui pourrait encore être changé à ce texte en utilisant la méthode du point, la réponse est simple : presque tout ! Jetons encore un coup d'oeil à la définition des textes :

text greetings_txt
{
pos_x = 300;
pos_y = 250;
string = aloha_str;
flags = visible;
}

Nous pouvons utiliser greetings_txt.pos_x = 500; et le texte sera placéà 500 pixels du côté gauche de l'écran, nous savons déjà comment changer la chaîne pour ce texte et nous pouvons utiliser greetings_txt.visible = off; pour cacher le texte complètement. Ces lignes de code doivent être placées dans la fonction main, ou peuvent être dans une de vos fonctions ou à l'intérieur d'une fonction qui s'exécute lorsqu'on clique sur un bouton. Vous seriez gentil de faire cela pour moi, s'il vous plait!

Nous pouvons bien entendu utiliser la méthode du point pour les contrôles des panneaux, des textes, des entités (soyez patient nous verrons ce que c'est également)... OK, voici quelques exemples:

display_pan.visible = off; // cache le panneau nommé display_pan
test_pan.visible = on; // montre le panneau nommé test_pan s'il était chaché
hi_txt.string = newstring_str; // donne une nouvelle chaîne à hi_txt
error_pan.pos_y = 300; // donne une nouvelle position pour le pos_y du panneau nommé error_pan

Vous avez certainement noté que ma définitiopn, de text ne comportez pas la ligne de code font = some_font;.Si vous oubliez cette ligne, le moteur utilisera par défaut sa fonte interne _a4font et c'est ce qui s'est passé ici. Vous aimeriez utiliser une nouvelle fonte? pourquoi pas!

Fontes

Une fonte est un jeu de caractère qui peut être utilisé pour nos textes. 3DGS peut utiliser 2 types de fontes:
- les fontes true type, comme celles utilisées par Windows;
- fontes à espacement fixe, un jeu de caractère qui est lu à partir d'un fichier image bitmap.

Fontes True type

Vous avez différentes fontes true type d'installées sur votre PCpc; ouvrez le répertoire nommé \fonts à l'intérieur de votre répertoire windows et vous verrez ceci:

Si vous double cliquez sur une fonte vous verrez la totalité du jeu de caractère, tout comme des exemples de textes:

C'est votre police true type habituelle et vous pouvez voir que les caractères n'ont pas un espacement fice, que par exemple le" "i est moins large que le "m". Voici la définition d'une police true type:

font mon_nom_de_fonte = "nom_de_fonte_dans_windows", type_de_la_fonte, hauteur_du_caractere; // fonte true type

- mon_nom_de_fonte est le nom que je souhaite donner à notre fonte, par exemple fonte_arial;
- nom_de_fonte_dans_windows est le nom de la fonte tel qu'il apparaît dans le répertoire windows\fonts. Vous pouvez utiliser ici "Arial", "Times" (Times New Roman) et "Courier";ces fontes étant obligatoirement installées sur tous les PC utilisant Windows;
- type_de_la_fonte peut être 0 (normal), 1 (gras), 2 (italque), 3 (gras + italique)d comme dans votre traitement de texte;
- hauteur_du_caractere est la hauteur de la fonte de caractère en points, comme dans votre traitement de texte.

Et maintenant voici un exemple de fonte true type:

font arial_font = "Arial", 1, 20; // Arial, gras, un caractère a une hauteur de 20 points

Fontes à espacement fixe

Si vous choisissez d'utiliser une fonte à espacement fixe, "i" et"m" auront la même taille, aussi votre texte ressemblera à quelque chose comme ça:

Ces carrés rouges n'apparaissent pas à l'écran, je les ai dessiné simplement pour que vous vous rendiez bien compte que tous les caractères ont la même largeur. Voici d'ailleurs le mêm texte sans les carrés rouges:

Voici une définition de fonte à espacement fixe:

font mon_nom_de_fonte = <nom_de_la_bitmap>, largeur_du_caractere, hauteur_du_caractere; // fonte à espacement fixe

- mon_nom_de_fonte est le nom que je souhaite donner à notre fonte, par exemple adventure_font;
- nom_de_la_bitmap est le nom de l'image bitmap utilisée pour la fonte;
- largeur_du_caractere est la largeur du caractère (souvenez-vous que tous les caractères ont la même largeur);
- hauteur_du_caractere est la hauteur du caractère.

Et voici un exemple de fonte à espacement fixe:

font adventure_font = <adventure.pcx>, 20, 15; // utilise une image bitmap nommée adventure.pcx, un caractère faisant 20x15 pixels.

Tout ceci est bien joli, mais qu'en est-il de cette image bitmap? Bien, si vous souhaitez utilisez une fonte à espacement fixe vous devez créer tous les caractères par vous même. Vous créez un rectangle noir (RVB = 000) et vous dessinez vos caractères à l'intérieur. La séquence alphanumérique à l'intérieur de votre image doit correspondreau jeu de carctère utilisé par le script. Ici un exemple (vous pouvez ignorer les petits carrés verts ou vous pouvez ahjouter d'autres caractères à la fonte):

Les caractères doivent être rangés sur 4 rangs (32 caractères x 4 rangs dans mon exemple) ou sur 8 rangs. Si vous ne prévoyez pas d'utiliser les lettres mais uniquement les chiffres vous pouvez créer une petite image de fonte comme ceci (11 caractères x 1 rang):

note Importante :l'image bitmap doit avoir exactement 11 fois (11 x 1), 128 fois (32 x 4) ou 256 fois (32 x 8) la taille d'un caractère donné. Si vous ne respectez pas cette règle, vous aurez une eereur en voulant utiliser votre fonte.

L'image bitmap pour ces fontes à espacement fixe ne paraît pas simple à créer, n'est-ce pas? Avant de vous arracher les cheveux, sachez que vous pouvez trouver un générateur de fonte sur la page des outils Conitec. Vous aurez juste à choisir le nom de votre fonte, sa taille et à presser un bouton pour que l'image bitmap soit générée automatiquement.

Voici les pour et les contre pour ces 2 types de fontes:

Alors quel type de fonte allez-vous utiliser? Serait-ce une fonte true type ou une fonte à espacement fixe? Les textes sont mieux si vous utilisez une fontre true type mais vous ne pouvez pas vous permettre d'employer une police qui n'est pas installée sur tous les PC. Une fonte à espacement fixe peut-être utlisée sur tous les PC car vous distriburez son image bitmap avec votre jeu.

Regardez comment ces différentes fontes se présentent à l'écran et vous pourrez ainsi mieux choisir le meilleur type pour votre projet; je vous encourage d'ailleurs à utiliser les 2 types pour le même projet si vous en avez besoin.

Démarrez Sed et chargez le fichier script07_2 (dernier avertissement: ne pas oublier de sélectionner le nom du fichier script dans Options -> Configuration):

Ce script inclut 2 définitions de fonte et 2 textes qui utilisent différentes fontes et la même chaine de carctères test_str string. Exécuter le test du script script7_2 :

Je ne vous en voudrais pas si vous voulez voir à quoi ressemble l'image bitmap system.pcx; vous pouvez la trouver et l'ouvrir dans le répertoire \workshop07 folder (où pourrait-elle être autrement, je vous le demande?) ou vous pouvez jeter un oeil à l'image ci-dessous:

system.pcx = l'image bitmap utilisée pour la fonte à espacement fixe.

Je vous ai dit que le moteur ne s'inquiétera pas de savoir si les lettres ou les figures peintes sur la fonte sont jolies ou pas ; vous pouvez utiliser des textes et des chiffres pour montrer des images, des symboles étranges et ainsi de suite. Voici un exemple d'un d'ateliers multijoueurs d'Alain Brégeon qui peut être téléchargé sur la page de téléchargement Conitec :

Si la fonte est appelée icons.bmp, sa définition ressemblera à cela:

font icons_font = <icons.bmp>, 18, 30;

Définissons un panneau qui utilise cette fonte et un digit:

panel
some_pan
{
pos_x = 0;
pos_y = 0;
digits = 410, 200, 2, icons_font, 1, picture;
flags = overlay, refresh, visible;
}

Si la variable appelée picture est égale à 2, le "chiffre affiché sera une roquette blanche, si picture = 3 ce sera un petit coeur rouge. Si picture = 4 nous verrons une petite roquette rouge etc. Vous pouvez remplacer les symboles par un alphabet martien ou tout ce que vous voulez d'autres

Prêt à relever un défi? Essayez d'écrire le code qui bascule la fonte pour les 2 textes, 3 secondes après le chargement du niveau comme ci-dessous:

3 secondes après....

Solution: ajouter ces 3 lignes de code dans la fonction main:

function
main()
{
level_load
(work07_wmb);
sleep(3); // wait for 3 seconds
fixed_width_txt.font = arial_font; // bascule les fontes
true_type_txt.font = system_font;
// pour les 2 textes
}

Suivant: Position, angle et redimensionnement


workshop08

Précédent: Chaînes, textes et fontes

Position, angle et redimension (scale)

Si vous n'aimez pas écrire du code du tout, vous serez heureux d'apprendre que cet atelier va vous apprendre des choses utiles sans que vous ayez besoin de saisir la moindre ligne de code C-Script. Nous allons apprendre ce qui concerne la position des objets dans notre monde 3D, ses angles et le redimensionnement (scale).

Démarrez WED et ouvrez le niveau \workshop08 qui se trouve dans le répertoire:

Vous pouvez voir une pièce qui parait plutôt bien. Je parie qu'elle serait en core meilleure si nous exécutions le niveau aussi compilez-le et exécutez-le.

Si vous vous dites, oui c'est pas trop mal, alors montrez-moi mieux, s'il vous plait?

Je vous ai déjà dit que si nous n'écrivions pas du code pour changer la position de la caméra (notre "fenêtre" à l'intérieur du monde 3d) le moteur la placera à l'origine à chaque fois que vous démarrerez un niveau. Laissez le niveau en exécution et pressez la touche F11 - vous pouvez voir de nombreuses informations à l'écran mais nous nous intéresserons qu'a quelques unes d'entre elles:

Les 2 colonnes (xyz et ang) montre la position de la caméra et ses angles. Pressez la touche 0 pour libérer la caméra puis déplacez là en utilisant les touches de direction et la souris. J'ai bougé la caméra un petit peu et voici ce que ça donne:

Je trouve cette position de caméra meilleure car elle me permet de voir une plus grande partie du niveau. 5 valeurs sur 6 ont changé pour les colonnes "xyz" et"ang"; Il est clair que la caméra a changé ses positions xyz et 2 de ses angles.

Comment puis-je paramétrer une certaine position pour un objet donné? Jetez un coup d'oeil sur l'écran ci-dessous:

Nous pouvons paramétrer le x et le y pour chaque objet en changeant sa position dans la vue du haut (XY) et nous pouvons changer la hauteur (z) de l'objet en changeant sa position sur la vue arrière (XZ) ou la vue de côté (YZ). Clic droit sur un des blocs du niveau, choisissez propriétés (Properties) puis Position et vous verrez l'image suivante:

La première rangée donne les coordonnées pour le bloc du niveau en x (-375), y (-54) et z (-259.996). Changez une de ces valeurs et vous verrez que le bloc sélectionné (le rectangle rouge dans l'image ci-dessus) changera sa position, decette façon vous pouvez utiliser WED pour positionner n'importe quel objet à une certaine position dans le niveau.

Truc:Vous pouvez également changer la position X de votre objet dans la vue arrière (back) de WED et la position y dans la vue de côté (side).

La seconde rangée dans la fenêtre des propriétés de l'objet - Rotate - donne l'angle de l'objet sélectionné. Que sont-ces 3 angles ? Leurs noms sont pan, tilt et roll et ce sont les angles Euler; et si vous ne savez pas à quoi ils correspondent cette figure va vous éclairer:

Je ne voulais pas vous laisser jouer avec un grand avion dans une si petite pièce mais Anakin Skywalker demande pourquoi nous ne le ferions pas? Clic droit dans la vue du dessus dans WED (Top), choisissez Add Model et cliquez sur mig.mdl:

Ne vous avais-je pas dit que ce serait un grand avion dans une petite pièce? Ne soyez pas désolé, nous ne le ferons pas voler, essayez de placer l'avion près du centre de la piècecomme sur mon image puis cliquez sur lui, choisissez Properties -> position et jouez avec les 3 valeurs de "Rotate" pour changer ses angles. Vous noterez que lorsque vous placez un modèle dans votre niveau, l'éditeur de niveau donne un angle pan initial de 90 degrés. Assurez-vous d'avoir bien compris à quoi servent les 3 angles pan, tilt et roll car nous nous en servirons souvent dans les prochains ateliers..

La dernière rangée de valeurs dans "Object Properties" correspond àu redimensionnement (Scale) de l'objet. Clic droit sur l'avion et redimmensionner le en utilisant des valeurs plus grande que 1 pour augmenter sa taille et plus petite que 1 pour réduire sa taille.

Revenons au test de notre niveau, le fichier script08 quiexécute le niveau n'a que quelques lignes de code:

Qu'est-ce que vous dites? J'avais promis que nous n'écririons pas une seule ligne de code pour cet atelier, ok alors restons en la.


workshop09

 Précédent: Position, angle et redimensionnement

Les entités

Les entités sont des objets extérieurs qui peuvent être ajoutées à vos niveaux. Il y a 4 types d'entités : les modèles, les sprites, les cartes (map) et les terrains.

Les entités "modèle"

Un modèle est un objet 3D animé, stocké dans un fichier dont l'extension est "mdl". Les modèles peuvent être créés avec un logiciel de modelage comme Med (inclu dans 3DGS), 3D Studio Max, Maya, Lightwave, Milkshape, etc. Un modèle est composé de plusieurs triangles (également appelés faces ou polygones) collés ensemble et recouvert d'une "peau" (skin). A chaque fois que nous avons besoin d'un objet 3D animé (pour le joueur, ses ennemis, des animaux etc) nous utiliserons un modèle. Nous devons utiliser des modèles pour tous les personnages de notre jeu.

Si vous prévoyez de créer un jeu de qualité commerciale, vous allez devoir compter vos polygones. Si chaque personnage de votre jeu utilise des milliers de polygones, vous aurez besoin d'un pc haut de gamme pour pouvoir exécuter votre jeu.OK, vous avez un PC haut de gamme, mais qu'en est-il de vos clients? Ont-ls tous le dernier PC disponible sur le marché? Je ne le pense pas...

Cela peut paraître incompréhensible à un jeune apprenti 3DGS, mais nous ne vivons pas dans un monde virtuel "parfait". Si vous projetez de gagner de l'argent à partir de votre jeu vous devez le préparer soigneusement. Combien de monstres peuvent être visibles en même temps ? Pour le cas où j'utilise des modèles pour mes arbres n'ai-je pas intérêt à 'employer de simples images 2D pour eux ? Est-ce que j'ai vraiment besoin d'une superbe explosion à cet endroit du jeu?

Laissez moi créer un niveau de test sur mon PC. C'est un Pentium 4 tournant à 2GHz avec une carte graphique GeForce4 TI 4200. Bien, j'ai créé un niveau avec 8 sphères, chaque sphère ayant 10 000 polygones. Ce qui me fait un total de 80 000 polygones et le taux d'affichage est d'environ 30 fps (frames par seconde) ce qui est honorable pour un jeu de tir. Je sais que mes clients potentiels on des PCs plus lents, je décide donc de fonctionner avec 30 000 polygones. Si je veux créer un jeu de stratégie 3D et que je prévoie d'avoir jusqu'à 50 unités visibles sumultanément à l'écran, ces unités devront avoir 30 000 / 50 = 600 polygones chacunne, n'est-ce pas?

C'est toujours une bonne idée d'essayer de réduire le nombre de polygones (le nombre de triangles) de vos modèles au plus petit possible. Jetez un oeil sur les images ci-dessous:

Les 2 soldats semblent identiques et pourtant le modeleur a réussi à supprimer 250 polygones pour le modèle de droite. Ce qui permet de placer 46 modèles de ce type dans mon niveau au lieu de 33 et tous ces modèles pourront être visibles en même temps!

Truc Important: Seuls les modèles qui sont visibles à l'écran ont une incidence sur le taux d'affichage. Si vous avez 300 ennemis dans votre jeu mais que le joueur ne peut en voir que 10 en même temps, ne vous inquiétez pas le moteur ne gèrera que ces 10 ennemis et le taux d'affichage restera élevé.

N'importe qui peut créer un modèle avec beaucoup de polygones mais un bon modeleur pourra lui créer un modèle qui sera génial en apparence et qui pourtant ne contiendra que peu de triangles. Souvenez-vous que non seulement les personnages sont d'énormes consommateurs de ressources systèmes mais si vous avez une maison, une voiture ou tout autre entité dans votre niveau, il utilisera également des ressources systèmes. La bonne nouvelle c'est qu'Acknex fournit les outils permettant d'optimiser votre niveau, nous discuterons de cela dans la seconde partie du manuel C-Script.

Ouvrez n'importe quel modèle dans l'éditeur de modèles (Med), choisissez View -> Model Properties et vous pourrez voir son nombre de polygones (faces):

Les entités "Sprite"

Les sprites ne sont rien d'autre que des images 2D créées avec un programme de peinture. Ce ne sont pas des objets 3D; pour l'instant ils nous suffit d'imaginer que ce sont de minces feuilles de papier. Nous pouvons utiliser les sprites pour des panneaux, des signalisations routières, des jeux 2D, des effets spéciaux...nous pouvons également les utiliser pour simuler des objets 3D comme des arbres, des buissons, de l'herbe etc.

Créer une image bitmap dans votre programme favori de peinture, sauvez là au format pcx, bmp ou tga, copiez la dans votre répertoire de jeu (le même répertoire dans lequel vous avez sauvegardé votre fichier de niveau wmp) et vous pouvez ensuite l'ajouter dans votre niveau comme indiqué ci-dessous:

Chaque sprite peut avoir des parties transparentes, de la même façon qu'un panneau en mettant son drapeau overlay à 1. Vous devez utiliser la valeur RVB = 000 pour les parties transparentes:

Maintenant regardons ce que donne notre sprite dans un niveau de test:

Si le joueur n'a pas à monter sur le mur, nous n'avons pas besoin d'un modèle 3D pour le pot, un simple sprite fait l'affaire et il utilisera moins de mémoire vidéo.

Les sprites peuvent être paramétrés de différentes manières:

1) Sprites orientés, comme une peinture accrochée au mur;

Si je tourne autour d'un sprite orienté je peux voir qu'il ne s'agit de rien d'autre qu'un objet 2D, aussi nous utiliserons le sprite orienté pour un dessin sur un mur, une peinture, une tâche de sang sur le sol, etc.

2) Les sprites font face au joueur en permanence.

C'est le plus courremment utilisé, celui qui donnera l'impression d'objet 3D et qui optimisera aux mieux les performances sur des PC peu performants. Vous pouvez tourner autour autant que vous voulez, il appara^tra toujours face à vous.

Comment créons-nous un sprite normal? La réponse est simple : nous ajoutons notre sprite dans le niveau dans Wed et c'est tout!

Comment créons-nous un sprite orienté? Nous ajoutons notre sprite dans notre niveai via WED puis nous changeons un ou plusieurs de ses angles. De cette façon nous pouvons créer un sprite qui peut être utilisé pour un tapis, un tableau, etc, dépendant de la valeur de ses angles. Clic droit sur le sprite dans Wed, choisissez "Object Properties", puis Position:

L'ovale rouge montre les 3 angles qui peuvent être changés. Ces valeurs par défaut sont 90, 0, 0 pour les angles pan, tilt et roll et sont celles utilisées pour un sprite normal (non orienté!). Ajustez n'importe lequel de ces angles et vous transformerez un sprite
normal en sprite orienté. Vous pourriez mettre l'angle pan à 90.001 degrés, l'angle tilt à 0.001 ou 67.005 degrés ou l'angle roll à
55.000 ou 255.000 degrés ; n'importe quelle valeur fonctionne mais vous devez vous assurer que vous aimez ce que vous obtenez dans Wed.

Une dernière chose avant de passer aux entités de carte, certaines vieilles cartes 3D ne peuvent pas afficher les sprites de plus de 256x256 pixels. Assurez-vous d'avoir des sprites de 256 x 256 pixels ou moins si votre jeu doit s'exécuter sur des cartes Voodoo2 ou Voodoo3.

Les entités cartes (Map Entities)

Une entité carte (map entity) est un objet 3D fixe, créé par l'éditeur de niveau WED comme étant des blocs géométriques séparés et stockés dans un fichier wmb. Les entités "carte"Map peuvent être utilisées pour des parties d'un niveau appelées à se déplacer ou à disparaître comme un trou, un mur cassable, des portes, des plateformes, des ascenseurs, des véhicules etc. Ces entités ne sont rien d'autre que des petits niveaux compilés aussi vous ne pouvez pas changer leur taille durant l'exécutio - utilisez un modèle ou un sprite si vous avez besoin de jouer sur la taille. Vous pouvez convertir n'importe quel fichier de niveau (cela peut être une simple porte) en entité carte en chargeant ou créant le fichier wmp dans Wed, en le compilant et en copiant le fichier wmp et le fichier résultant wmp dans le répertoire courant. De cette manière on peut trouver des portes prédéfinies, des fournitures, des véhicules, etc qui peuvent être compilés dans le répertoire \prefabs à l'intérieur de votre répertoire 3DGS.

Les entités "Terrain"

Un terrain consiste en une grande texture mappée sur une grille rectangulaire de différentes hauteurs comme sur l'image ci-dessous:

La texture recouvrant le terrain peut contenir des routes, de la neige, des rochers, etc. Jetons de nouveau un oeil sur ce terrain, cette fois-ci il est recouvert d'une texture:

Cette image provient de l'éditeur de modèle MED. Son rendu est meilleur lorsqu'il est utilisé dans le jeu!

Vous pouvez créer des entités terrain dans Med en utilisant son merveilleux outil "Magnet" ou vous pouvez importer des "cartes de hauteur" (height maps) créées par d'autres programmes (Bryce, Terragen, etc). Une image de hauteur standard est une image en échelle de gris qui ressemble à celle présentée ci-dessous:

Cette image peut être convertie en une entité terrain par Med; les zones blanches représentant les hautes altitudes tandis que les zones noires représentes les basses altitudes.

Les entités terrain sont stockées en fichier avec une extension .hmp; elles ne fonctionnent pas avec la version standard du moteur. Néanmoins, vous pouvez créer des terrains sympas en utilisant Wed et un niveau de blocs, certaines grosses compagnies continuent de créer leurs terrains en blocs, ils gardent un bon aspect et nécessite moins de mémoire..

Voici un terrain fait de blocs:

Vous pouvez trouver une description détaillée des différents types d'entités dans le fichier d'aide de Wed. Les entités peuvent être créées en utilisant une des méthodes suivantes:

- en la plaçant dans le niveau par l'intermédiaire de l'éditeir de niveau Wed, comme sur l'image ci-dessous;

- en la créant dans le niveau lors de son exécution en utilisant l'instruction ent_create comme ceci;

ent_create (drone_mdl, temp, start_drone); // crée un drone

- en écrivant une définition d'entité ("entity") dans le script:

entity rocket_ent
{
type = <launcher.mdl>;
layer = 10;
view = camera;
x = 20;
y = -10;
z = -10;
}

Nous ne discuterons pas du code ici mais je voulais que vous en ayez un aperçu pour l'instant, sachant que ça n'est pas trop compliqué de travailler avec les entités lorsque vous utilisez le moteur Acknex.

Pourquoi voulez-vous créer une entité alors qu'on peut l'ajouter dans le niveau en utilisant Wed? Simplement peut-être parce que vous voulez avoir des balles visibles pour votre arme, ou une gerbe de particules lorsque la balle ricoche sur un mur. Si vous êtes appelés à utilser plusieurs centaines de balles avec une ou plusieurs armes, il ne serait pas raisonnable de toutes les placer dans votre niveau, c'est plus facile de les créer par ent_create au fur et à mesure de leur besoin.

Les entités qui sont créées avec la définition "entity" doivent être utilisées pour les armes du joueur, ses mains, etc parce qu'elles ont une propriété spéciale, elles sont visibles pour le joueur mais elle n'existe pas réellement dans notre monde 3D. Ces entités peuvent être des modèles 3D mais elles ne pourront jamais être touchées ou elles ne toucheront jamais rien dans le niveau, de cette façon vous pouvez être sur qu'elles ne pénètreront jamais dans un mur, ce qui est un avantage pour nous.

Nous approchons de la fin de cet atelier à présent mais je souhaite vous soumettre ce tableau, lisez-le attentivement et vous serez capable de choisir le type d'entité le plus approprié à chaque fois.

Suivant: Actions


workshop10

 Précédent: Les entités

Actions

Une action est une fonction spéciale qui peut être attachée à une entité, le joueur, un ascenseur, un monstre, une arme, etc. Vous pouvez attacher une action à une entité modèle, sprite, carte ou terrain. Toutes les actions créées dans notre script apparaissent dans la liste des actions de Wed comme sur l'image ci-dessous:

Jetons un coup d'oeil sur ce qui différencie une action d'une fonction:

Une action et une fonction ont des définitions identiques, regardez ces exemples:

action
add_numbers
{
b = a + 5;
}

function
add_numbers( )
{
b = a + 5;
}

L'action et la fonction ont l'air d'être les mêmes, néanmoins il y a une grande différence entre elles:

- Une fonction a besoin d'être appelée si vous voulez qu'elle s'exécute (re-lire le 3ème atelier pour plus de détails)
- Une action a besoin d'être attachée à une entité si vous voulez qu'elle s'exécute.

Les actions doivent être utilisées uniquement lorsque vous voulez changer les propriétés d'une ou plusieurs entités, utilisez les fonctions lorsqu'elles n'ont aucun rapport avec des entités (par exemple lorsque vous ajoutez des nombres comme sur l'exemple ci-dessus).

Prêt pour une action? Démarrez Wed et ouvrez le niveau nommé work10:

Exécutez le niveau et regardez ::

L'avion tourne sur lui même. Si vous avez étudié l'atelier 8 (Position, angle et redimensionnement) vous savez que l'avion change son angle pan continuellement.

Il est temps pour nous de voir le script associé au niveau, aussi démarrez Sed et ouvrez script10:

Avez-vous remarqué que les scripts sont de plus en plus court au fur et à mesure que nous avançons dans notre apprentissage? Peut-être que pour le dernier atelier il n'y aura plus qu'une ligne de code, qui sait...
Une bonne partie de ce code est facile à comprendre car nous l'avons vu à maintes reprises, aussi concentrons-nous sur le code utilisé par l'avion.

Nous avons créé une action nommée rotate_plane aussi son nom apparait dans la liste des actions. Bien mais que faire à partir de cette liste d'action et surtout où puis-je la voir?

Basculez sur Wed, sélectionnez le modèle de l'avion dans la vue de dessus, clic droit et choississez "Properties":

Cliquez sur l'onglet "Behaviour"1 (comportement) et sur "Choose Action" 2(choisir une action):

Vous pouvez voir la fenêtre "Choose Action" qui nous permet de sélectionner l'une des actions présentes dans notre script:

Dans notre script nous n'avons qu'une seule action nommée rotate_plane aussi c'est le seul nom que nous voyons dans la liste "Choose Action". Revenons à notre code:

action rotate_plane
{
while (1)
{
my.pan = my.pan + 1;
wait (1);
}
}

Certaines des actions ou des fonctions dans notre jeu ont besoin de s'exécuter sur une longue période de temps - certaines s'exéécutant même à partir du moment ou on démarre le jeu jusqu'à ce que le jeu s'arrête! Si vous voulez créer un jeu qui ressemble au "dragueur de mine" ou vous devez bouger la souris en permanence faute de quoi vous ne pourriez pas cliquer sur les carrés sans parler que vous ne pourriez pas sortir du jeu faute de pouvoir cliquer sur le "x" dans le coin supérieur gauche de la fenêtre. Toutes les fonctions et les actions que nous avons étudiées jusqu'à présent faisaient très bien leur travail mais ne s'exécutaient pas en permanence, elle réalisaient quelques choses puis s'arrêtaient de fonctionner. . L'avion que nous utilisons dans l'exemple de cet atelier tourne en permanence, aussi nous devons utiliser une instruction particulière qui permet à une action de s'exécuter en permanence.

Nous avons besoin d'apprendre comment fonctionne une nouvelle chose, la boucle while (1). Qu'est-ce qu'une boucle? Ce n'est rien d'autre qu'un bout de code qui répète le jeu d'instruction placé entre les accolades, une boucle typique ressemble à ceci:

while (telle condition est vraie)
{
// répète les instructions qui sont placées à l'intérieur de ces accolades
}

L'action ci-dessus utilise while (1); qui est la forme raccourcie de "aussi longtemps que 1 = 1" ce qui signifie que la boucle va s'exécuter en permanence. Vous utiliserez une boucle while (1) à chaque fois que vous aurez besoin qu'une action s'exécute en permanence, ce qui peut s'appliquer au joueur, à un ascenseur, un ennemi etc. Bien, donc la première ligne à l'intérieur de notre action nommée rotate_plane demande à l'entité de répéter en permance le contenu de la boucle, mais quel est le contenu de notre boucle qui doit être répété en permanece? Seulement 2 lignes de code:

my.pan = my.pan + 1;
wait (1);

La première ligne de code ajoute 1 degré à l'angle pan de l'avion. L'avion démarre avec un angle pan de 90 degrés (vérifiezson angle pan dans Wed si vous ne me croyez pas) et ensuite son angle pan prendra les valeurs 91, 92, 93, .... degrés, ainsi l'avion tournera autour de son angle pan.

Mais à quoi sert l'instruction "wait (1);" ? Laissez moi d'abord vous demander si vous avez entendu parler du multitâches? C'est la capacité d'exécuter plusieurs programmes simultanément. On peut imaginer que pendant que vous lisez cet atelier, vous écoutez de la musique sur ce même pc, que de temps en temps vous exécutiez le moteur acknex stoujours sur le même pc, peut-être y-a-t-il un antivirus qui s'exécute en tâche de fond... tous ces programmes donnent l'impression de s'exécuter en même temps parce que l'ordinateur bascule d'une tâche (programme) à une autre très rapidement, donnant l'impression que toutes les applications fonctionnenet en même temps.

La même chose doit se produire avec la boucle while; nous avons besoin de permettre aux autres actions et fonctions de s'exécuter dans notre jeu. Une boucle while qui ne s'arrêterait pas de temps en temps occuperait toutes les ressources systèmes parce qu'elle exécuterait les instructions de la boucle encore et encore et encore et encore, faisant même que l'horloge qui se trouve en bas à droite de votre barre des tâches ne pourraient se mettre à l'heure!

Bien alors comment suspendre une boucle while? La méthode la plus simple est d'insérer une instruction "wait (1);" la boucle répète les instructions placées entre les accolades puis s'arrêtera pour un cycle lorsqu'elle rencontrera l'instruction wait (1). C'est un tout petit changement mais cette ligne va permettre aux autres actions et fonctions d'exécuter leur prore code.

Il est temps de parler du cycle (frame) et du taux d'affichage (frame rates). Ce que vous voyez à l'écran lorsque vous jouez à un jeu n'est rien d'autre qu'une série d'images fixes qui sont affichées les unes après les autres. Si votre pc peut afficher 50 images en une seconde, le jeu s'exécutera à 50 images par seconde.Le taux d'affichage dans ce cas sera de 50 frames par seconde où 50 fps. Une instruction wait (1) dit à la fonction ou à l'action qui l'a contient de s'arrêter pendant que le pc est en train d'afficher une de ces 50 images, chaque seconde.

Truc important
Chaque boucle while (1) doit inclure une instruction qui l'interrompt, normalement en utilisant une instruction "wait (1);". Si vous oubliez d'ajouter une instruction "wait" ou"sleep" à l'intérieur de la boucle while, le moteur donnera un message d'erreur qui ressemblera à ceci:

Lisez la seconde partie du manuel, "C-Script keywords" pour en savoir plus sur les instructions "wait" et "sleep".

Créons une nouvelle action, copier / coller le code ci-dessous à la fin de votre fichier script10:

action
change_roll
{
while (1)
{
my.roll = my.roll + 1;
wait (1);
}
}

Le script final doit ressembler à celui-ci:

Sauvegardez le script, basculez vers Wed, clic droit sur la vue de dessus et ajoutez un nouveau modèle mig comme indiqué ci-dessous:

Assurez-vous que le nouveau modèle soit visible facilement, choisissez une position idéale pour cela. Oh, vous ne savez pas comment procéder pour cela?

La caméra (notre vue à l'intérieur du monde 3D) peut-être controlé en utilisant des instructions C-Script, mais pour une bonne compréhension de l'ensemble je n'écrirais pas de code pour la caméra tant que nous n'aurons pas appris un minimum de chose. Par défaut la caméra appara^tra à l'origine :

x = 0
y = 0
z = 0

Jetez un oeil sur l'image ci-dessous pour voir le positionnement de la caméra dans Wed:

La camérra regarde vers la droite, aussi si je veux voir le nouvel objet dans mon niveau sa valeur x doit être supérieure à 0. Jetez un oeil sur l'image ci-dessous (avec un seul mig) pour voir comment j'ai choisi la position pour le premier avion:

Regardez la vue de dessus, il est clair que pour que le joueur pourra voir l'avion lors de l'exécution du jeu. Si vous avez vos propres positions dans la vue du dessus dans Wed, vous devez juste vous assurer que l'avion est à la bonne hauteur ce qui peut être fait à l'aide des vues arrière ou côté. Je vous encourage à ajouter un second modèle de mig comme montré ci-dessous:

Le second modèle d'avion (le rouge) a un x plus grand et un z légèrement plus grand que le premier modèle, vous pouvez le placer à la perfection par un clic droit et en choisissant ses valeurs x, y et z:

Cliquez sur "World positions" si vous en avez besoin; ce sont les coordonnées pour le monde "réel" 3D. Maintenant cliquez sur l'onglet "behaviour" dansd la fenêtre "Object Properties" comme montré ci-dessous puis cliquez sur le bouton "Choose action" :

Vous voyez apparaître la fenêtre "Choose Action" qui contient 2 actions dans la liste:

(Si l'action nommée change_roll n'apparaît pas dans votre liste d'action c'est que vous avez oublié de sauvegarder le fichier script modifié. Sauvegardez-le à présent puis chargez de nouveau le niveau appelé work10)

Cliquez sur change_roll, pressez OK et félicitez-vous, vous venez en fait d'assigner votre première action au deuxième modèle d'avion. Le nom de cette action est à présent change_roll:

Fermez la fenêtre "Object properties", sauvegardez le niveau, compilez-le et exécutez-le, vous devriez voir l'image suivante:

Cela vous permet de voir comment fonctionne l'angle roll! Vous pouvez déplacer les avions sur la gauche ou sur la droite dans Wed si vous n'aimez pas leur position changez leur valeur x et/ou y dans la vue de dessus ( top view) dans Wed et mettez différentes hauteurs (z) en utilisant les vues arrière (back) ou de côté (side).

Je vous encourage vivement à ajouter un troisième avion et de créer une nouvelle action qui changera son angle tilt dans une boucle while. Ne lisez pas la solution ci-dessous, je vous surveille!

Solution: ajouter une nouvelle action à la fin de votre fichier script et attachez là au troisième modèle d'avion:

action
change_tilt
{
while
(1)
{
my.tilt = my.tilt + 1;
wait (1);
}
}

Suivant: Les pointeurs


workshop11

 Précédent: Les actions

Les pointeurs

N'importe quel pointeur stocke une référence à un objet. Imaginons la situation suivante où vous désirez créer un clone de pong en utilisant le moteur Acknex:

Vous voulez que la raquette de gauche soit contrôlée par le joueur et celle de droite contrôlée par l'ordinateur. Le problème est... comment allez-vous dire dans votre code qui est le joeur et qui est l'ordinateur? La réponse est simple, vous créez un pointeur, qui est juste un autre nom pour l'objet. La définition typique d'un pointeur est la suivante ::

entity*  le_joueur;

ou

function*  check_status;

ou

string*  mon_nom;

ou

panel*  game_over;

ou

bmap*  health_picture;

Bien, vous pouvez voir que nous pouvons définir des pointeurs pour les entités, les fonctions, les chaînes de caractères, les panneaux et les images bitmaps. Nous avons simplement ajouté un "*" au mot clé de l'objet et nous avons créé un pointeur.

Je vous sents abasourdi par ce que vous venez d'apprendre, aussi nous allons démarrer un exemple : démarrez Wed et ouvrez le fichier du niveau nommé work11 qui se trouve dans le répertoire \workshop11:

Le niveau est une version légèrement modifiée du niveau avec la maison et le modèle du magicien:

Ce niveau a 2 modèles de magicien; compilez-le et exécutez-le immédiatement:

Ah je vois, les magiciens jumeaux sont debout et en rouge et en bleu. Ils ne font rien de spécial mais il n'exécutent pas toutes leurs animations comme dans le premier atelier; ceci tout simplement parce qu'ils ont une action qui leur est affectée. Attacher n'importe quelle action à n'importe quelle entité fera qu'il n'y aura pas d'animation chaotique.

Il est temps d'écrire un peu de code à la console, pressez la touche Tab sur votre clavier et entrez la ligne suivante:

wizard.x = 300;

Le magicien rouge sera plus proche de la caméra!

Mais pourquoi est-ce le magicien rouge qui a bougé, pourquoi ce n'est pas le magicien bleu? Ou pourquoi ne bougent-ils pas tous les deux en même temps? Et pourquoi on ne voit pas la maison bouger?

Je suis désolé de de voir poser autant de questions à la fois, mais il y a une seule phrase pour répondre à toutes ces questions: j'ai utilisé un pointeur pour le magicien rouge. Vous voyez, nous vivons dans un monde cruel. Ces méchant ordinateurs n'ont aucune pitié pour nous, pauvres humains. Vous et moi savons à quoi ressemble le modèle du magicien mais l'ordinateur, lui s'en moque complètement. Si vous demandez à l'ordinateur de déplacer le magicien rouge il va vous rire à la figure il ne le connait pas et se moque éperdument de savoir qui est et ou se trouve le magicien rouge. Vous devez donc utiliser un pointeur pour chaque entité qui nécessite un traietement spécial de la part de votre ordinateur.

Démarrons Sed; nous allons nous intéresser au contenu du fichier script nommé script11:

Merci mon Dieu! Le script ne paraît pas du tout compliqué!

Nous paramétrons la résolution d'écran et ssa profondeur de couleurs, nous définissons une chaîne nommée work11_wmb (le niveau que nous allons charger) et nous définissons un pointeur nommé "wizard". Regardons d'un peu plus près cette ligne de code:

entity* wizard;

Nous avons défini un pointeur qui pourra être utilisé par une entité et nous l'avons appellé "wizard" (sans les guillemets bien entendu). Nous pouvons utiliser n'importe quel autre nom ici, ça n'a aucune importance si nous utilisons un pointeur nommé robot_12 pour une entité singe.

La fonction main charge simplement le niveau nommé work11_wmb. Revenons à nos pointeurs, nous allons regarder l'action nommée wizard_with_pointer:

action
wizard_with_pointer
{
wizard = me;
my.ambient = 100;
}

Nous avons défini un pointeur nommé wizard, n'est-ce pas? La première ligne de code assigne le pointeur à l'entité rattachée à cette action. En d'autres mots, "wizard = me;" signifie, c'est moi qui m'appelle wizard! A partir de cette ligne l'entité attachée à cette action sera connue sous le nom de "wizard" ! Et vous savez quoi? L'action nommée wizard_with_pointer est attachée au modèle du magicien rouge c'est pourquoi le magicien rouge répond au nom de "wizard".

La seconde ligne de l'action met le drapeau ambien pour le magicien rouge à 100, ce qui le fera paraître plus lumineux. Curieux de voir la différence? Regardez l'image ci-dessous:

La seconde action ne contient pas de pointeur aussi elle se contente d'augmenter la valeur du drapeau ambient du modèle qui lui est attaché.

action wizard_simple
{
my.ambient = 100;
}

Bien et vous savez quoi de nouveau...cette action est attachée au modèle du magicien bleu. Oh, et j'oubliais de vous dire que "my" est également un pointeur! C'est un pointeur prédéfini aussi nous n'avons pas besoin d'écrire sa définition au préalable. Pas d'inquiétude, nous en apprendrons plus à son sujet vers la fin de cet ateleir.

Donc récapitulons, la définition d'un pointeur se fait en 2 étapes:

1) Nous définissons le pointeur en une simple ligne de code:

entity* horse;

2) Nous donnons ce nom à celui qui sera son propriétaire en plaçant une ligne qui contient son nom dans l'action qui nous intéresse:

action players_horse
{
horse = me;
............
}

A partir de maintenant vous êtes capable de contrôler l'entité qui à l'action players_horse qui lui est attachée en utilisant simplement la méthode du point: object.property

Amusons-nous encore un petit peu avec notre niveau de test, vous voulez bien? Exécutez le niveau de nouveau et tapez cette ligne de code à la console:

wizard.z = 100;

Le magicien a changé sa hauteur! Vous pouvez jouer avec ses valeurs x, y, z, pan, tilt, roll, invisible, transparent... Si vous voulez cacher le magicien tapez:

wizard.invisible = on;

et il disparaîtra! Tapez

wizard.invisible = off;

et vous devriez le voir réapparaître.

La bonne nouvelle c'est que vous pouvez modifier les propriétés du magicien rouge depuis d'autres actions ou fonctions de votre script. Copiez et collez le code ci-dessous à la fin de votre fichier script script10 :

function move_up()
{
wizard.z = wizard.z + 5;
}

on_u = move_up;

Le fichier script modifié doit ressembler à ceci:

Vous pouvez voir une action nommée move_up qui augmente la hauteur (z) du magicien de 5 quants, si sa position initiale était de 15 quants, cette fonction fera qu'elle vaudra 20 et ainsi de suite. that increases the height (z) of the wizard with 5 quants; if its initial height was 15 quants, the function will set it to 20 and so on. Maintenant cette ligne de code semble étrange:

on_u = move_up;

Bien, on_u signifie "lorsque le joueur presse la touche U sur le clavier" et move_up est le nom de la fonction, écrite sans parenthèses, sera exécutée chaque fois que nous presserons la touche "U" (ça n'a pas d'importance que l'on soit en majuscule ou pas). Donc à chaque pression de la touche "U" la fonction move_up ajoutera de nouveau 5 quants à la hauteur du magicien rouge.

Sauvegardez le script, exécutez le niveau et pressez la touche "U" plusieurs fois pour faire monter le magicien. Il est clair que la fonction nommée move_up() sait qui est "wizard".

Note finale: le pointeur le plus important utilisé par Acknex est"my". Revenons à l'action attachée au magicien bleu:

action
wizard_simple
{
my.ambient = 100;
}

La ligne de code à l'intérieur de l'action met le drapeau ambient à 100 pour n'importe quelle entité qui lui est attachée; "my.ambient = 100;" means "MOI, l'entité à qui cette action est attachée, doit mettre mon drapeau ambient à 100". Attachez cette action à un sprite et le drapeau ambient pour ce sprite sera mis à 100; attachez lui une entité wmb et il mettra son drapeau ambient à 100. On pourrait penser que "my" est le pointeur universel, chaque entité peut l'utiliser mais il reste inconnu en dehors de l'action ou de la fonction qui le contient . Si vous essayer de taper

my.invisible = on;

à la console ça ne fonctionnera pas parce que "my" est inconnu en dehors de toute action ou fonction, néanmoins le code ci-dessous rendra invisible l'entité qui lui est attachée:

action
hide_me
{
my.invisible = on;
}

Suivant: le branchement If - Else


workshop12

 Précédent: Les pointeurs

Branchement si - sinon (If - Else)

Si le montant de mes dettes est supérieur à 1500 €uros il va me falloir trouver un nouvel emploi, sinon je garde cet emploi..
Je vais très bien, merci. Je n'ai pas subitement perdu la raison, c'est juste un exemple pour illustrer le branchement "si - sinon" (if - else), le code associé est ci-dessous:

if
(mes_dettes> 1500)
{
trouver_nouvel_emploi(
);
}
else
{
garder_emploi_actuel( );
}

Vous utilisez l'instruction "if" (si) lorsque vous voulez que votre programme réagisse différemment en fonction de certaines conditions : entrée utilisateur, nombre aléatoire, le résultat mathématique d'une opération, etc. Voici la forùme de base d'une instruction "IF":

if (telle condition est vraie)
{
// exécute les instructions qui sont placées à l'interieur des accolades
}

Une forme un peu plus complexe de l'instruction "if" est listée ci-dessous:

if (telle condition est vraie)
{
// exécute les instructions
qui sont placées à l'interieur des accolades
}
else //sinon
{
// exécute
les instructions qui sont placées à l'interieur de ces accolades
}

Les instructions placées à l'intérieur des accolades du "else" sont exécutées uniquement si "telle condition" n'est pas vraie. Voici un exemple concret:

if
(my_age > 65)
{
revenu = 2000;
}
else
// age est inférieur ou égal à 65?
{
revenu = 3000;
}

Il est clair que mon revenu sera soit 2000, soit 3000 parce qu'une seule des branches sera exécutée (revenu = 2000 ou revenu = 3000, pas les deux).

Nous pouvons tirer quelques conclusions:
- l'instruction de branchement "si" démarre avec le mot clé "if" suivi d'une paire de parenthèses;
- la paire de parenthèses contient une expression ("telle condition") qui peut être vraie ou fausse;
- si l'expression est vraie, le jeu d'instructions placé à l'intérieur des premières accolades sera exécuté;
- si l'expression est fausse et n'utilise pas "else", le jeu d'instructions placé à l'intérieur des premières accolades est sauté (il n'est pas exécuté);
- si l'expression est fausse et que nous utilisons également un branchement "else", le jeu d'instructions placé à l'intérieur des premières accolades est sauté et le jeu d'instructions placé à l'intérieur des deuxièmes accolades sera exécuté.

Maintenant que nous en savons un peu plus, ouvrons le fichier script12 dans Sed:

Le code ne paraît pas très compliqué, nous avons les variables habituelles pour la résolution et les couleurs, une nouvelle variable nommée weight à qui nous attribuons une valeur initiale de 300, une chaîne qui est utilisée pour le nom du niveau et deux chaînes de caractères (strings): "Fluffy!" et "Skinny!". Nous affichons le texte en utilisant une fonte prédéfinie. La partie intéressante du code se situe dans la boucle while (1) placée à l'intérieur de la fonction main():

while (1)
{
if (weight > 200)
{
weight_txt.string = fluffy_str;
}
else
{
weight_txt.string = skinny_str;
}
wait (1);
}

J'espère que vous avez noté la présence de l'instruction "wait (1);" à l'intérieur de la boucle , cet instruction interrompt la boucle de temps en temps permettant aux autres actions et fonctions de s'exécuter dans le même temps. Le reste du code est simple: si weight est plus grand que 200, nous mettons fluffy_str comme chaîne utilisée par le texte nommé weight_txt (en utilisant la méthode du point); si weight est inférieur ou égal à 200, nous mettons skinny_str comme chaîne utilisée par weight_txt.

Exécutez le script et vous verrez le texte suivant au centre de votre écran:

Maintenant pressez la touche Tab sur votre clavier et tapez la ligne de code suivante à la console:

weight = 100;

Le texte change passant de "Fluffy!" à"Skinny!" parce que c'est la branche "else" qui est exécutée si weight est inférieur ou égal à 200.

Nous avons besoin d'une boucle dans ce cas car nous avons besoin de surveiller la valeur de "weight" en permanence afin de pouvoir afficher le texte approprié lorsque l'utilisateur tape une nouvelle valeur à la console.

Imaginons que vous souhaitez quitter le programme lorsque vous tapez cette line:

weight = 0;

à la console. Comment feriez-vous? Vous devez ajouter un nouveau "if" qui compare weight avec zéro; copiez et collez le code ci-dessous à l'intérieur de la fonction main:

if (weight == 0)
{
exit;
}

Le résultat doit être celui de l'image ci-dessous:

Les nouvelles lignes de code (en vert) ne paraissent pas trop compliquées, si weight vaut zéro alors le moteur s'arrête (souvenez-vous nous avons déjà vu "exit" dans un atelier précédent). Exécutez le script et tapez

weight = 0;

à la console. Le moteur s'arrêtera car le nouveau "if" a correctement fait son travail.

Attendez une minute! Pourquoi "==" dans la première ligne du code? Est-ce une faute de frappe? Non, non, ce n'est pas une faute de frappe. Lorsque vous comparez 2 expressions (weight et zero dans notre exemple) vous devez utiliser "==" à la place de "=", parce que une ligne de code qui ressemblerait ) ceci :

if (weight
= 0)
{
// do some stuff
}

signifie qu'on met weight à la valeur zéro au lieu de le comparer avec zéro. Le moteur exécute ce qui se trouve d'abord entre parenthèses (weight = 0) puis ce qui est à l'extérieur des parenthèses. Les types de Conitec nous ont facilité la vie, le moteur affichera un message d'erreur si vous utiliser un seul signe "=" pour comparer 2 expressions:

Truc important
Utilisez le double signe égal lorsque vous voulez comparer deux expressions à l'intérieur d'une boucle, d'un branchement "if", etc.

if (a == 3) // correct
{
do_some_stuff
}

if (a = 3) // mauvais!
{
do_some_stuff
}

Nous avons parlé un peu au sujet des expressions, mais qu'est-ce qu'une expression? Une expression (arithmétique) est une séquence de variables, nombres, opérateurs etc qui sont liés ensembleis a sequence of variables, numbers, operators, etc that are linked together. Bien que ce soit joli d'avoir de simples expressions comme celle-ci:

if
(energy < 50) // simple expression dans les parenthèses
{
health = health - 10;
}

il est également possible de travailler avec des expressions beaucoup plus compliquées comme celle-ci par exemple:

if ((armor + energy * 0.25) > (health * (1
- class / 3))) // expression plus compliquée
{
health = health + 5;
}

Truc important
Vous pouvez combiner autant d'expressions que vous voulez, en utilisant les parenthèses comme dans l'exemple ci-dessus. Les mêmes règles que celles que vous avez apprises à l'école en mathématiques s'appliquent ici. Désolé mais vous devez connaitre les mathématiques si vous voulez être un bon programmeur.

Regardez le tableau ci-dessous qui récapitule les façons pour comparer 2 expressions entre elles. (vous pouvez utiliser ce tableau pour les instructions "if", "while", etc):

Quelques fois vous aurez besoin de vérifier que plusieurs conditions soient vraies en même temps. Imaginons que vous souhaitiez tirer une balle, le code devra s'assurer que :
a) Votre santé (health) est supérieure à zéro (les joueurs morts ont rarement l'occasion de pouvoir tirer des balles);
b) Vos munitions (ammo) sont supérieures à zéro (vous devez avoir au moins une balle si vous voulez tirer sur quelque chose ou sur quelqu'un).

Il y a bien entendu plusieurs méthodes pour résoudre ce problème, j'ai choisi l'imbrication des branchements "if", c'est à dire que vous allez trouver un branchement "if" dans les accolades d'un branchement "if". Pour être plus clair voici un exemple:

if (player_health
> 0)
{
if (ammo > 0)
{
fire_bullets();
}
}

Que se passe-t-il? Tout d'abord la santé du joueur est comparée avec 0, si player_health <= 0, le reste du code sera ignoré. Si le joueur est vivant (player_health > 0), nous vérifierons si ammo est plus grand que 0. Si le joueur n'a pas assez de munitions (ammo <= 0) le reste du code sera ignoré, autrement si ammo > 0, la fonction fire_bullets() sera exécutée.

Suivant: Utilisons le clavier


workshop13

 Précédent: le branchement si - sinon (If - Else)

Utilisons le clavier

Si vous ne pouvez pas contrôler un jeu, c'est que vous êtes surement en train de regarder un film. La bonne nouvelle est donc que le moteur Acknex permet de contrôler ce qui se passe dans le niveau en utilisant le clavier, la souris, une manette de jeu et de simples instructions C-script. Si vous voulez utilisez un autre périphérique avec le moteur (comme un fusil à rayon lumineux par exemple) vous pouvez utiliser le kit de développement SDK pour développer votre propre interface en utilisant C++ ou delphi.

Acknex peut faire 3 choses différentes lorsque vous pressez une touche sur votre clavier:

1) Acknex met une variable prédéfinie à 1 lorsqu'on presse une touche sur le clavier. La bonne nouvelle c'est que ces variables prédéfinies utilisent des noms "parlant" comme :

key_a, key_b, key_shift, key_space, key_pause, key_f1, etc.

Vous pouvez vérifier si key_d vaut ON (1) et si ceci est vrai, vous pouvez être sur que le joueur a pressé la touche D.

2) Acknex génère un code de balayage. C'est un simple nombre mais sa valeur dépend de la touche pressée. Vous pouvez vérifier le code de la touche pressée en utilisant l'instruction key_lastpressed. Lisez la seconde partie du manuel pour trouver plus d'information sur ces mots clés, vous trouverez également une table qui reprend tous les codes.

Cette méthode est utilisée dans de rares cas, comme la redéfinition des touches. Vous trouverez un exemple dans le magazine utilisateur.

3) Acknex est capable d'exécuter une fonction spécifique lorsque nous pressons une touche sur le clavier, si nous avons attaché une fonction à une touche en particulier. J'ai utilisé un exemple de ceci dans un atelier précédent, celui qui parlait des pointeurs:

function
move_up()
{
wizard.z = wizard.z + 5;
}

on_u = move_up;

Cette exemple exécute une fonction définie au préalable nommée "move_up" lorsque nous pressons la touche "U" (ça n'a aucune importance que l'on presse "U" ou"u". Notez que le nom de la fonction doit être donné sans parenthèses.

Truc important
Je vous encourage à lire tous les ateliers si vous voulez apprendre beaucoup au sujet du moteur Acknex et de C-Script parce que le code des articles est expliqué étape par étape. Oh, et surtout ne faites pas un copier/coller du code depuis le magazine, j'en donne souvent une version "allégée", vous trouverez un lien vers le code complet sur la première page de chaque magazine.

Truc important de la part du traducteur français
Le principe du balayage (scancode) consiste à donner un nombre à chaque touche sans s'occuper de ce qu'il y a de sérigraphié dessus. La première touche porte le numéro 1, la deuxième touche le numéro 2, la deuxième touche de la deuxième rangée le numéro 16 etc. Il ne vous aura pas échappé que cette deuxième touche de la deuxième rangée esr sérigraphiée "A" sur un clavier français dit "AZERTY". Mais sur certains claviers, "QWERTY" par exemple cette touche est sérigraphiée "Z".

Le moteur a été développé par des programmeurs utilisant un clavier allemand donc si vous voyez key_q ou on_q dans un programme il s'agit de la deuxième touche de la deuxième rangée de votre clavier et peut-être que cette touche sur votre clavier est un a. Vous trouverez en annexe du manuel un récapitulatif des différents claviers francophones, le clavier suisse est différent duclavier français qui est lui-mêmme différent du clavier canadien ou belge. En cas de doute utiliser le scancode .

Il est temps de reprendre le travail! Démarrez Wed, ouvrez work13, compilez-le et exécutez-le et vous verrez les 3 méthodes d'utilisation du clavier vu ci-dessus, en action:

Cette jolie texture de ciel est créée par Sitni Sati; j'ai utilisé une basse résolution d'image car je souhaite que la taille des ateliers soit la plus petite possible.

Pressez "Z" (le W du clavier allemand) ou"S" pour monter ou descendre la caméra, pressez "Q" (le A du clavier allemand) et "D" pour changer l'angle de la caméra. Pressez "1" pour rendre le niveau plus lumineux et pressez "2" pour le rendre plus sombre. Pressez "R" pour rétablir les valeurs initiales de la caméra.

Je suis persuadé que vous ne serez pas surpris d'apprendre que toutes ces choses sont faites à partir d'un petit fichier script:

La première chose dont nous allons discuter est la boucle while:

while (1)
{
if (key_w == on) //touche W du clavier allemand donc Z sur un clavier français
{
camera.tilt += 1;
}
if (key_s == on)
{
camera.tilt -= 1;
}
if (key_a == on) //touche A du clavier allemand donc Q sur un clavier français
{
camera.pan += 1;
}
if (key_d == on)
{
camera.pan -= 1;
}
if (key_lastpressed == 19) // if "R" is pressed
{
camera.pan = 0;
camera.tilt = 0;
}
wait (1);
}

Vous avez noté bien entendu que la boucle contient le "wait (1);" nécessaire, instruction qui l'interrompt de temps en temps pour permettre aux autres actions et fonctions de s'exécuter en même temps. Regardons comment fonctionne la première méthode de test clavier : si nous pressons la touche Z (ou W) le code ajoute 1 degré à l'angle tilt de la caméra; si nous pressons la touche "S" le code enlève 1 degré à l'angle tilt de la caméra. Pressez "Q" (ou "A") pour ajouter 1 degré à l'angle pan de la caméra et "D" pour soustraire un degré à l'angle pan de la caméra.

J'espère que vous vous souvenez de la méthode du point : objet.propriété. La caméra (notre vueà l'intérieur du monde 3D) est également un objet, aussi nous jouns sur ces angles, positions et ambiances en utilisant la méthode du point. Oh et pour ces instructions simplifiées:

camera.tilt += 1;

fait exactement la même chose que son grand frère:

camera.tilt = camera.tilt + 1;

Vous pouvez utiliser le même raccourci pour n'importe quel autre opérateur mathématiques par le moteur: "+", "-", "*", "/", "%". Jetons un oeil à la dernière partie de la boucle qui utilise le scancode (balayage) correspondant à la deuxième méthode de test du clavier:

if (key_lastpressed == 19) // la touche 19 est la cinquième de la deuxième rangée en l'occurence le "R"
camera.pan = 0;
camera.tilt = 0;
}

La variable prédéfinie nommée key_lastpressed stocke la valeur du scancode de la dernière touche pressée sur le clavier. Par conséquent lorsque vous pressez la touche "R", key_lastpressed aura la valeur 19 (le scan code qui correspond à la touche "R"). L'instruction "if" teste si "R" est pressé et si c'est vrai il remet à 0 les valeur de la caméra (ses angles initiaux sont pan = 0, tilt = 0).

Comme expliqué plus haut le code scancode généré par le moteur n'a bien entendu rien à voir avec les codes ASCII ou ANSI bien qu'il puisse être converti en ASCII / ANSI (Si vous ne savez pas ce qu'est l'ASCII ou l'ANSI oubliez cett phrase).

Jetons un oeil aux 2 fonctions qui s'exécutent lorsqu'on presse une touche sur le clavier:

function bright_lights()
{
camera.ambient = 100;
}

function dim_lights()
{
camera.ambient = 0;
}

on_1 = bright_lights;
on_2 = dim_lights;

La première fonction (bright_lights) s'exécute lorsque nous pressons la touche "1" sur le clavier, la fonction augmente la lumière en mettant le drapeau "ambient" de la caméra à 100. La seconde fonction s'exéute lorsqu'on presse la touche "2" sur le clavier et met "ambient" à zéro. Notez l'absence des parenthèses pour les 2 fonctions dans les lignes de code "on_1 = ..." and "on_2 = ...".

La méthode clavier qui fonctionne avec le scancode n'est pas la plus utilisée. Vous devez utiliser la méthode "on_x = fait_quelquechose;" (remplacez "x" avec la touche que vous voulez) lorsque vous voulez exécuter une action ou une fonction spécifique qui exécute ou arrête quelque chose (ouvrir une porte, allumer une lumière, charger un niveau, ajouter 2 nombres etc). Utilisez la méthode "if (key_x == on)" et une boucle while lorsque vous voulez contrôler une action ou une fonction qui est supposée s'exécuter en permanence (mouvements d'un joueur, de caméra, d'un véhicule, etc).

Suivant: Utilisation de la souris


workshop14

 Précédent: Utilisation du clavier

Utilisation de la souris

Vous pouvez choisir parmi 3 modes de souris, chacun de ces modes peut être utilisé avec une simple ligne de code comme celle-ci:

mouse_mode = 0; // nous pouvons utiliser 0, 1 ou 2 ici

Mettez "mouse_mode = 0;" et le pointeur de la souris devient invisible, comme si la souris n'existait pas du tout (bon paramètre pour les courses de voitures, jeu de tir, etc). Utilisez "mouse_mode = 1;" lorsque vous voulez créer un pointeur de souris qui est visible et qui soit capable de contrôler la position de la caméra ou ses angles (ex: jeu d'action à la première / troisième personne, jeu de rôles). Pour finir, mettez "mouse_mode = 2;" pour obtenir un pointeur visible, ne pouvant pas contrôler la camera mais pouvant se déplacer librement, pouvoir cliquer des objets (ex jeu de stratégie...). Nous allons bien entendu voir tout ces modes en action dans la suite de cet atelier.

Oh, j'allais oublier : mouse_mode est une variable prédéfinie, vous pouvez en lire plus dans la seconde partie du manuel.

Démarrez Wed et ouvrez le niveau nommé work14, compilez-le et exécutez-le:

Personne à la maison... déplacez la souris et vous serez capable de modifier les angles pan et tilt de la caméra:

Maintenant pressez la touche "," (le"M" du clavier allemand) une fois et voyez ce miracle:

Un réticule gris est venu de nulle part! Je peux déplacer la caméra et le réticule change de position également!

Pressez la touche "," (le"M" du clavier allemand) une nouvelle fois et vous verrez un curseur à l'écran:

Maintenant c'est étrange! Le curseur peut se déplacer mais la caméra ne bouge plus du tout!

Vous pouvez presser la touche "," (le"M" du clavier allemand) autant de fois que vous voulez pour tester les 3 modes de la souris et pendant que vous faites cela, jetez un coup d'oeil contenu dans le fichier script14:

Le code ne paraît pas trop compliqué, je crois que je me répète mais bon...

Nous avons défini 2 bitmaps (une pour le curseur et une pour le réticule), vous pouvez voir ces images dans le répertoire \workshop14. Regardons le code utilisé dans la fonction main:

function main()
{
level_load (work14_wmb);
while (1)
{
mouse_pos.x = pointer.x;
mouse_pos.y = pointer.y;
camera.pan -=
mouse_force.x;
camera.tilt += mouse_force.y;
wait (1);
}
}

Nous chargeons le niveau puis nous répétons quelques lignes à l'intérieur d'une boucle while (1) qui utilise bien entendu une instruction "wait (1);". Regardons de plus près les deux premières lignes de code à l'intérieur de la boucle:

mouse_pos.x = pointer.x;
mouse_pos.y = pointer.y;

Les variables prédéfinies nommées mouse_pos.x et mouse_pos.y contrôle la position du pointeur de la souris à l'écran, si mouse_pos.x = 200 et mouse_pos.y = 300 (juste un exemple), le pointeur apparaît à l'écran juste comme sur l'image ci-dessous:

Quoi? Vous êtes en train de me dire que les variables prédéfinies nommées pointer.x et pointer.y convertissent les mouvements de la souris en coordonnées d'écrans en pixels - c'est exactement les données dont nous avons besoins pour mouse_pos.x et mouse_pos.y! Je me demande si elles sont vraiement faite pour cela... Peu importe, vous n'avez pas besoin de connaître tout l'historique, mettez ces 2 lignes dans une boucle while et vous pourrez utiliser la souris dans n'importe quel projet. Oh, et n'oubliez pas bien entendu d'ajouter l'instruction "wait (1);" à l'intérieur de votre boucle!

Jetons un oeil aux deux lignes de code suivantes:

camera.pan -= mouse_force.x;
camera.tilt += mouse_force.y;

Ok, nous déplaçons les angles pan et tilt de la caméra en utilisant mouse_force.x et mouse_force.y; ce sont deux variables prédéfinies qui stocke la vitesse avec laquelle la souris s'est déplacée horizontalement (mouse_force.x) et verticalement (mouse_force.y). Dès que vous arrêtez le mouvement, mouse_force.x et mouse_force.y sont mises à zéro, mais leur valeurs vont de -1 ào 1.

Regardons la fonction qui change la variable prédéfinie nommée mouse_mode:

function
change_mouse_mode()
{
mouse_mode += 1;
mouse_mode %= 3;
if (mouse_mode ==
1)
{
mouse_map = crosshair_pcx;
}
if (mouse_mode
== 2)
{
mouse_map = cursor_pcx;
}
}

on_m = change_mouse_mode;

Il est clair que cette fonction s'exécute lorsque nous pressons la touche "M" (clavier allemand donc "," pour clavier français). Lorsque nous démarrons le programme mouse_mode est à zéro (c'est sa valeur par défaut) aussi le pointeur n'est pas apparent. A chaque fois que vous presserez la touche "M" (",") la fonction change_mouse_mode() s'exécute une fois puis s'arrête. Expliquons les deux lignes suivantes:

mouse_mode += 1;
mouse_mode %= 3;

Vous vous souvenez que "mouse_mode += 1;" est juste la version raccourcie pour "mouse_mode = mouse_mode + 1;". Ces deux instructions font la mêmee chose, elle incrémente de 1 mouse_mode. La valeur initiale de mouse_mode étant de zéro, à présent mouse_mode = 1. Le pointeur de souris apparaît sous la forme d'un réticule qui peut être déplacé etla soruis contrôle la caméra dans le mêm temps. C'est le bon mode à utiliser pour une action dans un jeu de rôle ( RPG = role-playing game).

La seconde ligne de code "mouse_mode %= 3;" est la version raccourcie pour"mouse_mode = mouse_mode % 3;" ok? L'opérateur modulo (%) est le reste de la division entre 2 nombres, 14 % 3 = 2 parce que 14 = 3 * 4 + 2 et le reste de l'opération est 2.

Pourquoi avons-nous besoin d'utiliser cet opérateur modulo? Simplement parce que ça nous permet de "borner" les valeurs d'une opération utilisant l'opérateur modulo. Si nous prenons le modulo de n'importe quel nombre par rapport à 3 nous obtiendrons uniquement 0, 1 ou 2. Si nous prenons le modulo de n'importe quel nombre par rapport à 7 nous obtiendrons uniquement: 0, 1, 2, 3, 4, 5 or 6.

Nous avons besoin de mettre mouse_mode à une valeur valide 0, 1 ou 2. Que se passe-t-il lorsque le joueur presse la touche "M" (",") 5 fois? Nous ne pouvons pas accepter que mouse_mode prenne la valeur 5! La seconde ligne nous prémunie donc contre cette possibilité car nous sommes sur que mouse_mode = 2 lorsque nous pressons "M" '",") 5 fois en effet 5 = 3 * 1 + 2, avec 2 comme reste. Vous pouvez presser "M" (",") autant de fois que vous voulez car mouse_mode aura toujours la valeur : 0, 1, 2, 0, 1, 2, 0, 1, 2, ...

Regardons le reste du code à l'intérieur de notre fonction change_mouse_mode():

if
(mouse_mode == 1)
{
mouse_map = crosshair_pcx;
}
if
(mouse_mode == 2)
{
mouse_map = cursor_pcx;
}

Ces lignes de code change l'image bitmap du pointeur de la souris (prédéfinie comme mouse_map) en une des images bitmaps : crosshair_pcx ou cursor_pcx. Ce sera tout le code qui sera expliqué dans ce fichier script! Vous pouvez noter que nous utilisé aucun code pour cacher le pointeur de la souris lorsque mouse_mode est mis à zéro; le moteur fait cela par lui-même..

Les variables nommées mouse_force.x et mouse_force.y répondent au mouvement de la souris (lorsqu'elles ont des valeurs différentes de zéro qui peuvent être utilisées dans nos scripts) uniquement si mouse_mode est à 0 ou à 1. N'imaginez pas que vous pourrez déplacer la caméra si vous avez mis mouse_mode à 2; c'est pourquoi ce mode de souris est utilisé pour les jeux de stratégie, etc.

Vous pouvez mélanger les 3 modes de souris dans un même jeu, comme je l'ai fait dans cet atelier. Si vous désirez avoir une scéne coupée (cut scene), vous pouvez vouloir cacher la souris pendant que les personnages se parlent (mouse_mode = 0); dés la fin de la scène coupé vous basculez avec mouse_mode = 1 ou mouse_mode = 2, en fonction du type de jeu que vous créez.

Etes-vous prêts pour apprendre de nouvelle choses? Copier / coller ces lignes de code à l'intérieur de la fonction main():

if (mouse_left == on)
{
camera.ambient += 1;
}
if (mouse_right == on)
{
camera.ambient -=
1;
}

Votre nouveau script devrait ressembler à celui ci-dessous (les nouvelles lignes sont en vert):

Exécutez de nouveau le niveau et vous noterez quelque chose d'intéressant : vous pouvez jouer sur l'ambiance du niveau en utilisant simplement le bouton gauche ou droite de la souris. Le truc est tout simple, nous savons déjà que les différentes valeurs de camera.ambient jouaient sur la lumière ambiante de notre niveau. Ce que nous ne savons pas c'est les boutons de la souris utilisent des variables prédéfinies nommées mouse_left, mouse_middle (non utilisée dans notre exemple) et mouse_right, qui sont mises à "on"lorsque le bouton de la souris correspondant est appuyé et mises à "off" lorsque le bouton est relâché.

Vous vous souvenez de cette ligne de code?

if (key_w == on)
{
........
}

Oui! Nous l'avons utilisée pour changer l'un des angles de la caméra dans un atelier précédent! La même méthode peut être utilisée pour les 3 boutons de la souris; il suffit de remplacer key_votre_touche par mouse_votre_bouton (left, middle ou right) et vous pourrez contrôler ce que vous voulee à l'aide de la souris!

Ok, faisons une pause.

Suivant: Utilisation de la manette de jeux


workshop15

 Précédent: Utilisation de la souris

Utilisation d'une manette de jeu

Si vous prévoyez de créer un simulateur de vol et que vous envisagez de le vendre, ce serait bien que vous utilisiez une manette de jeu. La bonne nouvelle c'est que le code vous permettant cela est très simple. Bien mais il y a également des mauvaises nouvelles : vous devez avoir une manette de jeu si vous voulez tester cet atelier. Ne deséspérez pas si vous n'avez pas de manette pour l'instant, vous pourrez reprendre cet atelier au moment opportun.

Bien, par quoi, allons-nous commencer? Tout d'abord vous devez brancher la manette dans le connecteur correspondant puis vous devez ouvrir le panneau de configuration de windows:

C'est le panneau de Windows XP Professionnel, le votre peut donc différer de celui-ci si vous utilisez une autre version de Windows. Double cliquez sur "contrôleurs de jeu" pour l'ouvrir:

Puis vérifiez les différents paramètres de votre manette, y compris le calibrage lorsqu'il existe:

Il est important que la manette soit bien installé, vous n'avez pas accès à ces paramètres depuis le moteur Acknex

Ok, revenons à notre merveilleux moteur : démarrez Wed, ouvrez work15, compilez le niveau et exécutez-le:

C'est toujours notre bonne vieille maison mais cette fois-ci nous pouvons déplacer la caméra à l'aide de la manette de jeu! Utilisez le premier bouton de la manette pour augmenter la hauteur de la camera (z) et le deuxième bouton pour la baisser. Pressez les 2 boutons en même temps pour remettre la caméra à sa position initiale.

Tout ceci peut paraître un peu compliqué aussi j'ai fait en sorte que le code présent dans le fichier script15 soit le plus simple possible:

Le code est simple n'est-ce pas! Regardons ce que fait la fonction main: elle charge le niveau, attend 3 cycles puis met camera.pan à 90 degrés. C'est le bon angle pour voir la maison de face et oui, nous avons de l'instruction wait (3)car il faut que le niveau soit complètement chargé avant de modifier les positions / angles de la caméra.

Truc important
Utilisez une instruction wait (3) après chaque level_load dans tous vos jeux. De cette façon vous saurez avec certitude que les autres actions, fonctions iu instructions fonctionneront correctement après que le niveau soit chargé.

C'était la partie la plus facile. Regardons le code à l'intérieur de la boucle while (1):

 while(1)
{
camera.x -=
joy_force.x;
camera.y += joy_force.y;
if (joy_1 == on)
{
camera.z += 1;
}
if (joy_2 == on)
{
camera.z -=
1;
}
if ((joy_1 == on) && (joy_2 == on))
{
camera.x = 0;
camera.y = 0;
camera.z = 0;
}
wait(1);
}

Nous avons parlé dans l'atelier précédent de mouse_force.x et mouse_force.y; bien, joy_force.x et joy_force.y fonctionne de la même façon: leur valeur change vont de -1 à 1 en fonction de la vitesse avec laquelle vous déplacez la manette. Lorsque vous ne bougez pas la manette, joy_force.x et joy_force.y sont mis à zéro, auquel cas la caméra ne bouge pas du tout.

J'ai trouvé que c'était plus sympa de bouger la caméra (plutôt que de la tourner) aussi joy_force.x et joy_force.y change les positions x et y positions de la caméra. Si vous voulez inverser la direction des mouvements par rapport aux axes x et y de la manette remplacez "-=" par "+=" et / ou "+=" par "-=" dans l'une ou les deux lignes du code mentionné ci-dessus.

Vous vous souvenz de ce que nous avons appris au sujet du clavier et de la souris? Chaque touche ou bouton de souris est associé à une variable qui peut être mise à "on" si la touche ou le bouton est pressé. Nous pouvons vérifier si une touche est pressée par une simple ligne de code:

if (key_t == on)
{
// faire ce code si la touche "T" est pressée
}

La même méthode s'applique à la manette:

if (joy_1 == on)
{
// faire quelque chose
}

Vous ne serez pas surpris d'apprendre qu'Acknex peut contrôler une ou deux manettes, chacunne d'elle pouvant avoir 10 boutons. Le petit bout de code ci-dessus fera donc quelque chose si le premier bouton de la manette est pressé.

Ok, donc les boutons joy_1 et joy_2 contrôle la hauteur (z) de la caméra, ce qui est bien puisque la manette elle-même contrôle le x et y de la caméra, utilisant joy_force.x et joy_force.y. Par contre les dernières ligne de code à l'intérieur de la boucle while me donne mal à la tête:

if ((joy_1 == on) &&
(joy_2 == on))
{
camera.x = 0;
camera.y = 0;
camera.z = 0;
}

Ce sont les lignes de code qui remettent la caméra à sa position initiale (x = 0, y = 0, z = 0) - il n'y a aucun doute la dessus. Attendez une minute, cela se produit lorsqu'on appuie simultanément sur les 2 boutons donc (joy_1 == on) && (joy_2 == on) doit signifier "joy_1 == on ET joy_2 == on", les deux boutons de la manette sont pressés en même temps. Qu'est-ce que je suis malin...

Vous vous souvenez de nos instructions "if" imbriquées?.

if (joy_1 == on)
{
if (joy_2 == on)
{
if (joy_3 == on)
{
if (joy_4 == on)
{
// faire quelque chose si les 4 premiers boutons sont appuyés en même
temps
}
}
}
}

Nous allons à présent réécrire ce vilain code en utilisant l'opérateur ET "&&":

if ((joy_1 == on) && (joy_2 == on) && (joy_3 == on) && (joy_4 == on))
{
// faire quelque chose si les 4 premiers boutons sont appuyés en même temps
}

Je sais, je sais... le code est plus propre, plus court, plus beau etc. C'est pour cela que l'opérateur "ET" a été inventé et vous devez l'utiliser aussi souvent que possible.

Si le "ET" vous a impressionné, j'ai une bonne nouvelle pour vous, le "ET" a un frère, le "OU". Cet opérateur"OU" s'écrit || (il faut utiliser la touche alt gr et la touche 6 deux fois) est utilisé lorsque quelque chose est vrai ou quelque chose d'autre est vrai ou quelque chose d'autre est vrai... Imaginons que vous souhaitiez arrêter le moteur lorsque variable nommée gold à la valeur 1000 ou 2000 ou 3000. Vous pourriez écrire le code de cette façon:

function
some_function()
{
if (gold == 1000)
{
exit;
}
if (gold == 2000)
{
exit;
}
if (gold == 3000)
{
exit;
}
}

Que dire? Le code va fonctionner, d'accord, mais l'opérateur "OU" rendra cela beaucoup plus simple, voyez plutôt:

function some_function()
{
if ((gold == 1000) || (gold
== 2000) || (gold == 3000))
{
exit;
}
}

Truc important
Si votre manette n'est pas calibrée correctement la caméra peut se mettre à tourner sur elle même lorsque vous utiliserez un jeu fait avec le moteur Acknex (votre projet ou celui d'un autre). Débranchez la manette si vous ne l'utilisez pas ou calibrez-là correctement.

Truc important
Si vous vérifiez plusieurs expressions en même temps (en utilisant && ou ||] vous avez besoin d'utiliser des parenthèses séparées pour chacune des expressions puis de metttre des parenthèses à l'ensemble des expressions, comme sur l'exemple ci-dessous:

Problème:
Si a = 2 et b = 3 arrêter le moteur

Solution:
if ((a == 2) && (b == 3))
{
exit;
}

On arrive à la fin de cet atelier, je vous félicite. Mais voici un petit devoir de classe, comment réécririez-vous le code dans script15 si vous voulez que le joueur puisse changer la hauteur de la caméra (z) en utilisant les deux boutons de la manette OU la touche "A" (pour monter - clavier allemand) et "Z" (pour descendre - clavier allemand)?

Solution: remplacer deux lignes de code dans la fonction main:

if (joy_1 == on) must be replaced with if ((joy_1 == on) || (key_a == on))
if (joy_2 == on) must be replaced with if ((joy_2 == on) || (key_z == on))


workshop16

 Précédent: Utilisation de la manette

Utilisation des outils de mise au point

Bien à présent vous savez comment écrire du code. Vous avez appris à travailler avec les variables, les fonctions, les images bitmaps, les panneaux, les fenêtres, les chaînes de caractère, les textes, les polices de caractère, les entités, les actions, les pointeurs... Quel énorme travail, mais que se passe-t-il lorsque les choses se passent mal et que vous ne pouvez pas interroger Oncle Tom pour lui demander ce qui ne va pas dans votre code? Pourquoi subitement alors que vous lancez le jeu votre ordinateur se met àfabriquer du pop corn, ouvrir le lecteur de floppy? Allo il y a quelqu'un pour m'aider? Personne, au secours....

Si le paragraphe ci-dessus vous fait penser à un film d'horreur alors ce qui suit va vous rassurer, les développeurs du moteur ont développé leurs propres outils qui pourront vous aider à détecter et corriger tous les bugs de votre code. Je vous encourage à utiliser les outils de mise au point aussi souvent que possible, quelques fois vous serez incapable de voir les défauts de votre code uniquement avec une lecture approfondie du fichier.

Assez parlé, au boulot! Ouvrez le fichier Script16:

Je peux voir une variable nommée energy et un peu de code dans la fonction main...à quoi servent ces variables screen_color?

Ces 3 variables contrôlent la couleur de l'écran lorsque vous n'avez pas chargé de niveau. Vous pouvez utiliser n'importe quelle combinaison des 3 couleurs avec red (rouge) = 0, green (vert) = 0 et blue (bleu) = 0 vous aurez un écran noir et avec red = 255, green = 255, blue = 255 vous aurez un écran blanc.

Nous nous mettons un écran vert dans main c'est pourquoi screen_color est mis à sa valeur maximale qui est 255. Lorsque nous pressons la touche "d" la fonction decrease_energy() est exécutée aussi ragardons-là en détail.

function decrease_energy()
{
energy -=
40;
if
(energy < 70)
{
screen_color.red = 0;
screen_color.green = 0;
screen_color.blue = 255;
}
if (energy
< 30)
{
screen_color.red = 255;
screen_color.green = 0;
screen_color.blue = 0;
}
if (energy
== 0)
{
exit;
}
}

A chaque fois que nous presserons la touche "d" du clavier, "energy" diminuera car nous otons 40 de sa valeur actuelle. Si"energy" est inférieur à 70, l'écran changera de couleur en devenant bleu car screen_color.red et screen_color.green sont mis à 0 et screen_color.blue = 255. Si nous pressons la touche"d" de nouveau, "energy" diminuera encore devenant inférieur à 30, ce qui fait que l'écran changera de nouveau de couleur pour devenir rouge. Pour terminer lorsque "energy" est à zéro, le moteur s'arrête. Regardons cette fonction au travail en la lançant à partir de SED et le bouton "Test run":

Jusque là tout va bien. Pressons à présent la touche"d".

Génial! L'écran passe du vert au bleu comme prévu, allez soyons fou pressons de nouveau la touche "d" !

Génial l'écran devient rouge. Il est temps de terminer ce show coloré en pressanrt une dernière fois la touche"d"!

Hmm, Hmm...J'avais déjà cette couleur auparavant. Ah je sais c'est mon clavier qui fonctionne mal, réessayons une nouvelle foison ne va quand même pas se laisser embêter par du mauvais matériel, appuyons plus ferment sur la touche "d"!

Et bien non, inutile de casser le clavier, le problème doit être ailleurs, le moteur refuse de s'éteindre lorsque energy est à zéro. Il ne nous reste plus qu'à corriger ce bug, revenons dans Sed et cliquons sur "Watch" dans le bas de l'écran:

C'est l'endroit ou vous pourrez jeter un oeil sur vos variables.Vous pourrez voir les valeurs des variables se changer en temps réel et vous pourrez même donner de nouvelles valeurs aux variables qui sont montrées durant le jeu!

Sed et le motteur Acknex sont 2 programmes différents aussi ce serait une bonne idée d pouvoir les visualiser tous les 2 en mêm temps. A moins que vous ne disposiez de plusieurs écrans vous allez devoir exécuter le moteur en mode fenêtre et non plus en plein écran et ça tombe bien Sed nous permet de faire cela. Sélectionnez Options -> Configuration:

Vous voyez apparaître cette fenêtre:

Cochez "Window" puis pressez OK. A partir de maintenant le moteur fonctionnera en mode fenêtre jusqu'à ce que vous décochiez la case "Window". Re démarrons le script script16:

Génial, à présent je peux voir le moteur et l'éditeur de script en même temps. Vous pouvez être appelé à déplacer l'une ou l'autre des fenêtres de façon à apercevoir la zone "Watch" de SED; si vous avez un bon écran vous devez avoir assez de place pour cela. Voici ce qu eça donne sur mon moniteur en 1280 x 1024 pixels:

Ajoutons à présent un "watch"!(une variable dont on souhaite visualiser le contenu). Choisissez Debug -> Add Watch:

Cette nouvelle fenêtre apparaît:

N'oubliez pas que vous ne pouvez visualiser que des variables aussi c'est un nom de variable qu'il faut saisir ici. Nous n'avons que 3 variables dans script16 et on peut supposer que video_mode et video_depth sont ok, parce que le code les concernant n'a pas été écrit par moi. Tapez donc "energy" (sans les guillemets) puis pressez OK; Le nom de la variable et sa valeur actuelle apparaissent dans la zone "Watch". Nous venons donc de créer un watch, un"espion" qui nous montre la valeur de la variable nommée energy.

Vous pouvez voir que energy = 0 pour l'instant, alors que le script lui donne la valeur 100. Pourquoi cette anomalie? Tout simplement parce que le fichier script n'a pas encore été exécuté, faisons-le donc dès maintenant!

Maintenant Energy a bien la valeur 100 parce que le fichier script16a été lancé...mais c'est quoi ces valeurs x, y, z? Bien c'est tout simplement que votre watch peut également être un vecteur qui est composé de 3 valeurs séparées. Si vous montrez une variable normale comme notre energy, la valeur de la variable est stockée dans son x. Si nous avions défini la variable energy[3] à la place vous pourriez avoir energy.x = 100 pour la santé, energy.y = 50 pour l'armure et peut-être energy.z = 20 pour la vitesse, Comprendo?

Le programle semble s'exécuter normalement, pressons une fois la touche "d":

Energy est mis à 60, ce qui est normal (100-60). Pressons "d" une fois encore:

Energy passe cette fois-ci à 40 comme prévu, pressons une troisème fois la toche "d", le moteur devrait s'arrêter n'est-ce pas?

Vu! Le moteur ne s'arrête pas car la valeur de energy n'est pas 0 mais -20 now, donc la branche du if demandant l'arrêt du moteur n'est jamais exécutée:

if (energy == 0)
{
exit;
}

Nous devons modifier le code de cette façons:

if
(energy < 0)
{
exit;
}

Je vous laisse faire la modif et faire les tests

Suivant: la mise au point avancée


workshop17

 Précédent: Utiliser les outils de mise au point

Mise au point avancée

Si votre jeu a plus que quelques lignes de code il peut (et c'est certainement probable) avoir des bugs. Vous savez à présent comment utiliser les watchs mais que pouvez-vous faire lorsque les données de la variable change de valeur trop rapidement? Et est-il possible de montrer une entité particulière plutôt que les valeurs d'une variable?

Ouvrons le fichier Script17 pour l'instant:

Nous avons utilisé un script un peu ressemblant dans le dixième atelier mais j'ai effectué quelques changement au code. J'ai mis l'ambient de l'avion à 100 et j'ai défini une variable (plane_pan) qui a tout le temps la même valeur que l'angle pan du joueur.Pourquoi fais-je cela?Simplement parce que je veux montrer l'angle de l'avion et nous savons que nous pouvons montrer que des variables ou des vecteurs.mais pas my.pan ou tout autre variable liée à une entité. Revoyez l'atelier précédent si vous avez déjà oublié tout cela.

Mais que faisons-nous avec l'avion? Il utilise une boucle while qui ajoute 2 degrés à son angle pan à chaque frame et après une rotation complète (pan = 360) ile moteur s'arrête. Regardons si le code fait ce qu'on lui demande!

L'avion tourne comme prévu mais le moteur ne s'arrête pas après une rotation complète, en fait il ne s'arrête pas du tout. Qu'est-ce qui peut bien être mauvais dans ces quelques lignes de code? Pressez la touche échap pour sortir du programme et demandons à voir (watch) la variable nommée plane_pan.

Assurez-vous que le moteur va fonctionner en mode fenêtre en utilisant dans SED Options -> Configuration pour faire appara^tre la fenêtre:

Cochez "Window" s'il n'est pas déjà coché puis OK. Maintenant allez dans Debug -> Add Watch:

Ajoutez un watch nommé "plane_pan" (sans les guillemets):

Assurez-vous de bien utiliser le même nom pour le watch et la variable sinon votre watch sera inutile! Mintenant cliquez sur l'onglet "Watch" pour faire apparaître le watch nouvellement créé:

Il est temps d'exécuter de nouveau le fichier script! Vous n'êtes pas curieux de voir notre valeur plane_pan?

J'ai essayé de saisir le moment où plane_pan est proche de 360 degrésmais les écarts sont trop grands car les variables "watchs" sont mises à jour toutes les 500 ms! Essayons de mettre les mises à jour des watchs plus souvent. Quittez le moteur et basculez sur SED, choisissez Options -> Configuration -> Environment:

Choisissez 100 ms à la place de 500 ms, puis pressez OK et exécutez de nouveau le fichier script.

C'est le même résultat, voire pire. Les nombres changent trop vite à présent. Je pense que 500 ms est une bonne valeur pour la majorité des projets car il met à jour siffisemment souvent tout en ne consommant pas trop de précieuses resources systèmes. Que pouvons-nous faire alors? Ce qui serait bien ce serait de pouvoir interrompre la boucle while pour mettre le code au point, n'est-ce pas?

Je sais! TC'est une instruction qui fait cela très bien - breakpoint! Modifiez le fichier script comme sur l'image ci-dessous:

J'ai ajouté une seule ligne au fichier script, le moteur fera une pause à chaque frame lorsqu'il rencontrera l'instruction breakpoint, et le logiciel de mise au point sera activé pour effectuer du pas à pas à l'intérieur de notre script. Soyez patient vous comprendrez bientôt ce que signifie le pas à pas. A la place de taper une ligne breakpoint; dans le script vous pouvez placer également un point d'arrêt temporaire sur n'importe quelle ligne grâce au menu Debug de SED. Ce point d'arrêt temporaire ne sera actif que pendant la durée d'exécution de SED.

Exécutons de nouveau notre script17:

L'avion s'est arrêté et vous pouvez voir une ligne de code dans le coin supérieur gauche de la fenêtre du moteur.

<= my.pan = my.pan + 2

Appuez une fois sur la barre "Espace".

Quelque chose a changé, l'avion a légèrement tourné et à présent nous pouvons voir 2 lignes de code dans la fenêtre du moteur:

3.000 <= my.pan = my.pan + 2
<= plane_pan = my.pan

Egalement dans SED la ligne est en surbrillance pour indiquer l'instruction en cours. Le logiciel de mise au point exécute les instructions ligne par ligne et affiche les résultats de l'opération sur le côté gauche de l'écran.Il est à noter que l'angle pan de l'avion est à 3 degrés ce qui signifie que sa valeur initiale était à 1. Le watch affiché montre toujours 0 car nous n'avons pas encore exécutée la ligne plane_pan = my.pan. Pressons la barre Espace une nouvelle fois!

3.000 <= plane_pan = my.pan + 2
<= (my.pan == 360)

La valeur stockée dans my.pan a été copiée dans plane_pan (les 2 sont à 3 à présent) et que croyez-vous qu'il se passe à présent? Notre watch affiche la même valeur bien entendu. Pressons de nouveau la barre espace!

0.000 <= (my.pan == 360)
<= wait (1)

Le résultat de l'opération (my.pan == 360) est 0 (faux); ce qui est normal puisque my.pan n'a que 3 degrés pour l'instant! Si my.pan avait eu une valeur de 360 degrées, le résultat de l'opération aurait donné 1 (vrai) et la première ligne aurait ressemblée à celle-ci:

1.000 <= (my.pan == 360)

Nous arrivons à la fin de la bouclecar je vois l'instruction wait (1) d'affichée par le logiciel de mise au point. Pressons encore une fois la barre espace:

1.000 <= wait (1)
<= )

Vous pouvez voir que le wait (1) a été exécutée aussi la boucle while est prête à recommencer. Pressez espace de nouveau

0.000 <= )
<= (1)

Le moteur vérifie si le (1) de while (1) est vrai. Je vois avez dit que "while (1)" était la même chose que while (1 == 1)" qu est donc toujours vraie. Appuez sur espace une nouvelle fois:

1.000 <= (1)
<= breakpoint;

Nous avons obtenu le bon résultat pour "while (1)" -c'est le 1.000 qui apparaît sur la gauche et arrive le breakpoint, aussi nous pressons espace de nouveau:

0.000 <= breakpoint;
<= my.pan = my.pan + 2

Je suis impatient de voir comment réagit la prochaine ligne de code, pressons espace encore une fois:

5.000 <= my.pan = my.pan + 2
<= plane_pan = my.pan

L'avion a légèrement tourné. Oh je vois son angle pan a la valeur 5 degré à présent. Je suis sur que la valeur sera copiée dans mon watch dès que je presserais de nouveau la barre espace!

5.000 <= plane_pan = my.pan
<= (my.pan == 360)

Bien les choses vont donc se répéter encore et encore et my.pan prendra les valeurs 1, 3, 5, 7, ... Vous pouvez presser Ctrl + Espace pour désactiver le logiciel de mise au point jusqu'à ce qu'il détecte une nouvelle instruction breakpoint; dans notre cas il en trouve une rapidement puisque nous l'avons mis dans une boucle while. Autrement vous devez presser la touche échap pour déasctiver complètement le logiciel de mise au point et c'est exactement ce que nous allons faire.

Qu'y-a-t-il de mauvais avec ce code? Pourquoi n'arrêtee-t-il pas le moteur lorsque l'angle pan atteint 360 degrés? Ou est le bug? Allo il y a quelqu'un?

(Deux semaines plus tard) Je sais! J'ai mis un mauvais angle pan à mon avion dans Wed. Si l'avion démarre avec une valeur initiale de son angle pan qui est impaire la valeur apparaîtra exactement comme nous l'avons vu : 1, 3, 5, 7, ... 357, 359, 361, 363... Maintenant je sais pourquoi le moteur ne s'arrête pas car nous sautons de 359 à 361 sans passer par la case 360, on ne touche donc pas les 20 000...oh pardon je me croyais au Monopoly...Voyons tout de suite cela dans Wed.

Je suis vraiment désolé. La valeur par défaut de l'avion dans Wed est de 90 degrés, j'ai du tourner l'avion par inadvertance car sa valeur est de 89 degrés.' Remettez 90 degrés, compilez le niveau de nouveau et tout devrez entrer dans l'ordre

Qu'est-ce que j'ai voulu vous montrer? Je veux voir l'angle pan qui passe de 359 à 361 mais je ne veux pas pressez la barre espace des dizaines, voire des centaines de fois. On ne pourrait pas activer le logiciel de mise au piont uniquement lorsque certaines conditions sont réunies?

Laissez-moi réfléchir, mais oui on peut le faire. Il y a une instruction qui permet de mettre des points d'arrêt conditionnels, qui sont activés lorsqu'une condition particulière existe. Voici quelques exemples :

breakpoint_on (key_y == 1); // active le logiciel de mise au point lorsque la touche "Y" est pressée

breakpoint_on (energy == 0); // active le logiciel de mise au point lorsque la variable nommée"energy" est à zéro

breakpoint_on (my.pan > 357); // active le logiciel de mise au point lorsque l'angle pan est plus grand que 357 degrées

Attention tout de même, les instructions breakpoint_on ralentissent considérablement tout le script car les conditions des points d'arrêt sont calculés après chaque instruction. Maintenant corrigeons le fichier script17 de la bonne façon:

Exécutez le script et l'avion s'arrêtera lorsque plane_pan = 359 degrées (si vous avez laissé une valeur impaire dans Wed bien entendu):

Maintenant pressez la barre espace et vous pourrez voir la prochaine valeur pour plane_pan qui est 361 degrées:

L'avion passe de 359 à 361 degrés, aussi le branchement qui doit arrêter le moteur n'est jamais exécuté. A présent une chose amusante, cliquez sur le x en haut à droite de la fenêtre du moteur A6 pour la fermer puis pressez sur échap. Vous devriez voir quelque chose comme :

le moteur a affiché une instruction "exit" (l'opérating system a demandé au moteur de faire cela) aussi à présent vous pouvez faire espace pour arrêter le moteur. Pensez à utiliser un breakpoint_on si vous avez besoin d'activer le mode de mise au point lorsqu'une certaine instruction se produit - c'estun outil de mise au point extrémement puissant.

Il y a une autre instruction de mise au point qui peut rendre de grands services et son nom est "watched". C'est un pointeur, un nom prédéfini pour une entité qui sera montrée par le logiciel de mise au point.

watched = me;

Placez simplement cette ligne ci dessus dans une action attachée à l'entité qui a besoin d'être mise au point et vous disposerez d'une multitude d'information. Modifions notre script de cette façon:

Notez que j'ai enlevé le code qui arrêtait le moteur lorsque my.pan = 360 degrées parce que j'ai souhaité avoir une bonne vision des valeurs affichées par le logiciel de mise au point.

Vous pouvez voir le type de l'entité (mdl), son nom interne utilisé par Wed (mig_mdl_000), le nom du fichier (MIG.MDL), la position (x, y, x), les valeurs des angles (pan, tilt, roll), son ambient (100) et plus encore! Vous pouvez voir le détail de toutes ces valeurs dans la seconde partie du manuel.

Je parie que vous commencez à être un peu fatigué - patience la fin de l'atelier approche!

Certains d'entre vous ont peut-être noté que plane_pan peut avoir une valeur supérieure à 360 degrés:

L'image ci-dessus montre une valeur de plane_pan de 433 degrés! Est-ce un bug du moteur? Non, la valeur de l'angle augmente / diminue tout le temps si l'entité continue de tourner dans la même direction. C'est une fonctionnalité, non un bug et c'est pratique pour déterminer le nombre de tour effectué par une entité. Vous voulez savoir quand l'avion aura fait au moins 2 tours, vérifiez si son angle pan est supérieur à 2 * 360 = 720 degrés! Et si votre angle a besoin d'être dans l'intervalle 0...359 degrés, vous pouvez placer une simple ligne dans la boucle while de votre code pour résoudre le problème:

my.pan %= 360; // limite pan à 0...359 degrés

Jetez un oeil au fichier modifié:

Croyez le ou pas cette version de code a u bug! Exécutez le fichier script modifié et vous verrez par vous même que le moteur rerfuse de sarrêter malgré une bonne valeur de son angle pan dans Wed. Votre travail à la maison consiste à éradiquer ce méchant bug.

Solution: my.pan %= 360 limite l'angle pan à 0...359 degrés, aussi il ne peut jamais être égal à 360 degrés. Changez la branche "if" de cette façon:

if
(my.pan >= 358)
{
exit;
}


workshop 18

Précédent: Mise au point avancée

Mouvement d'entité

Si votre jeu montre de nombreux écrans statiques uil doit également inclure du code qui déplace des entités. Vous pouvez utiliser une des deux méthodes présentées ci-dessous si vous voulez déplacer une entité (entité modèle, entité sprite ou entité carte):

- Changer sa position directement;

- Utiliser l'instruction c_move pour déplacer l'entité.

1. Changer la position d'une entité

J'aimerais commencer par parler de cette méthode en mentionant qu'elle est réellement simple mais elle doit être utilisée dans de très rares cas.. Nous avons vu les positions x, y et z d'une entitédans le 8ème atelier et à présent nous allons apprendre à les modifier dans Wed. Démarrez Wed et ouvrez le niveau qui se trouve dans le répertoire \workshop18 (work18.wmp).

C'est un simple niveau qui n'est rien d'autre qu'un étroit couloir avec quelques lumières et une entité modèle qui ressemble à une sphère. Compilez le niveau et exécutez-le en utilisant le fichier script script18:

Je peux voir une partie de la spère (en bas de l'écran) et l'étroit couloir. Appuez sur la touche "S" (S comme Start)!

La balle commence à se déplacer! Elle change son ambient en fonction du niveau de la lumière dans le niveaude, ce qui rend pas mal...

Mais que c'est-il passé? La balle a pénétrée dans le mur! Ah, la vier n'est pas un long fleuve tranquille...regardons le contenu du fichier script18:

Jetons un oeil à la fonction main:

function
main()
{
fps_max = 30;
level_load (work18_wmb);
wait (3);
camera.x = -100; // set a static position
for the camera
camera.y = 0;
camera.z = 70;
}

La première ligne de code limite le taux d'affichage à 30 frames par seconde (30 fps). Si vous avez un bon PC il peut afficher beaucoup plus que 30 fps;cette ligne de code s'assureque le script fonctionne à la même vitesse sur un PC avec un processeur à 500 MHz qu'à 10 GHz.

Les lignes suivantes demandent au moteur de charger le niveau et d'attendre 3 cyccles, n'oubliez pas d'ajouter l'instruction "wait (3);" après une instruction level_load afin de laisser assez de temps au moteur pour charger le niveau avant de nous déplacer. Pour terminer nous mettons les paramètres de la caméra (x, y, z) à une bonne position; nous pourrions également paramétrer les angles pan, tilt et roll mais la position initiale de la caméra avec l'angle pan le long de l'axe des x est exactement ce dont nous avons besoin.

Il est temps de voir le code pour l'action attachée à notre modèle sphère:

action my_ball
{
while (key_s == off)
{
wait (1); // wait until the player presses the "S" key
}

Vous avez appris comment on travaillait avec le clavier! La boucle "while" ci-dessus attend que le joueur presse la touche "S" sur le clavier. Dans ce cas je reprends l aboucle "while" vue à l'atelier workshop10:

while (telle condition est vraie)
{
// repeter les instructions qui sont placées entre les accolades
}

que nous pouvons traduire par :

while (key_s n'est pas pressée) //tant que la touche "S" n'est pas pressée
{
wait (1); // rrépéter cette instruction
}

Pour résumer la première boucle while répètera l'instruction "wait (1);" tant que le joueur n'aura pas pressée la touche "S" sur le clavier. Regardons à présent la deuxième boucle à l'intérieur de l'action my_ball:

  while (1)
{
my.x += 5;
// déplace l'entité ball le long de l'axe des x
wait (1);
}
}

La boucle while change la position de l'entité balle (le modèle sphère) en ajoutant 5 quants à sa coordonnées x à chaque cycle. Vous pouvez essayer d'autres valeurs que le 5 afin d'augmenter ou de réduire la vitesse du mouvement.

La première méthode de déplacement d'une entité est réellement simple : vous changez une ou plusieurs coordonnées de l'entité (x, y, z) dans une boucle while et c'est tout!

On peut également faire monter notre balle en ajoutant cette ligne de code dans le fichier script18:

Sauvegardez le script et exécutez-le, vous verrez la même image

Pressez "S" pour démarrer le mouvement de la balle, elle continue son mouvement sur l'axe des x mais cette fois elle augmente sa hauteur (z) également!

La seule mauvaise nouvelle c'est que la balle pénètre dans le plafond.

On a mis le doigt sur le principal (et le seul) inconvénient de cette méthode. Lorsque nous changeons directement les coordonnées d'une entité, on n'a aucun moyen de contrôle par rapport à la géométrie du niveau. Les entités peuvent les pénétrer, passer à travers les murs, les sols, les plafonds, les portes etc. Rien ne peut les arrêter! C'est donc une bonne méthode si vous prévoyez de permettre à votre monstre de pouvoir passer à travers les murs mais c'est peu probable que vous utilisiez cette possibilité si vous créez un jeu normal. (Mais qu'est-ce qui est normal aujourd'hui?).

Truc important : Déplacer une entité en changeant ses coordonnées x, y et z est vraiment très simple mais cette méthode ne doit pas être utilisée par les débutants. Vous devez absolument savoir ce que vous faites lorsque vous utilisez cette méthide!

2. Utilser l'instruction c_move

Cette instruction c_move déplace une entité et gère le système de collisionpendant les déplacements.Ce qui signifie que la balle s'arrêtera lorsqu'elle se cognera dans les murs, le plafond, avec une autre entité etc, ce qui est une bonne chose. Démarrez Wed, chargez le niveau work18 (si vous ne l'avez pas déjà fait) et exécutez le niveau en utilisant le fichier script script18_2:

Rien de neuf jusqu'ici, aussi pressons la touche "S" à présent!

La balle se déplace selon les axes x et z comme précédemment et je pense qu'elle va encore rencontrer le plafond...

Que se passe-t-il? L'entité a cogné le plafond mais elle ne l'a pas traversé, mieux que cela, elle a continué à glisser le long du plafond pour s'arrêter au bout du couloir. C'est un vrai déplacement d'entité ou quoi?

Si vous pensez que le code qui fait une chose aussi excitante est compliqué, alors vous vous trompez. Voici le fichier script18_2 qui déplace la balle en utilisant c_move:

N'oubliez pas de choisir le fichier script18_2 dans les options de Sed -> Configuration -> CSC / WDL file to run; sinon il continuera à utiliser l'ancien fichier script18.

Une seule ligne de code a changé - la ligne qui utilise la nouvelle instruction c_move:

c_move (my, nullvector, vector(5, 0, 2), glide);

La forme habituelle de c_move est écrite ci-dessous:

c_move (entity, relative_speed, absolute_speed, movement_type)

Je sais que cette ligne vous parait légèrement compliquée mais je vais vous expliquer chacun de ses termes:

- c-move est le nom de l'instruction qui peut déplacer n'importe quelle entité et gérer la détection de collision pendant le déplacement. A chaque fois que vous aurez besoin de déplacer une entité qui peut se cogner avec la géométrie du niveau ou avec d'autres entités vous devez utiliser l'instruction c_move. Besoin d'un code de mouvement pour le joueur, un monstre, un véhicule, une balle etc? Alors c'est beaucoup mieux d'utiliser c_move!

- entity est le nom de l'entité qui doit être déplacée. J'ai utilisé le pointeur prédéfini my, car je veux déplacer la balle - qui est l'entité qui a son action nommée move_ball qui lui est attachée. Vous pouvez utiliser n'importe quel autre pointeur d'entité à la condition qu'il ait été défini avant lque vous utilisiez la ligne de code de c_move.

- relative_speed est la vitesse de déplacement de l'entié dans la direction (angles) pointée par l'entité; j'ai utilisé nullvector pour relative_speed dans mon exemple du script script18_2. C'est bien mais qu'est-ce que nullvector vous demandez-vous? Ce n'est rien d'autre qu'un nom pour un vecteur prédéfini (un jeu de 3 variables consécutives) dont toutes les composantes sont à zéro. Chaque fois que nous utilisons nullvector, le moteur comprend que nous l'alimentons avec une suite de zéros. Vous pouvez utiliser nullvector ou vector(0, 0, 0) ici parce que le moteur comprendra la même chose. Ici il ignorera la vitesse relative de l'entité.

- absolute_speed est la vitesse qui déplace l'entité dans une direction absolue, sans utiliser la direction actuelle (angles) pointées par l'entité. J'ai utilisé vector(5, 0, 2) ici, ce qui signifie que la balle se déplacera avec une vitesse de 5 quants / frame le long de l'axe des x, 0 quants / frame le long des axes des y et 2 quants / frame le long des axes des z.Comme vous pouvez le voir, vector (5, 0, 2) crée un vecteur temporaire sans nom, mais ce vecteur agit comme 3 variables qui ont 3 valeurs différentes.

- movement_type met le type du mouvement qui sera exécuté tant que la ligne du code de l'instruction c_move sera exécutée. j'ai utilisé glide dans mon exemple, mais il y a de nombreuses autres possibilmités listées dans la deuxième partie du manuel.Je vais vous en drécrire quelques unes à présent:

a) glide - l'entité glissera le long des murs ou des autres entités lorsqu'elle entrera en collision avec elles;

b) ignore_passable - ignore (passe à travers) tous les blocs passables et les entités si elles ont leur drapeau passable de mis;

c) ignore_models - ignore (passe à travers) tous les modèles même s'ils ne sont pas passables

Vous pouvez combiner ces options en les additionnant, glide + ignore_passable fera que l'entité glissera le long des murs et des entités mais passera à travers les blocs et les entités qui ont leur drapeau passable de mis.

J'ai surchargé votre cerveau avec de nombreuses informations, aussi c'est normal sipour vous tout cela reste encore un peu confus. La partie la plus délicarte est celle qui parle de la vitesse relative et de la vitesse absolue, n'est-ce pas? Imaginons que nous voulions créer un jeu de course de voitures:

Maintenant jetez un oeil à la voiture bleue. Si j'écrivais une action qui ressemble à ceci :

action
blue_car_1
{
while (1)
{
c_move (my, nullvector, vector(3, 0, 0), glide);
wait (1);
}
}

la voiture bleue se déplacerait comme l'indique la flèche jaune dans l'image ci-dessous:

Comment arrivons-nous à cela? Bien nous utilisons uniquement absolute_speed, et vector(3, 0, 0) dit à la voiture de se déplacer selon l'axe des x car seul le composant x du vecteur a une valeur différente de zéro.Et comme l'axe des x pointe tout droit vers la droite de l'écran, c'est ce qu fait que la voiture bleue avance de cette façon et dans cette direction..

Si nous utilisons une action qui ressemble à ceci:

action
blue_car_2
{
while (1)
{
c_move (my, vector(3, 0, 0), nullvector, glide);
wait (1);
}
}

la voiture bleue se déplacera en suivant la flèche jaune comme sur cette image:

Cette fois-ci nous utilisons relative_speed, ce qui fait que la voiture se déplace dans la direction donnée par son angle pan. Peut-être aurez-vous envie d'utiliser tout le temps relative_speed dans vos projets. Besoin d'un monstre qui poursuit le joueur? Il suffit de tourner le monstre en direction du joueur (ce qui se fait en quelques lignes) et utilisez l'instruction c_move en utilisant son paramètre relative_speed!

Mais alors pourquoi Conitec a-t-il inventé la possibilité d'avoir les deux vitesses (relative_speed et absolute_speed)? Pourquoi ne pas utiliser ""some_speed" pour répondre à tous les cas de figure?

Nous pourrions bien entendu faire cela mais le code serait compliqué dans certains cas. Imaginons que nous voulons créer un jeu de tir et un de ses épisodes se passe en Sibérie qui est un endroit glacé et neigeux. Il serait assez facile de gagner ce niveau, mais il y a ce vent froid soufflant du nord qui repousse le joueur. Comment coderiez-vous quelque chose qui ressemble à cela ? Quelque chose qui vous pousse loin de votre but quand vous vous tenez tranquille, ou vous résiste quand vous vous déplacez vers votre but (le pôle nord) ? Comment dire : "il y a cette force venant du secteur nordique de la carte vers le joueur, et je suis celui qui va écrire le code pour cela" ? Vous avez la solution, absolute_speed va vous aider. Voici la ligne du code qui déplace une entité dans la direction pointée par son angle pan et applique une force négative (juste comme un vent) venant du nord (comme vu dans la vue supérieure de Wed) : :

c_move (my, vector(3, 0, 0), vector(0, -1, 0), glide);

Cette entité (ça peut-être le joueur, un véhicule, etc) se déplacera de 3 quants / frame dans la direction donnée par ses propres angles pendant qu'il subira les effets d'une vitesse négative (-1 quant / frame) sur l'axe des y. Le résultat est une combinaison des 2 vitesses (relative_speed et absolute_speed). Vous utiliserez cette combinaison lorsque vous voudrez ajouter une force exterieure (comme la gravité, le gite etc). Comment faire en sorte que le joueur reste sur le sol? Utilisez un vecteur qui a sa composante z négative pour absolute_speed:

c_move (my, vector(5, 0, 0), vector(0, 0, -2), glide);

Je pense que je vous ai donné assez d'information sur c_move, aussi il est temps de passer au devoir à la maison. J'ai créé un nouveau projet pour vous afinque vous ne perdiez pas de temps à le faire. Démarrez Wed et ouvrez le niveau homework18.

C'est une simple boite avec une voiture à l'intérieur, aussi exécutez le niveau en utilisant le fichier script home18:

Cette petite voiture peut se déplacer en utilisant soit relative_speed soit absolute_speed. Pressez les touches "Q" et"S" pour changer l'angle pan de la voiture puis pressez la touche espace pour la voir se déplacer dans la direction donnée par son angle pan (relative_speed). Pressez les touches de direction "Haut", "Bas", "Gauche" ou"Droite" pour déplacer la voiture en utilisant absolute_speed (coordonnées absolues du monde).

Maintenant voici à quoi ressemble le script home18:

Je sais que ce script peut vous paraître légèrement trop gros mais il contient de simples instructions et beaucoup de commentaires. J'ai mis les bons angles et la bonne position pour la caméra dans main et le reste des lignes déplacent la voiture en utilisant absolute_speed (lignes 29 à 44) et relative_speed (lignes 46 à 57). Si vou sn'aimez pas ma position de caméra vous pouvez presser la touche "Zero" pour la libérer et la déplacer où vous voulez.

Votre devoir à la maison consiste à exécuter ce niveau encore et encore jusqu'à ce que vous compreniez comment c_move fonctionne. Je vous encourage à changer toutes les valeurs utilisées pour les vecteurs avec leurs composantes x, y et z. Que se passe-t-il si vous remplacez la dernière instruction last c_move avec celle ci-dessous?

c_move (my, vector(4, 0, 4), nullvector, glide);

Peut-être que la voiture va se mettre à voler car la composante z de sa relative_speed est positive, mais pourquoi ne pas essayer vous même? Jouez avec ce script jusqu'à ce que vous soyez sur de bien avoir assimilé l'instruction c_move; vous aurez besoin de cette instruction dans tous vos jeux!

A présent je vais faire une petie pause mais j'espère vous retrouver à mon retour...

Suivant: Utiliser "time"


workshop 19

Précédent: mouvement d'entité

Utiliser time

Savez-vous que vos cients potentiels ont des PC différents? Oh, vous le saviez déjà? Bien et peut-être pensez-vous que votre jeu fonctionnera à différents taux d'affichage sur leur PC. En quoi cela devrait vous préoccuper? Démarrez Wed, ouvrez le fichier work19 compilez-le et exécutez-le en utilisant le fichier script19:

La voiture tourne en permanence, je parie qu'il change son angle pan dans une boucle while ! Vérifions cela dans le fichier script19 dans Sed:

Vu? Il fait ce qu'il a à faire. C'est agréable de voir des petits scripts de temps en temps, n'est-ce pas?

Jetez un oeil à la fonction main; la première ligne de code limite le taux d'affichage à 30 frames par seconde. Mais que se passera-t-il si je mets fps_max à 500? Faisons le changement maintenant :

Exécutez le script de nouveau et vous noterez que la voiture tourne beaucoup plus vite. Pressez la touche Tab sur votre clavier pour retrouver un vieil ami (la console) et tapez la ligne de code suivante puis pressez la touche Entrée:

fps_max = 10;

La rotation est vraiment saccadée et la vitesse de rotation a largement diminuée! La voiture fait une rotation complète en 5 secondes à 30 fps, et à présent elle a besoin de 16 secondes pour une rotation complète Comprenez que certains (si ce n'est plusieurs) de vos clients auront de vieux PC et que le taux d'affichage sera bas sur leur système. Et n'oubliez pas que leur argent à la même couleur! Comment pouvons-nous gérer cela?

Voici une règle d'or : votre jeu doit être génial sur les nouveaux PC et doit être aussi bon que possible sur les vieux PC. Conitec a fait un travail remarquable avec le moteur Acknex, faisant en sorte qu'il fonctionne avec toutes les bonnes cartes 3D disponibles sur le marché. Voyons ce que VOUS, vous pouvez faire avec cela:

- Vous pouvez vendre votre jeu accompagné de la meilleure carte 3D du marché. Si vous vendez beaucoup de copies de votre jeu, soyez sur que le revendeur de la carte vous fera un très bon prix ! :)

- Vous programmer votre jeu "sagement", vous assurant qu'il fonctionnera à la même vitesse (ce qui ne veut pas dire avec le même taux d'affichage) sur les PC listés comme répondant aux critères de "configuration minimale requise" aussi bien que sur les PC qui existeront en 2010.

Revenons à notre exemple. Le taux d'affichage sera plus grand ou plus petit selon la configuration du PC et il n'y a rien à faire contre cela, mais vous pouvez vous assurer que la voiture fera une rotation complète en 5 secondes pour un taux d'affichage allant de 10 à 1000 fps.

Une des méthodes, utilisée dans les ateliers précédents consiste à mettre fps_max à une petite valeur. Cette techniquea largement été utilisée sur les vieux jeux mais aujourd'hui elle ne donne plus satisfaction car l'idéal est que votre jeu tourne le plus vite possible sur les PC performants (c'est pour cela que nous les avons payé plus chers) et à un taux d'affichage "honnête" sur les PC moins performants, il ne faut donc pas limiter le taux d'affichage

Si je mets fps_max à 30 et que mes clients ont des nouveaux PC je vais les traiter comme si ils avaient de vieux PC sans parler de ceux qui ont des PC qui ne peuvent pas dépasser les 10 fps. je vous ai dit que fps_max limite uniquement la partie haute du taux d'affichage, il n'y a pas d'instruction magique pour doubler ou tripler les petits taux d'affichage.

Petie note au passage, le taux d'affichage ne dépend que du processeur et de la carte vidéo; ajouter de la mémoire ou mettre un disque dur plus gros n'augmentera pas votre taux d'affichage par seconde.

Bien maintenant que nous avons toutes les données du problème, regardons la solution! Vous avez juste à éditer une ligne dans notre fichier script script19:

Sauvegardez le script et exécutez le niveau de nouveau, vous noterez que la voiture fait un tour complet autour de son angle pan en 5 secondes, juste comme avant. Mainetant pressez Tab et regardez ce qui se passe en limitant le taux d'affichage à 10 fps:

fps_max = 10;

Surprise! Le mouvement est saccadé mais la voiture fait un tour complet en ... 5 secondes! Cette fois le taux d'affichage n'a aucune incidence sur la vitesse de rotation. Essayez différentes valeurs pour fps_max (10...100) et vous noterez que la vitesse de rotation est toujours indépendante du taux d'affichage. Bien mais quel est ce mystérieux time et comment fonctionne-t-il?

Le nouveau mot clé - time - nous donne la durée du dernier cycle d'affichage en ticks (un tick = 1/16 seconde) ce qui traduit en bon français donne la formule suivante :

time = 16 / fps

Ce qui signifie que time = 1 lorsque le taux d'affichage est de 16 fps, time = 0.5 lorsque le taux d'affichage vaut le double (32 fps) etc; notez que time diminue sa valeur lorsque le taux d'affichage augmente. Imaginons que nous voulons déplacer entité en augmentant sa coordonnée x dans une boucle while:

action
move_entity
{
while (1)
{
my.x += 1;
wait (1);
}
}

Mon PC est ancient et ne permet que 25 fps,alors que votre nouveau PC délivre 100 fps. Ce qui signifie que la boucle while ci-dessus s'exécute 25 fois par seconde sur mon PC et 100 fois par seconde sur votre ordinateur. En d'autres mots, mon PC ajoute 25 quants (1 quant à chaque frame) à la coordonnée x de l'entité chaque seconde alors que votre PC ajoute 100 quants (1 quant chaque frame) à la coordonnée x de l'entité chaque seconde. Jetez un oeil sur l'image ci-dessous pour voir la distance parcourue sur les 2 PC dans le mêm intervalle de temps de 3 secondes:

Mainteant ajoutons cette instruction miraculeuse time:

action
move_entity
{
while (1)
{
my.x += 1 * time;
wait (1);
}
}

La boucle s'exécute toujours 25 fois par seconde sur mon PC et 100 fois par seconde sur votre PC, à cela nous n'y pouvons rien !Par contre la distance parcourue à chaque frame dépendra du taux d'affichage à présent. Faisons de simples calculs mathématiques:

time = 16 / 25 fps = 0.64 sur mon PC

time = 16 / 100 fps = 0.16 sur votre PC.

Ce qui signifie que l'entité dans la boucle while ci-dessus couvrira une distance de 25 frames * 1 * time = 25 * 1 * 0.64 = 16 quants en une seconde sur mon PC et 100 frames * 1 * time = 100 * 1 * 0.16 = 16 quants en une seconde sur votre PC! L'entité couvrira la même distance sur n'importe quel PC, peu importe qu'il ait un grand ou un petit taux d'affichage.

Comment devons-nous utiliser time dans nos projets? Nous multiplions le côté droit des expressions (ou les variables apparaissant dans nos expressions) avec time et c'est fait. Voici quelques exemples:

my.z += 2; sera changé en my.z += 2 * time;

my.roll += 1; sera changé en my.roll += 1 * time;

c_move (my, nullvector, vector(5, 0, 2), glide); sera changé en c_move (my, nullvector, vector(5 * time, 0, 2 * time), glide);

Ca n'a aucun sens de multiplier zéro par time le résultat donnant : zéro.

Il y a quelques paramètres qui peuvent changer la valeur donnée par time (comme time_smooth, fps_min) mais vous en apprendrez plus à leur sujet dans la deuxième partie du manuel C-Script . Ne soyez pas désolé si vous paraissez légèrement désapp, nous allons à présent utiliser time dans tous les prochains ateliers vous faisant devenir le maitre du temps!

Suivant: Sprites. Sprites Animés


workshop 20

Précédent utiliser time

Sprites. sprites animés .

Mais au fait, pourquoi avons-nous besoin de ces sprites après tout? why do we need these sprites, after all? Prenons un cas concret:

C'est une copie d'écran d'un niveau réalisé par Cant, et je pense qu'il est superbe. A présent jetez un oeil attentif sur l'image ci-dessous (ce n'est pas le jeu des 7 erreurs mais presque):

Bien c'est le même écran et pourtant il lui manque une petite touche de magie , it's the same shot, but some of the magic has disappeared! La barrière a disparu, les lampes ne jettent plus d'éclats et même les images collées sur la palissade sur le côté gauche ont disparu! Et oui vous avez compris, toutes ces choses sont des sprites. Vous pouvez utiliser n'importe quel logiciel de peinture pour réaliser vos sprites. J'utilise (C'est George qui parle NDT) Paint Shop Pro parce qu'il est très bon marché et qu'il fait du très bon travail mais vous pouvez tout aussi bien utiliser ce produit plus cher qu'est Photoshop, ou tout simplement ceproduit gratuit qu'est Gimp. Dessinez simplement votre image 2D, sauvegardez-là en tant que fichier image bmp, tga ou pcx puis ajoutez-la à votre niveau.

Je vous sents impatient de mettre votre talent de peintre en pratique aussi démarrez votre logiciel de peinture et nous allons créer un sprite dès à présent:

- Démarrez avec une image de 256 x 512 pixels en lui donnant un fond rouge:

- Dessinez 2 lignes noires (RVB = 000) comme sur l'image ci-dessous:

- A présent emplissez l'intérieur avec un dégradé métallique:

- Et pour terminer, emplissez les parties rouges avec du noir (RVB = 000) et sauvegardez votre fichier en tant que fichier tga.

J"ai ajouté ce sprite dans un des niveaux de Can en remplacement de l'un de sessprites d'éclats lumineux originaux:

Pour un coup d'essai, ce n'est pas si mal que cela mais je ne peux pas voir à travers le rayon lumineux... laissez-moijouer avec quelques drapeaux et quelques valeurs "ambient" dans Wed:

Bien, vous ne pensiez pas qu'une combinaison de drapeaux changrait autant notre sprite, non? Je pourrais quitter mon job de programmeur pour entamer une longue carrière de créateur de sprites! :) N'oubliez pas que vous pouvez créer des sprites orientés et des affiches, relisez le 9eme atelier pour vous le remémorer.

Il est temps à présent de nous amuseravec des sprites animés, démarrez Wed, ouvrez work20.wmp et exécutez-le en utilisant le script script20.wdl:

Le texte qui s'affiche ("Acknex rules!") est un sprite animé de 29 frames; jetez un oeil au fichier logo+29.pcx qui se trouve dans le répertoire \workshop20 si vous voulez voir à quoi il ressemble. Maintenant pressez la touche "E":

Nous avons déclenché une explosion. En fait nous avons joué l'animation d'un sprite explosion. Vous devez sortir du jeu et le redémarrer si vous souhaitez voir cette explosion de nouveau. Il y a deux type d'animations:

1) Les animations en boucle;

2) les animations qui ne fonctionnent qu'une fois.

Une animation est jouée en boucle si ses frames sont jouées plus d'une fois.Vous pouvez vouloir utiliser une animation en boucle pour simuler le feu dans une cheminée par exemple ou pour une enseigne lumineuse sur les boutiques de votre ville dans votre jeu, pour un écran d'ordinateur qui affiche différentes choses etc. D'un autre côté vous pouvez utiliser une animation qui ne fonctionne qu'une fois (c'est à dire un sprite qui jouera toutes ses frames une seule fois puis qui s'arrête) comme une explosion, un effet de téportation etc. Bien entendu vous pouvez utiliser une animation qui ne fonctionne qu'une fois plusieurs fois pour simuler plusieurs explosions par exemple.

Je sais, je sais...je vous sents impatient d'en apprendre plus sur ces sprites animés. Regardons à quoi ressembleune image faite pour de l'animation:

L'image a 5 carrés qui correspondent à 5 frames d'animation. Le moteur affichera ces images une par une commençant par la plus à gauche et se déplaçant une par une vers la droite. Si la vitesse de l'animation est suffisemment importante le joueur n'a pas l'impression d'assister à un diaporama ennuyeux mais bien à une animation "réelle"

Bien, comment allez-vous créer vos sprites animés? Vous pouvez commencer par charger des sprites à partir de Acknex Unlimited, le site 3DGS qui offre des ressources gratuites pour les développeurs de jeux ou vous pouvez créer vos propres animations en utilisant votre logiciel de peinture favorite. Choisissez la bonne taille pour une frame, puis créer vos différentes frames et pour terminer vous les coller dans une même image. Si votre frame à une taille de 128 x 32 pixels et que votre animation contient 4 frames, l'image finale devra faire 512 x 32 pixels, parce que 512 = 128 x 4, suis-je clair? Oh, et bien entendu vous n'utilisez pas les cadres jaunes qui apparaîssent sur l'image ci-dessus, ils ne sont là que pour illustrer mon propos afin que vous ayez une bonne vision des différentes frames.

Vous pouvez utiliser autant de frame que vous le souhaitez pour vos animations, souvenez-vous simplement que plus il y a de frames et plus l'effet est joli mais plus vous utilisez de mémoire. Un sprite de 256 x 128 pixels à besoin de 256 x 128 x 2 bytes = 65,536 bytes = 64 Kb. Ce qui signifie que si votre sprite à 16 frames d'animation il aura besoin de 64 Kb x 16 = 1Mb de mémoire vidéo.

N'oubliez pas que vous pouvez (et que vous devez) utiliser le même modèle de sprite animé encore et encore sans aucun problème, parce que la mémoire utilisée n'est allouée qu'une seule fois, en clair c'est mieux d'utiliser un mêm sprite 10 fois que 2 sprites différents. Bien entendu tout cela dépend de votre liste "configuration minimale requise".

La dernière chose à savoir, pour l'instant, c'est la convention de nommage des sprites. Comme vous avez pu le voir, le moteur Acknex est un bon moteur mais il n'est pas devin et il ne peut pas savoir ce que vous avez prévu de faire avec votre sprite. Ce serait donc bien que vous lui disiez quelque chose du genre "Cher moteur, vous serait-il possible de bien vouloir considérer ce sprite comme étant un sprite animé, si cela est possible bien entendu! Pouvez-vous faire cela pour moi?"Et comment pouvons-nous faire cela? En choisissant un nom approprié pour le sprite animé. Voici quelques exemples :

fire+5.pcx

lightning+32.tga

my_explosion+12.bmp

Voyez-vous ce que je vois? Vous pouvez choisir n'importe quel nom pour votre sprite mais vous devez ajouter "+" et le nombre de frames que contient le sprite. Que se passe-t-il si j'oublie de donner un nom correct à mon sprite animé? Il sera tout simplement traité comme un sprite simple, sans animations! Voyez par vous même:

La première image montre la vue de côté de Wed (Wed's side view) montrant la même image placée dans le niveau en utilisant 2 noms différents. Encore une fois j'utilise la même image bitmap, mais le moteur a détecté que muzzle+5.pcx était un sprite avec 5 frames d'animation, et a donc découpé l'image en 5 morceaux (5 frames). La seconde image montre comment les sprites sont montrés par le moteur, vous allez être obligé de me croire muzzle+5.pcx apparaît bien comme une image animée tandis que muzzle.pcx affiche toutes les frames en même temps. J'ai mis un cadre violet dans la deuxième image pour que vous compreniez plus facilement, mais il n'apparaît pas en réalité puisqu'il n'est pas contenu dans le sprite.

Regardons à présent le contenu du fichier script20.wdl:

J'utilise 2 2 sprites animés pour la démo, le premier qui est le sprite en boucle "Acknex rules!" et le second sprite est celui utilisé pour l'explosion montrée une seule fois.

Commet créer un sprite pouvant s'afficher en boucle? Il n'y a pas de restrictions pour le programmeur mais vous devez vous assurez que la dernière frame et la première frame sont similaires (pas identiques) sinon il y aura un décrochage dans l'animation et ça ne sera pas terrible.

Jetons un oeil en premier à l'action attachée au sprite "Acknex rules!" :

action acknex_loop
{
my.flare = on;
while (1)
{
my.frame += 0.8 * time;
my.frame %= 30;
wait (1);
}
}

Le sprite a son drapeau "flare" de mis. Ce qui signifie que les zones sombres du sprite seront plus transparentes que les zones claires ce qui donne un meilleur rendu du sprite. Regardez la différence sur ces 2 images :

Vous pouvez voir que le tour noir des lettres visible sur l'image de droite n'existe pas sur l'image de gauche car nous avons mis le drapeau "flare" à on. Vous pouvez jouer avec les drapeaux : "flare", "transparent", "bright" lorsque vous créez votre effet - sprite. Vous aurez plus d'informations sur ces drapeaux dans le manuel C-Script.

"Acknex rules" joue ses frames d'animation dans une boucle while (1), ce qui signifie que l'animation commence à s'exécuter dès le lancement du moteur et ne s'arrêtera qu'avec l'arrêt du moteur. Nous augmentons la frame de l'animation en ajoutant "0.8 * time" à la frame d'animation courante tout le temps, jouez avec la valeur 0.8 si vous voulez augmenter ou diminuer la vitesse d'animation.

Mêm s f my.frame monte au dessus de 100, nous ne pouvons pas voir plus de 29 frames car notre image n'en a pas plus, exact? C'est le pourquoi de ma ligne de code "my.frame %= 30;" qui limite my.frame dans l'intervalle : 0...29, permettant ainsi au sprite de boucler en permanence. Nous avons déjà parlé de l'opérateur modulo (%) dans l'atelier 14;il ne serait peut-être pas inutile de vous replonger dans les explications si vous avez oublié comment cet opérateur fonctionne.

Il est temps de passer à la deuxième animation (une seule fois):

action
explosion
{
my.flare = on;
my.ambient
= 100;
while (key_e == off) {wait (1);}
while
(my.frame < 12)
{
my.frame
+= 0.7 * time;
wait (1);
}
}

Le sprite explosion a son drapeau "flare" de mist;sa valeur "ambient" est mise à 100 car une explosiondoit être très lumineuse, n'est-ce pas? Examinons la ligne de code suivante:

while (key_e == off) {wait (1);}

Cette ligne demande au moteur d'attendre que key_e ("E" sur votre clavier) soit pressée. Ce qui signifie que cette boucle attend patiemment que vous daignez presser la touche "E":

while (my.frame < 12)
{
my.frame += 0.7 * time;
wait (1);
}

Cette simple boucle augmente le paramètre "frame" de notre sprite explosion jusqu'à ce que frame = 12 (notre sprite explosion a seulement 11 frames). Une fois encore, jouez avec 0.7 si vous voulez augmenter ou diminuer la vitesse d'animation du sprite. L'animation sera jouée une seule fois puis s'arrêtera - ce qu'une animation qui ne fonctionne qu'une seule fois est sensée faire!

Tirons quelques conclusions:

- Les sprites qui fonctionnent en boucle on besoin d'une boucle "while (1)";

- Les sprites qui ne fonctionnent qu'une seule fois ont besoin d'une boucle "while (my.frame < (number_of_frames + 1))" ;

- Les sprites qui fonctionnent en boucle ont besoin d'une instruction "my.frame %= (nombre_de_frames + 1);" dans leur boucle "while";

- Les sprites qui ne fonctionnent qu'une seule fois n'ont pas besoin de la ligne de code ci-dessus dans leur boucle "while".

Jesais, vous aimeriez avoir quelques exemples à présent, en voici quelques uns:

a)animation en boucle, le sprite a 5 frames:

action
looped_5
{
while (1)
{
my.frame += 1.5 * time; // 1.5 = speed
my.frame
%= 6; // 5 animation frames + 1
wait (1);
}
}

b) animation une seule fois, 10 frames

action oneshot_10
{
while (my.frame < 11) // 11 = 10 animation frames + 1
{
my.frame += 0.2 * time; // 0.2 = speed
wait (1);
}
}

Ces deux exemples doivent servir de squelette pourtous les sprites animés et les effets spéciaux. Je vous encourage à ajouter les lignes suivantes :

my.flare = on;

my.transparent = on;

my.ambient = 100;

au début de vos actions, essayer différentes combinaisons de ces 3 lignes et comparez les différents résultats.

Suivant: Modèles. Modèles animés


workshop 21

Précédent : Sprites. Sprites animés

Modèles. Modèles animés.

Si vous prevoyez de créer un jeu, vous voudrez utiliser des modèles pour vos véhicules, personnages etc. Bien, vous voudrez également "épicer" votre niveau en accrochant quelques modèles sur les murs, comme je l'ai fait avec la torche sur l'image ci-dessous:

Vous n'avez pas besoin d'avoir un diplôme d'ingénieur si vous prévoyez d'utiliser des modèles non animés dans votre jeu, utilisez la fonction "Add model" qui se trouve dans Wed pour le placer dans votre niveau et vous n'avez plus qu'à le placer à l'endroit désiré.Mais comment pouvons-nous utiliser ces modèles animés qui ont fiere allure? En fait il y a 2 types de modèles animés:

1)Les modèles qui utilisent l'animation par frames.

2) Les modèles qui utilisent l'animation par os (bones).

Le premier type de modèle utilise l'animation par frame comme le fait un sprite animé sauf que le modèle est un objet 3D, lui. J'ai démarré MED, regardezun modèle qui utilise l'animation par frames:

Les animations peuvent être jouées dans une boucle (pour l'attente (standing), la marche (walking), la course (running) etc) ou nous pouvons avoir une animation qui ne se répète pas comme le saut par exemple. Vous pouvez utiliser de nombreuses frames d'animation pour votre modèle,la quantité de mémoire vidéo utilisée par les modèles dépend principalement de la taille de la peau (skin), le nombre d'animation a très peu d'influence sur cette mémoire.

Un modèle classique à plusieurs animations et c'est ce que montre le "frame names" dans Med:

Oui je sais, MED ne vous montre pas les différentes animations avec des couleurs différentes, j'ai utilisé un logiciel de peinture pour illustrer mon propos qui est de vous montrer que chaque animation doit avoir un nom distinct. Si vous avez plusieurs animations de mort (death) pour votre modèle vous pourriez les nommer de cette façon :

- deatha1... deatha30 (la première animation de mort (death) a 30 frames)

- deathb1... deathb5 (la deuxième animation de mort (death) a 5 frames)

- rip1... rip8 (la troisième animation de mort (death) a 8 frames)

Ce que j'essaye de vous montrer ici c'est que le nom importe peu mais il est important d'avoir un nom différent pour chaque animation. Bien mais comment écrire le code qui utilise ces animations? Démarrez Wed, ouvrez work21.wmp et exécutez--le en utilisant le script script21.wdl:

Le garde sur la partie gauche de l'écran joue son animation "marche" (walk) mais le garde de droite ne fait rien! Mais attendez un peu et.....

Je vois ! Le garde de gauche continue son animation dans une boucle tandis que le garde de droite mourrant sous vos yeux exécute une animation sans répétition (death)! Examinons le fichier script:

Comme vous pouvez le constater, C-Script est quand même génial, avec peu de ligne on arrive à faire des choses extraordinaires. Regardons l'action qui fait marcher notre garde de gauche:

action
walking_guard
{
while (1)
{
ent_animate(my, "walk", walk_percentage, anm_cycle);
// "walk" animation loop
walk_percentage
+= 3 * time; // 3 = animation speed for "walk"
wait (1);
}
}

Nous utilisons une boucle while (1) car nous voulons que notre animation "marche" (walk) s'exécute en permanence, parlons plutôt de la suite du code:

ent_animate(my, "walk", walk_percentage, anm_cycle);

Cette instruction anime l'entité "my" (l'entité qui a cette action qui lui est attachée) utilisant son animation bouclée "walk", à la vitesse donnée par la variable nommée "walk_percentage", et joue l'animation en un cycle (dans une boucle) à cause du paramètre anm_cycle. Voici la forme générale de l'instruction "ent_animate":

ent_animate(entity, animation_name, animation_percentage, animation_mode);

- "entity" est le nom de l'entité qui sera animée. Vous n'êtes pas obligé d'utiliser "my" ici si vous n'en n'avez pas envie, définissez un pointeur pour votre entité et vous serz capable d'utiliser son nom également:

Ex: ent_animate(kung_fu_master, "rofl", masters_speed, anm_cycle);

- "animation_name" est le nom de l'animation donné par Med (mais sans les chiffres associés aux différentes frames) n'oubliez pas de mettre le nom de l'animation entre guillemets (""), sinon vous aurez un message d'erreur. Encore une fois vous pouvez donner le nom que vous voulez à votre animation dans MED mais vous devez utiliser le même ici dans votre fichier script:

Ex: ent_animate(my, "eternue", nose_speed, anm_cycle);

- "animation_percentage" est le pourcentage de l'animation. C'est une simple variable qui doit changer de valeur si vous voulez animer le modèle, si animation_percentage est à 0, le modèle affiche sa premire frame d'animation et si animation_percentage = 100 le modèle affichera sa dernière frame d'animation.

Notre modèle "guard" a seulemnt 4 frames d'animation pour la marche (walking) (walk1... walk4) mais l'animation ne parait pas du tout saccadé dans notre démonstration. En fait si vous jetez un oeil approfondi sur les images ci-dessous vous verrez que le garde donne l'impression d'avoir plus de frames d'animation pour la marche. Cette particularité nommée smooth frame interpolation (interpolation douce entre les frames) est construite dans le moteur A6, le moteur calcule les animations intermédiaires et les place entre les les frames existantes, donnant cette animation réaliste mêm pour un modèle ayant peu de frames.

La variable nommée"walk_percentage" de notre exemple augmente sa valeur tout le temps et c'est pourquoi notre modèle marchant est animé, jouez avec "3" si vous voulez augmenter ou diminuer la vitesse de l'animation.

- "animation_mode" dit au moteur s'il doit jouer l'animation dans une boucle (animation_mode = anm_cycle) ou s'il doit ne la jouer qu'une seule fois (animation_mode = 0).

C'est tout ce que vous avez à savoir à propos de "ent_animate" si vous prévoyez d'animer votre modèle en utilisant l'animation de frames. Et pour rendre les choses encore plus claires, jetons un oeil à l'action qui est attachée au garde de droite, celui qui meurt sous vos yeux dans une animation sans boucle (il ne manquerait plus qu'il ressucite!):

action dead_guard
{
sleep (5); // wait for 5 seconds
while (1)
{
ent_animate(my, "death", death_percentage, 0); // "death" one-shot animation
death_percentage += 2 * time; // 2 = animation speed for "death"
wait (1);
}
}

Le futur mourant attend 5 secondes, il n'y a pas le feu tout de même, puis démarre son animation. J'ai utilisé ce délai car votre moniteur peut prendre 1 ou 2 secondes pour changer de résolution et il aurait été dommage que vous n'assistiez pas au spectacle du garde mourant en direct sous vos yeux.

La ligne "ent_animate" jouera l'animation "death" en utilisant la variable "death_percentage". C'est une animation qui ne boucle pas car "animation_mode" est mis à zéro. Jouez avec la valeur "2" si vous voulez augmenter ou diminuer la vitesse de l'animation.

J'ai utilisé une boucle while (1) pour le garde mourant donc cette boucle continuera à s'exécuter (bien que le garde soit mort) en ne faisant...rien sauf à manger un peu de temps CPU. Une version plus élégante de cette action ressemblerait à ceci:

action dead_guard_2
{
sleep (5); // wait for 5 seconds
while (death_percentage <= 100) // death_percentage will range from 0 to 100 here
{
ent_animate(my, "death", death_percentage, 0); // "death" one-shot animation
death_percentage += 2 * time; // 2 = animation speed for "death"
wait (1);
}
}

La boucle while ci-dessus s'exécutera tant que death_percentage sera inférieur ou égal à 100, et s'arrêtera dès que death_percentage sera supérieur à 100 (c'est à dire que la dernière frame de l'animation "death" soit jouée).Je vous invite à coller cette action à la fin du fichier script21.wdl; de l'attacher à un des gardes, compiler le niveau de nouveau et de le regarder mourir sous vos yeux dans son animation sans boucle "death" comme expliqué plus haut.

Vous n'auriez pas oublié vos devoirs à la maison? Pourquoi n'essayerez-vous pas de créer une simple action pour un modèle qui serait animé en utilisant son animation de marche (walk) tout en le déplaçant en utilisant l'instruction "c_move" en même temps. Utilisez l'action walking_guard comme base (il est déjà prêt à jouer son animation de marche dans une boucle) et ajoutez une simple ligne qui déplacera l'entité en utilisant "c_move" dans la boucle while(1).

Solution: ajoutez une ligne de code à l'action walking_guard:

action walking_guard_2
{
while (1)
{
c_move (my, vector(2 * time, 0, 0), nullvector, glide); // note the time-corrected speed
ent_animate(my, "walk", walk_percentage, anm_cycle); // "walk" animation loop
walk_percentage += 3 * time; // 3 = animation speed for "walk"
wait (1);
}
}

Suivant: Animation avancée de modèles OS (Bones)


workshop 22

Précédent : Modèles. Modèles animés

Animation avancée de modèles. Os (Bones).

Si vous avait fait l'atelier précédent, vous avez appris que les modèles pouvaient être animés en utilisant des frames. Aussi tout ce que vous avez à faire c'est de créer des frames pour l'attente, pour la marche, pour la course, le tir, le saut, la mort etc. Mais que se passe-t-il si vous voulez courrir et tirer en même temps? Bien sur vous pouvez créer une autre animation pour cela et la nommer "tir_en_courant" ou quelque chose comme ça. Ou vous pouvez utiliser les os (bones) et créer n'importe quelle combinaison des animations existantes en utilisant simplement du code C-Script, comme de marcher et de regarder en haut en même temps ou peut-être de ramper et de tirer en même temps ou...bref vous l'avezcompris voici de nouveaux horizons qui s'ouvrent à nous.

Démarrez Wed, ouvrez work22.wmp et exécutez-le en utilisant le script script22.wdl:

Vous pouvez voir le robot qui joue son animation de marche (walk) dans une boucle while; n'oubliez pas qu evous pouvez presser la touche "0" si vous voulez jouer avec la caméra en utilisant les flèches de direction, les touches "Début", "Fin", "Page préc" et "Page suiv". Maintenant pressez et maintenez enfoncée la touche espace pendant un cycle:

Le robot a tourné ses armes vers le côté gauche de l'éran. Relâchez la barre espace et les armes retournent à leur position originale. A présent cliquez ici pour voir le robot marcher dans MED et ici pour le voir tourner (vous avez besoin de Windows Media Player 9 ou supérieur). Vous noterez que ces 2 animations (marche et arme qui tourne) sont bien distinctes et cependant notre script les a mélangées superbement et notre robot marche et tourne ses armes en même temps. Ah j'oubliais, si l'animation est saccadée sur le petit film c'est parce que j'ai essayé de faire le film le plus petit possible.

Le fichier script est assez court également, jugez par vous même

La seule chose qui réclame notre attention c'est l'action bones_test:

action
bones_test
{
while(1)
{
ent_animate(my, null, 0, 0);
walk_speed +=
2 * time;
my.pose = 1;
ent_animate(my, "walk", walk_speed, anm_cycle);

Nous avons déjà discuté de "ent_animate" dans notre atelier précédent, la première ligne de code dans notre boucle while remet à 0 tous les os pour notre modèle, les remettant à leur position d'origine. Il n'y a rien de magique avec cette ligne de code : mettre le nom de l'animation à "null" fait le job si vous utiliser les os. N'oubliez pas de lire le manuel Med si vous voulez en apprendre plus au sujet de la création d'os et de l'animation des os.

Nous avons défini une variable nommée "walk_speed" qui contrôle la vitesse de l'animation; changez "2" si vous voulez modifier la vitesse de l'animation "marche" (walk) pour notre robot. Chaque modèle peut avoir jusqu'à 4 poses differentes; ce qui signifie que jusqu'à 4 animations d'os différentes peuvent être combinées en même emps, comme de courrir en tirant, en tournant la tête et en lançant une grenade. Nous allons combiner 2 animations dans cet atelier et la première pose est utilisée pour la marche (walking) donc my.pose = 1;.

La ligne de code suivante anime le robot en utilisant son animation de marche : "walk", comme explmiqué dans l'atelier précédent. Ok regardons encore une fois la définition de "ent_animate" nous avons donc encore besoin de sa référence.

ent_animate(entity, animation_name, animation_percentage, animation_mode);

Iln'y a rien d'inhabituel avec notre ligne de code "ent_animate" : elle anime notre modèle en utilisant son animation de marche ("walk") à la vitesse donnée par "walk_speed" et l'animation boucle ar il y a le paramètre "anm_cycle". Voyons plutôt la prochaine ligne de code de notre action:

ent_blendpose(my, 2, 1, 100);

Voic une ligne qui fait quelque chose de nouveau et d'intéressant : elle copie l'animation de marche ("walk") dans l'animation qui fait tourner l'arme ("turn"), car c'est l'animation "tourne" qui prend la main lorsqu'on presse la barre espace et nous devons permettre au modèle de continuer à marcher même lorsqu'il tourne ses armes, non? Voici la forme générale de l'instruction "ent_blendpose":

ent_blendpose(entity, target_pose, source_pose, blending_factor);

- "entity" est le nom de l'entité qui doit être animée. Vous n'êtes pas obligé d'utiliser "my" ici si vous n'en n'avez pas envie. N'importe quel pointeur (défini auparavant) fera tout aussi bien l'affaire;

- "target_pose" est le numéro de la position qui va stocker l'animation résultante. J'ai choisi 2 ici, qui est utilisé pour "turn".

- "source_pose" est le numéro de position qui est utilisé pour l'animation source. J'ai utilisé 1 ici car c'est la position (mise à travers de " my.pose = 1;") pour la marche (walking);

- "blending_factor" est le pourcentage (0...100) qui donne la quantité de mélange pour les 2 positions (source et destination). Si on utilise 0 "target_pose" restera inchangé, mais si on met 100 (ce que j'ai fait dans mon exemple) "source_pose" sera copié (complètement mixé) à "target_pose".

Mais en quoi consiste cette action de mixage (blending)? Vous pouvez poser cette question et je ne veux pas vous faire attendre plus longtemps. Lorsque nous voulons mélanger, fusionner, mixer 2 ou plusieurs animations, le moteur utilise une combinaison des 2 (ou plus) positions; plus grand est la valeur de "blending_factor" et plus grande sera le mélange entre l'animation source et l'animation cible. Revenons à notre action:

     if ((key_space == on) && (turn_speed < 100))
{
turn_speed += 10 * time;
}
if ((key_space == off) && (turn_speed > 0))
{
turn_speed
-= 10 * time;
}

Les lignes ci-dessus vérifie si nous avons pressé la barre espace ou pas. Si elle est pressée et que turn_speed a une valeur inférieure à 100, sa valeur sera augmentée de la vitesse donnée par "10 * time"; sinon si la barre n'est pas pressée et que turn_speed est supérieur à 0, sa valeur sera diminuée à la vitesse donnée par "10 * time". Mine de rien ce petit code donne à la variable nommée "turn_speed" une valeur pouvant aller de 0 à 100 si nous pressons et maintenons enfoncé la touche espace et diminue doucement "turn_speed" si nous relachons la barre espace. Voici l'illustration de ce phénomène:

Le joueur attend une 1 seconde et lorsqu'il presse la touche espace "turn_speed" démarre son ascension en ajoutant "+10 * time" à sa valeur initiale à chaque frame, et s'arrête lorsqu'elle atteint 100, même si le joueur continue de presser la touche espace. secondes ont à présent passé et le joueur décide de relacher la barre espace aussi "turn_speed" commence sa descente en diminuant sa valeur de "-10 * time" à chaque frame, jusqu'à atteindre zéro.

     if (turn_speed > 0)
{
my.pose =
2;
ent_animate(my,
"turn", turn_speed, anm_add);
ent_blendpose(my, 1, 2, turn_speed); // blend "turn" (2nd pose) into
"walk" (1st)
}
wait(1);
}
}

La dernière partie de l'action vérifie si "turn_speed" est plus grand que 0. Si oui, la seconde position du modèle est choisie et nous animons le modèle avec "ent_animate" et son animation "turn" en utilisant le paramètre "anm_add". Ce mode d'animation ne peut pas être utilisé pour l'animation des sommets (par frame cf notre atelier précédent) c'est pourquoi je n'en ai pas parlé à ce moment là. il ajoute le nouvel angle d'os à l'ancien, le résultat remplaçant complètement l'ancien, ce qui signifie que le modèle conserve sa marche même si nous pressons la touche espace afin de déclencher son action de tourner ses armes.

La dernière instruction "ent_blendpose" mélange parfaitement les 2 animations car turn_speed, qui fait ici office de "blending_factor" augmente et diminue ses valeurs en douceur comme montré dans l'image un peu plus haut. En mélangeant la seconde position ("turn") dans la première position ("walk") nous pouvons être sur que notre modèle n'aura pas de changements brusques mais des animations en douceur même en combinant leurs animations d'os..

Revoyons toute l'action dans son ensemble (brièvement):

action
bones_test
{
while(1)
{
ent_animate(my, null, 0, 0);
walk_speed
+= 2 * time;
my.pose = 1;
ent_animate(my, "walk", walk_speed, anm_cycle);
ent_blendpose(my, 2, 1, 100);
if ((key_space == on) && (turn_speed <
100))
{
turn_speed += 10 * time;
}
if ((key_space == off) && (turn_speed >
0))
{
turn_speed -= 10 * time;
}
if (turn_speed > 0)
{
my.pose =
2;
ent_animate(my,
"turn", turn_speed, anm_add);
ent_blendpose(my, 1, 2, turn_speed);
}
wait(1);
}
}

Il y a 3 instructions "ent_animate" dans cette action:

- La première remt à zéro les animations (les positions os) chaque frame;

- la seconde instruction anime le robot en utilisant son animation de marche ("walk");

- la troisième ligne "ent_animate" s'exécutera uniquement si la barre espace est pressée pour jouer l'animation de tourner l'es armes ("turn").

Nous utilisons également 2 instructions "ent_blendpose":

- la première copie (mélange à 100%) la première position de marche ("walk") dans la seconde position ("turn");

- la deuxième instruction fait un mélange doux entre les 2 animations parce que le facteur de mélange est donné par une variable qui augmente et diminue sa valeur en douceur.

Ce paragraphe termine l'atelier parlant de l'animation avec os. Le code peut paraître un peu compliqué pour l'instant mais n'oubliez pas que vous pouvez très bien faire votre jeu avec pratiquement que des animations par frame et n'utiliser l'animation par os qu'en cas de nécessité absolue

Suivant Variables globales. Variables locales


workshop 23

Précédent l'animation avancée des modèles. Os (bones)

Variables globales . Variables locales .

Si vous avez lu le deuxième atelier, celui qui parle des variables) peut-être vous êtes-vous étonné qu'on n'aborde pas le sujet des variables globales et locales. Est-ce un concept si difficile à comprendre pour un débutant?

Jusqu'à présent, vous avez utilisé des variables globales tout le temps sans le savoir. J'avais besoin d'expliquer d'abord les actions et les fonctions car nous en avons besoin pour pouvoir comprendre par la suite comment fonctionnent les variables locales. Démarrons un exemple, démarrez Wed chargez work23.wmp et exécutez-le en utilisant le script script23.wdl:

Ca ressemble à notre bonne vieille planète terre. J'ai utilisé un cube texturé de noir pour le niveau et j'ai placé un modèle de sphère à l'intérieur, c'est pourquoi vous ne voyez pas les limites du niveau

Maintenant voic ce que j'appelle un joli script ! Le modèle sphère change son angle pan en ajoutant "2 * time" à chaque frame, becparce que"rotation_speed" est mis à 2. TC'est, comme vous avez pu le deviner une variable globale, une variable qui est définie en dehors de l'action ou de la fonction. Comme je l'ai déjà dit, nous n'avons jusqu'à présent défini que des variables globales dans les ateliers précédents sans le savoir! Maintenant exécutez le niveau de nouveau, pressez la touche Tab pour faire apparaître le mode console et tapez la ligne de code suivante:

rotation_speed = 5;

La sphère tourne plus vite, non? Nous pouvons contrôler la vitesse de rotation en utilisant la console parce que la variable nommée "rotation_speed" est connue de toutes les fonctions ou actions y compris la fonction incluse dans le moteur qui gère l'affichage de la console. C'est comme cela que fonctionne une variable globale!

A l'inverse, une variable locale ne sera connue qu'à l'intérieur de la fonction ou de l'action qui inclu sa définition. Transformons notre variable globale en une variable locale en déplaçant la ligne qui définit "rotation_speed" à l'intérieur de l'action nommée "mother_earth":

Maintenant exécutez le script de nouveau:

La planète tourne comme avant, à présent tapez la même ligne à la console :

rotation_speed = 5;

Cette fois-ci la vitesse de rotation n'a pas changé du tout! La fonction qui gère l'affichage de la console ne connait plus la variable car la variable "rotation_speed" est à présent une variable locale, elle n'est donc connue que de l'action nommée "mother_earth". Si je lets une ligne qui donne une valeur à "rotation_speed" dans la fonction "main":

le moteur génèrera un message d'erreur car la fonction main ne connait pas la variable locale qui est défini à l'intérieur de l'action nommée "mother_earth":

Construisons un autre exemple qui utilisse les variables locales, copier / coller leslignes de code suivantes à la fin de votre fichier script:

action
mother_earth2
{
var rotation_speed = 5;
while (1)
{
my.pan += rotation_speed
* time;
wait (1);
}
}

Voici à quoi doit ressembler votre script à présent:

A présent ajouter une deuxième sphère dans votre niveau et attachez lui l'action "mother_earth2". Jetez un oeil ci-dessous pour voir où mettre approximativement la deuxième sphère dans Wed:

Sauvegardez le niveau, compilez-le et exécutez-le:

Nous avons bien 2 spères qui tournent à présent, chacune ayant sa propre vitesse de rotation. C'est exactement ce qui doit être car nous avons défini une variable locale nommée rotation_speed (mise à 2) dans l'action "mother_earth" et une variable locale nommé...hum, hum... rotation_speed (mise à 5) dans l'action"mother_earth2"! Nous avons défini 2 variables avec le mêm nom et pour résultat nous avons 2 vitesse de rotation différentes pour nos planètes car se sont des variables locales. Quelle autre preuve voulez-vous? Ces variables locales n'intérferrent pas entre elles même si elles ont le même nom!

Maintenant ne vous méprenez pas sur mon compte, j'aime également les variables globales. Elles sont nécessaires mlorsque certaines données sont utiles à plusieurs actions et / ou fonctions! Vous voulez que tous les monstres semettent à danser lorsque kle joueur meurt? Il n'y a rien d'autre de mieux à faire que de définir la variable "santé" du joeur en tant que variable globale comme cela les monstrespourront vérifier cette valeur à partir de leur action respective! réciproquement, vous utiliserez les variables locales pour toutes les instructions qui prennent uniquement place à l'intérieur des fonctions ou actions de mouvement, animation etc.

Suivant :Variables d'entité (skills). Drapeaux (Flags)


workshop 24

Précédent Variables globales Vvariables.lLocales

Variables d'entité (skills). Drapeaux (Flags).

Acknex utilise des variables nommées "skills", qui sont spéciales, pré-construites et variables locales. Une entité qui peut-être un modèle, un sprite etc a 100 variables "skills", les 20 premières étant accessibles directement à partir de la fenêtre "object Properties" de Wed et les autres sont accessibles uniquement à partir d'instructions C-Script.

Si vous avez déjà utilisé Wed auparavant vous avez peut-être noté la fenêtre "Object Properties" window. Sélectionnez n'importe quelle entité, cliquez-là avec le bouton droit de la souris et choisissez ""Properties", puis cliquez sur l'onglet "behaviour" pour voir ses skills:

J'ai mis SKILL1 à 6 et SKILL2 à 3, mais cela n'a aucune incidence sur l'entité tant queje ne lis pas ces valeurs par un code C-Script. Qu'est-ce que vous attendez? Démarrez Sed et ouvrez le fichier script script24:

Démarrez le script et vous allez retrouver un bon ami à nous, notre planète en rotation.

Je pense que vous serez d'accord avec moi pour dire qu'une ligne particulière attire notre attention:

my.pan += my.skill1 * time;

La sphère change son angle pan en ajoutant "my.skill1 * time" à chaque frame.Je suis curieux de voir la valeur de skill1 dans Wed? Voici un écran:

Ce qui signifie que nous pouvons agir sur la vitesse de rotation sans toucherdu tout au script car nous pouvons entrer une valeur pour SKILL1en utilisant la fenêtre "Object Properties" de Wed! Notre simple ligne de code charge la valeur mise dans Wed dans le moteur. Jetez un oeil sur cette ligne de code:

my.pan += 4 * time;

Et jetez un autre oeil sur la ligne de code de notre script:

my.pan += my.skill1 * time;

Quelle différence y-a-t-il entre les deux lignes? Nous avons remplacé le "4"par"my.skill1", qui est la première variable de l'entité attachée à cette action. C'est tout ce que nous avons à faire si nous vouons utiliser les skills pour nos actions. Maintenant allez-y, mettez différentes valeurs à SKILL1 dans Wed, re-compilez le niveau après chaque changement et voyez les changements par vous même. Faites attention qu'en mettant SKILL1 = 0 vous allez ajouter zéro degré à l'angle pan à chaque frame, aussi la planète ne va pas tourner du tout.

Nous pouvons utiliser n'importe quel autre skill (my.skill2... my.skill100) pour contrôler la vitesse de rotation mais souvenez-vous que seules les 20 premières variables Skill sont accessibles à partir de Wed! En règle général vous utiliserez les 20 premieres variables skill pour entrer des valeurs à partir de Wed, vous éviterez d'utiliser les skills 21...50 car la plupart sont utilisées par les templates livrés avec A6, et vous utiliserez skills 51...100 comme variables locales dans C-Script. Si vous ne prévoyez pas d'utiliser les templates alors vous pouvez bien entendu user et abuser de tous les skills (1...100).

Pourquoi vouloir utiliser des skills plutôt que des variables locales? Tout d'abord, parce qu'elles existent déjà. Chaque entité inclu 100 variables skills, aussi nous n'avons pas besoin d'utiliser de la mémoire supplémentaire pour d'autres variables locales. Besoin d'une raison encore plus importante? Nous pouvons utiliser ces skills pour embellir notre fenêtre "Object Properties" dans Wed

Voici une copie d'écran d'un simulateur de conduite (pas une course de voiture) développé pour un de mes clients. Vous pouvez voir que les vieux noms Skill1...Skill20 ont disparu et sont remplacés par des noms beaucoup plus parlants à présent! Avons-nous bespin de faire cela? Je pense que ouiârce que :

1) Nous vieillissons et notre mémoire n'est plus ce qu'elle était. Un projet de qualité commerciale prend entre 6 à 24 mois pour voir le jour et c'est préférable de voir quelque chose comme "vitesse_initiale" dans Wed plutôt que "SKILL3"; de cette façon nous n'avons pas besoin de relire des pages de code pour savoir à quoi correspond telles ou telles variables Skill;

2) Notre créateur de niveau doit être capable de créer, tester et peupler les niveaux avec toute sorte de monstres sans avoir besoin de graphiques compliqués ou de notre présence. Ce qui signifie que nous les programmeurs pourront rentrer plus tôt à la maison car le désigner n'aura pas besoin qu'on reste près de lui:)

Comment redéfinissons-nous les noms des variables dans Wed? Démarrez Wed, chargez le niveau work24_2.wmp file, compilez-le et exécutez-le en utilisant le script script24_2.wdl, vous pouvez voir la même planète tournant, mais un peu plus sombre. Sélectionnez la planète et regardez dans l'onglet "behaviour" de ses propriétés:

Notre planète peut changer sa vitesse de rotaion et sa brillance en utilisant ses propres variables SKILL1 et SKILL2, qui sont maintenant connues comme "Rotation_speed" et "Brightness"! Jouez un peu avec ces valeurs; "Brightness" produit des effets visibles dans une plage de -100 à 100. N'oubliez pas de recompiler le niveau après chaque changement si vous voulez voir l'effet de vos changements.

Fini de vous amuser? Alors voyons de plus près le contenu du fichier script24_2.wdl:

Nota Bene : au moment de l'écriture de cet atelier avec la version A6.22 il semblerait qu'il y ait un bug et il est nécessaire que le script se termine par une ligne blanche (que vous ne voyez pas sur l'image mais il y a une ligne 32 dans le script) pour que le remplacement des noms fonctionne.

Nous allons parcourir les changements pas à pas.

define rotation_speed, skill1;
define brightness, skill2;

Les 2 lignes ci-dessus donnent de jolis noms à skill1 et skill2. C'est vraiment simple! Imaginons que nous fassions un jeu ensemble. J'adore donner des noms compliqués àmes variables (en fait ce n'est pas vrai j'ai horreur de ça mais faisons comme ci pour l'instant) aussi voici une de mes définitions de variable:

var combien_de_vies_dispose_le_joueur_avant_de_mourir_définitivement_et_irrémédiablement = 3;

Vous n'aimez pas le nom de ma variable? (qui l'aimerait d'ailleurs!). Aussi vous voudriez le changer mais vous ne pouvez pas parce que :

a) Je peux devenir très méchant;

b) Le reste du code donnera des erreurs car j'ai utilisé combien_de_vies_dispose_le_joueur_avant_de_mourir_définitivement_et_irrémédiablement de nombreuses fois dans mon code et donc il faudrait penser à le modifier partout.

Alors que devons nous faire? Ajouter une simple instruction "define":

define nombre_de_vies, combien_de_vies_dispose_le_joueur_avant_de_mourir_définitivement_et_irrémédiablement;

De cette façon l'ancienne variable a un nouveau nom. Je peux utiliser mon ancien nom, vous pouvez utiliser votre nouveau nom et ils vécurent heureux (et eurent de nombreux enfants, non je m'égare) et bien entendu chacun de nous peut modifier la valeur de cette variable.

Donc voivi comment fonctionne "define". Revenons à notre script, je suis donc capable d'utiliser "my.rotation_speed" à la place de "my.skill1" à partir de maintenant et "my.brightness" à la place de "my.skill2". Aussi simple que cela! Voyons la suite :

// uses rotation_speed, brightness

Voici une ligne de commentaire inhabituelle, elle est placée juste avant la définition de l'action. C'est cette ligne qui dit à Wed que l'action qui suit va utiliser les noms "rotation_speed" et "brightness" définis auparavant et c'est ce qui fait que Wed changera le nom SKILL1 par "Rotation_speed" (la majuscule est automatique) et SKILL2 par "Brightness". Vous pouvez ajouter autant de noms définis par define dans la ligne de commentaire du moment que vous les séparier par des virgules.

Il est temps de regarder l'action dans son entier:

//
uses rotation_speed, brightness
action mother_earth_beauty
{
my.ambient = my.brightness;
while (1)
{
my.pan += my.rotation_speed * time;
wait (1);
}
}

La sphère met son ambient à la valeur entrée en utilisant "my.brightness" (my.skill2) dans Wed et tourne avec la vitesse donnée par "my.rotation_speed" (my.skill1) dans Wed.

Encore une chose vous ne devez pas utiliser de noms avec des espaces comme "define my health skill3;" ou"// uses players armor", mais je pense que vous le saviez déjà. C'est tout ce que nous avons à savoir sur ce type de commentaires. Il y en a beaucoup plus et vous pouvez les retrouver dans le manuel C-script (comment tag).

Acknex utilise également des drapeaux ("flags") qui sont identiques aux interrupteur que vous utilisez dans votre maison pour allumer la lumière (c'est à dire qu'ils ont 2 états, allumé ou éteint, 1 ou 0, on ou off). Chaque entoté inclut 8 drapeaux (flags) qui peuvent être mis à on (coché) ou à off (décoché) dans la mêm fenêtre "Object Properties" dans Wed.

L'image ci-dessus montre Flag1 et Flag3 de mis à "on" (cochés), le reste des drapeaux (flags) étant "off" (décochés). Nous pouvons utiliser ces drapeaux dans C-Script en utilisant my.flag1... my.flag8. Démarrez Sed et chargez le fichier script24_3:

C'est un tout petit script car il commence à se faire tard, on arrive à la fin de cet atelier et que vous commencez à fatiguer. l'action vérifie simplement l'état du premier drapeau de l'entité qui est attachée à l' action nommée"flag_example". Si le drapeau est coché dans Wed ("on") le modèle sera transparent. Regardez ce qui se passe si vous cochez / décochez flag1 dans Wed (pensez à recompiler après chaque changement):

Croyez-le ou pas, nous pouvons donner aussi de jolis noms à ces drapeaux en utilisant la même méthde ("define"nom du drapeau) et en plaçant une ligne de commentaire ("uses") juste avant l'action qui l'utilise. Vous pouvez voir quelques drapeaux avec de jolis noms sur mon projet de simulateur sur l'image ci-dessous:

Nous utiliserons de nombreuses Skills et de nombreux drapeaux dans nos prochains ateliers même si nous avons pu nous en dispenser jusqu'à présent!

Il est temps de faire notre devoir à la maison, créer une action qui utilise les 3 premiers Skills dans Wed nommés "Pan_speed", "Tilt_speed" et "Roll_speed" pour contrôler la vitese de rotation de l aplanète en changeant ses angles pan, tilt et roll angles dans une boucle "while(1)". La même action doit utiliser flag1, nommé "Transparency", pour contrôler la transparence de la planète.

Voici ce que vous devriez obtenir (les valeurs n'ont aucune importance).

Solution: voici à quoi doit ressembler votre code:

var video_mode = 7; // 800x600 pixels
var video_depth = 32; // 32 bit mode

string home24_wmb = <home24.wmb>;

define
pan_speed, skill1;
define tilt_speed, skill2;
define roll_speed, skill3;
define see_through, flag1;

function
main()
{
level_load (home24_wmb);
}

//
uses pan_speed, tilt_speed, roll_speed, see_through
action wild_planet
{
if (my.see_through == on) // first flag is checked in Wed?
{
my.transparent = on; // then
make the sphere transparent
}
while (1)
{
my.pan += my.pan_speed * time;
my.tilt += my.tilt_speed * time;
my.roll += my.roll_speed * time;
wait (1);
}
}