[回到版面]
回應模式
名 稱
內 文
附加圖檔[] []
  • 可附加圖檔類型:GIF, JPG, JPEG, PNG, WEBM,瀏覽器才能正常附加圖檔
  • 附加圖檔最大上傳資料量為 3072 KB。
  • 當檔案超過寬 125 像素、高 125 像素時會自動縮小尺寸顯示
  • 目前附加圖檔使用量大小: 175965 KB / 500000 KB
  • 回覆時程式碼縮排會被trim消掉,請善用[code][/code]標色或貼到ideone等網站
  • LaTeX記法可以用「$$」或「\( \)」包起來,例如「$\sum_{k=1}^{k=n} k^2 = \frac{n(n+1)(n+2)}{6}$」
  • 投稿時請點擊畫像認證後,再按下 [送出] 按鈕提交。
  • 鬧板、攻擊性發言、煽動性發言請無視(回應者也無視),並使用del或在貓管理部向管理員回報。
  • 新介面尚處於測試階段,如果有任何問題可以向管理員或於程設交流版反映。

檔名:1554042902239.png-(746 KB, 600x800)
746 KB
C++無名19/03/31(日)22:35:02 ID:LoCw3BWYNo.13133del
class Player
{
public:
//friend class StateMachine;

void update();
void draw();

void setStateMachine(StateMachine* stateMachine);

//int getPosX();
//void setPosX(int posX);

private:
StateMachine* stateMachine_;
int posX_, posY_;
int velX_, velY_;
};

class StateMachine
{
public:
StateMachine(Player* player);
private:
Player* player_;
...
};

class IdleState : public ActiveStateMachine
{...};

class WalkState : public ActiveStateMachine
{...};


想要在角色上安置一個狀態機,update()會呼叫stateMachine_
角色的position與velocity修改都交給stateMachine_處理

寫一寫發現到這樣做,狀態機無法去更改class Player的私有值
friend class也無法應用在多型的狀況
如果為了要讀寫,多了一堆set與get的函式也覺得怪怪的
因為跟本不想讓外界去修改

請教大家如何解決這問題
還是狀態機根本不是這樣用的

//
順帶延伸一問
有些教學還會寫說少用繼承(is a)多用聚合(has a)
其實上面想講的也是,我聚合的元件想更改主類別的私有變數就不知道怎麼處理了
無名19/03/31(日)23:37:57 ID:/aeb7Bz.No.13134del
狀態機換狀態時不是只修改自己而已嗎?
其他物件注意到才自我修改隨機應變
為什麼要狀態機去動其它物件的私有成員?
無名19/04/01(一)00:20:32 ID:Vaqx/wfcNo.13135del
檔名:1554049232110.png-(34 KB, 800x500)
34 KB
你的程式很奇怪,
如果是player要使用的處理抽出成為StateMachine,那你就不應該在裡面使用【StateMachine(Player* player)】

而是應該讓player去註冊StateMachine,例如
【Player(IStateMachine* stateMachine)】
接著由外面撰寫Player的註冊方式。

至於如果要改變Player的屬性,你可以宣告一些行為,例如Move之類,給StateMachine或其他處理進行呼叫。
原po19/04/01(一)00:31:59 ID:XaeWTPBwNo.13136del
>>13134
這是我自己的想法

用狀態機是想要讓鍵盤輸入的時候
會根據不同狀態有不同的動作 不想設一堆FLAG來判定目前狀態
指標stateMachine指去不同狀態
等於說我每個狀態接收到鍵盤輸入都有不同的處理方式
stateMachine再回Call player去修改速度或位置的資料(當然資料還包括貼圖等等)

總之核心思想就是我想用狀態機來處理鍵盤輸入
如果我用法不對也請大家指點我正確的使用方式


然後程式碼最後幾行打錯
修正 IdleStat與WalkState都是繼承StateMachine
無名19/04/01(一)00:36:50 ID:jhWfaHJkNo.13137del
>>如果為了要讀寫,多了一堆set與get的函式也覺得怪怪的
OOP就是這樣用的
所有的member variable都透過set與get讀寫
不過你可以把X跟Y併成只有一組函式同時處理
然後順便做些position是否位在不可進入的地區、角色是否處於禁止移動狀態之類的檢查
以後需要做log之類的操作時也可以統一在set裡面處理

