Unity3D小游戏——牧师与魔鬼(动作分离版)

本篇博客是对https://www.cnblogs.com/LC32/p/15420714.html代码的进一步改进。

1.增加裁判

首先创建一个JudgeController作为裁判类,并且要求裁判需要通过导演才能得到对应的场景控制器。把原来写在FirstController中的GetAndSetGameState函数迁移到裁判类中,形成了裁判类的UpdateGameState方法。原来的场景控制器FirstController需要在Awake和初始化函数中初始化一个裁判类。将原来调用GetAndSetGameState函数的地方修改成请求裁判类裁决。修改后裁判类的代码如下

public class JudgeController{

    FirstController firstCtrl;

    public JudgeController(){
        firstCtrl = SSDirector.GetInstance().CurrentSceneController as FirstController;
    }

    //判断游戏状态
    public int UpdadeGameState(){
        if(firstCtrl.gameState != FirstController.PLAYING) return firstCtrl.gameState;
        //判断是否失败
        int[,] rolePos = new int[2, 3]{{0, 0, 0}, {0, 0, 0}};
        foreach(RoleController r in firstCtrl.RoleCtrl){
            rolePos[r.roleType, r.roleState]++;
        }
        if((rolePos[0,0]>0 && rolePos[0,0]<rolePos[1,0]) || 
           (rolePos[0,1]>0 && rolePos[0,1]<rolePos[1,1]) || 
           (rolePos[0,2]>0 && rolePos[0,2] < rolePos[1,2])){
            return FirstController.FAILED;
        }  
        //判断是否成功
        foreach(RoleController r in firstCtrl.RoleCtrl){
            if(r.roleType == 0 && r.roleState != FirstController.RIGHTLAND){
                return FirstController.PLAYING; 
            }
        }
        return FirstController.WIN;
    }
}

2.动作分离

在上一篇文章中,游戏对象的移动由MoveController和Move共同管理,这样做的坏处是在FirstController中仍然保留有一小部分的用于管理对象运动的代码。在动作分离版的代码中,管理动作的代码被分解成以下三部分,CCActionManager用于管理所有动作,CCMoveAction用于管理“移动”这种动作,特殊的是在这个游戏中只有移动这个动作。Move则是移动这个动作的实体。

Unity3D小游戏——牧师与魔鬼(动作分离版)

 

 在CCActionManager中主要实现了MoveRole()和MoveBoat()两个函数。通过调用CCMoveAction中的MoveTo和MoveSeqcenceTo来实现两种不同形式的移动效果。

public class CCActionManager
{
    public CCMoveAction moveBoatAction;
    public CCMoveAction moveRoleAction;

    public FirstController controller;

    public CCActionManager(){
        controller = SSDirector.GetInstance().CurrentSceneController as FirstController;
        controller.actionManager = this;

        moveBoatAction = new CCMoveAction();
        moveRoleAction = new CCMoveAction();
    }


    public bool IsMoving(){
        return moveRoleAction.IsMoving() || moveBoatAction.IsMoving();
    }


    public void MoveRole(BoatController BoatCtrl, RoleController RoleCtrl, int destination, int seat){
        Vector3 finalPos;
        if(destination == FirstController.RIGHTLAND){
            finalPos = Position.roleRightPos[seat];
        }
        else if(destination == FirstController.LEFTLAND){
            finalPos = Position.roleLeftPos[seat];
        }
        else{
            if(BoatCtrl.onLeftside){
                finalPos = Position.seatLeftPos[seat];
            }
            else{
                finalPos = Position.seatRightPos[seat];
            }
        }
        moveRoleAction.MoveSequenceTo(RoleCtrl.GetModelGameObject(), finalPos);

    }


