Brick Breaker

Dependencies:   4DGL-uLCD-SE mbed-rtos mbed

Game.h

Committer:
hotwheelharry
Date:
2014-10-21
Revision:
0:099e4258aba4

File content as of revision 0:099e4258aba4:

#include <vector>
#include "Graphics.h"
#include <cmath>
#include <string>
#include <sstream>


float frand(){
    return (float)rand()/(float)RAND_MAX;   
}
double round(double d)
{
  return floor(d + 0.5);
}

class Melody{
    public:
    std::vector<float> notes;
};

class Audio{
private:
    Mutex mutex;
    AnalogOut& audio;
public:
    Audio(AnalogOut& ao) : audio(ao)
    {   
    }
    
    void playSong(Melody& s){
        mutex.lock();
        
        mutex.unlock();
    }
    void triggerShot(){
        mutex.lock();
        
        mutex.unlock();   
    }
    void run(){
        while(true){
            
            Thread::wait(100);   //ms        
        }
    }
};

class Controller{
public:

    AnalogIn& sliderh;
    AnalogIn& sliderv;
    DigitalIn& button;
public:
    Controller(AnalogIn& sliderh, AnalogIn& sliderv, DigitalIn& btn) : sliderh(sliderh), sliderv(sliderv), button(btn)
    {
        
    }  
};



class Physics{
private:

public:
    float dt;  
    
    void step(Scene& scene){      
       Block& b = scene.ball;
       
      if(b.locked)
        {
            b.store_prev();
            b.updated = true;
            b.next_coord.x = scene.paddle.coord.x + scene.paddle.size.x/2.0 - b.size.x/2.0;
            b.next_coord.y = scene.paddle.coord.y - b.size.y - 1;
            b.next_velocity.x = 0;
            b.next_velocity.y = 0;
            
            b.next_swap();
            return;
        }
       
       
        //move things
       if(b.velocity.x != 0 || b.velocity.y != 0)
       {
            b.store_prev();
            b.updated = true;
            b.next_coord.x = b.coord.x + dt * b.velocity.x;
            b.next_coord.y = b.coord.y + dt * b.velocity.y;
            
            b.next_velocity.x = b.velocity.x;
            b.next_velocity.y = b.velocity.y;
       }
       
       if( b.coord.x < 0)
       {
           b.next_coord.x = 0;
           b.next_velocity.x = b.velocity.x * -1.0;
       }
       if( b.coord.x + b.size.x > 128){
           b.next_coord.x = 128-b.size.x;
           b.next_velocity.x = b.velocity.x * -1.0;   
       }
       
       if(b.coord.y < 0)
        {
           b.next_coord.y = 0;
           b.next_velocity.y = b.velocity.y * -1.0;
       }
        
        //collision with blocks
        int hitcount = 0;
       for(std::list<Block>::iterator j = scene.blocks.begin(); j != scene.blocks.end(); j++){ 
            if(j->color == 0x444444){
                hitcount++;
            }
           if( j->interactive && b.touching( *j ) ){
               bool h = false;
               bool v = false;
               
               //from right
               if( b.coord.x > j->coord.x && b.coord.x < (j->coord.x + j->size.x) ){
                   b.next_coord.x = j->coord.x + j->size.x;
                   b.next_velocity.x = b.next_velocity.x * -1.0;
                   h = true;
               }
               //from left
               if(b.coord.x + b.size.x > j->coord.x && b.coord.x < (j->coord.x) ){
                   b.next_coord.x = j->coord.x - b.size.x;
                   b.next_velocity.x = b.next_velocity.x * -1.0;
                   h = true;
               }
               
               // from top
               if( b.coord.y + b.size.y > j->coord.y && b.coord.y < (j->coord.y) ){
                    b.next_coord.y = (j->coord.y - b.size.y);
                    b.next_velocity.y = b.next_velocity.y * -1.0;
                    b.next_coord.x = b.coord.x;
                    v = true;
               }
               //from bottom
               if( b.coord.y < j->coord.y + j->size.y && b.coord.y + b.size.y > (j->coord.y) ){
                    b.next_coord.y = (j->coord.y + j->size.y);
                    b.next_velocity.y = b.next_velocity.y * -1.0;
                    b.next_coord.x = b.coord.x;
                    v = true;
               }
               
               if(h || v){
                   
                   j->color = 0x444444;
                   j->updated = true;
                   j->interactive = false;
               }
               
               
               
               
               
               
               scene.score++;
                std::stringstream ss;
                ss << "Score:" << scene.score;
                scene.text[0].message = ss.str();
                scene.text[0].updated = true;
                
           }
           else{
                b.color = WHITE;   
           }
       }
       
       if(hitcount == scene.blocks.size()){
            scene.beat = true;   
       }
       
       
       
       //collision with paddle
       if(b.next_coord.y + b.size.y > scene.paddle.coord.y && b.next_coord.y - b.velocity.y < scene.paddle.coord.y
         && (b.next_coord.x + b.size.x > scene.paddle.coord.x && b.next_coord.x < scene.paddle.coord.x + scene.paddle.size.x)){
               if(!b.locked){                       
                   float pmid = scene.paddle.coord.x + scene.paddle.size.x/2.0;
                   float bmid = b.next_coord.x + b.size.x/2.0;
                   float d = bmid - pmid;
                   b.next_velocity.x = b.velocity.x + d/(scene.paddle.size.x/2.0) * 30.0;
                   if(b.next_velocity.x > 50)
                   { b.next_velocity.x = 50; }
                   if(b.next_velocity.x < -50)
                   { b.next_velocity.x = -50;}    
                   
                   b.next_velocity.y = (b.velocity.y * -1.0) * 1.01;
                   b.next_coord.x = b.coord.x;
                   b.next_coord.y = scene.paddle.next_coord.y - b.size.y - 1;
               }
       }
        
        
        //update all the new positions
        b.next_swap();
        
    };
    
};


