独立日记 2015年12月26日 day5 有限状态机 FSM

来源:互联网 发布:亿次元 淘宝 编辑:程序博客网 时间:2024/05/01 09:59

独立日记 2015年12 月26日 day5 有限状态机 FSM

今天的流水账:
  2:00 入睡
  11:40 起床
  14:00~20:00 跑酷游戏

  今天是高产出的一天。

有限状态机实现:

  跑酷游戏中的主角有很多状态,跑、跳、二段跳、死亡。如果全部都用if/switch来切换状态,那代码就会有坏味道了,稍微多添加一个状态, 那么代码就会指数级增长。所以就实现了一个有限状态机来管理主角的状态。基本思路是,实现一个状态类和一个跳转类,状态类中用一个字典来存储跳转事件的名称和对应的跳转对象。跳转类充当一个结构体,负责存储源状态对象、目标状态对象、和跳转事件名称、和一个做为回调的函数指针。 上图。

然后实现一个状态机类来管理状态和跳转。贴上全部代码。

using UnityEngine;  using System.Collections;  using System.Collections.Generic;public class FSM {      // 定义函数指针类型    public delegate void FSMTranslationCallfunc();    /// <summary>    /// 状态类    /// </summary>    public class FSMState     {               public string name;        public FSMState(string name)        {            this.name = name;        }        /// <summary>        /// 存储事件对应的条转        /// </summary>        public Dictionary <string,FSMTranslation> TranslationDict = new Dictionary<string,FSMTranslation>();    }    /// <summary>    /// 跳转类    /// </summary>    public class FSMTranslation    {        public FSMState fromState;        public string name;        public FSMState toState;        public FSMTranslationCallfunc callfunc; // 回调函数        public FSMTranslation(FSMState fromState,string name, FSMState toState,FSMTranslationCallfunc callfunc)        {            this.fromState = fromState;            this.toState   = toState;            this.name = name;            this.callfunc = callfunc;        }    }    // 当前状态    private FSMState mCurState;    // 状态    Dictionary <string,FSMState> StateDict = new Dictionary<string,FSMState>();    /// <summary>    /// 添加状态    /// </summary>    /// <param name="state">State.</param>    public void AddState(FSMState state)    {        StateDict [state.name] = state;    }    /// <summary>    /// 添加条转    /// </summary>    /// <param name="translation">Translation.</param>    public void AddTranslation(FSMTranslation translation)    {        StateDict [translation.fromState.name].TranslationDict [translation.name] = translation;    }    /// <summary>    /// 启动状态机    /// </summary>    /// <param name="state">State.</param>    public void Start(FSMState state)    {        mCurState = state;    }    /// <summary>    /// 处理事件    /// </summary>    /// <param name="name">Name.</param>    public void HandleEvent(string name)    {        if (mCurState != null && mCurState.TranslationDict.ContainsKey(name)) {            Debug.LogWarning ("fromState:" + mCurState.name);            mCurState.TranslationDict [name].callfunc ();            mCurState = mCurState.TranslationDict [name].toState;            Debug.LogWarning ("toState:" + mCurState.name);        }    }}

测试代码

//        Idle,               // 闲置//        Run,                // 跑//        Jump,               // 一段跳//        DoubleJump,         // 二段跳//        Die,                // 挂彩        // 创建状态        FSM.FSMState idleState = new FSM.FSMState("idle");        FSM.FSMState runState  = new FSM.FSMState("run");        FSM.FSMState jumpState = new FSM.FSMState("jump");        FSM.FSMState doubleJumpState = new FSM.FSMState("double_jump");        FSM.FSMState dieState  = new FSM.FSMState("die");        // 创建跳转         FSM.FSMTranslation touchTranslation1 = new FSM.FSMTranslation(runState,"touch_down",jumpState,Jump);        FSM.FSMTranslation touchTranslation2 = new FSM.FSMTranslation(jumpState,"touch_down",doubleJumpState,DoubleJump);        FSM.FSMTranslation landTranslation1 = new FSM.FSMTranslation(jumpState,"land",runState,Run);        FSM.FSMTranslation landTranslation2 = new FSM.FSMTranslation(doubleJumpState,"land",runState,Run);        // 添加状态        PlayerModel.Instance ().fsm.AddState (idleState);        PlayerModel.Instance ().fsm.AddState (runState);        PlayerModel.Instance ().fsm.AddState (jumpState);        PlayerModel.Instance ().fsm.AddState (doubleJumpState);        PlayerModel.Instance ().fsm.AddState (dieState);        // 添加跳转        PlayerModel.Instance ().fsm.AddTranslation (touchTranslation1);        PlayerModel.Instance ().fsm.AddTranslation (touchTranslation2);        PlayerModel.Instance ().fsm.AddTranslation (landTranslation1);        PlayerModel.Instance ().fsm.AddTranslation (landTranslation2);        PlayerModel.Instance ().fsm.Start (runState);
写给女票的:

  原型模式:使用原型实例指定创建对象的种类,并通过赋值原型创建新的对象。上图上图上图!
什么时候用?
  要实例化的类是在运行时决定的。 
  不同类的实例间的差异仅是状态的若干组合。因此肤质更加方便。
  对象不容易创建,赋值一个对象仅改些属性比重新创建一个对象方便。

深拷贝与浅拷贝 :

一句话概括浅拷贝;拷贝过程中新的对象中指针类型的成员,只赋值原型对象的指针值,不复制指针所指向的实际的内存资源。 
深拷贝:拷贝内存,新的对象中指针成员之向新的内存。

实现:

  在Cocoa Touch中使用NSCopying协议实现深拷贝。

////  CommonClass.h//  Prototype////  Created by 凉鞋 on 15/12/26.//  Copyright © 2015年 凉鞋. All rights reserved.//#import <Foundation/Foundation.h>@interface CommonClass : NSObject <NSCopying>@property CommonClass *member;- (id)copyWithZone:(NSZone *)zone;@end////  CommonClass.m//  Prototype////  Created by 凉鞋 on 15/12/26.//  Copyright © 2015年 凉鞋. All rights reserved.//#import "CommonClass.h"@implementation CommonClass@synthesize member;- (id)copyWithZone:(nullable NSZone *)zone{    CommonClass *retObj = [CommonClass allocWithZone:zone];    retObj.member = [self.member copy];    return retObj;}@end////  main.m//  Prototype////  Created by 凉鞋 on 15/12/26.//  Copyright © 2015年 凉鞋. All rights reserved.//#import <Foundation/Foundation.h>#import "CommonClass.h"int main(int argc, const char * argv[]) {      @autoreleasepool {        // insert code here...        CommonClass * protoObj = [CommonClass new];        protoObj.member = [CommonClass new];        NSLog(@"%@",protoObj.member);        CommonClass * newObj = [protoObj copy];        NSLog(@"%@",newObj.member);    }    return 0;}

转载请注明地址:独立日记

微信公众号:QWERTeam

0 0
原创粉丝点击