Comme faire bouger une carte et un sprite - By Martisse

Author :  Martisse

Bonjour, j'ai créé une carte grâce a tiled (24064) puis un personnage de (76). J'aimerais savoir comment faire pour faire bouger la carte et le personnage comme dans le jeu Cats ans coin. Pour l'instant j'ai codé que quand que on appui sur gauche, la carte va a droite, si on appui sur droite la carte va a gauche. Or cette méthode ne fonctionne pas bien.

Pouvez vous m'aider ?

Author :  Steph

Des tutoriels très complets sur le sujet sont actuellement en préparation au sein de l'Académie... encore un petit peu de patience :-)

En attendant, tu peux étudier le code open source des jeux qui ont été publiés et qui utilisent cette technique.

Author :  chris-scientist

Tu peux regarder le workshop Apprenez la programmation orientée objet avec Sokoban, tu y trouveras une première approche de la gestion d'une "caméra" et de la gestion des déplacements du personnage. Cependant, le workshop fait usage de la programmation orientée objet (avec des classes, méthodes, etc).

Sinon comme l'a dit Steph, des workshops sont en préparation et ces notions seront abordées en programmation procédurale (dans un premier temps).

Author :  Martisse

Je vai y jeter un œil, mais je trouve ça un peu complexe.

Author :  chris-scientist

N'hésite pas à poser des questions !

Author :  deeph

Autrement j'avais présenté ma façon de faire (en gros) avec Picomon ici : https://gamebuino.com/fr/community/topic/image-et-map#c7811

Author :  jicehel

Je ne te garantie pas que ça t'aide mais je l'espère. J'avais fais un tuto sur le Sokoban un peu avant Chris-scientist mais en non POO, si ça peut t'aider et t'apporter un angle différent, tu le trouveras ici:

https://gamebuino.com/fr/creations/sokoban-partie-1-preparons-notre-jeu

https://gamebuino.com/fr/creations/sokoban-partie-2-ajoutons-les-graphismes

https://gamebuino.com/fr/creations/sokoban-partie-3-creons-la-vie

Si ça te dis, essaye de suivre ces 3 parties, la partie 1 à priori ne te servira à rien d'autre qu'à mieux comprendre l’enchaînement avec la partie 2 car tu as déjà fait cette partie d'après ce que j'ai compris, mais la partie 2 d'expliquera comment intégrer tes sprites et la 3 comment te déplacer et les afficher. Si ce n'est pas clair, fais moi un retour et j'essayerais d'expliquer plus clairement.  Encore une fois, ce sont des tutos qui datent un peu et une série de tutos arrivent qui les reprendront sous forme de Workshop avec des étapes plus claires, mais en attendant, si ça peut t'aider...

Author :  Martisse

j'ai déja essayé mais je cherche une méthode plus facile.

Author :  Martisse

cela devrait m'aider; merci

Author :  Codnpix

Salut, je suis sur une problématique similaire pour un projet perso, en gros l'idée que j'ai utilisée est que le sprite a des coordonnées relatives à la map (dont l'origine est 0, 0) et la caméra qui est en fait l'écran dessine l'ensemble des images a des coordonnées décalées en fonction de la position du sprite. Je ne sais pas si c'est très clair donc voici un petit extrait de mon code : 

un controlleur récupère les entrées et les passe au modèle du sprite : 

void GameController::getInputs() {
//...
  if(gb.buttons.repeat(BUTTON_RIGHT, 1)){
    this->character->reqWalkRight();
  }
  if(gb.buttons.repeat(BUTTON_LEFT, 1)){
    this->character->reqWalkLeft();
  }
  if(gb.buttons.pressed(BUTTON_A)) {
    this->character->reqJump();
  }
  if(gb.buttons.repeat(BUTTON_DOWN, 1)) {
    this->character->reqFall();
  }
  if(gb.buttons.released(BUTTON_LEFT) || gb.buttons.released(BUTTON_RIGHT)) {
    this->character->reqStand();
  }

this->character->applyGravity();//gravity is an input, kind of…

}

Du côté du sprite les inputs sont traités comme ça :

void Character::init() {
  this->reqXMarker = 'n';
  this->setPosition(40, SPACE_H - CHARACTER_H);//tmp
}

void Character::reqWalkRight() {
this->reqXMarker = 'r';
}

void Character::reqWalkLeft() {
this->reqXMarker = 'l';
}

void Character::reqStand() {
this->reqXMarker = 'n';
}

Puis il met sa position est mise à jour en conséquence : 

void Character::updatePos() {

if(this->reqXMarker == 'r') {
this->vx = 1;
} else if (this->reqXMarker == 'l') {
this->vx = -1;
} else if (this->reqXMarker == 'n') {
this->vx = 0;
}

//…
//je ne mets pas tout ici car c'est encore un peu en cours de développement, il faut gérer les collisions etc
//mais pour la partie déplacements c'est à peu près opé.

}

Ensuite l'astuce se situe plutôt au niveau de la vue, donc de ce qu'on pourrait appeler la caméra :

le calcul qui permet de dessiner la vue à l'endroit du sprite est le suivant : 

void View::followCharacter(float charX, float charY) {
  if (charX + CHARACTER_W / 2 <= SCREEN_W / 2) this->setCameraPosX(0);
  else if (charX + CHARACTER_W / 2 >= SPACE_W - SCREEN_W / 2) this->setCameraPosX(-SPACE_W + SCREEN_W);
  else this->setCameraPosX(SCREEN_W / 2 - charX - CHARACTER_W / 2);

if (charY + CHARACTER_H / 2 >= DECOR_TILE_H - SCREEN_H / 2) this->setCameraPosY(-(DECOR_TILE_H - SCREEN_H));
else if (charY + CHARACTER_H / 2 <= SCREEN_H / 2) this->setCameraPosY(0);
else this->setCameraPosY(SCREEN_H / 2 - charY - CHARACTER_H / 2);
}

Puis la fonction draw affiche tout ça avec les valeurs précédemment calculées : 

void View::draw(float charX, float charY, Space* space) {
  this->followCharacter(charX, charY);

gb.display.clear();
//background
for (uint8_t tile = 0; tile < 8; tile++) {
gb.display.drawImage(this->cameraPosX + tile * BACKGROUND_TILE_W, 0 / 1.5, backgrounds[this->spaceIndex]);
}
//decorPart1
gb.display.drawImage(this->cameraPosX, this->cameraPosY, decorMaps[this->spaceIndex][0]);
//decorPart2
gb.display.drawImage(this->cameraPosX + DECOR_TILE_W, this->cameraPosY, decorMaps[this->spaceIndex][1]);

//character
gb.display.drawImage(this->cameraPosX + charX, this->cameraPosY + charY, charSprite);
}

Voilà, je ne sais pas si c'est très explicite car il y a des parties du code que je ne prend pas le temps de détailler et il en manque pas mal de morceaux mais je pense que ça résume pas mal un exemple de ce que tu cherches à faire. J'espère que ça te donnera un peu d'inspiration :).

Bon courage !

Author :  Steph

Ha Ha Ha ... je vois que tu as adopté la POO et l’architecture MVC ;-)

