top of page

Pong (la paleta del jugador)


Esta es la segunda de las cuatro entregas que hemos diseñado para que programes desde cero una versión sencilla del juego "Pong" mediante FUSION-C V1.2.


Objetivo


Como todos sabréis, el "Pong" consta de dos paletas de juego y una pelota a la que debes golpear con la paleta para que el otro jugador la devuelva, evitando que esta salga del terreno de juego.


En este artículo trabajaremos con la paleta de juego del jugador, situada en el lado izquierdo de la pantalla. En conjunto aprenderemos a crearla y a moverla.




Introducción


En el artículo anterior, introdujimos las secciones en las que debería dividirse un archivo de C, así como su orden de definición dentro del archivo. Estas, como recordatorio, son: la sección de documentación, la del preprocesador, la de definición de macros y constantes simbólicas, la de definición de tipos, la de definición de prototipos de las funciones, la de definición de las variables globales, la sección de la función principal y el bucle de juego, y finalmente, la sección con la implementación de las funciones definidas por el usuario.


Sección de documentación


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


Sección del preprocessador


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


Sección de definición de tipos


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

Sección de definición de los prototipos de les funciones


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

Sección de definición de las variables globales


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
};

A continuación explicamos las variables más destacables y nuevas en el primer artículo "Pong (la pelota)".


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



Usaremos el array "moves" para saber en todo momento qué operación hemos hecho sobre las coordenadas (x, y) de la pala del jugador en función del movimiento de los cursores.


Si tenemos en cuenta la figura de más arriba, que recoge los movimientos posibles de los cursores, podemos observar las 9 posiciones de nuestro array, siendo la 0 la de ausencia de movimiento.


Como la paleta del jugador se puede mover en las direcciones 1 y 5, en estas posiciones del array tendremos el valor que deberemos sumar o restar a la coordenada "y" según se presione el cursor, hacia arriba o hacia abajo.


Hemos definido la pala del jugador, como un Sprite de 3x8. Crearemos un patrón para la tabla de patrones a través de la variable "PatternPad". El concepto de Sprite lo recogerá la variable "PlyPad" del tipo Sprite que hemos creado nosotros.


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


Sección de la función main y el bucle de juego


Hemos creado la variable "joy" para recoger, a través de la función de FUSION-C "JoystickRead", pasándole el parámetro "0" para indicarle que lea la entrada de los cursores. Con la ayuda del array "moves" explicado más arriba, actualizaremos la coordenada "y" de la pala del jugador con la siguiente asignación "PlyPad.y+=moves[joy]".


También aprovecharemos al inicio de la función "main (void)" para inicializar la pala del jugador en lo que respecta a las coordenadas (x, y).


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

El ciclo de juego consiste en dos funciones, la función que dibuja la pelota en la pantalla "DrawSprite()" y "FT_Wait()", que impone una pausa en el movimiento de la paleta del jugador para que el dibujo fluya a una velocidad controlada, ni muy rápida ni muy lenta.


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ón de las funciones definidas por el usuario


Cabe mencionar que aquí hemos incorporado un control para que la paleta del jugador no salga de los límites verticales de la pantalla dentro de la función de dibujo de los sprites, "DrawSprite(void)", teniendo en cuenta el tamaño de esta y limitando la zona a y>10 y 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)	
    {}
  }
}

A continuación, os dejamos el código completo y al final un enlace donde podréis ejecutar online el ejemplo que hemos trabajado.


//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)	
    {}
  }
}

Te ofrecemos un adelanto de lo que incluirá el siguiente artículo de la serie. En este nuevo artículo combinaremos los resultados del primer "Pong (la pelota)" y de este segundo "Pong (la paleta del jugador)" para crear un "Front Pong". El jugador podrá mover su paleta y hacer rebotar la pelota, la cual a su vez rebotará contra el escenario y volverá hacia el jugador.


Haz clic aquí para ver el ejemplo funcionando.







Comments


bottom of page