OpenGL 圖形庫的使用(五十一)—— 實戰(zhàn)之2D游戲 - 碰撞 球Ball

版本記錄

版本號 時間
V1.0 2018.01.20

前言

OpenGL 圖形庫項目中一直也沒用過惠呼,最近也想學(xué)著使用這個圖形庫漱贱,感覺還是很有意思妇垢,也就自然想著好好的總結(jié)一下易迹,希望對大家能有所幫助宰衙。下面內(nèi)容來自歡迎來到OpenGL的世界
1. OpenGL 圖形庫使用(一) —— 概念基礎(chǔ)
2. OpenGL 圖形庫使用(二) —— 渲染模式睹欲、對象菩浙、擴展和狀態(tài)機
3. OpenGL 圖形庫使用(三) —— 著色器、數(shù)據(jù)類型與輸入輸出
4. OpenGL 圖形庫使用(四) —— Uniform及更多屬性
5. OpenGL 圖形庫使用(五) —— 紋理
6. OpenGL 圖形庫使用(六) —— 變換
7. OpenGL 圖形庫的使用(七)—— 坐標(biāo)系統(tǒng)之五種不同的坐標(biāo)系統(tǒng)(一)
8. OpenGL 圖形庫的使用(八)—— 坐標(biāo)系統(tǒng)之3D效果(二)
9. OpenGL 圖形庫的使用(九)—— 攝像機(一)
10. OpenGL 圖形庫的使用(十)—— 攝像機(二)
11. OpenGL 圖形庫的使用(十一)—— 光照之顏色
12. OpenGL 圖形庫的使用(十二)—— 光照之基礎(chǔ)光照
13. OpenGL 圖形庫的使用(十三)—— 光照之材質(zhì)
14. OpenGL 圖形庫的使用(十四)—— 光照之光照貼圖
15. OpenGL 圖形庫的使用(十五)—— 光照之投光物
16. OpenGL 圖形庫的使用(十六)—— 光照之多光源
17. OpenGL 圖形庫的使用(十七)—— 光照之復(fù)習(xí)總結(jié)
18. OpenGL 圖形庫的使用(十八)—— 模型加載之Assimp
19. OpenGL 圖形庫的使用(十九)—— 模型加載之網(wǎng)格
20. OpenGL 圖形庫的使用(二十)—— 模型加載之模型
21. OpenGL 圖形庫的使用(二十一)—— 高級OpenGL之深度測試
22. OpenGL 圖形庫的使用(二十二)—— 高級OpenGL之模板測試Stencil testing
23. OpenGL 圖形庫的使用(二十三)—— 高級OpenGL之混合Blending
24. OpenGL 圖形庫的使用(二十四)—— 高級OpenGL之面剔除Face culling
25. OpenGL 圖形庫的使用(二十五)—— 高級OpenGL之幀緩沖Framebuffers
26. OpenGL 圖形庫的使用(二十六)—— 高級OpenGL之立方體貼圖Cubemaps
27. OpenGL 圖形庫的使用(二十七)—— 高級OpenGL之高級數(shù)據(jù)Advanced Data
28. OpenGL 圖形庫的使用(二十八)—— 高級OpenGL之高級GLSL Advanced GLSL
29. OpenGL 圖形庫的使用(二十九)—— 高級OpenGL之幾何著色器Geometry Shader
30. OpenGL 圖形庫的使用(三十)—— 高級OpenGL之實例化Instancing
31. OpenGL 圖形庫的使用(三十一)—— 高級OpenGL之抗鋸齒Anti Aliasing
32. OpenGL 圖形庫的使用(三十二)—— 高級光照之高級光照Advanced Lighting
33. OpenGL 圖形庫的使用(三十三)—— 高級光照之Gamma校正Gamma Correction
34. OpenGL 圖形庫的使用(三十四)—— 高級光照之陰影 - 陰影映射Shadow Mapping
35. OpenGL 圖形庫的使用(三十五)—— 高級光照之陰影 - 點陰影Point Shadows
36. OpenGL 圖形庫的使用(三十六)—— 高級光照之法線貼圖Normal Mapping
37. OpenGL 圖形庫的使用(三十七)—— 高級光照之視差貼圖Parallax Mapping
38. OpenGL 圖形庫的使用(三十八)—— 高級光照之HDR
39. OpenGL 圖形庫的使用(三十九)—— 高級光照之泛光
40. OpenGL 圖形庫的使用(四十)—— 高級光照之延遲著色法Deferred Shading
41. OpenGL 圖形庫的使用(四十一)—— 高級光照之SSAO
42. OpenGL 圖形庫的使用(四十二)—— PBR之理論Theory
43. OpenGL 圖形庫的使用(四十三)—— PBR之光照Lighting
44. OpenGL 圖形庫的使用(四十四)—— PBR之幾篇沒有翻譯的英文原稿
45. OpenGL 圖形庫的使用(四十五)—— 實戰(zhàn)之調(diào)試Debugging
46. OpenGL 圖形庫的使用(四十六)—— 實戰(zhàn)之文本渲染Text Rendering
47. OpenGL 圖形庫的使用(四十七)—— 實戰(zhàn)之2D游戲 - Breakout
48. OpenGL 圖形庫的使用(四十八)—— 實戰(zhàn)之2D游戲 - 準(zhǔn)備工作
49. OpenGL 圖形庫的使用(四十九)—— 實戰(zhàn)之2D游戲 - 渲染精靈
50. OpenGL 圖形庫的使用(五十)—— 實戰(zhàn)之2D游戲 - 關(guān)卡

