NXP

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

2019-07-12 14:01发布

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)); } } } }