标签:csdn 游戏 for循环 ace 结构 eve stop 而且 size
我们试图找到在不同的情境 (动作、需求) 下那些同样的部分。我们对详细事件做抽象。而且期待抽象的结果适用于全部的详细的事例。
这样。原来的非常多工作就成为 应用抽象的理论 的过程,不再须要创造力。因此也不再能吸引我们。
那么,我们再对抽象的结果继续抽象,直到形而上。
2. 状态机的引擎
引擎,就是上文中提到的开发出一个游戏。然后能衍生出非常多游戏的技术。代码的核心部分、流程部分不会改变,仅仅有数据 (甚至能够在外部文件里) 才随需求的变化而变化。
状态机,也能够用引擎实现。
实现这一目标的技术也存在已久。就是查表。查表的经典案例是 求三角函数 (在一定精度下),常量时间复杂度的解决方式 就是查表。事先把三角函数在不同度数下的值都求出来。放在hash表 (?
) 里。你要查哪个度数。我就去查哪个度数相应的函数值。
在这个案例里,查表的那段代码,不随三角函数由sin变成cos或tan而发生不论什么变化。
这就是引擎。被查的表就是数据。
3. 接口
我们期待的接口跟前一篇普通青年中的全然一样。在主函数中调用 void state_change(enum message m) 向状态机传递消息,用 test.in 作为測试用例。主函数还知道,一共就这样几种消息:
enum message { play, stop, forward, backward, record, pause };
记得么,一共4个。 (1) 当前状态。 (2)当前消息。 (3)将迁移到的状态,(4)在状态迁移中的动作。我们期待能用表格,而不是如普通青年一文中用代码(switch-case)的方式描写叙述。由于我们相信,改表格比改代码easy。
状态迁移表与状态迁移图全然等价。
1 struct transition fsm[transition_num] = { 2 /* current_state, message/event, next_state*/ 3 {s_play, stop, s_stop}, 4 {s_play, pause, s_pause}, 5 {s_pause, pause, s_play}, 6 {s_pause, stop, s_stop}, 7 {s_stop, forward, s_forward}, 8 {s_stop, play, s_play}, 9 {s_stop, backward, s_backward}, 10 {s_stop, record, s_record}, 11 {s_forward, stop, s_stop}, 12 {s_backward, stop, s_stop}, 13 {s_record, stop, s_stop} };
1 enum state { s_stop=‘s‘, s_play=‘p‘, s_forward=‘f‘, s_backward=‘b‘, s_pause=‘_‘, s_record=‘r‘ }; 2 enum message { play, stop, forward, backward, record, pause }; 3 4 struct transition { 5 enum state current; 6 enum message m; 7 enum state next; 8 };
1 #define transition_num 11
即,每一个状态都能够有一些"副作用"。这与迁移时的动作是等价的,证明略去。假设仅想在迁移时写代码,也能够利用这样的方法实现。
状态机的动作 表格例如以下:
1 struct state_action state_action_map[state_num] = { 2 {s_stop, do_stop}, 3 {s_play, do_play}, 4 {s_forward, do_forward}, 5 {s_backward, do_backward}, 6 {s_pause, do_pause}, 7 {s_record, do_record}};
第一列是状态,第二列是相应的动作。这样。每添加一个状态 (假设它有相应动作)。就在这里添加一行;动作相应的函数须要实现。后面会介绍。
类似于状态迁移图,为了遵循C语言语法。我们须要在此前声明例如以下。
1 #define state_num 6 2 typedef void (*action_foo)() ; 3 4 enum state { s_stop=‘s‘, s_play=‘p‘, s_forward=‘f‘, s_backward=‘b‘, s_pause=‘_‘, s_record=‘r‘ }; 5 6 /* action starts */ 7 void do_stop() {printf ("I am in state stop and should doing something here.\n");} 8 void do_play() {printf ("I am in state play and should doing something here.\n");} 9 void do_forward() {printf ("I am in state forward and should doing something here.\n");} 10 void do_backward() {printf ("I am in state backward and should doing something here.\n");} 11 void do_pause() {printf ("I am in state pause and should doing something here.\n");} 12 void do_record() {printf ("I am in state record and should doing something here.\n");} 13 14 struct state_action { 15 enum state m_state; 16 action_foo foo; 17 };
第2行和第7行到第12行,以及第16行,使用了函数指针(指向函数的指针。一个指针,它的基类型是一个函数),用于表示要运行的动作。第4行,是状态枚举。
第14行到第17行。是 状态-动作 相应关系的结构体。
第7行至第12行。是动作的运行部分。当添加的状态须要动作时,程序猿要在此处添加一个函数,它遵守第2行的签名约定。
6. 引擎
假设表格的数据结构已定,代码就好写了。我们的引擎代码的核心部分是查表,遍历表格,找到与当前状态、当前消息匹配的将迁移到的状态。
我们还是自顶向下。如果 查表部分已经完毕,为主函数提供与 普通青年一文同样的接口--而内部实现是不同的。
1 void state_change(enum message m) 2 { 3 static state = s_stop; 4 enum state next; 5 int index = 0; 6 7 index = lookup_transition(state, m, fsm); 8 if(index!=ERR) 9 { 10 state = fsm[index].next; 11 lookup_action(state, state_action_map)(); 12 } 13 return; 14 }
以上,完毕了状态迁移4要素中的3个:当前状态、当前消息、将迁移到的状态。
第11行。完毕的功能是运行与状态相应的动作。这里又用到函数指针。
在代码 lookup_action(state, state_action_map)() 中,lookup_action(state, state_action_map) 用于找到状态 state 相应的动作。后面的 "()",是由于这个动作是一个函数指针。能够使用这种方式运行这个指针指向的函数。与上文中的 fsm 參数类似,state_action_map是为了应对有多个状态-动作表的情况。这里能够略过。
不管数据 (状态迁移、状态-动作)怎样变化。引擎代码都不会变化。所以。甚至能够把引擎放在静态或动态链接库里,或者把数据放在外部文件中。执行时再加载。从而提高部署时的灵活性。
7. 查表
刚刚用到的两个没有定义的函数 lookup_transition(state, m, fsm) 和 lookup_action(state, state_action_map) 都使用了查表的方法。
代码例如以下。能够看出。二者的结构很类似,遍历数组 (for循环) ,找到符合条件的元素 (if推断)。然后把该元素的索引或者该元素结构体的某个成员返回。
ERR 和 ACTION_NOT_FOUND 是用来容错的,万一表格有误。没有查到匹配的项。
1 int const ERR = -1; 2 int lookup_transition (enum state s, enum message m, struct transition * t) 3 { 4 int ret=ERR; 5 int i; 6 for(i=0;i<transition_num;++i) 7 { 8 if(t[i].current == s && t[i].m == m) 9 { 10 ret = i; 11 } 12 } 13 return ret; 14 } 15 16 action_foo ACTION_NOT_FOUND = NULL; 17 action_foo lookup_action(enum state s, struct state_action* a) 18 { 19 action_foo ret = ACTION_NOT_FOUND; 20 int i=0; 21 for (i=0;i<state_num;++i) 22 { 23 if(s == a[i].m_state) 24 { 25 ret = a[i].foo; 26 } 27 } 28 return ret; 29 }
这才干让我们对这个世界保留一丝希望。未来才可以和值得期待。
这一篇和上一篇的代码在这里[http://download.csdn.net/detail/younggift/7569627]。
标签:csdn 游戏 for循环 ace 结构 eve stop 而且 size
原文地址:http://www.cnblogs.com/gavanwanggw/p/6855623.html