Création d'un space invaders sur ESPLGE de Corax

OK, bon, je n’ai pas tout compris avec le problème actuellement sur les variables locales mais du coup j’ai réécris un peu le programme pour que ça fonctionne et comme ça ne bougeait pas fort en réponse à mon petit challenge, j’ai rajouté le test de collision entre le tir du vaisseau et les ennemis.

Du coup ça donne ça:

// Tuto Space invader - Part 5: Add timer for shots and invaders move and make them go down

/*settings*{"name":"Space_Invad","author":"Jicehel","image":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,119,7,112,0,112,0,119,7,119,0,0,112,0,7,7,7,7,7,0,7,0,0,0,7,112,7,7,7,7,7,0,7,112,0,0,0,7,7,112,7,119,7,0,7,0,0,0,119,112,7,0,7,7,0,119,7,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,112,112,7,7,0,7,0,112,7,112,0,0,112,119,7,7,0,7,0,112,7,7,0,0,112,119,119,0,112,112,7,7,7,7,0,0,112,112,119,0,112,112,7,119,7,7,0,0,112,112,7,0,7,0,7,7,7,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}*/


// define constantes
	
#define invader_init_speed 	2
#define invader_lines 		4
#define invader_columns 	6

#define timer_ship_shot 	1
#define timer_invaders  	2
#define timer_invaders_shot 3

#define debug 0

// Sprites
// Invader 8 pixels x 8 pixels x 5 rows x 2 frames with 2 separation lines between rows 

char invader[]= {
0x00, 0x70, 0x07, 0x00, 
0x00, 0x77, 0x77, 0x00, 
0x07, 0x77, 0x77, 0x70, 
0x07, 0x77, 0x77, 0x70, 
0x77, 0x07, 0x70, 0x77, 
0x77, 0x77, 0x77, 0x77, 
0x07, 0x70, 0x07, 0x70, 
0x07, 0x00, 0x00, 0x70, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x05, 0x50, 0x00, 
0x00, 0x55, 0x55, 0x00, 
0x05, 0x55, 0x55, 0x50, 
0x55, 0x05, 0x50, 0x55, 
0x55, 0x55, 0x55, 0x55, 
0x00, 0x50, 0x05, 0x00, 
0x05, 0x05, 0x50, 0x50, 
0x50, 0x50, 0x05, 0x05, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x05, 0x50, 0x00, 
0x00, 0x55, 0x55, 0x00, 
0x05, 0x55, 0x55, 0x50, 
0x55, 0x05, 0x50, 0x55, 
0x55, 0x55, 0x55, 0x55, 
0x00, 0x50, 0x05, 0x00, 
0x05, 0x00, 0x00, 0x50, 
0x00, 0x50, 0x05, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x60, 0x06, 0x00, 
0x00, 0x06, 0x60, 0x00, 
0x06, 0x66, 0x66, 0x60, 
0x06, 0x06, 0x60, 0x60, 
0x60, 0x66, 0x66, 0x06, 
0x66, 0x00, 0x00, 0x66, 
0x60, 0x60, 0x06, 0x06, 
0x06, 0x00, 0x00, 0x60, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x60, 0x60, 0x06, 0x06, 
0x60, 0x06, 0x60, 0x06, 
0x66, 0x66, 0x66, 0x66, 
0x66, 0x06, 0x60, 0x66, 
0x00, 0x66, 0x66, 0x00, 
0x06, 0x00, 0x00, 0x60, 
0x06, 0x60, 0x06, 0x60, 
0x66, 0x00, 0x00, 0x66, 
0x00, 0x70, 0x07, 0x00, 
0x00, 0x77, 0x77, 0x00, 
0x07, 0x77, 0x77, 0x70, 
0x07, 0x77, 0x77, 0x70, 
0x77, 0x07, 0x70, 0x77, 
0x77, 0x77, 0x77, 0x77, 
0x07, 0x70, 0x07, 0x70, 
0x07, 0x00, 0x00, 0x70, 
0x70, 0x00, 0x00, 0x07, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x05, 0x50, 0x00, 
0x00, 0x55, 0x55, 0x00, 
0x05, 0x55, 0x55, 0x50, 
0x55, 0x05, 0x50, 0x55, 
0x55, 0x55, 0x55, 0x55, 
0x00, 0x50, 0x05, 0x00, 
0x05, 0x00, 0x00, 0x50, 
0x00, 0x50, 0x05, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x05, 0x50, 0x00, 
0x00, 0x55, 0x55, 0x00, 
0x05, 0x55, 0x55, 0x50, 
0x55, 0x05, 0x50, 0x55, 
0x55, 0x55, 0x55, 0x55, 
0x00, 0x50, 0x05, 0x00, 
0x05, 0x05, 0x50, 0x50, 
0x50, 0x50, 0x05, 0x05, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x60, 0x60, 0x06, 0x06, 
0x60, 0x06, 0x60, 0x06, 
0x66, 0x66, 0x66, 0x66, 
0x66, 0x06, 0x60, 0x66, 
0x00, 0x66, 0x66, 0x00, 
0x06, 0x60, 0x06, 0x60, 
0x66, 0x00, 0x00, 0x66, 
0x00, 0x60, 0x06, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
0x00, 0x06, 0x60, 0x00, 
0x06, 0x66, 0x66, 0x60, 
0x06, 0x06, 0x60, 0x60, 
0x60, 0x66, 0x66, 0x06, 
0x66, 0x00, 0x00, 0x66, 
0x60, 0x60, 0x06, 0x06, 
0x06, 0x00, 0x00, 0x60, 
0x06, 0x00, 0x00, 0x60  
};


