[C-Engine] n°6 : Ajout d'un objectif
Posté le 14/04/2016 17:22
Si vous possédez une version ultérieur à celle du 14 / 04, ce tuto nécessite une mise à jours du C-Engine,
Etape 1 : Création de la pièce.
Pour commencer , commençons par créer la pièce. Vous savez le faire donc je vous donne tout de suite le code.
Les sprites :
const unsigned char Po1[]={0x1e,0x0,0x21,0x0,0x40,0x80,0x8c,0x40,0x88,
0x40,0x88,0x40,0x8c,0x40,0x40,0x80,0x21,0x0,0x1e,0x0};
const unsigned char Po2[]={0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x70};
Sprite S_Coins1(Po1,10,10);
Sprite S_Coins2(Po2,5,10,3,0);
Sprite S_Coins[]={S_Coins1,S_Coins2};
Animation A_Coins(S_Coins,2,150);
La déclaration de l'objet :
Object * Coins = new Object;
Coins->GetTransforms()->SetXY(100,14);
Coins->GetRender()->SetRender(A_Coins);
Coins->AffectTag("Coins");
La fonction AffectTag() permet de nommer l'objet, utile pour plu-tard.
N'oubliez pas de l'associer au moteur.
Game.AddObject(Coins);
Etape 2 : Mise en place dans le script du joueur.
Ensuite, nous voulons que lorsque le joueur touche la pièce, elle soit détruite.
Dans le script du joueur, nous allons tout d'abord commencer par la condition qui est "si le joueur touche la pièce " qui dans le C-Engine s'écrit :
if(GetObject()->CollisionTag("Coins");// Pas définitif
{
}
Nous retrouvons le tag que nous avions donné à la pièce.
Maintenant il faut détruire la pièce, pour cela il nous faut l'adresse en mémoire de la pièce, déclarons donc une variable qui peut stocker une adresse d'objet que nous allons nommer Buffer.
Object * Buffer; // Cette ligne n'est pas définitive
Ensuite nous allons utiliser utiliser une fonction qui renvoie une adresse en mémoire du premier objet portant le tag donné en paramètre qui touche le joueur.
Object * Buffer = GetObject()->CollisionTagO("Coins");//A placer à la fin du script du joueur.
Si le joueur ne touche pas de pièce alors Buffer est égale à NULL sinon il possède l'adresse de la pièce. Nous pouvons donc tester la valeur de Buffer pour connaitre si le joueur touche la pièce.
if(Buffer != NULL) // A mettre à la suite de la déclaration de Buffer.
{
}
Ensuite nous allons détruire la pièce, si le joueur touche la pièce, avec la commande suivante :
GetEngine()->DelObject(Buffer);
Vous pouvez essayer de compiler, normalement lorsque vous touchez la pièce elle disparaît.
Etape 3 : Ajout d'un score et script GUI.
Maintenant que nous avons détruit la pièce, nous pouvons rajouter un score et une gui.
Pour la GUI, il faut créer un nouveau script que vous nommerez GUI et qui contiendrerra une variable pour stocker le score comme ceci.
class GUI: public Script
{
public:
void Start();
void Update();
void AddCoins(int v);
int coins;
};
Cette class possède une fonction pour augmenter le score. Elle est très basic.
void GUI::AddCoins(int v)
{
coins += v;
}
Dans la fonction Start(), nous allons initialiser à 0 le score.
void GUI::Start()
{
coins = 0;
}
Après avoir réalisé ceci, vous pouvez créer l'affichage que vous voulez pour afficher le score.
Il existe la fonction PrintV(x,y,v) qui affiche un nombre en x y de valeur v.
Pour écrire du texte je vous conseille PrintMini(x,y,"Votre Texte",0).
Personnellement, j'ai choisi un cadre avec à l'intérieur écrit "Score:".
Voici le code:
void GUI::Update()
{
ML_rectangle(-1,-1,128,7,1,ML_BLACK,ML_WHITE);
PrintMini(5,1,"Score :",0);
PrintV(35,1,coins);
}
Pour finir nous allons lié le script du joueur à la GUI en rajoutant ceci à la déclaration de la class Control.
class Control: public Script
{
public:
void Update();
GUI * S_GUI;
};
Dans la condition où la pièce est détruite vous pouvez rajouter 1 point au score affiché.
S_GUI->AddCoins(1);
Pour finir, il faut dans la fonction Jeu créer la GUI puis la lié au moteur et au script du joueur.
GUI * S_GUI = new GUI; // à placer après la déclaration du niveau.
Game.AffectScript(*S_GUI);
ScriptPerso->S_GUI = S_GUI;
Vous pouvez compiler, le score est affiché et la pièce ajout 1 point au score.
Je met à disposition les sources du projet que j'ai obtenu
-ici-
Etape 4 : Allez plus loin.....
Maintenant que vous pouvez créer des pièces, créer un timeur dans la class GUI qui débute à 30 puis qui toutes les secondes diminue de 1.
UpdateEverySecond() vous aidera, cette fonction est identique à Update mais elle est appelé qu'une fois par seconde.
Ensuite fixez un objectif de 10 pièces au joueur. Et si il n'a pas ramassé toutes les pièces avant la fin du chrono alors il perd et le jeu quitte sinon il gagne.
Vous pouvez bien sur agrandir la map.
La fonction GetEngine()->StopGame() vous aidera et pour l'affichage de l'écran de fin de partie vous pouvez faire:
if(le joueur a perdu)
{
ML_clear_vram();
PrintMini(20,30,"Perdu",0);
ML_display_vram();
Sleep(500);
GetEngine()->StopGame();
}
Bonne chance pour ce petit test, envoyer moi en MP vos réponses.
Fichier joint
Citer : Posté le 26/04/2016 16:09 | #
Est ce que quelqu'un a réalisé la partie "Aller plus loin " ?
- Kirby's DreamLand : Gobe , Gobe , Gobe !!!
- L'invasion Seanchans : Détruit la flotte ennemis a bord du "Danseur des vagues".
Citer : Posté le 30/04/2016 15:43 | #
Je me suis permis de couper une ligne contenant des sprites pour éviter de déformer la mise en page
Citer : Posté le 08/05/2016 23:28 | #
Pourquoi le scipt pour tester la collision n'est pas associé à la pièce ?
Citer : Posté le 09/05/2016 07:54 | #
C est pour éviter trop de calcul, ici la fonction GetObject avec le tag pièce est appellée une seule fois par frame alors que si on le met sur la pièce, elle serait appellée plusieurs fois par frame. Après c'est tout à fait envisageable.
- Kirby's DreamLand : Gobe , Gobe , Gobe !!!
- L'invasion Seanchans : Détruit la flotte ennemis a bord du "Danseur des vagues".
Citer : Posté le 09/05/2016 13:48 | #
Pourquoi elle serait appelé plusieurs fois par frames ?
Si c'est dans la fonction update, cette fonction est appelé une fois par frame.
(J'ai pas essayé, j'ai juste lu tes tutos )
Par ce que ça me parait plus logique. Je ne suis plus certain, mais il me semble que c'est toi qui te base sur rpg maker. Et bien, il n'y a aucun script associé au héros. On ne vérifie pas si la héros touche la pièce, mais si la pièce touche le héros. Ça permet de faire des copier coller facilement.
Citer : Posté le 09/05/2016 17:48 | #
Oui mais si il y a plusieurs pièces, chacune des pièces va vérifier si elle touche le joueur alors que ici on vérifie une seule fois si le joueur touche une pièce. Sur un Pc, on peut négliger les calculs mais sur calculatrice, si il y a 250 pièces ça commence à faire beaucoups de calcul.
- Kirby's DreamLand : Gobe , Gobe , Gobe !!!
- L'invasion Seanchans : Détruit la flotte ennemis a bord du "Danseur des vagues".
Citer : Posté le 09/05/2016 19:10 | #
D'accord, mais je ne comprends pas comment tu peux vérifier si le héros touche une ou des pièce(s) sans faire le test de collision pour toutes les pieces...
Citer : Posté le 09/05/2016 19:11 | #
En gros si il touche une pièce il arrête de chercher. Et puis ça m'évite de mettre un script sur les pièces.
- Kirby's DreamLand : Gobe , Gobe , Gobe !!!
- L'invasion Seanchans : Détruit la flotte ennemis a bord du "Danseur des vagues".
Citer : Posté le 09/05/2016 19:25 | #
Faire ça ne réduit en rien le nombre de calculs.
Uniquement à LA frame où la héros touche une pièce le calcul s'arrete plus tôt. Plus tôt de combien ? Aucune idée, c'est plus ou moins aléatoire. Tout le reste du temps tu fais le test de collision pour toutes les pièces.
Si tu veux gagner vraiment en perf, tu fais les test une frame sur trois, vu la vitesse du héros, on ne risque pas de louper une pièce
Citer : Posté le 09/05/2016 19:37 | #
Oui après chacun peut optimiser le C-Engine, je donne les bases puis vous faites évoluer le projet. Je suis content que quelqu’un propose quelque chose qui ne soit pas " J'ai une erreur". Si tu veux mettre le test de collision sur la pièce tu peux très bien le faire car tout est déjà dans les tutos.
- Kirby's DreamLand : Gobe , Gobe , Gobe !!!
- L'invasion Seanchans : Détruit la flotte ennemis a bord du "Danseur des vagues".
Citer : Posté le 10/05/2016 19:07 | #
En gros si il touche une pièce il arrête de chercher.
Imaginons, disons, un jeu en 2D en vue de dessus, où l'on peut faire apparaître (par exemple en tuant des mobs) des objets en drop, qui se placent à n'importe quelle position (au pixel) en attendant qu'on les ramasse.
Avec ce comportement, même si deux objets sont théoriquement à portée du joueur, un seul sera ramassé. Dommage, non ?
Citer : Posté le 10/05/2016 19:18 | #
Oui mais la frame d'après c'est à dire environ 20 ms plus tard, l'autre objet est ramassé.
Ajouté le 10/05/2016 à 19:20 :
Et puis il y a plusieurs façon de faire, il est possible de créer sa propre fonction qui renvoi un tableau d'adresse de tout les objets ayant le tag "tag", et étant proche de à 10 pixels.
- Kirby's DreamLand : Gobe , Gobe , Gobe !!!
- L'invasion Seanchans : Détruit la flotte ennemis a bord du "Danseur des vagues".
Citer : Posté le 11/05/2016 17:13 | #
Oui mais la frame d'après c'est à dire environ 20 ms plus tard, l'autre objet est ramassé.
Un défaut structurel ne peux pas être masqué par un effet de vitesse, c'est assez aberrant ! Bon allez, je suis chiant : rien ne dit qu'à la fin de ce jeu tu pourras pas avoir 100 items en drop en même temps. (Enfin, je crois que tu as compris x) ).
Et puis il y a plusieurs façon de faire, il est possible de créer sa propre fonction qui renvoi un tableau d'adresse de tout les objets ayant le tag "tag", et étant proche de à 10 pixels.
Tu disais que l'arrêt de la recherche se faisait pour des raisons d'optimisation non ? S'il faut comparer des chaînes de caractères pour trouver des tags pour chaque objet, la vitesse en prend un coup bien plus grand... Et puis ce serait plus lourd que d'attribuer des scripts (de simples pointeurs) aux objets, par ailleurs.
Citer : Posté le 11/05/2016 17:18 | #
+1 pour Lephe. C'est pas parce que le jeu fonctionne bien pour toi que c'est pareil pour tout le monde x)