top of page

Pong (la pala del jugador)


Aquesta és la segona de les quatre entregues que hem dissenyat perquè programis des de zero una versió senzilla del joc Pong mitjançant FUSION-C V1.2.


Objectiu


Com tots sabreu el "Pong" consta de dues pales de joc i una pilota a la que li has de donar amb la pala perquè l’altre jugador la torni tot evitant que aquesta surti del terreny de joc.


En aquest article treballarem amb la pala de joc del jugador, la situada a l’esquerra de la pantalla. En concert aprendrem a crear-la i a moure-la.




Introducció


Al passat article us vam introduir les seccions en que s’hauria de dividir un fitxer de C així com el seu ordre de definició dins al fitxer. Aquestes a mode recordatori són: la secció de documentació, la del preprocesador, la de definició de macros i constants simbòliques, la de definició de tipus, la de definició de prototipus de les funcions, la de definició de les variables globals, la secció de la funció main i el bucle de joc i per últim la secció amb la implementació de les funcions definides per l’usuari.



Secció de documentació

//
// pad.c
// Fusion-C Pong game example articles
// Here we will learn how to move de player pad
// MoltSXalats 2023
//


Secció del preprocessador


#include "fusion-c/header/msx_fusion.h"
#include "fusion-c/header/vdp_sprites.h"
#include "fusion-c/header/vdp_graph2.h"


Secció de definició de tipus


typedef struct {     
	char spr;
	char y;
    char x;
    char pat;
} Sprite;

Secció de definició dels prototipus de les funcions


void DrawSprite(void);
void GameStart(void);
void FT_Wait(int);

Secció de definició de les variables globals


signed char DirX;
signed char DirY;

char PlyScore,CpuScore;

Sprite PlyPad;

const signed char moves[9]={0,-1,0,0,0,1,0,0,0};

const char PatternPad[]={

0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000
};


Tot seguit expliquem les variables més destacables y noves al primer article “Pong (la pilota)”.


const signed char moves[9]={0,-1,0,0,0,1,0,0,0};



Utilitzarem l’array “moves” per saber en tot moment quina operació hem de fet sobre les coordenades (x,y) de la pala del jugador en funció del moviment dels cursos.


Si tenim en compte la figura de més amunt, que recull els moviments possibles dels cursos, podem observar  les 9 posicions del nostre array. Essent la 0 la de d'absència de moviment. 


Com que la paleta del jugador es pot moure en la les direccions 1 i 5, dins aquestes posicions de l’array tindrem el valor que haurem de sumar o restar a la coordenada “y” segons el premut al cursor, cap amunt o cap avall.


Hem definit la pala del jugador, com un Sprite de 3x8. En crearem un patró per la taula de patrons a través de la variable "PatternPad". El concepte de Sprite el recollirà la variable "PlyPad" del tipus Sprite que hem creat nosaltres.