char bunker[]= {
0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 
0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 
0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 
0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
0x55, 0x55, 0x50, 0x00, 0x00, 0x05, 0x55, 0x55, 
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 
0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x05, 0x55, 
0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x05, 0x55, 
0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x05, 0x55
};

char player[]= {
0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 
0x00, 0x00, 0x26, 0x62, 0x00, 0x00, 
0x00, 0x00, 0x63, 0x16, 0x00, 0x00, 
0x00, 0x02, 0x63, 0x16, 0x20, 0x00, 
0x02, 0x21, 0x63, 0x36, 0x12, 0x20, 
0x21, 0xc1, 0x26, 0x62, 0x1c, 0x12, 
0x21, 0xc2, 0x21, 0x12, 0x2c, 0x12, 
0x22, 0x20, 0x04, 0x40, 0x02, 0x22
};


char shot_beam{] = {
0x22, 
0x22, 
0x22, 
0x22
};


//define variables

// invaders variables
int invader_x;
int invader_y = 20;
int invader_speed;
int frame;      			// We'll use 2 frames 0 and 1
int i;
int max_x, min_x, max_y, min_y;
int sprite_invader = 0;  	// max sprite invader = 18
int invader_w =	8;
int invader_h =	8;
int invader_space_w = 2;	
int invader_space_h = 2;
int life_invader; // temp variable with noumber of lifes keeping 
int col_hitted;  // temp variable of column hitted
int shot; // temp variable of shot hitting
int first_column, last_column;
int last_row;
int y_endline;
int nb_life = 3;


// player variables
int player_x;
int player_y;
int player_speed;
int sprite_player = 9;


// shots variables
int max_shot = 6;
int sprite_shot = 10;   	// max sprite shot = 22
int shoots_done;
int next_shot;
int shot_speed = 2;         // speed of the shot move
int timer_cooldown, delay_invader_shot, delay_move_invaders;
int shot_live;
int shot_x,shot_y;


// bunkers variables
int sprite_bunkers = 29;
int y_bunkers = 88;


// game variables
int key;
int score;


// Clear the shot then it goes out of the screen
void clear_shot() {
	spritesetvalue(shot, S_LIVES, 0);
	--shoots_done;
};


// The shot of the ship have hit something
void shot_hit() {
	if (life_invader > 0) {
		score = score + 10;
		drawparticle(spritegetvalue(col_hitted, S_X + 0.5 * invader_w ), spritegetvalue(col_hitted, S_Y) + life_invader * (invader_h + invader_space_h), random(3)+1);
		--life_invader;
		spritesetvalue(col_hitted, S_LIVES, life_invader);
		if (life_invader > 0){
			 int height = life_invader * (invader_h + invader_space_h) - invader_space_h
		     spritesetvalue(col_hitted, S_HEIGHT, life_invader * (invader_h + invader_space_h) - invader_space_h);     
	    } else {
			spritesetvalue(col_hitted, S_HEIGHT,0);
		}
	clear_shot();
	}
};


