Mini Pool game for two players
Dependencies: PokittoLib
This is a small, fully documented Mini Pool game for 2 players intended as a programming tutorial
Revision 0:1850dcae680f, committed 2018-10-12
- Comitter:
- Pokitto
- Date:
- Fri Oct 12 17:09:04 2018 +0000
- Commit message:
- initial
Changed in this revision
diff -r 000000000000 -r 1850dcae680f GameObject.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GameObject.cpp Fri Oct 12 17:09:04 2018 +0000 @@ -0,0 +1,135 @@ +#include "Pokitto.h" +#include "GameObject.h" + +Pokitto::Display gobj_d; +int flipper = 0; + + +GameObject::GameObject() { + x = random(-20,20); + y = random(-15,15); + vx = 0;//random(-100,100)/100.0f; + vy = 0;//random(-100,100)/100.0f; + width = 5; + height = 5; + if (flipper) color = 7; //random(3,12); + else color = 4; + flipper = 1 - flipper; + if (color == 5) color = 2; + orig_color = color; + bounce = 0.9f; + acceleration = 0.15f; + friction = 0.98f; + mass = 1.0f; + centerX = 55+x; + centerY = 44+y; + movable=true; + visible=true; + active=true; +} + +void GameObject::draw() { + if (!visible) return; + gobj_d.setColor(color); + gobj_d.fillRect(55-width/2+x,44-height/2+y,width,height); + centerX = 55+x; + centerY = 44+y; +} + +void GameObject::move() { + if (!active) return; + if (!movable) return; + x += vx; + y += vy; + centerX = 55+x; + centerY = 44+y; + vx *= friction; + vy *= friction; + if (abs(vx*10) < 1 && abs(vy*10) <1) vx = vy = 0; // practically stopped +} + +bool GameObject::isMoving() { + if (vx == 0 && vy == 0) return false; + return true; +} + +void GameObject::remove() { + active=false; + visible=false; + vx = 0; + vy = 0; +} + +void GameObject::moveX(float n) { + x += n; + centerX = 55+x; +} + +void GameObject::moveY(float n) { + y += n; + centerY = 44+y; +} + +void GameObject::accelerateX(float a) { + vx += a*acceleration; +} + +void GameObject::accelerateY(float a) { + vy += a*acceleration; +} + +void GameObject::bounceY() { + vy = -vy * bounce; +} + +void GameObject::bounceX() { + vx = -vx * bounce; +} + +void GameObject::bounceY(float bouncefactor) { + vy = -vy * (bounce*bouncefactor); +} + +void GameObject::bounceX(float bouncefactor) { + vx = -vx * (bounce*bouncefactor); +} + +bool GameObject::checkCollision(GameObject& other) { + if (active == false || other.active == false) return false; + other.color = 2; + if ((x + width/2 >= other.x - other.width/2) && (x - width/2 < other.x + other.width/2) && (y + height/2 >= other.y - other.height/2) && (y - height/2 < other.y + other.height/2)) return true; + other.color = other.orig_color; + return false; +} + +void GameObject::doCollision(GameObject& other) { + if (active == false || other.active == false) return; + if (!other.movable) { + //movable vs. immovable collision + if (x - width/2 < other.x - other.width/2 || x + width/2 > other.x + other.width/2) { + // collision in vertical wall + bounceX(); + } else { + // collision in horizontal wall + bounceY(); + } + } else { + // movable vs. movable + //vx = ((mass-other.mass)/sum_mass)*vx + ((other.mass*2)/sum_mass)*other.vx; + //other.vx = ((mass*2)/sum_mass)*vx + ((other.mass-mass)/sum_mass)*other.vx; + //vy = ((mass-other.mass)/sum_mass)*vy + ((other.mass*2)/sum_mass)*other.vy; + //other.vy = ((mass*2)/sum_mass)*vy + ((other.mass-mass)/sum_mass)*other.vy; + float tvx, tvy; + tvx = vx; tvy = vy; + vx = other.vx*bounce; vy = other.vy*bounce; + other.vx = tvx*bounce; other.vy = tvy*bounce; + } + // move the object out of each other to avoid more collisions + int i=0; + while (checkCollision(other) && ++i < 10) {move(); if (other.movable) other.move();} +} + +void GameObject::setColor(int c) { + color = c; + orig_color = c; +} \ No newline at end of file
diff -r 000000000000 -r 1850dcae680f GameObject.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GameObject.h Fri Oct 12 17:09:04 2018 +0000 @@ -0,0 +1,53 @@ +#ifndef GAMEOBJECT_H +#define GAMEOBJECT_H + + +class GameObject { + +public: + float x; // paikka pelikentällä + float y; + float centerX; // paikka ruudulla + float centerY; + float vx; + float vy; + float acceleration; + float friction; + float width; + float height; + float bounce; + float mass; + + int color; + int orig_color; + bool visible; + bool movable; + bool active; + + void setColor(int); + bool isMoving(); + + virtual void draw(); + virtual void move(); + virtual void remove(); + + void accelerateX(float); + void accelerateY(float); + + void moveX(float); + void moveY(float); + + void bounceX(float); + void bounceY(float); + + void bounceX(); + void bounceY(); + + virtual bool checkCollision(GameObject&); + virtual void doCollision(GameObject&); + + GameObject(); + +}; + +#endif \ No newline at end of file
diff -r 000000000000 -r 1850dcae680f My_settings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/My_settings.h Fri Oct 12 17:09:04 2018 +0000 @@ -0,0 +1,16 @@ +/* This is an example of how to set your own project settings + +To use + +1. make a copy of this file by pressing right mouse button on top of this file +in the mbed online compiler, then choose "Clone" + +2. See that the copy is in the root of the project (where your main cpp files are), not inside the PokittoLib folder +Drag & drop to move if needed + +3. rename the clone to "My_settings.h" + +*/ + +#define PROJ_HIRES 0 +#define PROJ_ENABLE_SOUND 0 \ No newline at end of file
diff -r 000000000000 -r 1850dcae680f PokittoLib.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PokittoLib.lib Fri Oct 12 17:09:04 2018 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/Pokitto/code/PokittoLib/#123aefc978a7
diff -r 000000000000 -r 1850dcae680f main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Oct 12 17:09:04 2018 +0000 @@ -0,0 +1,227 @@ +#include "Pokitto.h" // Include the Pokitto library +#include "GameObject.h" // Include the simple physics library + +Pokitto::Core mygame; // Create a Pokitto app/game object + +#define MAX_BALL_OBJECTS 7 // max amount of balls + +GameObject balls[MAX_BALL_OBJECTS]; // Array of balls +GameObject player; // player-object (for aiming) +GameObject bumpers[4]; // Four sides of table +GameObject pockets[4]; // Four pockets + +enum GameStates { Start, Aim, Hit, Win }; // Game states + +/** global variables (accessible from everywhere in the code **/ +GameStates gamestate = Start; +int ballsinplay = 7; // how many balls in the game +int player1points = 0; +int player2points = 0; +int gameturn = 1; // which players turn +bool player_pocketed = false; //continue turn if player pocketed their own color ball on their turn + +// starting arrangement of the balls +void initballs(){ + balls[0].x = -30; balls[0].y = 0; balls[0].active = true; balls[0].visible = true; balls[0].setColor(1); + balls[1].x = 10; balls[1].y = 0; balls[1].active = true; balls[1].visible = true; balls[1].setColor(7); + balls[2].x = 10; balls[2].y = 10; balls[2].active = true; balls[2].visible = true; balls[2].setColor(4); + balls[3].x = 10; balls[3].y = -10; balls[3].active = true; balls[3].visible = true; balls[3].setColor(4); + balls[4].x = 20; balls[4].y = -10; balls[4].active = true; balls[4].visible = true; balls[4].setColor(7); + balls[5].x = 20; balls[5].y = 0; balls[5].active = true; balls[5].visible = true; balls[5].setColor(4); + balls[6].x = 20; balls[6].y = 10; balls[6].active = true; balls[6].visible = true; balls[6].setColor(7); +} + +/** MAIN is where a typical C++ program begins executing the program **/ + +int main () { + mygame.begin(); // start Pokitto engine (display, buttons, sound) + mygame.display.setFont(fontTiny); // Tiny font active + mygame.display.bgcolor = 13; // Background color to dark green (13) + mygame.display.invisiblecolor = 13; // Make text background (13) invisible + + /** PROGRAM LOOP... runs the entire life of the program + ie. as long as mygame.isRunning() returns logical true (=1) **/ + + while (mygame.isRunning()) { + + // Draw table bumpers + for (int i=0; i<4; i++) bumpers[i].draw(); + // Draw table pockets + for (int i=0; i<4; i++) pockets[i].draw(); + // Calculate balls vs. bumpers collisions + for (int i=0; i<ballsinplay; i++) { + for (int j=0; j<4; j++) { + if (balls[i].checkCollision(bumpers[j]) && gamestate != Start) { + balls[i].doCollision(bumpers[j]); + } + } + } + + // Calculate balls vs. balls collisions + for (int i=0; i<ballsinplay; i++) { + for (int j=0; j<ballsinplay; j++) { + if (i != j) { // do not check collision with self!! + if (balls[i].checkCollision(balls[j]) && gamestate != Start) { + balls[i].doCollision(balls[j]); + } + } + } + } + + // Calculate balls colliding with pockets + for (int i=0; i<ballsinplay; i++) { + for (int j=0; j<4; j++) { + if (balls[i].checkCollision(pockets[j]) && gamestate != Start) { + // Ball in pocket! + balls[i].remove(); // remove ball from table + if (balls[i].color == 7) { + player1points++; // red ball point for player 1 + if (gameturn == 1) player_pocketed = true; // player gets a new shot! + } + if (balls[i].color == 4) { + player2points++; // yellow ball point for player 2 + if (gameturn == 2) player_pocketed = true; // player gets a new shot! + } + if (balls[i].color == 1) { + // White ball in pocket, player lost + if (gameturn==1) { player1points=0; player2points = (ballsinplay-1)/2; } //player 2 vwins + else { player1points = (ballsinplay-1)/2; player2points = 0;} //player 1 wins + } + if (player1points == (ballsinplay-1)/2 || player2points == (ballsinplay-1)/2) gamestate = Win; + } + } + } + + /** UPDATE loop, refresh the display **/ + if (mygame.update()) { + int balls_stopped = 0; // for calculating balls that have come to a standstill + // Draw balls + for (int i=0; i<ballsinplay; i++) balls[i].draw(); + // Select white color for text + mygame.display.color = 1; + switch (gamestate) { + case Start: + /** case Start ... initialize table and game **/ + mygame.display.print(16,8,"MiniPool"); + mygame.display.print(16,16,"Press A"); + + // Zero points and variables + player1points = 0; + player2points = 0; + gameturn = 1; + + // Put balls in starting position + initballs(); + + /** Table **/ + // Top bumper in place + bumpers[0].x = 0; bumpers[0].y = -49; bumpers[0].width = 110; bumpers[0].height=20; + bumpers[0].setColor(5); + // Bottom bumper in place + bumpers[1].x = 0; bumpers[1].y = 49; bumpers[1].width = 110; bumpers[1].height=20; + bumpers[1].setColor(5); + // Left bumper in place + bumpers[2].x = -59; bumpers[2].y = 0; bumpers[2].width = 20; bumpers[2].height=88; + bumpers[2].setColor(5); + // Right bumper in place + bumpers[3].x = 59; bumpers[3].y = 0; bumpers[3].width = 20; bumpers[3].height=88; + bumpers[3].setColor(5); + // Make bumpers stationary + bumpers[0].movable = bumpers[1].movable = bumpers[2].movable = bumpers[3].movable = false; + + /** Pockets **/ + // Left top pocket in place + pockets[0].x = -59; pockets[0].y = -49; pockets[0].width = 30; pockets[0].height=30; + pockets[0].setColor(0); + // Right top pocket in place + pockets[1].x = 59; pockets[1].y = -49; pockets[1].width = 30; pockets[1].height=30; + pockets[1].setColor(0); + // Right bottom pocket in place + pockets[2].x = 59; pockets[2].y = 49; pockets[2].width = 30; pockets[2].height=30; + pockets[2].setColor(0); + // Left bottom pocket in place + pockets[3].x = -59; pockets[3].y = 49; pockets[3].width = 30; pockets[3].height=30; + pockets[3].setColor(0); + // Make all pockets stationary + bumpers[0].movable = pockets[1].movable = pockets[2].movable = pockets[3].movable = false; + + // if A pressed, move to Aim game state + if (mygame.buttons.released(BTN_A)) { + player.x = balls[0].x; player.y = balls[0].y; + gamestate = Aim; + } + break; + case Aim: + player_pocketed = false; // put this back to false, its for checking if a ball was pocketed during the Hit state + /** case Aim ... in this gamestate, player moves targetting line **/ + if (gameturn == 1) { + mygame.display.color = 7; // red + mygame.display.print(16,8,"player 1 turn"); + } else { + mygame.display.color = 4; // yellow + mygame.display.print(16,8,"player 2 turn"); + } + + // draw targetting line + mygame.display.setColor(1); // white + mygame.display.drawLine(player.centerX,player.centerY,balls[0].centerX,balls[0].centerY); + // check button presses + if (mygame.buttons.rightBtn()) player.moveX(1); + if (mygame.buttons.leftBtn()) player.moveX(-1); + if (mygame.buttons.upBtn()) player.moveY(-1); + if (mygame.buttons.downBtn()) player.moveY(1); + // if button A released, a hit begins + if (mygame.buttons.released(BTN_A)) { + // give initial speed to the cue ball (the white ball) + balls[0].vx = (player.x - balls[0].x) * balls[0].acceleration; // X direction strength + balls[0].vy = (player.y - balls[0].y) * balls[0].acceleration; // Y direction strength + gamestate = Hit; // go to next gamestate + } + break; + case Hit: + /** case Hit ... in this state balls move until they are all stopped **/ + // now count all stationary balls + for (int i=0; i < ballsinplay; i++) { + // if ball is stationary or no longer on the table + if (balls[i].isMoving() == false || balls[i].active == false) { + balls_stopped++; // count inactive balls + } + } + if (balls_stopped == ballsinplay) { + // all balls in play are no longer active, time for a new shot + player.x = balls[0].x; player.y = balls[0].y; + if (player_pocketed == false) { + // player did not pocket any of his/her own balls, so does not get a new turn + if (gameturn == 1) gameturn = 2; + else gameturn = 1; // change game turn + } + gamestate = Aim; + } + break; + case Win: + /** case Win ... player 1 or 2 won **/ + if (player1points > player2points) { + mygame.display.color = 7; // red + mygame.display.print(16,8,"player 1 WON!"); + } else { + mygame.display.color = 4; // yellow + mygame.display.print(16,8,"player 2 WON!"); + } + mygame.display.color = 1; // white + mygame.display.print(16,16,"Press A"); + // if button A released, game begins again + if (mygame.buttons.released(BTN_A)) { + gamestate = Start; + } + break; + + } + } + // Calculate movement of balls (outside of display update loop, we get more calculations and therefore more accuracy like this!) + for (int i = 0; i< ballsinplay; i++) balls[i].move(); + // needed for updating targetting line + player.move(); + // draw white ball always, even outside display update loop (speed streak effect!) + balls[0].draw(); + } +} \ No newline at end of file