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