當然
如果你覺得這些未來可能會省下的麻煩遠不及當下造成的
也可以把private砍了不要用OOP


StateMachine如果都是被Player持有、管理的話
我會選擇不在StateMachine裡面記錄*player_
而是update每次呼叫他的時候都用參數傳
這可以讓StateMachine更方便地在不同Player之間傳遞 (也許哪天你會用得到)
甚至做成static,然後就可以拿來==了
原po19/04/01(一)03:30:41 ID:ksYN8n2ENo.13138del
檔名:1554060641052.jpg-(156 KB, 800x800)
156 KB
>>13135
>>StateMachine(Player* player)
因為我想要狀態機可以去控制玩家

>>而是應該讓player去註冊StateMachine
>>例如【Player(IStateMachine* stateMachine)】
說的註冊跟這行意思不一樣嗎?不太懂意思
void setStateMachine(StateMachine* stateMachine);

>>至於如果要改變Player的屬性,你可以宣告一些行為,例如Move之類,給StateMachine或其他處理進行呼叫
思考後應該會朝這方向去撰寫


>>13137
>>OOP就是這樣用的 所有的member variable都透過set與get讀寫
會懷疑自己主因是
在寫的當下覺得好像在幹脫褲子放屁的蠢事...
state machine明明就自己人我居然還要創個接口引導他
一直執著在state machine也是物件的一部份
雖然在這個player案例中,私有座標額外set get挺合理的 畢竟外部也有機會使用

>>也可以把private砍了不要用OOP
寫這程式目的一之也是要習慣OOP的模式,砍掉B格就降低了XD
的確看到有人的code直接不用private

>>我會選擇不在StateMachine裡面記錄*player_
>>而是update每次呼叫他的時候都用參數傳
這招會怕寫到後面參數越來越多 突發狀況需要修改之前沒想到的參數
造成要修改大量程式碼 我真的是寫個程式怕東怕西

希望都是以物件修改不會影響到另一個物件為目標 但好難
也覺得自己看的不夠多,寫的時候都會陷入很長的思考時間
無名19/04/01(一)04:25:23 ID:MKut03IQNo.13139del
>>13138
為何如此設計,StateMachine功用不應該綁訂Player才對,這樣設計你之後用了NPC那樣難道要讓他繼承Player?
設計讓狀態機只記錄狀態,包一份函數物件(std::function)進去,讓狀態機切換狀態時自動觸發正確的函數就行。
class StateMachine
{
public:
typedef std::function<void(std::string state)> CallbackFunc;
StateMachine();
void addState(std::string state, CallbackFunc callback);
void run();
private:
std::map<std::string, CallbackFunc> stateMap
};
無名19/04/01(一)05:50:11 ID:MKut03IQNo.13140del
>state machine明明就自己人我居然還要創個接口引導他
那樣就用閉包或用std::bind將成員函數跟this綁訂就好,重點是在Player成員函數將依賴注入到StateMachine,像這樣:
#include <functional>
#include <map>
#include <string>
#include <iostream>

template <typename Enum>
class StateMachine {
public:
typedef std::function<Enum(Enum state)> CallbackFunc;
StateMachine() {
}
void addState(Enum state, CallbackFunc callback) {
stateMap[state] = callback;
}
Enum run(Enum state) {
auto callback = stateMap[state];
if(callback != nullptr) {
return callback(state);
} else {
std::cout << "Error, callback function is nullptr" << std::endl;
return state;
}
}
private:
std::map<Enum, CallbackFunc> stateMap;
};

