商城网站 前置审批,做网站连带责任,比如做百度知道 .html,这些都是我们不可控制的网站!,蔡甸网站建设文章目录 特殊效果数据结构生成逻辑更新逻辑 文本渲染类结构构造函数加载函数渲染函数 特殊效果
为提高游戏的趣味性#xff0c;在游戏中提供了六种特殊效果。
数据结构
PowerUp
类只存储存活数据#xff0c;实际逻辑在游戏代码中通过Type字段来区分执行
class PowerUp … 文章目录 特殊效果数据结构生成逻辑更新逻辑 文本渲染类结构构造函数加载函数渲染函数 特殊效果
为提高游戏的趣味性在游戏中提供了六种特殊效果。
数据结构
PowerUp
类只存储存活数据实际逻辑在游戏代码中通过Type字段来区分执行
class PowerUp : public GameObject
{
public:// powerup statestd::string Type;float Duration;bool Activated;// constructorPowerUp(std::string type, glm::vec3 color, float duration, glm::vec2 position, Texture2D texture): GameObject(position, POWERUP_SIZE, texture, color, VELOCITY), Type(type), Duration(duration), Activated() { }
};Game中存在容器存储目前存活的PowerUp对象
std::vectorPowerUp PowerUps;生成逻辑
当玩家消灭一个方块后按固定概率随机生成或不生成一个随机能力的砖块。
//Game::DoCollision()// destroy block if not solid
if (!box.IsSolid)
{box.Destroyed true;this-SpawnPowerUps(box);
}生成策略
bool ShouldSpawn(unsigned int chance)
{unsigned int random rand() % chance;return random 0;
}
void Game::SpawnPowerUps(GameObject block)
{if (ShouldSpawn(75)) // 1 in 75 chancethis-PowerUps.push_back(PowerUp(speed, glm::vec3(0.5f, 0.5f, 1.0f), 0.0f, block.Position, ResourceManager::GetTexture(powerup_speed)));if (ShouldSpawn(75))this-PowerUps.push_back(PowerUp(sticky, glm::vec3(1.0f, 0.5f, 1.0f), 20.0f, block.Position, ResourceManager::GetTexture(powerup_sticky)));if (ShouldSpawn(75))this-PowerUps.push_back(PowerUp(pass-through, glm::vec3(0.5f, 1.0f, 0.5f), 10.0f, block.Position, ResourceManager::GetTexture(powerup_passthrough)));if (ShouldSpawn(75))this-PowerUps.push_back(PowerUp(pad-size-increase, glm::vec3(1.0f, 0.6f, 0.4), 0.0f, block.Position, ResourceManager::GetTexture(powerup_increase)));if (ShouldSpawn(15)) // Negative powerups should spawn more oftenthis-PowerUps.push_back(PowerUp(confuse, glm::vec3(1.0f, 0.3f, 0.3f), 15.0f, block.Position, ResourceManager::GetTexture(powerup_confuse)));if (ShouldSpawn(15))this-PowerUps.push_back(PowerUp(chaos, glm::vec3(0.9f, 0.25f, 0.25f), 15.0f, block.Position, ResourceManager::GetTexture(powerup_chaos)));
}更新逻辑
生成完后会在Update中调用以下函数下落更新并每帧检查是否与玩家发生碰撞
不同状态下能力内部标志位变化
DestoryedActivated下落状态falsefalse与玩家碰撞后truetrue倒计时结束后truefalse
Destroyed决定是否要渲染其图像Activated决定是否要启用其计时器最后的状态则决定了是否要将其移除出列表
刚碰撞时根据Type字段执行附加能力的逻辑倒计时结束后执行取消附加能力的逻辑。流程完毕后移除出数组
//绘制
for (PowerUp powerUp : this-PowerUps)if (!powerUp.Destroyed)powerUp.Draw(*Renderer);//检查碰撞
for (PowerUp powerUp : this-PowerUps)
{if (!powerUp.Destroyed){if (powerUp.Position.y this-Height)powerUp.Destroyed true;if (CheckCollision(*Player, powerUp)){ // collided with player, now activate powerupActivatePowerUp(powerUp);powerUp.Destroyed true;powerUp.Activated true;}}
}//启用能力
void ActivatePowerUp(PowerUp powerUp)
{if (powerUp.Type speed){Ball-Velocity * 1.2;}else if (powerUp.Type sticky){Ball-Sticky true;Player-Color glm::vec3(1.0f, 0.5f, 1.0f);}else if (powerUp.Type pass-through){Ball-PassThrough true;Ball-Color glm::vec3(1.0f, 0.5f, 0.5f);}else if (powerUp.Type pad-size-increase){Player-Size.x 50;}else if (powerUp.Type confuse){if (!Effects-Chaos)Effects-Confuse true; // only activate if chaos wasnt already active}else if (powerUp.Type chaos){if (!Effects-Confuse)Effects-Chaos true;}
}//每帧更新轮询何时撤销能力
void Game::UpdatePowerUps(float dt)
{for (PowerUp powerUp : this-PowerUps){powerUp.Position powerUp.Velocity * dt;if (powerUp.Activated){powerUp.Duration - dt;if (powerUp.Duration 0.0f){// remove powerup from list (will later be removed)powerUp.Activated false;// deactivate effectsif (powerUp.Type sticky){if (!IsOtherPowerUpActive(this-PowerUps, sticky)){ // only reset if no other PowerUp of type sticky is activeBall-Sticky false;Player-Color glm::vec3(1.0f);}}else if (powerUp.Type pass-through){if (!IsOtherPowerUpActive(this-PowerUps, pass-through)){ // only reset if no other PowerUp of type pass-through is activeBall-PassThrough false;Ball-Color glm::vec3(1.0f);}}else if (powerUp.Type confuse){if (!IsOtherPowerUpActive(this-PowerUps, confuse)){ // only reset if no other PowerUp of type confuse is activeEffects-Confuse false;}}else if (powerUp.Type chaos){if (!IsOtherPowerUpActive(this-PowerUps, chaos)){ // only reset if no other PowerUp of type chaos is activeEffects-Chaos false;}}}}}// Remove all PowerUps from vector that are destroyed AND !activated (thus either off the map or finished)// Note we use a lambda expression to remove each PowerUp which is destroyed and not activatedthis-PowerUps.erase(std::remove_if(this-PowerUps.begin(), this-PowerUps.end(),[](const PowerUp powerUp) { return powerUp.Destroyed !powerUp.Activated; }), this-PowerUps.end());
}
文本渲染
文本渲染部分依赖于一个库FreeType在项目中只拿来读取ttf生成像素数据然后记录在自定义的Character结构中。
// 宽度、高度、左上角偏移、水平距离
struct Character
{unsigned int TextureID;glm::ivec2 Size;glm::ivec2 Bearing;unsigned int Advance;
};创建文字渲染器类TextRenderer来负责文字的渲染
类结构
class TextRenderer
{
public:// 预处理记录的需要的字符内容借助FreeTypestd::mapchar, Character Characters;// 文字渲染Shader就是渲染一个四边形然后采样纹理并渲染上去Shader TextShader;TextRenderer(unsigned int width, unsigned int height);void Load(std::string font, unsigned int fontSize);void RenderText(std::string text, float x, float y, float scale, glm::vec3 color glm::vec3(1.0f));private:unsigned int VAO, VBO;
};构造函数
构造函数中负责初始化shader参数初始化VAO和VBO但VBO的具体顶点数据会在绘制时动态计算出来
TextRenderer::TextRenderer(unsigned int width, unsigned int height)
{// load and configure shaderthis-TextShader ResourceManager::LoadShader(res/shaders/text.vs, res/shaders/text.frag, nullptr, text);this-TextShader.SetMatrix4(projection, glm::ortho(0.0f, static_castfloat(width), static_castfloat(height), 0.0f), true);this-TextShader.SetInteger(text, 0);// configure VAO/VBO for texture quadsglGenVertexArrays(1, this-VAO);glGenBuffers(1, this-VBO);//绑定VAOVBOglBindVertexArray(this-VAO);glBindBuffer(GL_ARRAY_BUFFER, this-VBO);//填充VBO数据glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);//规划VBO数据布局glEnableVertexAttribArray(0);glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);//解绑glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);
}加载函数
外部提供字体文件.ttf路径和字体大小内部利用FreeType将前128字符转换为使用Characters存储
void TextRenderer::Load(std::string font, unsigned int fontSize)
{// 如果之前已经Load过清除this-Characters.clear();// 初始化并加载 FreeType libraryFT_Library ft;if (FT_Init_FreeType(ft))std::cout ERROR::FREETYPE: Could not init FreeType Library std::endl;// 将字符加载为faceFT_Face face;if (FT_New_Face(ft, font.c_str(), 0, face))std::cout ERROR::FREETYPE: Failed to load font std::endl;// 设置加载字体的大小这里是设置为 fontSize 参数指定的大小。第一个参数为 0表示不限制宽度第二个参数是目标字体大小FT_Set_Pixel_Sizes(face, 0, fontSize);// 关闭了 OpenGL 中的字节对齐限制使得字节数据可以按 1 字节对齐这样可以避免在纹理生成时出现内存填充问题glPixelStorei(GL_UNPACK_ALIGNMENT, 1);// 通过循环加载前 128 个 ASCII 字符。for (GLubyte c 0; c 128; c){// FT_Load_Char 用来加载字符的字形信息如果加载失败则输出错误信息并跳过该字符if (FT_Load_Char(face, c, FT_LOAD_RENDER)){std::cout ERROR::FREETYTPE: Failed to load Glyph std::endl;continue;}// 为每个字符生成一个纹理unsigned int texture;glGenTextures(1, texture);glBindTexture(GL_TEXTURE_2D, texture);//使用 GL_RED 格式来存储单通道的灰度数据glTexImage2D(GL_TEXTURE_2D,0,GL_RED,face-glyph-bitmap.width,face-glyph-bitmap.rows,0,GL_RED,GL_UNSIGNED_BYTE,face-glyph-bitmap.buffer);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//将原始数据转换为Character数组Character character {texture,glm::ivec2(face-glyph-bitmap.width, face-glyph-bitmap.rows),glm::ivec2(face-glyph-bitmap_left, face-glyph-bitmap_top),face-glyph-advance.x};Characters.insert(std::pairchar, Character(c, character));}// 清理资源glBindTexture(GL_TEXTURE_2D, 0);FT_Done_Face(face);FT_Done_FreeType(ft);
}渲染函数
使用并设置文字shader使用当前的VAO遍历所有提供的字符在Characters中取出对应的数据计算位置长宽更新顶点缓存绑定记录的纹理绘制完后偏移光标位置
void TextRenderer::RenderText(std::string text, float x, float y, float scale, glm::vec3 color)
{// activate corresponding render state this-TextShader.Use();this-TextShader.SetVector3f(textColor, color);glActiveTexture(GL_TEXTURE0);glBindVertexArray(this-VAO);// iterate through all charactersstd::string::const_iterator c;for (c text.begin(); c ! text.end(); c){Character ch Characters[*c];// 计算位置和长宽float xpos x ch.Bearing.x * scale;float ypos y (this-Characters[H].Bearing.y - ch.Bearing.y) * scale;float w ch.Size.x * scale;float h ch.Size.y * scale;// 为每个字符更新对应的VBO缓存float vertices[6][4] {{ xpos, ypos h, 0.0f, 1.0f },{ xpos w, ypos, 1.0f, 0.0f },{ xpos, ypos, 0.0f, 0.0f },{ xpos, ypos h, 0.0f, 1.0f },{ xpos w, ypos h, 1.0f, 1.0f },{ xpos w, ypos, 1.0f, 0.0f }};// 绑定指定的纹理glBindTexture(GL_TEXTURE_2D, ch.TextureID);// update content of VBO memoryglBindBuffer(GL_ARRAY_BUFFER, this-VBO);glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);glBindBuffer(GL_ARRAY_BUFFER, 0);// render quadglDrawArrays(GL_TRIANGLES, 0, 6);// 更新光标位置x (ch.Advance 6) * scale; // bitshift by 6 to get value in pixels (1/64th times 2^6 64)}glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);
}