最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

游戲編程模式(二):命令模式和享元模式

2023-07-07 03:47 作者:寧牁兒  | 我要投稿

命令模式

命令模式在GoF中有個(gè)晦澀的定義:

將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可撤銷的操作。

高度抽象的定義加上蹩腳的翻譯使其難懂,接下來會(huì)使用一些代碼案例描述我們開發(fā)過程中可能遇到的場(chǎng)景,并展示解耦的過程演化。

一.

在實(shí)現(xiàn)人物控制的功能時(shí),簡(jiǎn)單的實(shí)現(xiàn)會(huì)是:

void InputHandler::handleInput()
{
? ?if (isPressed(BUTTON_X)) jump();
? ?else if (isPressed(BUTTON_Y)) fireGun();
? ?...
}

二.

游戲中一般會(huì)有配置按鍵的功能,這時(shí)就要求類似jump()這種方法調(diào)用轉(zhuǎn)變?yōu)榭勺儞Q的東西,自然我們會(huì)將其用一個(gè)對(duì)象來表示,這時(shí)我們就進(jìn)入了命令模式,用一個(gè)Command類來作為基類,將類似jump()這種游戲行為都定義為一個(gè)子類:

// 定義子類
class JumpCommand : public Command
{
public:
? ?virtual void execute() { jump(); }
};
class FireCommand : public Command
{
public:
????virtual void execute() { fireGun(); }
};

class InputHandler
{
public:
? ?void handleInput();
? ?// 綁定命令的方法……
private:
? ?Command* buttonX_;
? ?Command* buttonY_;
? ?...
};

void InputHandler::handleInput()
{
? ?if (isPressed(BUTTON_X)) buttonX_->execute();
? ?else if (isPressed(BUTTON_Y)) buttonY_->execute();
? ?...
}

此時(shí)就可以通過改變各個(gè)button變量的值來改變按鍵的設(shè)置。

三.

jump()這些行為方法一般會(huì)與某個(gè)玩家角色進(jìn)行關(guān)聯(lián),但是我們不應(yīng)該讓方法去找它們控制的角色,而是應(yīng)將角色對(duì)象作為參數(shù)傳進(jìn)去:

class JumpCommand : public Command
{
public:
? ?virtual void execute(GameActor& actor)
? ?{
? ? actor.jump();
? ?}
};

這樣做的好處就是可以靈活控制任意的角色,只需要傳入不同的角色對(duì)象。但此時(shí)需要把a(bǔ)ctor角色對(duì)象與handleInput()方法進(jìn)行解耦,把execute()的執(zhí)行放到外面去:

Command* InputHandler::handleInput()
{
? ?if (isPressed(BUTTON_X)) return buttonX_;
? ?if (isPressed(BUTTON_Y)) return buttonY_;
? ?...
}

Command* command = inputHandler.handleInput();
if (command)
{
command->execute(actor);
}

四.

在典型的回合制策略游戲中,一般會(huì)有回滾這一概念,可以撤銷或者重做玩家不喜歡的操作。命令模式完美地提供了這一問題的解決方案。

比如,在實(shí)現(xiàn)移動(dòng)某個(gè)單位的功能時(shí),代碼可能如下:

class MoveUnitCommand : public Command
{
public:
...
? ?virtual void execute()
? ?{
? ? unit_->moveTo(x_, y_);
? ?}
private:
? ?Unit* unit_;
? ?int x_, y_;
};

這里的命令更特殊,將x,y作為成員變量,這意味著控制代碼會(huì)在玩家做出操作時(shí)創(chuàng)造一個(gè)實(shí)例:

Command* handleInput()
{
? ?Unit* unit = getSelectedUnit();
? ?if (isPressed(BUTTON_UP)) {
? ? ? ?// 向上移動(dòng)單位
? ? ? ?int destY = unit->y() - 1;
? ? ? ?return new MoveUnitCommand(unit, unit->x(), destY);
? ?}
? ?if (isPressed(BUTTON_DOWN)) {
? ? ? ?// 向下移動(dòng)單位
? ? ? ?int destY = unit->y() + 1;
? ? ? ?return new MoveUnitCommand(unit, unit->x(), destY);
? ?}
? ?// 其他的移動(dòng)……
? ?return NULL;
}

在此基礎(chǔ)上,可以增加一個(gè)記錄移動(dòng)之前位置的變量,來達(dá)到撤銷操作的目的:

class MoveUnitCommand : public Command
{
public:
? ?...
? ?virtual void execute()
? ?{
? ? ? ?// 保存移動(dòng)之前的位置
? ? ? ?xBefore_ = unit_->x();
? ? ? ?yBefore_ = unit_->y();
? ? ? ?unit_->moveTo(x_, y_);
? ?}
? ?virtual void undo()
? ?{
? ? unit_->moveTo(xBefore_, yBefore_);
? ?}
private:
? ?Unit* unit_;
? ?int xBefore_, yBefore_;
? ?int x_, y_;
};

五.

撤銷和重做是一對(duì)正反操作,實(shí)現(xiàn)類似軟件中的撤銷列表和重做列表,只需將其維護(hù)成一個(gè)鏈表或數(shù)組:

維護(hù)一個(gè)命令鏈表或數(shù)組


享元模式

享元模式非常簡(jiǎn)單,稍微提一下。

游戲開發(fā)中,如果要呈現(xiàn)一片巨大的森林,成千上萬的樹,每棵樹都由上千的多邊形組成,在不做任何優(yōu)化的情況下,可以就是每秒送到GPU六十次的百萬個(gè)多邊形。

一.

定義一個(gè)樹看起來會(huì)是:

class Tree
{
private:
? ?Mesh mesh_; ?//多邊形網(wǎng)格
? ?Texture bark_;
? ?Texture leaves_; //樹皮、樹葉紋理
? ?Vector position_; //位置
? ?double height_;
? ?double thickness_; //高度厚度
? ?Color barkTint_;
? ?Color leafTint_; //顏色
};

二.

享元模式簡(jiǎn)單到甚至不需要去知道有這么個(gè)設(shè)計(jì)模式,自然地就會(huì)把它用在代碼中。GoF稱之為固有狀態(tài),即上下文無關(guān)的部分,剩余部分是變化狀態(tài),那些每個(gè)實(shí)例獨(dú)一無二的東西。在這個(gè)例子中,是每棵樹的位置,高度和顏色:

class TreeModel
{
private:
? ?Mesh mesh_;
? ?Texture bark_;
? ?Texture leaves_;
};

class Tree
{
private:
? ?TreeModel* model_; //所有樹共用一個(gè)模型實(shí)例
? ?Vector position_;
? ?double height_;
? ?double thickness_;
? ?Color barkTint_;
? ?Color leafTint_;
};

拓展一下,多數(shù)情況下不會(huì)在一開始就創(chuàng)建所有享元,當(dāng)你需要一個(gè)時(shí),一般會(huì)先檢查是否已經(jīng)創(chuàng)建了一個(gè)相同的實(shí)例,這通常意味著需要將構(gòu)造函數(shù)封裝在檢查實(shí)例是否已經(jīng)存在的接口之后,這也許會(huì)用到工廠方法。

為了返回一個(gè)已有的享元,通常需要一個(gè)存儲(chǔ)它們的地方,使用對(duì)象池會(huì)是一個(gè)好辦法。

狀態(tài)模式(會(huì)在接下來的章節(jié)中總結(jié))中,經(jīng)常會(huì)出現(xiàn)一些沒有任何“獨(dú)一無二”字段的狀態(tài)對(duì)象,這時(shí)享元模式會(huì)派上用場(chǎng)。


游戲編程模式(二):命令模式和享元模式的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
迁西县| 虹口区| 武定县| 西峡县| 松江区| 双城市| 双江| 满洲里市| 安仁县| 荔浦县| 烟台市| 宁化县| 长治县| 西青区| 呼伦贝尔市| 张家界市| 凌海市| 东乡县| 恩施市| 阿图什市| 达州市| 广河县| 耿马| 贵州省| 汝州市| 江安县| 长海县| 武义县| 无为县| 灌南县| 泾源县| 白山市| 东乌珠穆沁旗| 新竹市| 昌江| 威信县| 南漳县| 新乐市| 江达县| 平湖市| 裕民县|