class="markdown_views prism-github-gist">
最近一直在研究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
");
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中存放的是顶点着 {MOD}器代码(GLSL语言),defaultFshaderStr存放片断着 {MOD}器代码。
//
// Created by czh on 18-9-18.
//
#ifndef OPENGL_ES_GAME_H
#define OPENGL_ES_GAME_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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 Collision;
class Game {
public:
GameState state;
float width, height;
std::vector 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
"
"layout (location = 0) in vec4 vertex;
"
"out vec2 TexCoords;
"
"uniform mat4 model;
"
"uniform mat4 projection;
"
"uniform vec4 location;
"
"void main()
"
"{
"
" TexCoords.x = vertex.z * location.x + location.z;
"
" TexCoords.y = vertex.w * location.y + location.w;
"
" gl_Position = projection * model * vec4(vertex.xy, 0.0f, 1.0f);
"
"}
";
const char *defaultFshaderStr =
"#version 300 es
"
"precision mediump float;
"
"in vec2 TexCoords;
"
"out vec4 color;
"
"uniform sampler2D image;
"
"uniform vec3 spriteColor;
"
"void main()
"
"{
"
" color = vec4(spriteColor, 1.0) * texture(image, TexCoords);
"
"}
";
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(this->width), static_cast(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));
}
着 {MOD}器程序
//
// 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 << "
"
<< infoLog << "
-- ----------------------------------------------------- "
<< 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 << "
"
<< infoLog << "
-- ----------------------------------------------------- "
<< 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 ResourceManager::textures;
std::map 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
#include
#include
#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> tileData;
if (fstream) {
while (std::getline(fstream, line)) // Read each line from level file
{
std::istringstream sstream(line);
std::vector 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> 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));
}
}
}
}