class Player {
public:
enum class State {
Stop, Idle, Walk
};
Player() : state(State::Idle), step(0) {
stateMachine.addState(State::Idle, [this](State){
std::cout << "\tIdle...";
return State::Walk;
});
stateMachine.addState(State::Walk, [this](State){
if(step < 10) {
std::cout << "\tWalk Step " << step++;
return State::Walk;
} else {
std::cout << "\tOk!";
return State::Stop;
}
});
stateMachine.addState(State::Stop, [this](State){
return State::Stop;
});
}
bool updata() {
std::cout << "state is " << static_cast<int>(state) << std::endl;
state = stateMachine.run(state);
std::cout << ", next state is " << static_cast<int>(state) << std::endl;
return state != State::Stop;
}
private:
int step;
StateMachine<Player::State> stateMachine;
State state;
};

int main(int argc, char* argv[]) {
Player player;
while(player.updata()){
}
return 0;
}
無名19/04/01(一)13:36:29 ID:8BuKfqyMNo.13141del
>>13138
>>在寫的當下覺得好像在幹脫褲子放屁的蠢事...
直覺也感覺得出來OOP有病
這帖藥服用看看
functional programming
無名19/04/01(一)20:49:32 ID:jhWfaHJkNo.13142del
>>13138
>>在寫的當下覺得好像在幹脫褲子放屁的蠢事...
不要懷疑
OOP真的就是在脫褲子放屁
看起來好像很蠢,等哪天你要放的不是屁時就知道脫褲子有多重要了

>>state machine明明就自己人
封裝的東西給不給摸不是看他是不是自己人
而是看邏輯上是否有必要、是否有特殊性
如果你要對某成員做一個看起來很普通、外面的人也會做的操作
那別說是StateMachine,就連Player自己的method也該透過set處理
只有在做很特別、只有主人才能做的事情時才可以直接摸他
原po19/04/01(一)20:54:34 ID:5y/epedMNo.13143del
檔名:1554123274833.jpg-(124 KB, 1000x750)
124 KB
>>13139
初衷也只是想讓狀態不管有多少種,Player都不需要大幅度改動
這邊的CallbackF是Player的function嗎?
這樣我追加一個狀態是不是就要在player裡面追加一個function?
>>13140
突然秀了太高端的東西有點招架不太住
不管如何還是多謝提供我不同的寫法
而且感覺為了滿足我的問題,類別的相依性變得有點太強
發文也只是在懷疑我這寫法是不是超爛而已
不用真的幫我滿足詭異的條件拉XD

>>13141
感謝推薦,一直覺得自己見識太少
當初有這個發想也是從"狀態模式"衍伸過來
google查了幾個人寫的,解決方法不是設public就是直接傳遞參數
真的自己寫過才發現很多東西都不是這麼理所當然

最後我的感想是…我還是乖乖傳參數&做介面好了
原po19/04/01(一)22:04:19 ID:XaeWTPBwNo.13144del
>>13142
我大概知道你的意思
總而言之封裝不是對外對內的問題
而是碰了會不會發生事情的問題

