​使用unity实现《魔鬼与牧师(动作分离版)》小游戏

前言

这是中山大学软件工程学院2023年3D游戏编程与设计的第五次作业,也欢迎大家学习参考交流
github个人主页: innitinnit (github.com)

目录

前言

博客内容概述

游戏内容简述

实现逻辑与代码区别

动作管理器的UML设计图​编辑


博客内容概述

        本次作业要求在上一次作业的基础上使用集成 CCAction的方法,使得动作管理从场景控制器中分离并利用接口消息传递机制,设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束,实现游戏结束判定从场景控制器中分离 。

        上一次作业的链接:使用unity实现《魔鬼与牧师》小游戏-CSDN博客

游戏内容简述

游戏目标:将3个牧师和3个魔鬼从河的一端安全地送到河的另一端。
游戏规则:在运送过程中,船可以搭载两个人,而且必须有一人掌船。
游戏结果:无论何时,只要河一边的魔鬼数量多于牧师的数量,游戏就会以失败结束。当三个牧师与魔鬼都平安到达河的另一端时胜利。
游戏对象的行为
角色:上下船、划船
魔鬼:当两岸任意一边人数多于牧师时杀死牧师,游戏结束
船:有人时可以动

实现逻辑与代码区别

其改变部分主要在于改变了controller中move的调用方式:

public void moveCharacters(dpGame.CharacterController chr)
    {
        if (u.status == 0) return;
        if (forbidEvent()) return;
        if (chr.getState() == 1)
        {
            BankController bank;
            if (boat.getLR() == 0)
            {
                bank = leftBank;
            }
            else
            {
                bank = rightBank;
            }
            boat.outOfBoat(chr.getTag());
            chr.moveToBank(bank);
            //原版
            //chr.goMoving(bank.getPos(chr.getTag()));
            //bank.moveToBank(chr);

            // 动作分离版,改变了move的调用方式
            actionManager.moveCharacter(chr.getObj(), bank.getPos(chr.getTag()), speed);
            bank.moveToBank(chr);
        }
        else
        {
            BankController bank = chr.getBank();

            if (boat.getLR() == bank.getLR())
            {
                if (!boat.isFull())
                {
                    bank.outOfBank(chr.getTag());
                    chr.moveToBoat(boat);
                    //原版
                    //chr.goMoving(boat.getSeat());
                    //boat.moveToBoat(chr);

                    // 动作分离版,改变了move的调用方式
                    actionManager.moveCharacter(chr.getObj(), boat.getSeat(), speed);
                    boat.moveToBoat(chr);

                }
            }
        }
        u.status = checkGame();
    }

以及不再在controller中判断游戏是否达到结束条件,而是另写一个Judger脚本

public class Judger : MonoBehaviour {
    public int checkGame()
    {
        Controller controller = Director.getInstance().currentSceneController as Controller;
        int leftP = 0, rightP = 0, leftD = 0, rightD = 0;
        int[] LCount = controller.leftBank.getCount();
        leftP += LCount[1];
        leftD += LCount[0];

        int[] RCount = controller.rightBank.getCount();
        rightD += RCount[0];
        rightP += RCount[1];

        int[] Bcount = controller.boat.getCount();
        Debug.Log(Bcount[0] + " " + Bcount[1]);


        if (rightD + rightP == 6)		// win
			return 2;
        
        // 计算上船上的人
        if (controller.boat.getLR() == 0) {
            leftP += Bcount[1];
            leftD += Bcount[0];
        }
        else if (controller.boat.getLR() == 1) {
            rightP += Bcount[1];
            rightD += Bcount[0];
        }

        Debug.Log("LP: " + leftP + " LD: " + leftD); //测试用

        // 如果魔鬼数量大于牧师,并且牧师数量不为0就失败
        if (leftP < leftD && leftP != 0) {
            return 0;
        }
        if (rightP < rightD && rightP != 0) {
            return 0;
        }
        return 1;
    } 

    public void setForbid(bool b) {
        Controller controller = Director.getInstance().currentSceneController as Controller;
        controller.forbid = b;
    } 
}

后去调用SSAction接口:

public class SSAction : ScriptableObject {

    public bool enable = true;
    public bool destroy = false;

    public GameObject gameObject{get;set;}
    public Transform transform{get;set;}
    public ISSActionCallback callBack{get;set;}

    public virtual void Start()
    {
        throw new System.NotImplementedException();
    }

    public virtual void Update()
    {
        throw new System.NotImplementedException();
    }
}

public interface ISSActionCallback
{
    void SSActionEvent(SSAction action);
}

public class SSMoveToAction : SSAction
{
    public Vector3 target;
    public float speed;

    private SSMoveToAction() { }
    public static SSMoveToAction GetSSAction(Vector3 target, float speed)
    {
        SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();
        action.target = target;
        action.speed = speed;
        return action;
    }

    public override void Update()
    {
        this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
        if (this.transform.position == target)
        {
            this.destroy = true;
            this.callBack.SSActionEvent(this);
        }
    }

    public override void Start()
    {
        
    }
}

public class CCSequenceAction : SSAction, ISSActionCallback
{
    public List<SSAction> sequence; 
    public int repeat = -1;
    public int start = 0;

    public static CCSequenceAction GetSSAcition(int repeat, int start, List<SSAction> sequence)
    {
        CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();
        action.repeat = repeat;
        action.sequence = sequence;
        action.start = start;
        return action;
    }

    public override void Update()
    {
        if (sequence.Count == 0) return;
        if (start < sequence.Count)
        {
            sequence[start].Update();
        }
    }

    public void SSActionEvent(SSAction action)
    {
        action.destroy = false;
        this.start++;
        if (this.start >= sequence.Count)
        {
            this.start = 0;
            if (repeat > 0) repeat--;
            if (repeat == 0)
            {
                this.destroy = true;
                this.callBack.SSActionEvent(this);
            }
        }
    }

    public override void Start()
    {
        foreach (SSAction action in sequence)
        {
            action.gameObject = this.gameObject;
            action.transform = this.transform;
            action.callBack = this;
            action.Start();
        }
    }

    void OnDestroy()
    {
        foreach (SSAction action in sequence)
        {
            Destroy(action);
        }
    }
}

public class SSActionManager : MonoBehaviour
{
    private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
    private List<SSAction> waitingForAdd = new List<SSAction>();
    private List<int> waitingForDelete = new List<int>();

    protected void Update()
    {
        foreach (SSAction action in waitingForAdd)
        {
            actions[action.GetInstanceID()] = action;
        }
        
        waitingForAdd.Clear();

        foreach (KeyValuePair<int,SSAction> pair in actions)
        {
            SSAction action = pair.Value;
            if (action.destroy)
            {
                waitingForDelete.Add(action.GetInstanceID());
            } else if (action.enable)
            {
                action.Update();
            }
        }

        foreach (int key in waitingForDelete)
        {
            SSAction action = actions[key];
            actions.Remove(key);
            Destroy(action);
        }
        
        waitingForDelete.Clear();
    }

    public void RunAction(GameObject gameObject, SSAction action, ISSActionCallback callback)
    {
        action.gameObject = gameObject;
        action.transform = gameObject.transform;
        action.callBack = callback;
        
        waitingForAdd.Add(action);
        action.Start();
    }

}
动作管理器的UML设计图
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值