Author :  Codnpix

Ha Ha Ha ... je vois que tu as adopté la POO et l’architecture MVC ;-)

Grave ! J'essaye en tout cas ^^.

Author :  Martisse

Je vais regarder ça. C'est ce que j'ai essayé de faire en beaucoup, beaucoup plus simplifié...

Author :  Steph

Tu peux aussi nous poster ton code sur Gist pour qu'on puisse l'examiner et t'apporter une solution appropriée ;-)

Author :  Martisse

gist c'est GitHub? Ou c'est une autre méthode

Author :  Steph

C'est apparenté oui... il te faut un compte GitHub pour pouvoir poster un code à partager
Jette un oeil sur la Doc.

Author :  Martisse

Ok. Je ferai ça ce soir. Car j'ai des horaires de pc.

Author :  Martisse

Voici le code que j'ai fait. il est commenté;Voici ce que j'ai voulu faire : lorsque le personnage va a droite, la carte va a gauche et inversement...

https://gist.github.com/Martisse/15547028ebf1a4b6a5a88aaf5cdb3288

Author :  Codnpix

Sympatique petit univers :) !

Voici une proposition très simple de ce que tu pourrais faire, c'est exactement le même principe que mon exemple plus haut :

int positionCamera;
void setup() {
//...
}
void loop() {
  while(!gb.update());
  gb.display.clear();

//ENTREE
if(gb.buttons.repeat(BUTTON_RIGHT, 1)) { //déplacer personnage a droite
playerPosition_x = playerPosition_x + 1;
//position_carte = position_carte - 1; pas besoin de faire bouger la carte, la position du joueur suffit pour faire le calcul
}
if(gb.buttons.repeat(BUTTON_LEFT, 1)) { //déplacement personnage a gauche
playerPosition_x = playerPosition_x - 1;
//position_carte = position_carte + 1;
}
if(gb.buttons.pressed(BUTTON_B)) {
arme = 1;
}

//calcul positionCamera en fonction de playerPosition_x :

if(playerPosition_x <= gb.display.width() / 2) positionCamera = 0;//pour que la camera n'aille pas au delĂ  de l'image si le sprite arrive au bord Ă  gauche
else if (playerPosition_x >= 200) positionCamera = - 240 + gb.display.width();//mĂŞme chose pour le bord droit
else positionCamera = (gb.display.width() / 2) - playerPosition_x;//sinon la camera suit le sprite

//AFFICHAGE
gb.display.drawImage(positionCamera, 0, carte_1Data); //carte
gb.display.drawImage(positionCamera + playerPosition_x, 40, heroData); //héroine //il faut ajouter la position de la camera à celle du joueur pour que la relation soit établie.
gb.display.drawImage(positionCamera + 60, 40, ennemi_1Data); //ennemi
gb.display.setColor(BLACK);
gb.display.fillRect(0,0, 80,7); //carré noir affichant les donneés du jeu
gb.display.drawImage(2,0,faimData); //barre de faim
gb.display.drawImage(9,0,faimData); //barre de faim
gb.display.drawImage(16,0,faimData); //barre de faim

gb.display.drawImage(56,0, coeurData); //coeur
gb.display.drawImage(64,0, coeurData); //coeur
gb.display.drawImage(72,0, coeurData); //coeur
gb.display.setCursor(31,1);
gb.display.print("epee"); //type d'arme
}

Author :  Steph

Arf... avec le décalage horaire, tu m'as devancé (j'suis allé me coucher + tôt que toi !).

Bon, ben il semble que le pbm soit résolu :-)