第四十一章 2D游戏(1)

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

首先需要确认游戏机制:
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(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值