I still didn't get around to cleaning up the code, I've just added some comments...
#include <S65Display.h>
#include <RotaryEncoder.h>
#include <string.h>
#define WIDTH 176
#define HEIGHT 132
#define BAT_WIDTH 5
#define BAT_HEIGHT 30
#define BAT_INIT_X 5
#define BAT_INIT_Y 56
#define BALL 5
#define BAT_STEP 5
#define AI_STEP 2
#define MAX_TURNS 5
float ball_x = WIDTH / 2;
float ball_x_prev = ball_x;
float ball_y = HEIGHT / 2;
float ball_y_prev = ball_y;
float ball_dir = 0;
float bat_1_dir = 0;
int bat1_x = BAT_INIT_X;
int bat1_y = BAT_INIT_Y;
int bat1_y_prev = bat1_y;
int bat2_x = WIDTH - BAT_INIT_X - BAT_WIDTH;
int bat2_y = BAT_INIT_Y;
int bat2_y_prev = bat2_y;
int bat2_step = AI_STEP;
int p1_score = 0;
int p2_score = 0;
int ball_angle = 0; // angle between ball path and horizontal axis
int ball_angle_sign = 0; // sign of ball_angle : up = +1, down = -1, horizontal = 0
boolean score = false;
boolean gameover = false;
char buffer[256]; // String buffer
S65Display lcd;
RotaryEncoder encoder;
// Encoder must be serviced regularly.
ISR(TIMER2_OVF_vect)
{
TCNT2 -= 250; //1000 Hz
encoder.service();
}
void setup()
{
lcd.init(2);
encoder.init();
// More encoder stuff
//init Timer2
TCCR2B = (1<<CS22); //clk=F_CPU/64
TCNT2 = 0x00;
TIMSK2 |= (1<<TOIE2); //enable overflow interupt
score = false;
gameover = false;
lcd.clear(0);
initTurn();
startGame();
}
void loop(){
while(!score && !gameover){
checkControls();
updateAI();
updateFields();
drawScreen();
delay(10);
}
if(checkPress() && !gameover){ // if a player scored wait for rotary press
initTurn();
}
delay(10);
}
// initialize fields for the beginning of game/round
void initTurn(void){
lcd.clear(0);
ball_x = WIDTH / 2;
ball_x_prev = ball_x;
ball_y = HEIGHT / 2;
ball_y_prev = ball_y;
ball_dir = 0;
bat1_x = BAT_INIT_X;
bat1_y = BAT_INIT_Y;
bat1_y_prev = bat1_y;
bat2_x = WIDTH - BAT_INIT_X - BAT_WIDTH;
bat2_y = BAT_INIT_Y;
bat2_y_prev = bat2_y;
ball_angle = 0; // angle between ball path and horizontal axis
ball_angle_sign = 0; // up = +1, down = -1, horizontal = 0
score = false;
ball_dir = 1;
ball_angle = 45;
}
// start the game and wait for press on rotary encoder
void startGame(void){
lcd.drawText(35, 60, "Click to start", RGB(255,255,255), RGB(0,0,0));
while(!checkPress()){
delay(10);
};
lcd.clear(0);
}
boolean checkPress(void){ // checks if rotary encoder was pressed
int8_t press;
press = encoder.sw();
if (SW_PRESSED == press || SW_PRESSEDLONG == press) {
return true;
}
else{
return false;
}
}
void checkRotation(void){
moveBat(encoder.step());
}
void checkControls(void){
if(checkPress()){ // pause
lcd.drawText(45, 60, "Game paused", RGB(255,255,255), RGB(0,0,0));
while(!checkPress()){
}
lcd.clear(0);
}
checkRotation();
}
void moveBat(int rot){
if(!score && !gameover){
if(rot == 1){ // clockwise rotation, move bat up
if(bat1_y - BAT_STEP >= 0){ // only move up when there is enough space left
bat1_y -= BAT_STEP;
}
}
else if(rot == -1){ // anti-clockwise rotation, move bat down
if((bat1_y + BAT_HEIGHT + BAT_STEP) < HEIGHT){ // only move down when there is enough space left
bat1_y += BAT_STEP;
}
}
}
}
void updateFields(void){
if(ball_y <= 0 || ball_y + BALL >= HEIGHT){ // top or bottom of screen reached, bounce ball back
if(ball_angle_sign == -1){ // ball was going down
ball_angle_sign = 1; // ball is now going up
}
else{ // ball was going up
ball_angle_sign = -1; // ball is now going down
}
}
if((ball_x <= 12 && ball_x >= 11) && (ball_dir == 1)){ // check if ball has is in reach of bat1 (horizontal), for some reason checking for equality doens't seem to work here ?
if((ball_y + BALL) >= bat1_y && ball_y <= (bat1_y + BAT_HEIGHT)){ // ball is in reach of bat1 (vertical)
ball_dir = 0; // ball hits bat1, change direction
}
}
if((ball_x >= 160 && ball_x <= 162) && (ball_dir == 0)){ // check if ball has is in reach of bat2 (horizontal)
if((ball_y + BALL) >= bat2_y && ball_y <= (bat2_y + BAT_HEIGHT)){ // ball is in reach of bat2 (vertical)
ball_dir = 1; // ball hits bat2, change direction
}
}
if( ball_x > 0 && ball_x + BALL < WIDTH){ // ball is not near left or right edge
if(ball_dir == 0){ // ball is moving to the right
ball_x += cos(ball_angle); // cosine is always positive in 1st and 4th quadrant
if(ball_angle_sign == -1){ // check sign of angle
ball_y -= sin(ball_angle); // negative if angle in 4th quadrant
}
else{
ball_y += sin(ball_angle); // positive if angle in 1th quadrant
}
}
else{ // ball is moving to the left
ball_x -= cos(ball_angle); // cosine is always negative in 2nd and 3rd quadrant
if(ball_angle_sign == -1){
ball_y -= sin(ball_angle); // sine is always negative in 3rd quadrant
}
else{
ball_y += sin(ball_angle); // sine is always positive in 2nd quadrant
}
}
}
else{ // ball hits left or right edge
if(!score && !gameover){
if(ball_dir == 0){ // ball was going to the right
if(p1_score++ < MAX_TURNS){
p1_score++; // player 1 scores
}
else{
gameover = true;
}
}
else{ // ball was going to the left
if(p2_score < MAX_TURNS){
p2_score++; // player 2 scores
}
else{
gameover = true;
}
}
score = true;
}
}
}
void updateAI(void){
if(ball_y > (bat2_y + (BAT_HEIGHT / 2))){ // bat2 follows vertical position of ball, TODO : implement difficulty levels
if((bat2_y + BAT_HEIGHT + bat2_step) < HEIGHT){ // TODO : make function moveBat() that does the bound checking
bat2_y += bat2_step;
}
}
else{
if((bat2_y - bat2_step) >= 0){
bat2_y -= bat2_step;
}
}
}
void drawScreen(void){
// draw ball
lcd.drawRect( ball_x_prev, ball_y_prev, ball_x_prev + BALL, ball_y_prev + BALL, RGB(0,0,0));
lcd.drawRect( ball_x, ball_y, ball_x + BALL, ball_y + BALL, RGB(255,255,255));
ball_x_prev = ball_x;
ball_y_prev = ball_y;
// draw left bat
lcd.drawRect( bat1_x, bat1_y_prev, bat1_x + BAT_WIDTH, bat1_y_prev + BAT_HEIGHT, RGB(0,0,0));
lcd.drawRect( bat1_x, bat1_y, bat1_x + BAT_WIDTH, bat1_y + BAT_HEIGHT, RGB(255,255,255));
bat1_y_prev = bat1_y;
// draw right bat
lcd.drawRect( bat2_x, bat2_y_prev, bat2_x + BAT_WIDTH, bat2_y_prev + BAT_HEIGHT, RGB(0,0,0));
lcd.drawRect( bat2_x, bat2_y, bat2_x + BAT_WIDTH, bat2_y + BAT_HEIGHT, RGB(255,255,255));
bat2_y_prev = bat2_y;
drawScore();
}
void drawScore(void){
sprintf(buffer, "%d - %d", p1_score, p2_score);
lcd.drawText(72, 5, buffer, RGB(255,255,255), RGB(0,0,0));
}