此時我們已經(jīng)有了一個包含有很多磚塊和玩家的一個擋板的關(guān)卡句伶。與經(jīng)典的Breakout內(nèi)容相比還差一個球劲蜻。游戲的目的是讓球撞擊所有的磚塊,直到所有的可銷毀磚塊都被銷毀考余,但同時也要滿足條件:球不能碰觸屏幕的下邊緣先嬉。

除了通用的游戲?qū)ο蠼M件,球還需要有半徑和一個布爾值楚堤,該布爾值用于指示球被固定(stuck)在玩家擋板上還是被允許自由運動的狀態(tài)疫蔓。當(dāng)游戲開始時含懊,球被初始固定在玩家擋板上,直到玩家按下任意鍵開始游戲衅胀。

由于球只是一個附帶了一些額外屬性的GameObject岔乔,所以按照常規(guī)需要創(chuàng)建BallObject類作為GameObject的子類。

class BallObject : public GameObject
{
    public:
        // 球的狀態(tài) 
        GLfloat   Radius;
        GLboolean Stuck;


        BallObject();
        BallObject(glm::vec2 pos, GLfloat radius, glm::vec2 velocity, Texture2D sprite);

        glm::vec2 Move(GLfloat dt, GLuint window_width);
        void      Reset(glm::vec2 position, glm::vec2 velocity);
}; 

BallObject的構(gòu)造函數(shù)不但初始化了其自身的值滚躯,而且實際上也潛在地初始化了GameObject雏门。BallObject類擁有一個Move函數(shù),該函數(shù)用于根據(jù)球的速度來移動球掸掏,并檢查它是否碰到了場景的任何邊界茁影,如果碰到的話就會反轉(zhuǎn)球的速度:

glm::vec2 BallObject::Move(GLfloat dt, GLuint window_width)
{
    // 如果沒有被固定在擋板上
    if (!this->Stuck)
    { 
        // 移動球
        this->Position += this->Velocity * dt;
        // 檢查是否在窗口邊界以外,如果是的話反轉(zhuǎn)速度并恢復(fù)到正確的位置
        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;
}  

除了反轉(zhuǎn)球的速度之外丧凤,我們還需要把球沿著邊界重新放置回來募闲。只有在沒有被固定時球才能夠移動。

因為如果球碰觸到底部邊界時玩家會結(jié)束游戲(或失去一條命)愿待,所以在底部邊界沒有代碼來控制球反彈浩螺。我們稍后需要在代碼中某些地方實現(xiàn)這一邏輯。

你可以在下邊看到BallObject的代碼:

/******************************************************************
** This code is part of Breakout.
**
** Breakout is free software: you can redistribute it and/or modify
** it under the terms of the CC BY 4.0 license as published by
** Creative Commons, either version 4 of the License, or (at your
** option) any later version.
******************************************************************/
#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 dt, GLuint window_width)
{
    // If not stuck to player board
    if (!this->Stuck)
    {
        // Move the ball
        this->Position += this->Velocity * dt;
        // Then check if outside window bounds and if so, reverse velocity and restore at correct position
        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;
}

// Resets the ball to initial Stuck Position (if ball is outside window bounds)
void BallObject::Reset(glm::vec2 position, glm::vec2 velocity)
{
    this->Position = position;
    this->Velocity = velocity;
    this->Stuck = true;
}

首先我們在游戲中添加球仍侥。與玩家擋板相似年扩,我們創(chuàng)建一個球?qū)ο蟛⑶叶x兩個用來初始化球的常量。對于球的紋理访圃,我們會使用在LearnOpenGL Breakout游戲中完美適用的一張圖片:球紋理

// 初始化球的速度
const glm::vec2 INITIAL_BALL_VELOCITY(100.0f, -350.0f);
// 球的半徑
const GLfloat BALL_RADIUS = 12.5f;

BallObject     *Ball; 

void Game::Init()
{
    [...]
    glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2);
    Ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY,
        ResourceManager::GetTexture("face"));
}