>>就連Player自己的method也該透過set處理
這句話有點醒我
無名19/04/02(二)14:31:35 ID:REirT/y6No.13149del
>>13143
老實說,問題點不在那。你要讓StateMachine吃到Player的私有項很簡單,將StateMachine宣告在Player裡就好。
但是,因為你每個狀態都可能跳到別的狀態,所以相依性會變得很強,反而不好。
重點在於,狀態機負責的"狀態切換"跟"各狀態執行程式"應該要切開,把狀態視為是"容器",才能簡化狀態行為,符合OOP中單一職責原則。
下面給你你想要的打法
#include <memory>
#include <vector>
#include <iostream>
//hpp
class Player {
public:
class Act;
class Act1;
class Act2;
class Act3;

class Act {
public:
virtual void run(Player& a) = 0;
};
class Act1 : public Act {
public:
virtual void run(Player& a);
static Act* getInstance() {
return &_inst;
}
private:
static Act1 _inst;
};
class Act2 : public Act {
public:
virtual void run(Player& a);
static Act* getInstance() {
return &_inst;
}
private:
static Act2 _inst;
};
class Act3 : public Act {
public:
virtual void run(Player& a);
static Act* getInstance() {
return &_inst;
}
private:
static Act3 _inst;
};
Player() : act(Act1::getInstance()), flag(false){
}
void updata() {
act->run(*this);
}
private:
Act* act;
bool flag;
};
//cpp
void Player::Act1::run(Player& a) {
std::cout << "Act1" << std::endl;
if(a.flag) {
a.act = Act2::getInstance();
} else {
a.act = Act3::getInstance();
}
}
void Player::Act2::run(Player& a) {
std::cout << "Act2" << std::endl;
if(a.flag) {
a.act = Act1::getInstance();
a.flag = false;
} else {
a.act = Act3::getInstance();
a.flag = true;
}
}
void Player::Act3::run(Player& a) {
std::cout << "Act3" << std::endl;
if(a.flag) {
a.act = Act1::getInstance();
} else {
a.act = Act2::getInstance();
}
}
Player::Act1 Player::Act1::_inst;
Player::Act2 Player::Act2::_inst;
Player::Act3 Player::Act3::_inst;
//main
int main(int argc, char* argv[]) {
Player player;
for(int i=0; i<10; i++) {
player.updata();
}
return 0;
}
無名19/04/02(二)14:45:45 ID:REirT/y6No.13150del
為何StateMachine吃到Player的私有項是因為只有Player理面的成員才能吃到Player的私有項(封裝),
所以你要嘛就再Player裡面將"執行程式"(函數/成員函數)插入到StateMachine裡,
要嘛就宣告StateMachine是Player特製的(將StateMachine宣告在Player裡)。
無名19/04/02(二)15:06:19 ID:REirT/y6No.13151del
>>13143
沒錯,追加一個狀態就要在player裡面追加一個function,
>13140的寫法就是用lambda表達式動態宣告函數,其實沒很難。
或者你會想要改成一般的寫法?那樣就用std::bind將製作函數物件,將 成員函數綁訂this 變成一般函數給StateMachine使用。
#include <functional>
#include <map>
#include <string>
#include <iostream>

template <typename Enum>
class StateMachine {
public:
typedef std::function<Enum(Enum state)> CallbackFunc;
StateMachine() {
}
void addState(Enum state, CallbackFunc callback) {
stateMap[state] = callback;
}
Enum run(Enum state) {
auto callback = stateMap[state];
if(callback != nullptr) {
return callback(state);
} else {
std::cout << "Error, callback function is nullptr" << std::endl;
return state;
}
}
private:
std::map<Enum, CallbackFunc> stateMap;
};

class Player {
public:
enum class State {
Stop, Idle, Walk
};
Player() : state(State::Idle), step(0) {
//用bind將 成員函數 與 this 綁訂在一起.
stateMachine.addState(State::Idle, std::bind(&idle, this, std::placeholders::_1));
stateMachine.addState(State::Walk, std::bind(&walk, this, std::placeholders::_1));
stateMachine.addState(State::Stop, std::bind(&stop, this, std::placeholders::_1));
}
bool updata() {
std::cout << "state is " << static_cast<int>(state) << std::endl;
state = stateMachine.run(state);
std::cout << ", next state is " << static_cast<int>(state) << std::endl;
return state != State::Stop;
}
private:
State idle(State) {
std::cout << "\tIdle...";
return State::Walk;
}
State walk(State) {
if(step < 10) {
std::cout << "\tWalk Step " << step++;
return State::Walk;
} else {
std::cout << "\tOk!";
return State::Stop;
}
}
State stop(State) {
return State::Stop;
}

int step;
StateMachine<Player::State> stateMachine;
State state;
};

int main(int argc, char* argv[]) {
Player player;
while(player.updata()){
}
return 0;
}
無名19/04/02(二)20:49:45 ID:wvNn5Cb6No.13157del
檔名:1554209385512.png-(68 KB, 650x512)
68 KB
>>13149
>>13151
>>13140
到底是C++真的是這樣寫物件(OR狀態機真的這個搞剛)還是你們寫得特別複雜?
無名19/04/02(二)22:21:18 ID:Q/Y6zfwsNo.13159del
>>13157
我想是他寫得太複雜
還用了一堆菜鳥根本看不懂的進階語法