const char PatternPad[]={
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000

Secció de la funció main i el bucle de joc


Hem creat la variable “joy” per a recollir a través de la funció de FUSION-C “JoystickRead”, passant-li el paràmetre “0” per indicar-li que llegeixi, l’entrada dels cursos. Amb l’ajuda de l’array “moves” explicat més amunt actualitzarem la coordenada “y” de la pala del jugador amb la següent assignació "PlyPad.y+=moves[joy]".


També aprofitarem a l’inici de la funció “main (void)” per inicialitzar la pala del jugador pel que fa a les coordenades (x,y).


PlyPad.x=10;
PlyPad.y=100;

El bucle de joc consta de dues funcions, la funció que pinta la pilota en pantalla "DrawSprite()" i "FT_Wait()" que imposa una pausa al moviment de la pala del jugador per tal que el pintat flueixi a una velocitat controlada, ni molt ràpid ni molt lent.


void main (void)
{
	char joy;
	SetColors(15,0,0);
	Screen(5); // 256 x 212 pixel
	Sprite8();
	SpriteDouble(); // Magnified to 16 x 16 pixels
	KeySound(0);

	SetSpritePattern(1, PatternPad,8);

	// Defining Variables

	// Player Pad Sprite

	PlyPad.x=10;
	PlyPad.y=100;
	PlyPad.spr=0;
	PlyPad.pat=1;

	PlyScore=0;

	// Cpu Pad Sprite

	CpuScore=0;

	DirX=1;
	DirY=1;

	GameStart();
	
	while (Inkey()!=27)
	{	
		joy=JoystickRead(0);

		PlyPad.y+=moves[joy];
		DrawSprite();
		FT_Wait(170);
	}

	// Ending program, and return to DOS

	Screen(0);
	KeySound(1);
	Exit(0);
}


Implementació de les funcions definides per l’usuari


Fer esment que aquí hem incorporat un control per tal que la pala del jugador no surti dels límits verticals de la pantalla dins la funció de pintat dels sprites "DrawSprite(void)" tenint en compte del tamany d’aquesta limintant la zona a y>10 i y<196.


// Print the initial game screen
void GameStart(void)
{
	char Temp[5];

	// El texto es de 5 x 7
	PutText((256-20*8)/2,4,"Press SPACE to START",0);

	// Initial Positions
	PlyPad.x=10;
	PlyPad.y=100;

	DirX*=-1;

	DrawSprite();

	Itoa(PlyScore,Temp,10);
	PutText(10,4,Temp,0);

	Itoa(CpuScore,Temp,10);
	PutText(235,4,Temp,0);	

	while (!IsSpace(WaitKey()))
	{}

	PutText((256-20*8)/2,4,"                    ",0);
}

// Put all sprite on screen
void DrawSprite(void)
{

		PutSprite(PlyPad.spr,PlyPad.pat,PlyPad.x,PlyPad.y,15);

		// Check PlyPad Outside Game field
		if (PlyPad.y<10)
		{
			PlyPad.y=10;			
		}
		if (PlyPad.y>196)
		{
			PlyPad.y=196;
		}
}

// Wait Routine
void FT_Wait(int cicles) {
  unsigned int i;

  for(i=0;i<cicles;i++)
  {	
    while(IsVsync()==1)
    // With FUSION 1.3 use...
    //while(Vsynch()==0)	
    {}
  }
}

Tot seguit us deixem el codi sencer i al final un enllaç on podreu executar online l’exemple que hem treballat.


//Documentation section

//
// pad.c
// Fusion-C Pong game example articles
// Here we will learn how to move de player pad
// MoltSXalats 2023
//


// Preprocessor section

#include "fusion-c/header/msx_fusion.h"
#include "fusion-c/header/vdp_sprites.h"
#include "fusion-c/header/vdp_graph2.h"


// Definition section of macros and symbolic constants

#define TRUE 1
#define FALSE 0


// Type definition section

typedef struct { 
	char spr;	// Sprite ID
    char y;		// Y destination of the Sprite
    char x;		// X destination of the Sprite
    char pat;	// Pattern number to use
} Sprite;


// Definition section of function prototypes

void DrawSprite(void);
void GameStart(void);
void FT_Wait(int);


// Definition section of global variable

signed char DirX;					// Direction of the ball
signed char DirY; 

char PlyScore,CpuScore;

Sprite PlyPad;						// Defining Player Pad Structure

const signed char moves[9]={0,-1,0,0,0,1,0,0,0};

const char PatternPad[]={
						0b11100000,
						0b11100000,
						0b11100000,
						0b11100000,
						0b11100000,
						0b11100000,
						0b11100000,
						0b11100000
};


// Section of the main function and the game loop

void main (void)
{
	
	char joy;

	SetColors(15,0,0);
	Screen(5);					// 256 x 212 pixel
	Sprite8();
	SpriteDouble();				// Magnified to 16 x 16 pixels
	KeySound(0);

	SetSpritePattern(1, PatternPad,8);

	// Defining Variables

	// Player Pad Sprite

	PlyPad.x=10;
	PlyPad.y=100;
	PlyPad.spr=0;
	PlyPad.pat=1;

	PlyScore=0;

	// Cpu Pad Sprite

	CpuScore=0;

	DirX=1;
	DirY=1;

	GameStart();

	while (Inkey()!=27) 			// Main loop, ESC to Exit
	{

		joy=JoystickRead(0);		// Reading Joystick 0 (Keyboard)

		PlyPad.y+=moves[joy];		// Update the Y position of the Player Pad
		DrawSprite();
		FT_Wait(170);
	}

	// Ending program, and return to DOS
	Screen(0);
	KeySound(1);
	Exit(0);
}


// User defined functions section


// Print the initial game screen
void GameStart(void)
{
	char Temp[5];

	// El texto es de 5 x 7
	PutText((256-20*8)/2,4,"Press SPACE to START",0);

	// Initial Positions
	PlyPad.x=10;
	PlyPad.y=100;

	DirX*=-1;

	DrawSprite();

	Itoa(PlyScore,Temp,10);
	PutText(10,4,Temp,0);

	Itoa(CpuScore,Temp,10);
	PutText(235,4,Temp,0);	

	while (!IsSpace(WaitKey()))
	{}

	PutText((256-20*8)/2,4,"                    ",0);
}

// Put all sprite on screen
void DrawSprite(void)
{

		PutSprite(PlyPad.spr,PlyPad.pat,PlyPad.x,PlyPad.y,15);

		// Check PlyPad Outside Game field
		if (PlyPad.y<10)
		{
			PlyPad.y=10;			
		}
		if (PlyPad.y>196)
		{
			PlyPad.y=196;
		}
}

// Wait Routine
void FT_Wait(int cicles) {
  unsigned int i;

  for(i=0;i<cicles;i++)
  {	
    while(IsVsync()==1)
    // With FUSION 1.3 use...
    //while(Vsynch()==0)	
    {}
  }
}

Et fem un avanç del que portarà el següent article de la sèrie. En aquest nou article mesclarem els resultats del primer “Pong (la pilota)” i d’aquest segon “Pong (la pala del jugador)” per a fer un “Front Pong”. El jugador podrà moure la seva pala i fer-hi rebotar la pilota, aquesta a la vegada rebotarà contra l’escenari tornant de nou cap al jugador.


Clica aquí per a veure l'exemple funcionant.







Comments


bottom of page