This is the second of four installments we have designed for you to program from scratch a simple version of the Pong game using FUSION-C V1.2.
Objective
As you all know, Pong consists of two game paddles and a ball which you must hit with the paddle so that the other player can return it, all while preventing it from leaving the play area.
In this article, we will work with the player's game paddle, the one located on the left side of the screen. Together, we will learn how to create and move it.
Introduction
In the previous article, we introduced the sections into which a C file should be divided, as well as their order of definition within the file. As a reminder, these are: the documentation section, the preprocessor section, the section for defining macros and symbolic constants, the type definition section, the section for defining function prototypes, the section for defining global variables, the section for the main function and the game loop, and finally, the section with the implementation of the functions defined by the user.
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"
Type Definition Section
typedef struct {
char spr;
char y;
char x;
char pat;
} Sprite;
Function Prototypes Definition Section
void DrawSprite(void);
void GameStart(void);
void FT_Wait(int);
Global Variables Definition Section
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
};
Next, we explain the most notable and new variables from the first article "Pong (the ball)".
const signed char moves[9]={0,-1,0,0,0,1,0,0,0};
We will use the "moves" array to know at all times what operation we have performed on the (x, y) coordinates of the player's paddle based on the movement of the cursors.
If we consider the figure above, which captures the possible movements of the cursors, we can observe the 9 positions of our array. Being 0 the one of absence of movement.
Since the player's paddle can move in directions 1 and 5, within these positions of the array we will have the value that we must add or subtract to the "y" coordinate depending on the cursor pressed, either up or down.
We have defined the player's paddle as a 3x8 Sprite. We will create a pattern for the pattern table through the variable "PatternPad". The concept of Sprite will be captured by the variable "PlyPad" of the Sprite type that we have created.
const char PatternPad[]={
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000,
0b11100000
Section of the main function and the game loop
We have created the variable “joy” to collect, through the FUSION-C function “JoystickRead”, by passing the parameter “0” to indicate that it reads the joystick inputs. With the help of the “moves” array explained above, we will update the “y” coordinate of the player's paddle with the following assignment "PlyPad.y += moves[joy]".
We will also take advantage at the beginning of the “main (void)” function to initialize the player's paddle in terms of the (x, y) coordinates.
PlyPad.x=10;
PlyPad.y=100;
The game loop consists of two functions, the function that draws the ball on the screen "DrawSprite()", and "FT_Wait()", which imposes a pause on the movement of the player's paddle so that the drawing flows at a controlled speed, neither too fast nor too slow.
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);
}
Implementation of the Functions Defined by the User
It is worth mentioning that here we have incorporated a control so that the player's paddle does not go beyond the vertical limits of the screen within the sprite drawing function "DrawSprite(void)", taking into account its size by limiting the area to y>10 and 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)
{}
}
}
Next, we provide you with the complete code and, at the end, a link where you can run the example we have worked on online.
//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)
{}
}
}
We give you a preview of what the next article in the series will bring. In this new article, we will mix the results of the first "Pong (the ball)" and this second "Pong (User Pad)" to create a "Front Pong". The player will be able to move their paddle and bounce the ball off it, which in turn will bounce against the scenery and come back towards the player.
Click here to see the example working.
Comments