    public void MoveBoat(BoatController BoatCtrl, int destination){
        if(destination == FirstController.RIGHTLAND){
            moveBoatAction.MoveTo(BoatCtrl.GetModelGameObject(), Position.boatRightPos);
            for(int i = 0; i < 3; i++){
                if(BoatCtrl.seat[i] != -1){
                    RoleController r = controller.RoleCtrl[controller.IDToNumber(BoatCtrl.seat[i])];
                    moveRoleAction.MoveTo(r.GetModelGameObject(), Position.seatRightPos[i]);
                }
            }
        }
        else{
            moveBoatAction.MoveTo(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);
            for(int i = 0; i < 3; i++){
                if(BoatCtrl.seat[i] != -1){
                    RoleController r = controller.RoleCtrl[controller.IDToNumber(BoatCtrl.seat[i])];
                    moveRoleAction.MoveTo(r.GetModelGameObject(), Position.seatLeftPos[i]);
                }
            }
        }
    }
}

而CCMoveAction最主要做的事情是给特定的gameobject添加Move脚本并且设置脚本的属性

public class CCMoveAction
{
    GameObject moveObject;
    
    public bool IsMoving(){
        return(this.moveObject != null && this.moveObject.GetComponent<Move>().isMoving == true);
    }

    public void MoveTo(GameObject moveObject, Vector3 destination){
        Move test;
        this.moveObject = moveObject;
        if (!moveObject.TryGetComponent<Move>(out test)) {
            moveObject.AddComponent<Move>();
        }
        this.moveObject.GetComponent<Move>().moveAction = this;
        this.moveObject.GetComponent<Move>().destination = destination;
        this.moveObject.GetComponent<Move>().moveMode = Move.single;

    }

    public void MoveSequenceTo(GameObject moveObject, Vector3 destination){
        Move test;
        this.moveObject = moveObject;
        if (!moveObject.TryGetComponent<Move>(out test)) {
            moveObject.AddComponent<Move>();
        }
        this.moveObject.GetComponent<Move>().moveAction = this;
        this.moveObject.GetComponent<Move>().destination = destination;
        this.moveObject.GetComponent<Move>().moveMode = Move.sequence;
    }
}

Move相比上一版的改动主要在实现了多段移动。主要是拿一个数组存起所有移动阶段的目的地。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move : MonoBehaviour
{
    public static int single = 0;
    public static int sequence = 1;


    public bool isMoving;
    bool initialized;
    public int moveMode;
    public bool doneMoving;

    public float speed = 5;


    int n_seq;
    public Vector3[] desseq;
    public Vector3 destination;
    public CCMoveAction moveAction;


    public Move(){
        n_seq = 0;
        isMoving = false;
        initialized = false;
        moveMode = -1;
    }

    void Update()
    {
        if(moveMode == -1) return;
        if(!initialized){
            if(moveMode == single){
                desseq = new Vector3[1];
                desseq[0] = destination;
            }
            else if(moveMode == sequence){
                desseq = new Vector3[3];
                desseq[0] = transform.localPosition + new Vector3(0, 1, 0);
                desseq[1] = destination + new Vector3(0, 1, 0);
                desseq[2] = destination;
            }
            else{
                Debug.Log("ERROR!");
            }
            initialized = true;
        }     
        isMoving = true;
        if(n_seq >= desseq.Length){
            n_seq = 0;
            moveMode = -1;
            initialized = false;
            isMoving = false;
            return;
        }
        if(transform.localPosition == desseq[n_seq]){
            n_seq += 1;
            return;
        }
        transform.localPosition = Vector3.MoveTowards(transform.localPosition, desseq[n_seq], speed * Time.deltaTime);
    }
}

演示视频:https://www.bilibili.com/video/BV17v41137s1?spm_id_from=333.999.0.0

代码:https://gitee.com/GallonC/unityhomework/tree/master/homework3/Assets

运行方式:与上一版本完全相同,将链接中的Asset文件替换为Unity中一个新3D项目的Asset项目。将View中的UserGUI挂到主相机上,将FirstController挂到一个新创建的GameObject上。点击运行即可

上一篇:SAP ABAP异步调用出错记录


下一篇:rsync基础