// initialisation of values
void init(){
	
	// init game
	score = 0;
	setbgcolor(0);
	
	// init player
	player_x = 58;
	player_y = 105;
	player_speed = 0;
	spritesetvalue(sprite_player,S_WIDTH,12);
	spritesetvalue(sprite_player,S_HEIGHT,8);
	spritesetvalue(sprite_player, S_LIVES, nb_life);
	getsprite(sprite_player,player);
	
	// init invaders
	invader_x = 0;
	frame = 0;
	invader_speed = invader_init_speed;
	i = sprite_invader;
	for( int col = 0; col < invader_columns; col++ ){
			int x = invader_x + col * (invader_w + invader_space_w);
			spritesetvalue(i, S_WIDTH, invader_w);
			spritesetvalue(i, S_HEIGHT,invader_lines * (invader_h + invader_space_h)-invader_space_h);
			spritesetvalue(i, S_LIVES, invader_lines);
			getsprite(i, invader);
			putsprite(i, x, invader_y);
			i++;
		}
	}
	first_column = 1;
	last_column = invader_columns;
	last_row = invader_lines;
	
	max_x = invader_columns * (invader_w + invader_space_w);
	min_x = 0;
	min_y = invader_y;
	max_y = invader_y + invader_lines * (invader_h + invader_space_h) - invader_space_h;
	y_endline = 128 - invader_h;
	getsprite(1,invader);
	delay_move_invaders = 100;
	// if (debug == 1) delay_move_invaders = 600;
	delay_invader_shot = 500;
	
	// init player shots
	shoots_done = 0;
	for(int s = sprite_shot; s < (sprite_shot + max_shot); s++) {
		spritesetvalue(s, S_WIDTH, 2);
		spritesetvalue(s, S_HEIGHT,4);
		spritesetvalue(s, S_LIVES,0);
		// spritesetvalue(s, S_ON_COLLISION, shot_hit);
		// spritesetvalue(s, S_ON_EXIT_SCREEN, clear_shot);
		getsprite(s, shot_beam);
	}
	timer_cooldown = 600;
	
	// init bunkers
	for(int b = 0; b < 3; b++) {
		getsprite(b + sprite_bunkers, bunker);
		spritesetvalue(b + sprite_bunkers, S_WIDTH, 16);
		spritesetvalue(b + sprite_bunkers, S_HEIGHT, 12);
	}	
	
	setframerate(30);
	settimer( timer_ship_shot, timer_cooldown );
	settimer( timer_invaders, delay_move_invaders);
	settimer( timer_invaders_shot, delay_invader_shot);
}


// Ship shot add

void add_ship_shot() {
	if (next_shot >= sprite_shot) {
		putsprite(next_shot, player_x + 6, player_y - 5);	
		spritesetvalue(next_shot, S_LIVES, 1);
		++shoots_done;
	}
};