class Game{
private:
    Renderer& renderer;
    Audio& audio;
    Controller& controller;
    
    Physics physics;
    Scene scene;
    
    int level;
    
    Scene menu;
    
public:
    Game(Renderer& renderer, Audio& aud, Controller& ctrl) 
    : renderer(renderer), audio(aud), controller(ctrl)
    {  
        level = 0;
        scene.bg = Color((int)renderer.background);
        
        buildScene(); 
        physics.dt = 0.1;
    }

private:
    void buildMenu(){
        
    }
    void buildScene(){
        
        scene.lives = 3;
        scene.score = 0;
        scene.beat = false;
        
        // build bricks
        float vertical = 10;
        float spacing = 2;
        vec2 bgrid = {5,3};
        vec2 bsize;
        bsize.x = (renderer.screen.x-spacing) / (bgrid.x) - 2;
        bsize.y = 4;
        
        int colorscheme = level;
        
        for(int i = 0; i < bgrid.x; i++){
            for(int j = 0; j < bgrid.y; j++){
                Block b;
                b.velocity.x = 0;
                b.velocity.y = 0;
                b.size = bsize;
                b.coord.x = spacing + (bsize.x + spacing)*i;
                b.coord.y = spacing + (bsize.y + spacing)*j + vertical;
                b.copy();
                b.color = RED;
                switch(colorscheme){
                    case 0: b.color = Color(0x66+round(0x99*((float)(bgrid.y-j)/(float)bgrid.y)),0,0);
                            break;  
                    case 1: b.color = Color(0,0x66+round(0x99*((float)(bgrid.y-j)/(float)bgrid.y)), 0);
                            break;
                    case 2: b.color = Color(0,0,0x66+round(0x99*((float)(bgrid.y-j)/(float)bgrid.y)));
                            break;
                    case 3: b.color = Color(round(0xff*(frand())),
                                            round(0xff*(frand())),
                                            round(0xff*(frand()))
                                            );
                            break;
                            
                    default:  b.color = RED;
                }
                scene.blocks.push_back(b);
            }
        }
        
        Block pad;
        pad.locked = true;
        pad.size.x = renderer.screen.x / 4.0;
        pad.size.y = 4;
        pad.coord.x = renderer.screen.x / 4.0 + pad.size.x / 2.0;
        pad.coord.y = renderer.screen.y - spacing - pad.size.y;
        pad.copy();
        pad.color = WHITE;
        scene.paddle = pad;
        
        
        Block b;
        b.size.x = 4;
        b.size.y = 4;
        b.coord.x = pad.coord.x + pad.size.x/2.0 - b.size.x/2.0;
        b.coord.y = pad.coord.y - b.size.y - 1;
        b.color = WHITE;
        b.locked = true;
        b.copy();
        scene.ball = b;
        
        Text tscore;
        tscore.coord.x = renderer.screen.x / 6 - 12;
        tscore.coord.y = 0;
        tscore.font = FONT_7X8;
        tscore.color = WHITE;
        tscore.message = "Score:0";
        scene.text.push_back(tscore);
        
        Text tlives;
        tlives.coord.x = 0;
        tlives.coord.y = 0;
        tlives.font = FONT_7X8;
        tlives.color = WHITE;
        tlives.message = "Lives:3";
        scene.text.push_back(tlives);
    }
    void getInput(){
        float pos = controller.sliderh;
        scene.paddle.store_prev();
        scene.paddle.coord.x = (renderer.screen.x - scene.paddle.size.x - 4) * pos + 2;
        scene.paddle.updated = true;
        
        Block& b = scene.ball;
        if(b.locked)
        {
            if(controller.button ){
                b.locked = false; 
                b.velocity.y = -80.0;
            }
        }
    }
    void gameLogic(){
        if(scene.ball.coord.y > renderer.screen.y){
            scene.lives--;
            std::stringstream ss;
            ss << "Lives:" << scene.lives;
            scene.text[1].message = ss.str();
            scene.text[1].updated = true;
            
            scene.ball.locked = true;
        }
        
        if(scene.lives == 0){
            scene = Scene();
            level = 0;
            buildScene();  
            
            renderer.g.filled_rectangle(0, 0, 128, 10, renderer.background);
        }
        
        if(scene.beat){
            level++;
            scene.ball.store_prev();
            Block cb = scene.ball;
            
            int score = scene.score;
            scene = Scene();
            buildScene(); 
            scene.score = score;
            std::stringstream ss;
            ss << "Score:" << scene.score;
            scene.text[0].message = ss.str();
            scene.text[0].updated = true;
            
            renderer.g.filled_rectangle(cb.coord.x, cb.coord.y, cb.coord.x+cb.size.x, cb.coord.y+cb.size.y, renderer.background);
            renderer.g.filled_rectangle(0, 0, 128, 10, renderer.background);
            
        }
    }
public:
    void loop(){
        getInput();
        gameLogic(); 
        physics.step(scene);
        renderer.render(scene);
    }
    
};