class Player
{
public:
void update();
void moveTo(int x,int y);
int getX();
int getY();
int getVX();
int getVY();

private:
StateMachine* stateMachine_;
int posX_, posY_;
int velX_, velY_;
};

class StateMachine
{
public:
virtual void run()=0;
};

class WalkState : public StateMachine
{
public:
void run();
};
void Player::update()
{
stateMachine_->run(this);
}

void WalkState::run(Player *player)
{
player->moveTo(player->getX()+player->getVX(),player->getY()+player->getVY());
}

void Player::moveTo(int x,int y)
{
if(!isAccessible(x,y))
return;
posX_=x;
posY_=y;
}
無名19/04/02(二)22:32:10 ID:REirT/y6No.13160del
>>13159
不是啊,是提問者要求訪問項是私有變數。
更何況函數物件也是物件的一種,哪能算是進階語法...
無名19/04/02(二)22:43:28 ID:wvNn5Cb6No.13161del
檔名:1554216208768.png-(49 KB, 420x248)
49 KB
>>13159
看起來我對物件開發的觀念不是孤單的。

>>13160
我想應該是【有些東西能做,但不建議用,甚至不建議學/教】
這個道理吧
無名19/04/02(二)22:52:06 ID:REirT/y6No.13162del
>>13161
並不是啊,>>13159>>13149明明就是一樣的。
我是希望可以讓StateMachine不被綁訂到Player,讓其他類別(EX: class NPC)能使用才要這樣搞。
你用這樣的>>13159的寫法就是在寫class NPC要在寫另個StateMachine來作,這樣為何一開始要創造StateMachine。
無名19/04/02(二)23:01:10 ID:wvNn5Cb6No.13163del
檔名:1554217270671.png-(45 KB, 414x248)
45 KB
>>13162
你三個月後重新看這段程式碼,若你還有辦法逐行解說得出來寫作目標與實作手段的話.....我就當你厲害。
無名19/04/02(二)23:13:36 ID:REirT/y6No.13164del
>>13163
我是認為沒啥好吵的,但是你說不建議用我可不能接受。
首先>>13159>>13149是一樣的,差別在於>>13159只打了一半沒有完成它(當然我用了static成員,因為C++用new要delete)。
其次,我只花了2個類別(StateMachine跟Player)就完成了題目要求,並且StateMachine不依賴Player,Player依賴StateMachine。
>>13159的寫法要花5個類別(StateMachine、Player、IdleState、WalkState跟StopState),虛函數,繼承(實作),
會導致StateMachine依賴Player,Player、IdleState、WalkState跟StopState依賴StateMachine,
StateMachine依賴Player,IdleState跟StopState依賴WalkState,IdleState跟WalkState依賴StopState,StopState跟WalkState依賴IdleState。
你三個月後會忘掉2個類+1個依賴還是5個類別+11個依賴。
原po19/04/02(二)23:16:33 ID:EL9ZOFqkNo.13165del
檔名:1554218193251.gif-(21 KB, 300x300)
21 KB
>>13149
了解,簡單來說就是把狀態類別包進Player類別裡,他就不是外人了

>>13159
這個看了很舒服 我的舒適圈


感謝大家花時間寫CODE給我看
我C++學的也沒有到很深入,頂多用用STL
很多用法說實在我看都沒看過,不過既然各位都秀一手出來了
我還是會感激的把那些知識&關鍵字學起來,畢竟我就是見識太少

但就如我中間講到,我只是在自我懷疑我OOP寫法的正確性
比較想知道的是怎樣是正確的OOP觀念,而不是要滿足我詭異的條件
無名19/04/02(二)23:24:35 ID:wvNn5Cb6No.13167del
檔名:1554218675563.png-(69 KB, 558x469)
69 KB
>>13164
的確沒啥好吵的,你喜歡這樣開發就繼續這樣下去吧。(攤手)
無名19/04/02(二)23:26:13 ID:dLpXYWhcNo.13168del
檔名:1554218773640.jpg-(73 KB, 649x1000)
73 KB
我時常覺得OOP的寫法很容易寫成作繭自縛、推卸責任
幻想著好好用心的建立一個物件把事情做好、包裝裝好
接下來只要使喚這物件就可以輕鬆工作了
那並沒有解決問題
問題還是在那物件裡頭
試圖將物件分解成更小的物件只是個可以嘗試的方向
但常常是錯的
試圖將程式分解成更小的函式則幾乎總是可行