然后我們在每幀中調(diào)用游戲代碼中Update函數(shù)里的Move函數(shù)來更新球的位置:

void Game::Update(GLfloat dt)
{
    Ball->Move(dt, this->Width);
}  

除此之外相嵌,由于球初始是固定在擋板上的腿时,我們必須讓玩家能夠從固定的位置重新移動它。我們選擇使用空格鍵來從擋板釋放球饭宾。這意味著我們必須稍微修改ProcessInput函數(shù):

void Game::ProcessInput(GLfloat dt)
{
    if (this->State == GAME_ACTIVE)
    {
        GLfloat velocity = PLAYER_VELOCITY * dt;
        // 移動玩家擋板
        if (this->Keys[GLFW_KEY_A])
        {
            if (Player->Position.x >= 0)
            {
                Player->Position.x -= velocity;
                if (Ball->Stuck)
                    Ball->Position.x -= velocity;
            }
        }
        if (this->Keys[GLFW_KEY_D])
        {
            if (Player->Position.x <= this->Width - Player->Size.x)
            {
                Player->Position.x += velocity;
                if (Ball->Stuck)
                    Ball->Position.x += velocity;
            }
        }
        if (this->Keys[GLFW_KEY_SPACE])
            Ball->Stuck = false;
    }
}

現(xiàn)在如果玩家按下了空格鍵批糟,球的Stuck值會設(shè)置為false。我們還需要更新ProcessInput函數(shù)看铆,當(dāng)球被固定的時候徽鼎,會跟隨擋板的位置來移動球。

最后我們需要渲染球弹惦,此時這應(yīng)該很顯而易見了:

void Game::Render()
{
    if (this->State == GAME_ACTIVE)
    {
        [...]
        Ball->Draw(*Renderer);
    }
}  

結(jié)果就是球會跟隨著擋板否淤,并且當(dāng)我們按下空格鍵時球開始自由運動。球會在左側(cè)棠隐、右側(cè)和頂部邊界合理地反彈石抡,但看起來不會撞擊任何的磚塊,就像我們可以在下邊的視頻中看到的那樣:

我們要做的就是創(chuàng)建一個或多個函數(shù)用于檢查球?qū)ο笫欠褡矒絷P(guān)卡中的任何磚塊助泽,如果撞擊的話就銷毀磚塊啰扛。這些所謂的碰撞檢測(collision detection)功能將是我們下一個教程的重點嚎京。

后記

本篇已結(jié)束,后面更精彩~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隐解,一起剝皮案震驚了整個濱河市鞍帝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌煞茫,老刑警劉巖帕涌,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異溜嗜,居然都是意外死亡宵膨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門炸宵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辟躏,“玉大人,你說我怎么就攤上這事土全∩铀觯” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵裹匙,是天一觀的道長瑞凑。 經(jīng)常有香客問我,道長概页,這世上最難降的妖魔是什么籽御? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮惰匙,結(jié)果婚禮上技掏,老公的妹妹穿的比我還像新娘。我一直安慰自己项鬼,他們只是感情好哑梳,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绘盟,像睡著了一般鸠真。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上龄毡,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天吠卷,我揣著相機與錄音,去河邊找鬼沦零。 笑死撤嫩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蠢终。 我是一名探鬼主播序攘,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茴她,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了程奠?” 一聲冷哼從身側(cè)響起丈牢,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞄沙,沒想到半個月后己沛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡距境,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年申尼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垫桂。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡师幕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诬滩,到底是詐尸還是另有隱情霹粥,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布疼鸟,位于F島的核電站后控,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏空镜。R本人自食惡果不足惜浩淘,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吴攒。 院中可真熱鬧张抄,春花似錦、人聲如沸舶斧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茴厉。三九已至,卻和暖如春什荣,著一層夾襖步出監(jiān)牢的瞬間矾缓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工稻爬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嗜闻,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓桅锄,卻偏偏與公主長得像琉雳,于是被迫代替她去往敵國和親样眠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容