
上一篇中,我們的主戰(zhàn)坦克發(fā)出的炮彈還沒有實際的作用,今天我們就讓它擁有擊毀敵軍坦克的功能。
新增基礎API
Rect類
在Rect類中,我們添加下面兩個新接口。
Point GetTRPoint() const; // Get Top Right Point
Point GetBLPoint() const; // Get Bottom Left Point
這兩個函數(shù)的作用是返回矩形右上角和左下角的兩個點。這樣方便我們在計算炮彈是否擊中坦克時使用。
實現(xiàn)如下:
Point Rect::GetTRPoint() const
{
Point p = m_startPoint;
p.SetX(m_endPoint.GetX());
return p;
}
Point Rect::GetBLPoint() const
{
Point p = m_startPoint;
p.SetY(m_endPoint.GetY());
return p;
}
Object類
在判斷炮彈是否擊中坦克時,我們需要通過勢力范圍m_rectSphere這個屬性。我們?yōu)镺bject類中添加下面這個虛函數(shù)函數(shù):
virtual Rect GetSphere() = 0;
在所有的繼承類中,都要對這個函數(shù)進行實現(xiàn),實現(xiàn)方法很簡單就是返回m_rectSphere屬性即可。
Rect GetSphere()
{
return m_rectSphere;
}
Tank類
在坦克類中,我們需要添加一個設置坦克消失的接口,當坦克被擊中時,我們通過這個接口把m_bDisappear屬性設為true。
void SetDisappear()
{
m_bDisappear = true;
}
位置判斷
在游戲設計中,有個概念叫做“碰撞檢測”,用來判斷兩個元素是否碰在一起。比如我們的坦克大戰(zhàn)中,如何判斷炮彈是否擊中了坦克。另外,一些格斗類游戲中,人物出拳或踢腿是否擊中目標都需要有相應的算法來判斷。
網上有一些開源的庫可以幫助我們完成一些復雜形狀間的碰撞檢測。在這里,我們把炮彈和坦克之間的碰撞檢測簡化為兩個形狀勢力范圍是否重疊的判斷。也就是判斷兩個矩形是否重疊。
我們創(chuàng)建一個目錄Utils來存放一些功能性的代碼,里面先創(chuàng)建下面一組文件。
Shape.h
#ifndef __SHAPE_H__
#define __SHAPE_H__
#include "../Model/Rect.h"
class Shape
{
public:
static bool CheckPointInRect(Point& point, Rect& rect);
static bool CheckIntersect(Rect& rectA, Rect& rectB);
};
#endif
Shape是一個靜態(tài)類,里面有兩個靜態(tài)成員函數(shù)。
CheckPointInRect函數(shù)負責判斷一個點是否在一個矩形的范圍內。CheckInterSect函數(shù)負責判斷兩個矩形是否重合。
Shape.cpp
#include "Shape.h"
bool Shape::CheckPointInRect(Point& point, Rect& rect)
{
if (point.GetX() < rect.GetStartPoint().GetX() || point.GetX() > rect.GetEndPoint().GetX() ||
point.GetY() < rect.GetStartPoint().GetY() || point.GetY() > rect.GetEndPoint().GetY())
{
return false;
}
else
{
return true;
}
}
bool Shape::CheckIntersect(Rect& rectA, Rect& rectB)
{
if (CheckPointInRect(rectA.GetStartPoint(), rectB) ||
CheckPointInRect(rectA.GetEndPoint(), rectB) ||
CheckPointInRect(rectA.GetTRPoint(), rectB) ||
CheckPointInRect(rectA.GetBLPoint(), rectB))
{
return true;
}
else
{
return false;
}
}
判斷兩個矩形是否重合的方法很簡單,只要判斷第一個矩形的四個頂點是否在第二個矩形的范圍內即可。
功能實現(xiàn)
在main.cpp中,添加一個函數(shù)來實時判斷是否有炮彈擊中坦克的情況。
void CheckCrash()
{
for (list<Object*>::iterator it = lstMainTankBullets.begin(); it != lstMainTankBullets.end(); it++)
{
for (list<Tank*>::iterator itt = lstTanks.begin(); itt != lstTanks.end(); itt++)
{
if (Shape::CheckIntersect((*it)->GetSphere(), (*itt)->GetSphere()))
{
(*itt)->SetDisappear();
(*it)->SetDisappear();
}
}
}
}
分別遍歷主戰(zhàn)坦克的炮彈list和坦克list,兩兩進行碰撞檢測,發(fā)現(xiàn)有相交的就通過接口把兩個元素都設置為消失。后面的工作交給展示階段完成。
炮彈失效的動作我們已經在上一篇實現(xiàn)了,在這里只需要添加坦克銷售的動作。
for (list<Tank*>::iterator it = lstTanks.begin(); it != lstTanks.end();)
{
(*it)->Move();
if ((*it)->IsDisappear())
{
// Add a bomb
(*it)->Boom(lstBombs);
// Delete the tank
delete *it;
it = lstTanks.erase(it);
continue;
}
(*it)->Display();
it++;
}
繪制坦克時,發(fā)現(xiàn)失效后添加一個爆炸的對象,之后刪除這個坦克。
需要注意的是,在實現(xiàn)坦克的Boom接口時,我們創(chuàng)建的是一個大的爆炸。
void Boom(list<Object*>& lstBombs)
{
lstBombs.push_back(new Bomb(m_pos, LARGE));
}
一看代碼大家就應該明白了。
好了,運行一下程序看看效果是不是和文章開頭相同呢?
項目源碼托管在GitHub上,請大家自行下載。
我是天花板,讓我們一起在軟件開發(fā)中自我迭代。
如有任何問題,歡迎與我聯(lián)系。