既然Player的update要負責更新
那應該由StateMachine來呼叫Player::update
為什麼要StateMachine來修改別人的成員?
Player自己的零件應該自己管啊

如果StateMachine是Player專用的部下
那它也不能有權力把Player的私有成員全都抓來改
(上面提到的std::function就是一種限制權力的做法)

functional programming真的是OOP信徒必學的東西了
很多設計想法用FP準則去檢視就知道錯在哪了
無名19/04/02(二)23:35:06 ID:wvNn5Cb6No.13169del
檔名:1554219306820.jpg-(77 KB, 800x500)
77 KB
>>13168
你會有這想法主因是很多開發人員拿汽車輪胎裝在摩托車上面造成,跟慣老闆一個樣。

東西都可以學,但我覺得最後都必須忘記,抽出各類方法的開發精神才能打出....太極拳(?)
無名19/04/02(二)23:47:24 ID:REirT/y6No.13172del
>>13169
老實說,反正我實務上也不會這樣設計狀態機,實務上直接這樣就好了。
#include <iostream>

class Player {
public:
enum class State {
Stop, Idle, Walk
};
Player() : state(State::Idle), step(0) {
}
bool updata() {
std::cout << "state is " << static_cast<int>(state) << std::endl;
bool run = true;
switch(state) {
case State::Idle: {
std::cout << "\tIdle...";
state = State::Walk;
break;}
case State::Walk: {
if(step < 10) {
std::cout << "\tWalk Step " << step++;
state = State::Walk;
} else {
std::cout << "\tOk!";
state = State::Stop;
}
break;}
case State::Stop: {
run = false;
state = State::Stop;
break;}
}
std::cout << ", next state is " << static_cast<int>(state) << std::endl;
return run;
}
private:
int step;
State state;
};

int main(int argc, char* argv[]) {
Player player;
while(player.updata()){
}
return 0;
}
無名19/04/02(二)23:52:00 ID:Q/Y6zfwsNo.13173del
>>13162
>>跟>>13149明明就是一樣的。
邏輯上是差不多
但你寫了太多廢話又把名稱改了,別人根本看不懂就直接略過了
而且你把Act塞進Player裡,以後Act變更多類的時候Player宣告不就要胖死?
>>是提問者要求訪問項是私有變數。
那是提問者的誤解
我認為好的工程師在面對不合理的要求時
必須提出從更高層面改善系統的建議,直到得到了堅持照做的命令為止
而不是講都不講就傻傻照做

>>我是希望可以讓StateMachine不被綁訂到Player,讓其他類別(EX: class NPC)能使用才要這樣搞。
如果NPC有跟Player類似的methods存在,那他應該跟Player繼承自同個virtual class
然後就可以共用StateMachine了
如果他長得完全不像,那他的StateMachine用另外一套應該不奇怪吧
就算他半像不像,那也可以把run拆出runNPC分開處理

>>為何一開始要創造StateMachine。
為了讓StateMachine未來有機會新增更多virtual function,處理更多隨狀態而變的行為
而且不同狀態的程式碼可以拆散放在不同檔案,方便管理
>>13140那種寫法,不如直接變成純C風格一個int紀錄狀態然後處處switch還比較簡單一點


>>13165
>>但就如我中間講到,我只是在自我懷疑我OOP寫法的正確性
>>比較想知道的是怎樣是正確的OOP觀念,而不是要滿足我詭異的條件
我認為你不需要在意「正確的OOP」長怎樣
只要瞭解「正確的程式設計」就好
OOP只是這個問題的有力答案之一,但也不完全是正解

朝著正確的程式設計邁進、找出屬於你的優秀風格
即使最後得到的結果不是OOP,那又如何?
原po19/04/02(二)23:52:52 ID:EL9ZOFqkNo.13175del
>>13162
順帶說說我想好的架構想到的結果
首先是State Machine會分兩種去繼承,一種是主動(有input)一種是被動(自己RUN)
所以發文程式碼最後才會打錯

Monster、NPC、Player都繼承Object,差別在可不可以被控制
然後狀態機基本上一個"物種或人格",就要獨自創造一堆狀態機
當初就覺得這邊本來就是做遊戲的苦力活部分,要創一堆類別我無所謂
但至少在寫狀態的時候不用管到其他地方(判斷一堆flag之類的事情)

>>13168
>>既然Player的update要負責更新
>>那應該由StateMachine來呼叫Player::update
>>為什麼要StateMachine來修改別人的成員?
>>Player自己的零件應該自己管啊
void Player::input()
{
this->stateMachine_->input(this);//主要是這邊會控制Player(透過Player給的功能來控制)
...
}
void Player::update()
{
//先後順序造成的影響先不管
this->stateMachine_->update(this);//可能會用到(落下狀態)
//位置更新...等等
...
}

我自己的想法是這樣寫
後來也是想做跟>>13159做一樣的事情
這樣Player的東西應該就算是自己管了吧(?)


最後能有機會看到各種不同的CODE互相競爭我認為是很好的
沒看過別人的想法永遠不知道自己怎麼進步
大家的建議我也不可能每一個都用,但我都會吸收就是
我不是在官腔,謝謝各位
無名19/04/02(二)23:55:50 ID:wvNn5Cb6No.13176del
檔名:1554220550215.png-(66 KB, 420x247)
66 KB
>>13172
你可以試著把你switch裡面的邏輯抽出介面與實作後看看成品
無名19/04/03(三)00:06:38 ID:BZUs0hXkNo.13179del
>>13176
沒問題!
//TODO: Use OOP replace switch! 2019/04/03
switch(state) {
case State::Idle: {
std::cout << "\tIdle...";
state = State::Walk;
break;}
case State::Walk: {
if(step < 10) {
std::cout << "\tWalk Step " << step++;
state = State::Walk;
} else {
std::cout << "\tOk!";
state = State::Stop;
}
break;}
case State::Stop: {
run = false;
state = State::Stop;
break;}
}
無名19/04/03(三)00:09:03 ID:Rku4lbOcNo.13180del
檔名:1554221343162.png-(92 KB, 900x700)
92 KB
>>13179
說謊不打草稿阿!!!!下次檔案異動就是2029了吧!?
無名19/04/03(三)00:14:02 ID:bcYnr2VsNo.13181del
>>13175
>>Monster、NPC、Player都繼承Object,差別在可不可以被控制
這個就是封裝、多型的用處

試想
如果Monster沒有MP條的概念
而有某個State會持續扣MP
這個StateMachine如何兼顧Player與Monster的處理?

如果你讓他直接player_->mp-=10;
那你可能要為Monster重寫一份不扣mp的,而且中狀態的時候還要判斷Monster要改中別的狀態
或是每次扣mp時都多一個if判斷當事人是不是Monster
或是你要在Monster裡面塞一個完全用不到的隱型mp讓他扣

但如果你把Object的私有成員都封裝化,答案就會變得非常簡單:
讓Monster擁有一份自己的reduceMP,裡面是空的什麼都不做,只有Player::reduceMP才會真的扣MP
StateMachine只管呼叫player->reduceMP(10)就好
至於對方到底會不會真的扣MP,甚至對方扣了MP後會不會觸發什麼別的事件 (MP盾失效)
通通都不用讓StateMachine來煩惱
無名19/04/03(三)00:23:42 ID:Rku4lbOcNo.13183del
檔名:1554222222788.png-(139 KB, 800x473)
139 KB
>>13181
你應該是少提兩點
1.Object建議要改名
2.reduceMP記得寫一個宣告在"Object"


【刪除文章】[]
刪除用密碼: