Unity 3D游戏四:牧师与魔鬼动作分离版

前言

中山大学数据科学与计算机学院3D游戏课程学习记录博客。
游戏代码:gitee
游戏视频:bilibili
参考师兄的博客: 师兄博客

游戏要求

  • 实现动作分离,用动作控制器控制移动
  • 实现Check类

游戏实现

实现Check类

直接把原来FirstController.cs中的check函数拉出改成Check类即可。

实现动作分离

实现动作分离需要进行一定的程序设计。

  • 接口ISSActionCallback和状态SSActionEventType:
    接口定义了一个函数,为了实现动作的调度和动作完成消息的传递,与运动有关的类都要实现这个接口;
    状态定义了动作的开始状态和结束状态。
public enum SSActionEventType: int{started,competeted}    
public interface ISSActionCallback{      
    void SSActionEvent(            
	SSAction source,
	SSActionEventType events=SSActionEventType.competeted, 
	int intParam=0,
	string strParam=null,
	Object ObjectParam=null        
	)}
  • 实现动作基类SSAction:
    动作基类记录了动作是否被完成,动作来自哪个对象等信息。
    每一个基类对象都是一个动作。
    动作基类只允许交互动作产生,不允许在代码中凭空产生。

代码如下:

public class SSAction: ScriptableObject{    
    public bool enable=true; //是否存在    
    public bool destory=false; //是否删除        
    public GameObject gameobject; //动作对象    
    public Transform transform; //动作对象的transform    
    public ISSActionCallback callback; //回调函数
    /*防止用户自己new对象*/    
    protected SSAction(){ }                      
    public virtual void Start() {        
        throw new System.NotImplementedException();    
    }
    public virtual void Update() {        
        throw new System.NotImplementedException();    
    }
}
  • 实现移动功能子类SSMoveToAction:
    SSMoveToAction继承自SSAction,用于把物体移动到特定地点的操作。
    对象的创建由Unity负责。
    移动操作在Update函数中实现。
public class SSMoveToAction: SSAction{    
    public Vector3 target; //目的地    
    public float speed; //移动速率
    
    private SSMoveToAction(){ }        
    public static SSMoveToAction GetSSAction(Vector3 _target, float _speed) {        
        //unity创建        
    }
    public override void Start() { 
        //重写    
    }
    public override void Update() {
	//实现移动动作
    }
}
  • 实现动作组合类SequenceAction:
    实现船的移动可以很平滑,但是角色的移动需要先平移再下移。
    因此要用两个动作组合成角色的移动,所以引入动作组合类。
    通过动作组合类能够实现很多非常复杂的组合动作。
    通过聚合容器对象来实现多个动作的保存。
    这个类需要实现接口函数,方便动作之间的调度。
public class SequenceAction: SSAction,ISSActionCallback{       
    public List<SSAction> sequence; //动作列表    
    public int repeat = -1; //-1就是无限循环做组合中的动作    
    public int start = 0; //当前做的动作
    
    public static SequenceAction GetSSAcition(int repeat, int start, List<SSAction> sequence) {      
        //unity创建
    }
    public override void Start() {        
        //执行每个动作
    }
    public override void Update() {      
    	//调用动作的Update
        if (sequence.Count == 0) return;      
        if (start < sequence.Count) {            	
            sequence[start].Update();       
        }    
    }
    
    //实现接口    
    public void SSActionEvent( SSAction source, 
        SSActionEventType events = SSActionEventType.competeted,
    	int intParam = 0, string strParam = null, 
    	Object objectParam = null    ) {

	source.destory = false;       
	this.start++; //下一个动作        
	if (this.start >= sequence.Count) {            
	    this.start = 0;            
	    if (repeat > 0) repeat--;            
	    if (repeat == 0) { //动作组合结束           
	        this.destory = true; 
	        this.callback.SSActionEvent(this);     
	    }        
	}    
    }
}
  • 实现动作管理类SSActionManager:
    动作管理类需要存储所有的要被处理的动作,和已经处理过的动作,然后删去处理过的动作。
    代码如下:
public class SSActionManager : MonoBehaviour, ISSActionCallback {    
    private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); //动作字典    
    private List<SSAction> waitingAdd = new List<SSAction>(); //等待执行    
    private List<int> waitingDelete = new List<int>(); //等待删除             
    
    protected void Update() {  
        //更新链表中的动作
        //删去已经处理过的
    }	 
    //执行动作
    public void RunAction(GameObject gameobject, SSAction action,
        ISSActionCallback manager) {        
        action.gameobject = gameobject;        
        action.transform = gameobject.transform;        
        action.callback = manager;        
        waitingAdd.Add(action);        
        action.Start();    
    }
}
  • 实现本游戏的动作管理类ActionManager:
    本游戏的动作管理类需要实现船移动和角色移动。
    船移动一个动作;
    角色移动两个动作(假如没有这个角色移动,那么完全不需要动作链表!!)。
    代码如下:
public class ActionManager : SSActionManager {    
    public FirstController sceneController;    
    private SequenceAction boatMove;    
    private SequenceAction roleMove;
    
    protected void Start() {        
        sceneController = (FirstController)SSDirect.getInstance().CurrentSceneController;        
        sceneController.actionManager = this;    
    }
    
    protected new void Update() {        
        base.Update(); //直接用基类的
    }
    
    public void moveBoat(GameObject boat, Vector3 endPos, float speed) {        
        SSAction action1 = SSMoveToAction.GetSSAction(endPos, speed);        
        boatMove = SequenceAction.GetSSAcition(0, 0, new List<SSAction> { action1 });        
        this.RunAction(boat, boatMove, this);    
    }
    public void moveRole(GameObject role, Vector3 middlePos, Vector3 endPos, float speed) {        
        //两段移动        
        SSAction action1 = SSMoveToAction.GetSSAction(middlePos, speed);        
        SSAction action2 = SSMoveToAction.GetSSAction(endPos, speed);        
        //两个动作        
        roleMove = SequenceAction.GetSSAcition(1, 0, new List<SSAction> { action1, action2 });        
        this.RunAction(role, roleMove, this);    
    }
}

至此完成了练习内容。
详细代码见gitee。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值