首先需要确认游戏机制:
1.一个不能上下移动的挡板,只能左右移动
2.一个球在屏幕上运动,每次碰撞会使球根据碰撞位置改变运动方向
3.球运动到屏幕底部,则游戏结束
4.当所有方块被破坏,游戏胜利
其次,需要先定义一个超级游戏类:包含所有相关的渲染和代码。
作用是:管理游戏代码,将窗口代码和游戏进行解耦。这样就可以把相同的类迁移到不同的窗口库
封装一个初始化函数,一个更新函数,一个处理输入函数,一个渲染函数:
class Game
{
public:
// 游戏状态
GameState State;
GLboolean Keys[1024];
GLuint Width, Height;
// 构造函数/析构函数
Game(GLuint width, GLuint height);
~Game();
// 初始化游戏状态(加载所有的着色器/纹理/关卡)
void Init();
// 游戏循环
void ProcessInput(GLfloat dt);
void Update(GLfloat dt);
void Render();
};
该类包含了所有在一个游戏类中会出现的东西。
给定一个宽度和高度来初始化这个游戏,并使用Init函数加载着色器,纹理,并初始化所有的游戏状态。
可以通过调用ProcessInput函数,使用存储在Keys数组中的数据来处理输入。
在Update函数中更新游戏设置状态,举例:挡板和球的移动。
可以调用Render函数,对游戏进行渲染。当然,运动逻辑和渲染逻辑分别在Update和Render函数中体现
其中,GameState是一个枚举类:
// 代表了游戏的当前状态
enum GameState {
GAME_ACTIVE,
GAME_MENU,
GAME_WIN
};
用于跟踪游戏的状态,可以根据当前游戏的状态来决定渲染,或处理不同的元素。
Game类的头文件如下:
#ifndef GAME_H
#define GAME_H
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// Represents the current state of the game
enum GameState {
GAME_ACTIVE,
GAME_MENU,
GAME_WIN
};
// Game holds all game-related state and functionality.
// Combines all game-related data into a single class for
// easy access to each of the components and manageability.
class Game
{
public:
// Game state
GameState State;
GLboolean Keys[1024];
GLuint Width, Height;
// Constructor/Destructor
Game(GLuint width, GLuint height);
~Game();
// Initialize game state (load all shaders/textures/levels)
void Init();
// GameLoop
void ProcessInput(GLfloat dt);
void Update(GLfloat dt);
void Render();
};
#endif
代码文件如下:
#include "game.h"
#include "resource_manager.h"
Game::Game(GLuint width, GLuint height)
: State(GAME_ACTIVE), Keys(), Width(width), Height(height)
{
}
Game::~Game()
{
}
void Game::Init()
{
}
void Game::Update(GLfloat dt)
{
}
void Game::ProcessInput(GLfloat dt)
{
}
void Game::Render()
{
}
补充:当前代码文件是空的,因为处理逻辑还没有加进去
着色器和纹理最好也分别创建一个类:着色器类可能会接受2-3个字符串,并生成一个编译好的活色器,着色器类中包含很多工具,可以快速设置uniform值
纹理类会接受一个字节数组,宽度和高度,并生成一个2D纹理图像。
则,着色器的头文件如下:
#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
// General purpsoe shader object. Compiles from file, generates
// compile/link-time error messages and hosts several utility
// functions for easy management.
class Shader
{
public:
// State
GLuint ID;
// Constructor
Shader() { }
// Sets the current shader as active
Shader &Use();
// Compiles the shader from given source code
void Compile(const GLchar *vertexSource, const GLchar *fragmentSource, const GLchar *geometrySource = nullptr); // Note: geometry source code is optional
// Utility functions
void SetFloat (const GLchar *name, GLfloat value, GLboolean useShader = false);
void SetInteger (const GLchar *name, GLint value, GLboolean useShader = false);
void SetVector2f (const GLchar *name, GLfloat x, GLfloat y, GLboolean useShader = false);
void SetVector2f (const GLchar *name, const glm::vec2 &value, GLboolean useShader = false);
void SetVector3f (const GLchar *name, GLfloat x, GLfloat y, GLfloat z, GLboolean useShader = false);
void SetVector3f (const GLchar *name, const glm::vec3 &value, GLboolean useShader = false);
void SetVector4f (const GLchar *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLboolean useShader = false);
void SetVector4f (const GLchar *name, const glm::vec4 &value, GLboolean useShader = false);
void SetMatrix4 (const GLchar *name, const glm::mat4 &matrix, GLboolean useShader = false);
private:
// Checks if compilation or linking failed and if so, print the error logs
void checkCompileErrors(GLuint object, std::string type);
};
#endif
着色器的代码如下:
#include "shader.h"
#include <iostream>
Shader &Shader::Use()
{
glUseProgram(this->ID);
return *this;
}
void Shader::Compile(const GLchar* vertexSource, const GLchar* fragmentSource, const GLchar* geometrySource)
{
GLuint sVertex, sFragment, gShader;
// Vertex Shader
sVertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(sVertex, 1, &vertexSource, NULL);
glCompileShader(sVertex);
checkCompileErrors(sVertex, "VERTEX");
// Fragment Shader
sFragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(sFragment, 1, &fragmentSource, NULL);
glCompileShader(sFragment);
checkCompileErrors(sFragment, "FRAGMENT");
// If geometry shader source code is given, also compile geometry shader
if (geometrySource != nullptr)
{
gShader = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(gShader, 1, &geometrySource, NULL);
glCompileShader(gShader);
checkCompileErrors(gShader, "GEOMETRY");
}
// Shader Program
this->ID = glCreateProgram();
glAttachShader(this->ID, sVertex);
glAttachShader(this->ID, sFragment);
if (geometrySource != nullptr)
glAttachShader(this->ID, gShader);
glLinkProgram(this->ID);
checkCompileErrors(this->ID, "PROGRAM");
// Delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(sVertex);
glDeleteShader(sFragment);
if (geometrySource != nullptr)
glDeleteShader(gShader);
}
void Shader::SetFloat(

本文介绍了如何构建一个2D游戏,包括一个只能左右移动的挡板、反弹的球、游戏结束条件和胜利条件。文章详细阐述了游戏类的设计,包括初始化、处理输入、更新和渲染功能。同时,提到了使用枚举跟踪游戏状态,并讨论了着色器和纹理类的创建,以及静态资源管理器的实现。此外,还讲解了2D游戏中的投影矩阵和精灵渲染,包括顶点着色器和片段着色器的设定,以及渲染精灵的步骤。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