// Step procedure to make the game evolve between each draw
void step(){
	
	// manage invaders
	
	if (gettimer( timer_invaders  ) <= 0 ) {
		    char change_ligne = 0;
			frame = 1 - frame;
			max_x = max_x + invader_speed;
 		    min_x = min_x + invader_speed;
    		if (max_x > y_endline + invader_w) {
				invader_speed = -invader_init_speed;
				change_ligne = 1;
				min_x = min_x + invader_speed;
				max_x = max_x + invader_speed;
			}
    		if (min_x < invader_init_speed) {
				invader_speed =  invader_init_speed;
				change_ligne = 1;
				min_x = min_x + invader_speed;
				max_x = max_x + invader_speed;

			}
		
			for( int col = sprite_invader; col < (sprite_invader + invader_columns); col++ ){
				if (spritegetvalue(col, S_LIVES) > 0) {
					putsprite(col, spritegetvalue(col, S_X) + invader_speed, spritegetvalue(col, S_Y) + change_ligne * (invader_h + invader_space_h));
				}
				if ((change_ligne > 0) && (min_y > y_endline)) {
				  	int x = invader_x + col * (invader_w + invader_space_w);
					int y = invader_y;
					spritesetvalue(col, S_X, x);
					spritesetvalue(col, S_Y, y);
				}
			}
			
			if (change_ligne > 0) {
				if (min_y > y_endline) {
						max_x = invader_columns * (invader_w + invader_space_w);
						min_x = 0;
						min_y = invader_y;
						max_y = invader_y + invader_lines * (invader_h + invader_space_h) - invader_space_h;
						invader_speed =  invader_init_speed;
				} else {
						min_y = spritegetvalue(first_column,S_Y);
						max_y = spritegetvalue(first_column,S_Y) + invader_lines * (invader_h + invader_space_h) - invader_space_h;
					}
			}
	        // if (debug == 1) {
			//	gotoxy(0,15); putn(min_y);puts("    ");putn(max_y);
			//	rect(min_x, min_y, max_x, max_y);
			// }	
		    settimer( timer_invaders, delay_move_invaders);
	}

    // manage shots
	for(int s = 0; s < max_shot; s++) {
		shot = s + sprite_shot;
		shot_live = spritegetvalue(shot, S_LIVES);
		if ( shot_live > 0) {
			shot_y = spritegetvalue(shot, S_Y) - shot_speed;
			if (shot_y < 10) {
				clear_shot();
			} else {
				spritesetvalue(shot, S_Y, spritegetvalue(s + sprite_shot, S_Y) - shot_speed);
			}
		
		// test if an invader has been hitted

		if ((shot_y < max_y ) && (shot_y >= min_y)) {
			shot_x = spritegetvalue(shot, S_X);
			
			if ((shot_x < max_x) && (shot_x >= min_x)) {
				col_hitted = sprite_invader + ((shot_x - min_x) / (invader_w + invader_space_w));
				life_invader = spritegetvalue(col_hitted, S_LIVES);
				if (debug = 1) {
					// setcolor(2);
					// gotoxy(15,1); puts("col:");putn(col_hitted);puts("  ");
					// setcolor(6);
					// rect(min_x, min_y, max_x, (min_y + life_invader * (invader_h + invader_space_h)));
				}
				if (life_invader > 0) {
					if (shot_y < (min_y + life_invader * (invader_h + invader_space_h))) shot_hit();
				}
			}	
		}
	}


	// manage keyboard inputs
	key = getKey();
	if (key & KEY_RIGHT) { 
		player_speed = player_speed + 3 ;
	} else if (key & KEY_LEFT) { 
		player_speed = player_speed - 3 ;
	}  
	
	// manage limits 
    player_x = player_x + player_speed;
    if (player_x > 116) player_x = 116;
    if (player_x < 0)   player_x =  0;

    // test if the player try to shoot
	if (key & KEY_A) {
		if (shoots_done < max_shot) {
			if( gettimer( timer_ship_shot ) <= 0 ) {
					settimer( timer_ship_shot, timer_cooldown );
					for(int s = sprite_shot; s < (sprite_shot + max_shot); s++) {
						if (spritegetvalue(s, S_LIVES) == 0) {
			 				next_shot = s;
						}	
					}
					add_ship_shot();
				}
		}
	} 

	// reset speed (no inertia)
    player_speed = 0;
}


// Draw procedure
void draw(){
	
	clearscreen();
	
		if (debug == 1) {
			setcolor(1);
			gotoxy(0,0); putn(min_y); puts(" ");
			gotoxy(10,0); putn(max_y);puts(" ");
			gotoxy(0,1); putn(min_x); puts(" ");
			gotoxy(10,1); putn(max_x);puts(" ");
		} else {
			gotoxy(0,0); puts("score:");putn(score); puts(" ");
			gotoxy(10,0); puts("vies:      ");
			for(int v = 0; v < 3; v++) {
				putimage(player, 88 + v*13, 1, 12, 8);
			}
		}	 
	
	// draw shots
	for(int s = 0; s < max_shot; s++) {
		if (spritegetvalue(s + sprite_shot, S_LIVES) > 0) {
			putsprite(s + sprite_shot, spritegetvalue(s + sprite_shot, S_X),spritegetvalue(s + sprite_shot, S_Y));
		}
	}
	
	// draw invaders
	i = sprite_invader;
	for( int col = 0; col < invader_columns; col++ ){
		int x = spritegetvalue(i, S_X);
		int y = spritegetvalue(i, S_Y);
		getsprite(i, invader + frame * 192);
		putsprite(i, x, y);
		i++;
	}
	
	// draw bunkers
	putsprite(sprite_bunkers, 10, y_bunkers );
	putsprite(sprite_bunkers +1, 56, y_bunkers );
	putsprite(sprite_bunkers +2, 102, y_bunkers );
	
	// draw ship of the player
    putsprite(sprite_player, player_x, player_y);   // draw the sprite of the ship played

    delayredraw(); 									// wait until the frame is drawn. 
}


// Main procedure
void main(){
	init();
	while(1){		
       step();
       draw();		
	}
}

Bon il reste des choses à faire: Ajout des tir des aliens, test de collision des aliens avec le vaisseau, ajustement des valeurs maxi et mini pour gérer les déplacements des aliens et après on s’attaquera aux sons et à la musique… mais ça avance

Bon maintenant pour la prise en main de l’environnement, je pense que l’on a assez fait de tests. Personnellement, ça ma permit de découvrir esplge. Le programme devient un petit peu trop complexe pour faire un bon tuto mais vous avez les exemples donnés par Igor / Corax accessibles ici: http://segamiga.com/esplge/doc/#/samples/game_tutorial

Quand à notre jeu, en rajoutant la musique, le son et les collisions, il est presque finalisé mais un peu long. je vais le mettre sur mon github here: https://github.com/Jicehel/Invaders-for-espLGE

Merci pour ce super tuto !
Je suis le webmaster de segamiga.com, accepteriez-vous que je le mette en tutoriel dans la doc ?

Bien sûr Loopingstar. Avec plaisir, qu’il serve au plus de gens possible. Par contre je l’ai écrit en même temps que mes premiers essais après avoir lu les tutos, la construction est donc un peu brouillon et ressemble plus à un Devlog qu’à un réel tuto. Si tu veux, je peux en réécrire un version qui soit plus un vrai tuto mais si ça te convient, prends le et corrige ou améliore un peu si tu vois des choses qui pourraient être mieux ou améliorer.

Tu en voudrais d’autre sinon ? Je pourrais en faire un n pong si tu veux (pour le Pong, pas de problème, je pourrais en faire un pour un casse-briques mais la gestion correcte des collisions n’ait pas aussi simple qu’il n’y parait).

Avec plaisir pour le tuto Pong. D’ailleurs, peux-tu faire le tuto Pong en premier (comme ça tu pourras le mener a son terme). Ce serait top si tu pouvais le faire en anglais (pour toucher un max de monde), mais ce n’est pas une obligation bien sur :wink:

OK, je vais le faire en français et j’essayerais de le traduire en anglais après mais il faudra sans doute corriger mes approximation en traduction…

1 Like

j’ai contacté Igor et Roman car je souhaite mettre a jour la doc avec les nouvelles fonctions sur le débugger série, etc.
Il faut aussi que je mette a jour la doc de l’éditeur.
… et que je finisse mes jeux aussi lol :wink:

2 Likes

J’ai commencé le tuto de Pong en anglais vite fait. Je repars des bases: la structure et l’affichage à l’écran.
Ca donne ça https://fdoc.fr/B2qW
(https://www.fichier-doc.fr/2021/01/13/tuto-pong-en-1/)
Je continuerais bien sûr prochainement.

C’est prometteur !
C’est bien de partir des bases.

As-tu finalisé la traduction de la doc en français ? Si oui, je pourrai l’intégrer a la doc/wiki

Non, je l’écris directement en anglais par facilité. Comme ça, je dis ce que je peux en anglais. Ce sera plus simple pour moi de le retraduire en français alors que si j’écris en français, je risque d’avoir plus de mal à le retraduire en anglais … :wink:
Mais bon, ça avance bien, ça devrait être fini avant dimanche soir en anglais et sans doute en français.
Je t’envois le lien dès que la première version du tuto en anglais est finie.
On pourra demander à Roman de la traduire en russe. En fait ce serait bien si ce genre de documents était systématiquement en Anglais / Russe / Français (et plus si des volontaires veulent traduire)

lol, je parlais de la traduction en français du ficher PDF Mode d’emploi de shando69, que tu m’avais envoyé l’année dernière, mis non finie

Ah ok, désolé, ça m’avait échappé. Ça m’était complètement sorti de la tête. Je regarderais ce soir. Je ne me souviens plus si j’avais fini après. Je regarde, je relis et je te renvois la dernière version dans tous les cas.

OK, je ne sais plus si c’est ce que je t’avais envoyé mais la dernière version que j’ai c’est celle là: https://fdoc.fr/f7R4
(https://www.fichier-doc.fr/2021/01/14/espboy---presentation/)

@Loopingstar i have advance on Pong tuto
Updated file is here: https://fdoc.fr/X3QP

1 Like

Pong english tuto completed: https://fdoc.fr/0A3u

1 Like

Salut Jicehel,

Un petit message pour te dire que ton tuto Pong est en ligne !
J’ai passé beaucoup de temps à le convertir en markdown (j’aí aussi corrigé quelques fautes au passage, mais je n’ai pas tout relu).
Merci encore, au nom de la communauté :wink:
Si tu a des modifs a faire, dis le moi

Super. Merci à toi. J avais fait aussi le tuto pour apprendre à m en servir. Maintenant il faut que j en fasse un pour faire un programme via l IDE Arduino et ce sera moins simple que sur ESPLge

Sur le Discord, tu trouveras aussi le lien vers le github de mon jeu Highway (j’ai cru comprendre que tu attendais les sources ^^)

Oui, super. Bon, je passe un peu de temps sur autre chose en ce moment mais je vais y retourner dans pas longtemps :wink: