在NXP I.MX6上做一个基于Opencv和OpenGL的打砖块游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/czhzasui/article/details/83001265

最近一直在研究OpenGL,顺便搞了一个小游戏玩玩。话不多说上图:
在这里插入图片描述
就是用下面一个板接住弹来弹去的小球,直到把所有砖块都撞碎

主程序主要是开辟一个新线程然后后台监听DBus信号,这个游戏监听汽车上的转盘和按钮发送的DBus信号实现操控。新线程以每秒大约30帧刷新界面。command这个类是用来实现转盘和按钮DBus监听。

/***********************************************************************************************************************
 * Created by czh on 18-9-18
 *
 * Version 1.
 * Lastest version can been found:https://github.com/czhzasui/Breakout
 */
#include "game.h"
#include "command.h"

#define Refresh_Time 30

Game game(SCREEN_WIDTH, SCREEN_HEIGHT);
Command *command;

void mainLoop(Command *command) {
    while (!opengl_init(0)) {
        LOGI("opengl_init failed\n");
        usleep(100 * 1000);
    }
    game.init();
    while (GAME_QUIT != game.state) {
        QTime startTime = QTime::currentTime();

        game.processInput((float) Refresh_Time, command);

        game.update((float) Refresh_Time);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        game.render();
        postDisplay();

        QTime stopTime = QTime::currentTime();
        int elapsed = startTime.msecsTo(stopTime);
        if ((Refresh_Time - elapsed) > 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(Refresh_Time - elapsed));
        } else {
            if (elapsed >= Refresh_Time)
                std::cout << "Error:refresh delay" << std::endl;
        }
    }
    game.destory();
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    command = new Command();
    std::thread loop(mainLoop, command);
    loop.detach();

    return a.exec();
}

整个游戏都有game这个类控制。
game.h:使用OpenGL_ES 3.0,GameState中定义的是游戏的运行状态,默认GAME_ACTIVE。defaultVshaderStr中存放的是顶点着色器代码(GLSL语言),defaultFshaderStr存放片断着色器代码。

//
// Created by czh on 18-9-18.
//

#ifndef OPENGL_ES_GAME_H
#define OPENGL_ES_GAME_H

#include <QObject>
#include <QCoreApplication>
#include <QtDBus/QDBusConnection>
#include <QDebug>
#include <thread>
#include <unistd.h>
#include <opencv2/opencv.hpp>
#include <GLES3/gl3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <unistd.h>
#include "log.h"
#include "game.h"
#include "ui/openglTransaction.h"
#include "dbus/bootanimation_adaptor.h"
#include "dconfig.h"
#include "resource_manager.h"
#include "sprite_renderer.h"
#include "ui/openglTransaction.h"
#include "game_level.h"
#include "command.h"
#include "ball_object.h"

enum GameState {
    GAME_ACTIVE,
    GAME_MENU,
    GAME_WIN,
    GAME_QUIT
};

enum Direction {
    UP,
    RIGHT,
    DOWN,
    LEFT
};

typedef std::tuple<GLboolean, Direction, glm::vec2> Collision;

class Game {

public:
    GameState state;
    float width, height;
    std::vector<GameLevel> levels;
    GLuint level;
    GLboolean keys[1024];

    Game(GLuint width, GLuint height);

    ~Game();

    void init();

    void destory();

    void processInput(float refreshTime, Command *command);

    void render();

    void update(GLfloat refreshTime);

    void resetLevel();

    void resetPlayer();

    void doCollisions();

    Collision checkCollision(BallObject &one, GameObject &two);

    const char *defaultVshaderStr =
            "#version 300 es                                    \n"
            "layout (location = 0) in vec4 vertex;              \n"
            "out vec2 TexCoords;                                \n"
            "uniform mat4 model;                                \n"
            "uniform mat4 projection;                           \n"
            "uniform vec4 location;                             \n"
            "void main()                                        \n"
            "{                                                  \n"
            "   TexCoords.x = vertex.z * location.x + location.z;\n"
            "   TexCoords.y = vertex.w * location.y + location.w;\n"
            "   gl_Position = projection * model * vec4(vertex.xy, 0.0f, 1.0f);\n"
            "}                                                  \n";

    const char *defaultFshaderStr =
            "#version 300 es                                    \n"
            "precision mediump float;                           \n"
            "in vec2 TexCoords;                                 \n"
            "out vec4 color;                                    \n"
            "uniform sampler2D image;                           \n"
            "uniform vec3 spriteColor;                          \n"
            "void main()                                        \n"
            "{                                                  \n"
            "   color = vec4(spriteColor, 1.0) * texture(image, TexCoords);\n"
            "}                                                  \n";
    
private:
};


#endif //OPENGL_ES_GAME_H

game.cpp:游戏采用平面2D坐标系画图。

//
// Created by czh on 18-9-18.
//

#include "game.h"

const glm::vec2 PADDLE_SIZE(200, 20);
const GLfloat PADDLE_VELOCITY = 2.0f;
const glm::vec2 INITIAL_BALL_VELOCITY(0.07f, -0.245f);//y = -3.5f * x
const GLfloat BALL_RADIUS = 12.5f;

SpriteRenderer *spriteRender;
GameObject *paddle;
BallObject *ball;

Game::Game(GLuint width, GLuint height)
        : state(GAME_ACTIVE), keys(), width(width), height(height) {

}

Game::~Game() {
    delete spriteRender;
}

void Game::init() {
    system("killall -9 hmi");
    glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    glEnable(GL_CULL_FACE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    this->state = GAME_ACTIVE;

    ResourceManager::loadShader("sprite", defaultVshaderStr, defaultFshaderStr);

    glm::mat4 projection = glm::mat4(1.0f);
    projection = glm::ortho(0.0f, static_cast<GLfloat>(this->width), static_cast<GLfloat>(this->height), 0.0f, -1.0f,
                            1.0f);
    ResourceManager::getShader("sprite").setInteger("image", 0);
    ResourceManager::getShader("sprite").setMatrix4("projection", projection);
    ResourceManager::loadTexture2D("background", "/data/res/textures/background.jpg", false);
    ResourceManager::loadTexture2D("block", "/data/res/textures/block.png", false);
    ResourceManager::loadTexture2D("block_solid", "/data/res/textures/block_solid.png", false);
    ResourceManager::loadTexture2D("paddle", "/data/res/textures/paddle.png", true);
    ResourceManager::loadTexture2D("ball", "/data/res/textures/facebuke.png", true);

    ResourceManager::getShader("sprite").setVector4f("location", glm::vec4(1.0f, 1.0f, 0.0f, 0.0f));

    GameLevel levelOne;
    levelOne.load("/data/res/levels/one.lvl", this->width, this->height * 0.5);
    GameLevel levelTwo;
    levelTwo.load("/data/res/levels/one.lvl", this->width, this->height * 0.5);

    this->levels.push_back(levelOne);
    this->levels.push_back(levelTwo);
    this->level = 1;

    spriteRender = new SpriteRenderer(ResourceManager::getShader("sprite"));

    glm::vec2 paddlePos = glm::vec2(
            (this->width - PADDLE_SIZE.x) / 2,
            this->height - PADDLE_SIZE.y
    );
    paddle = new GameObject(paddlePos, PADDLE_SIZE, ResourceManager::getTexture2D("paddle"));
    glm::vec2 ballPos = paddlePos + glm::vec2(PADDLE_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2);
    ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY,
                          ResourceManager::getTexture2D("ball"));
}

void Game::destory() {
    system("/home/root/shell/hmi -platform eglfs &");
    QCoreApplication::exit(0);
}

void Game::processInput(float refreshTime, Command *command) {
    if (this->state == GAME_ACTIVE) {
        GLfloat dx = PADDLE_VELOCITY * refreshTime;
        if (Rotate_Left == command->rotate) {
            if (paddle->position.x >= 0) {
                paddle->position.x -= dx;
            }
            if (ball->stuck) {
                ball->position.x -= dx;
            }
        }
        if (Rotate_Right == command->rotate) {
            if (paddle->position.x <= this->width - paddle->size.x) {
                paddle->position.x += dx;
            }
            if (ball->stuck) {
                ball->position.x += dx;
            }
        }
        command->rotate = Rotate_Defalt;

        if (Key_Confirm == command->key) {
            ball->stuck = false;
        }
        if (Key_Homepage == command->key) {
            this->state = GAME_QUIT;
        }
        command->key = Key_Defalt;
    }
}

void Game::render() {
    if (this->state == GAME_ACTIVE) {
        spriteRender->drawSprite(ResourceManager::getTexture2D("background"), glm::vec2(0, 0),
                                 glm::vec2(this->width, this->height), 0.0f);
        this->levels[this->level].draw(spriteRender);
        paddle->draw(spriteRender);
        ball->draw(spriteRender);
    }
}

void Game::update(float refreshTime) {
    ball->move(refreshTime, this->width);

    this->doCollisions();

    if (ball->position.y >= this->height) {
        this->resetLevel();
        this->resetPlayer();
    }
}

void Game::resetLevel() {
    if (this->level == 0)
        this->levels[0].load("/data/res/levels/one.lvl", this->width, this->height * 0.5f);
    else if (this->level == 1)
        this->levels[1].load("/data/res/levels/one.lvl", this->width, this->height * 0.5f);
}

void Game::resetPlayer() {
    paddle->size = PADDLE_SIZE;
    paddle->position = glm::vec2(this->width / 2 - PADDLE_SIZE.x / 2, this->height - PADDLE_SIZE.y);
    ball->reset(paddle->position + glm::vec2(PADDLE_SIZE.x / 2 - BALL_RADIUS, -(BALL_RADIUS * 2)),
                INITIAL_BALL_VELOCITY);
}

void Game::doCollisions() {
    for (GameObject &brick : this->levels[this->level].bricks) {
        if (!brick.destroyed) {
            Collision collision = checkCollision(*ball, brick);
            if (std::get<0>(collision)) {
                if (!brick.isSolid)
                    brick.destroyed = GL_TRUE;
                Direction dir = std::get<1>(collision);
                glm::vec2 diff_vector = std::get<2>(collision);
                if (dir == LEFT || dir == RIGHT) {
                    ball->velocity.x = -ball->velocity.x;
                    GLfloat penetration = ball->radius - std::abs(diff_vector.x);
                    if (dir == LEFT)
                        ball->position.x += penetration; // Move ball to right
                    else
                        ball->position.x -= penetration; // Move ball to left;
                } else {
                    ball->velocity.y = -ball->velocity.y;
                    GLfloat penetration = ball->radius - std::abs(diff_vector.y);
                    if (dir == UP)
                        ball->position.y -= penetration; // Move ball back up
                    else
                        ball->position.y += penetration; // Move ball back down
                }
            }
        }
    }
    Collision result = checkCollision(*ball, *paddle);
    if (!ball->stuck && std::get<0>(result)) {
        GLfloat centerPaddle = paddle->position.x + paddle->size.x / 2;
        GLfloat distance = (ball->position.x + ball->radius) - centerPaddle;
        GLfloat percentage = distance / (paddle->size.x / 2);
        // Then move accordingly
        GLfloat strength = 2.0f;
        glm::vec2 oldVelocity = ball->velocity;
        ball->velocity.x = INITIAL_BALL_VELOCITY.x * percentage * strength;
        ball->velocity = glm::normalize(ball->velocity) * glm::length(oldVelocity);
        ball->velocity.y = -1 * std::abs(ball->velocity.y);
    }
}

Direction VectorDirection(glm::vec2 target) {
    glm::vec2 compass[] = {
            glm::vec2(0.0f, 1.0f),    // up
            glm::vec2(1.0f, 0.0f),    // right
            glm::vec2(0.0f, -1.0f),    // down
            glm::vec2(-1.0f, 0.0f)    // left
    };
    GLfloat max = 0.0f;
    GLuint best_match = -1;
    for (GLuint i = 0; i < 4; i++) {
        GLfloat dot_product = glm::dot(glm::normalize(target), compass[i]);
        if (dot_product > max) {
            max = dot_product;
            best_match = i;
        }
    }
    return (Direction) best_match;
}

Collision Game::checkCollision(BallObject &ball, GameObject &gameObject) {
    glm::vec2 ballCenter(ball.position + ball.radius);
    glm::vec2 brick_half_extents(gameObject.size.x / 2, gameObject.size.y / 2);
    glm::vec2 brick_center(gameObject.position.x + brick_half_extents.x, gameObject.position.y + brick_half_extents.y);
    glm::vec2 distance = ballCenter - brick_center;
    glm::vec2 clamped = glm::clamp(distance, -brick_half_extents, brick_half_extents);
    glm::vec2 closestPoint = brick_center + clamped;
    distance = closestPoint - ballCenter;
    if (glm::length(distance) < ball.radius)
        return std::make_tuple(GL_TRUE, VectorDirection(distance), distance);
    else
        return std::make_tuple(GL_FALSE, UP, glm::vec2(0, 0));
}

着色器程序

//
// Created by czh on 18-9-10.
//

#include "shader.h"

void Shader::compile(const GLchar *vShaderSource, const GLchar *fShaderSource, const GLchar *gShaderSource) {
    GLuint sVertex, sFragment, gShader;

    sVertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(sVertex, 1, &vShaderSource, nullptr);
    glCompileShader(sVertex);
    checkCompileErrors(sVertex, "VERTEX");

    sFragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(sFragment, 1, &fShaderSource, NULL);
    glCompileShader(sFragment);
    checkCompileErrors(sFragment, "FRAGMENT");

    if (gShaderSource != nullptr) {
        //gShader = glCreateShader(GL_GEOMETRY_SHADER);
        glShaderSource(gShader, 1, &gShaderSource, NULL);
        glCompileShader(gShader);
        checkCompileErrors(gShader, "GEOMETRY");
    }

    this->ID = glCreateProgram();
#ifdef SML
    std::cout << "#glCreateProgram ID:" << this->ID;
    if (gShaderSource == nullptr) {
        std::cout << " w/o_gShader" << std::endl;
    } else {
        std::cout << " w/_gShader" << std::endl;
    }
#endif
    glAttachShader(this->ID, sVertex);
    glAttachShader(this->ID, sFragment);
    if (gShaderSource != nullptr)
        glAttachShader(this->ID, gShader);
    glLinkProgram(this->ID);
    checkCompileErrors(this->ID, "PROGRAM");

    glDeleteShader(sVertex);
    glDeleteShader(sFragment);
    if (gShaderSource != nullptr)
        glDeleteShader(gShader);

}

Shader &Shader::use() {
    glUseProgram(this->ID);
    //std::cout << "#Use glUseProgram: " << this->ID << std::endl;
    return *this;
}

void Shader::setInteger(const GLchar *name, GLint value, GLboolean useShader) {
    if (useShader)
        this->use();
    glUniform1i(glGetUniformLocation(this->ID, name), value);
}

void Shader::setVector3f(const GLchar *name, const glm::vec3 &value, GLboolean useShader) {
    if (useShader)
        this->use();
    glUniform3f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z);
}

void Shader::setVector4f(const GLchar *name, const glm::vec4 &value, GLboolean useShader) {
    if (useShader)
        this->use();
    glUniform4f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z, value.w);
}

void Shader::setMatrix4(const GLchar *name, const glm::mat4 &matrix, GLboolean useShader) {
    if (useShader)
        this->use();
    glUniformMatrix4fv(glGetUniformLocation(this->ID, name), 1, GL_FALSE, glm::value_ptr(matrix));
}

void Shader::checkCompileErrors(GLuint object, std::string type) {
    GLint success;
    GLchar infoLog[1024];
    if (type != "PROGRAM") {
        glGetShaderiv(object, GL_COMPILE_STATUS, &success);
        if (!success) {
            glGetShaderInfoLog(object, 1024, NULL, infoLog);
            std::cout << "| ERROR::SHADER: Compile-time error: Type: " << type << "\n"
                      << infoLog << "\n -- ----------------------------------------------------- "
                      << std::endl;
        }
    } else {
        glGetProgramiv(object, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(object, 1024, NULL, infoLog);
            std::cout << "| ERROR::Shader: Link-time error: Type: " << type << "\n"
                      << infoLog << "\n -- ----------------------------------------------------- "
                      << std::endl;
        }
    }
}

纹理程序

//
// Created by czh on 18-9-10.
//

#include "texture.h"

Texture2D::Texture2D()
        : width(0), height(0), Internal_Format(GL_RGB), Image_Format(GL_RGB), Wrap_S(GL_REPEAT), Wrap_T(GL_REPEAT), Filter_Min(GL_LINEAR), Filter_Max(GL_LINEAR)
{
    glGenTextures(1, &this->ID);
}

void Texture2D::generate(GLuint width, GLuint height, unsigned char* data){
    this->width = width;
    this->height = height;
    glBindTexture(GL_TEXTURE_2D, this->ID);
    glTexImage2D(GL_TEXTURE_2D, 0, this->Internal_Format, width, height, 0, this->Image_Format, GL_UNSIGNED_BYTE, data);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, this->Wrap_S);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, this->Wrap_T);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, this->Filter_Min);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, this->Filter_Max);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture2D::bind() const
{
    glBindTexture(GL_TEXTURE_2D, this->ID);

}

渲染精灵程序

//
// Created by czh on 18-9-10.
//

#include "sprite_renderer.h"

SpriteRenderer::SpriteRenderer(Shader shader) {
    this->shader = shader;
    this->init();

}

SpriteRenderer::~SpriteRenderer() {
    glDeleteVertexArrays(1, &this->VAO);
}

void SpriteRenderer::drawSprite(Texture2D texture, glm::vec2 position, glm::vec2 size, GLfloat rotate, glm::vec3 color) {

    this->shader.use();
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(position, 0.0f));//move
    //model = glm::translate(model, glm::vec3(0.5f * size.x, 0.5f * size.y, 0.0f));
    model = glm::rotate(model, glm::radians(rotate), glm::vec3(0.0f, 0.0f, 1.0f));//rotate
    //model = glm::translate(model, glm::vec3(-0.5f * size.x, -0.5f * size.y, 0.0f));
    model = glm::scale(model, glm::vec3(size, 1.0f)); //scale

    this->shader.setMatrix4("model", model);

    this->shader.setVector3f("spriteColor", color);

    glActiveTexture(GL_TEXTURE0);
    texture.bind();

    glBindVertexArray(this->VAO);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
}

void SpriteRenderer::init() {
    GLuint VBO;
    glGenVertexArrays(1, &this->VAO);
    glBindVertexArray(this->VAO);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (GLvoid *) (0 * sizeof(float)));
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

资源管理程序

//
// Created by czh on 18-9-10.
//

#include "resource_manager.h"

std::map<std::string, Texture2D>    ResourceManager::textures;
std::map<std::string, Shader>       ResourceManager::shaders;

void ResourceManager::clear() {

}

Shader
ResourceManager::loadShader(std::string name, const GLchar *vShader, const GLchar *fShader, const GLchar *gShader) {
    Shader shader;
    shader.compile(vShader, fShader, gShader);
    shaders[name] = shader;
}

Shader ResourceManager::getShader(std::string name) {
    return shaders[name];
}

Texture2D ResourceManager::loadTexture2DFromfile(const GLchar *file, GLboolean alpha) {
    Texture2D texture;
#ifdef LOAD_TEXTURE_CV
    if (alpha) {
        texture.Internal_Format = GL_RGBA;
        texture.Image_Format = GL_BGRA;
    } else {
        texture.Internal_Format = GL_RGB;
        texture.Image_Format = GL_BGR;
    }
    cv::Mat image = cv::imread(file, CV_LOAD_IMAGE_UNCHANGED);
    texture.generate(image.size().width, image.size().height, image.data);
#else
    if (alpha) {
        texture.Internal_Format = GL_RGBA;
        texture.Image_Format = GL_RGBA;
    } else {
        texture.Internal_Format = GL_RGB;
        texture.Image_Format = GL_RGB;
    }
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(false);
    unsigned char *image = stbi_load(file, &width, &height, &nrChannels, 0);
    if (image == NULL) {
        std::cout << "loadTexture2D Error" << std::endl;
    }
    texture.generate(width, height, image);
    stbi_image_free(image);
#endif

#ifdef SML
    #ifdef LOAD_TEXTURE_CV
    std::cout << "#loadTexture2D \"" << file << "\" " << image.size().width << "*" << image.size().height;
    if (image.channels() == 4) {
        std::cout << " size:RGBA";
    } else if (image.channels() == 3) {
        std::cout << " size:RGB";
    }
    #else
    std::cout << "#loadTexture2D \"" << file << "\" " << width << "*" << height;
    if (nrChannels == 4) {
        std::cout << " size:RGBA";
    } else if (nrChannels == 3) {
        std::cout << " size:RGB";
    }
    #endif
#endif
    return texture;
}

Texture2D ResourceManager::loadTexture2D(std::string name, const GLchar *file, GLboolean alpha) {
    textures[name] = loadTexture2DFromfile(file, alpha);
#ifdef SML
    std::cout << " name:" << name << std::endl;
#endif
}

Texture2D ResourceManager::getTexture2D(std::string name) {
    return textures[name];
}

物件控制程序

//
// Created by czh on 18-9-18.
//

#include "game_object.h"

GameObject::GameObject() : position(0.0f, 0.0f), size(1.0f, 1.0f), velocity(0.0f), color(1.0f), rotation(0.0f), texture2D(),
                           isSolid(false), destroyed(false) {

}

GameObject::GameObject(glm::vec2 pos, glm::vec2 size, Texture2D texture2D, glm::vec3 color, glm::vec2 velocity)
        : position(pos), size(size), velocity(velocity), color(color), rotation(0.0f), texture2D(texture2D),
          isSolid(false), destroyed(false) {

}

void GameObject::draw(SpriteRenderer *spriteRenderer) {
    spriteRenderer->drawSprite(this->texture2D, this->position, this->size, this->rotation, this->color);
}

游戏的宏定义和配置参数。如果注释了LOAD_TEXTURE_CV这个宏,用stb_image库载入纹理,当然如果装了OpenCV的话就不需要注释,OpenCV载入纹理更快。游戏分辨率1280×480,具体可以根据自己的屏幕分辨率调整。

//
// Created by czh on 18-9-11.
//

#ifndef OPENGL_PRO_DCONFIG_H
#define OPENGL_PRO_DCONFIG_H

#include <iostream>
#include <GLES3/gl3.h>
#include <QTime>

#define SML
//#define LOAD_TEXTURE_CV
#define GL_BGR 0x80E0//opengl2.0 not support this!!
#define GL_BGRA 0x80E1

const GLuint SCREEN_WIDTH = 1280;
const GLuint SCREEN_HEIGHT = 480;


#endif //OPENGL_PRO_DCONFIG_H

小球控制程序

//
// Created by czh on 18-9-21.
//

#include "ball_object.h"

BallObject::BallObject() : GameObject(), radius(12.5f), stuck(true) {

}

BallObject::BallObject(glm::vec2 pos, GLfloat radius, glm::vec2 velocity, Texture2D sprite)
        : GameObject(pos, glm::vec2(radius * 2, radius * 2), sprite, glm::vec3(1.0f), velocity), radius(radius),
          stuck(true) {

}


glm::vec2 BallObject::move(GLfloat refreshTime, GLuint window_width) {
    if (!this->stuck)
    {
        this->position += this->velocity * refreshTime;

        if (this->position.x <= 0.0f)
        {
            this->velocity.x = -this->velocity.x;
            this->position.x = 0.0f;
        }
        else if (this->position.x + this->size.x >= window_width)
        {
            this->velocity.x = -this->velocity.x;
            this->position.x = window_width - this->size.x;
        }
        if (this->position.y <= 0.0f)
        {
            this->velocity.y = -this->velocity.y;
            this->position.y = 0.0f;
        }
    }
    return this->position;
}

void BallObject::reset(glm::vec2 position, glm::vec2 velocity) {
    this->position = position;
    this->velocity = velocity;
    this->stuck = true;
}

砖头控制程序

//
// Created by czh on 18-9-18.
//

#include "game_level.h"

GameLevel::GameLevel() {

}

void GameLevel::load(const GLchar *file, float levelWidth, float levelHeight) {

    this->bricks.clear();
    GLuint tileCode;
    std::string line;
    std::ifstream fstream(file);
    std::vector<std::vector<GLuint>> tileData;
    if (fstream) {
        while (std::getline(fstream, line)) // Read each line from level file
        {
            std::istringstream sstream(line);
            std::vector<GLuint> row;
            while (sstream >> tileCode)
                row.push_back(tileCode);
            tileData.push_back(row);
        }
        if (tileData.size() > 0)
            this->init(tileData, levelWidth, levelHeight);
    }
}

void GameLevel::draw(SpriteRenderer *spriteRenderer) {
    for (auto &gameObject : this->bricks) {
        if (!gameObject.destroyed) {
            gameObject.draw(spriteRenderer);
        }
    }
}

GLboolean GameLevel::isCompleted() {
    for (GameObject &tile : this->bricks)
        if (!tile.isSolid && !tile.destroyed)
            return GL_FALSE;
    return GL_TRUE;
}

void GameLevel::init(std::vector<std::vector<GLuint>> tileData, float levelWidth, float levelHeight) {
    GLuint height = tileData.size();
    GLuint width = tileData[0].size();
    GLfloat block_width = levelWidth / (float)width;
    GLfloat block_height = levelHeight / (float)height;

    for (GLuint y = 0; y < height; ++y) {
        for (GLuint x = 0; x < width; ++x) {
            if (tileData[y][x] == 1)        //Solid
            {
                glm::vec2 pos(block_width * x, block_height * y);
                glm::vec2 size(block_width, block_height);
                GameObject gameObject(pos, size, ResourceManager::getTexture2D("block_solid"), glm::vec3(0.8f, 0.8f, 0.7f));
                gameObject.isSolid = GL_TRUE;
                this->bricks.push_back(gameObject);
            } else if (tileData[y][x] > 1)  //Non-solid
            {
                glm::vec3 color = glm::vec3(1.0f);
                if (tileData[y][x] == 2)
                    color = glm::vec3(0.2f, 0.6f, 1.0f);//blue
                else if (tileData[y][x] == 3)
                    color = glm::vec3(0.0f, 0.7f, 0.0f);//green
                else if (tileData[y][x] == 4)
                    color = glm::vec3(0.8f, 0.8f, 0.4f);//yellow
                else if (tileData[y][x] == 5)
                    color = glm::vec3(1.0f, 0.5f, 0.0f);//orange

                glm::vec2 pos(block_width * x, block_height * y);
                glm::vec2 size(block_width, block_height);
                this->bricks.push_back(GameObject(pos, size, ResourceManager::getTexture2D("block"), color));
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/czhzasui/article/details/83001265