• 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则是移动这个动作的实体。

     在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上。点击运行即可

  • 相关阅读:
    TWinControl、TCustomControl和TGraphicControl对WM_PAINT消息的三种不同处理(虚函数的特点就是升升降降)
    VCL里的构造函数
    从良难
    TTimer源码研究
    Delphi的RTTI(许多参考链接)
    对ShortCut和TWMKey的研究
    TTimer很特殊
    TEdit的创建与显示过程
    VMware vSphere 服务器虚拟化之二十六 桌面虚拟化之View Persona Management
    Delphi Math里的基本函数,以及浮点数比较函数
  • 原文地址:https://www.cnblogs.com/LC32/p/15424201.html
Copyright © 2020-2023  润新知