Unity 3D 游戏编程设计g07

项目结构:

 

 

Control/Action/FollowAction

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

public class FollowAction : SSAction
{
    private float speed = 2f;            //跟随玩家的速度
    private GameObject player;           //玩家
    private PatrolData data;             //侦查兵数据

    private FollowAction() { }
    public static FollowAction GetSSAction(GameObject player)
    {
        FollowAction action = CreateInstance<FollowAction>();
        action.player = player;
        return action;
    }

    public override void Update()
    {
        //防止碰撞发生后的旋转
        if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0)
        {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
        }
        if (transform.position.y != 0)
        {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
        }

        Follow();

        //如果侦察兵没有跟随对象,或者需要跟随的玩家不在侦查兵的区域内
        if (data.wallSign != data.sign)
        {
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this, 1, this.gameobject);
        }
    }
    public override void Start()
    {
        data = this.gameobject.GetComponent<PatrolData>();
    }
    void Follow()
    {
        this.transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);
        this.transform.LookAt(player.transform.position);
    }
}

Control/Action/PatrolAction

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

public class PatrolAction : SSAction
{
    private enum Dirction { EAST, NORTH, WEST, SOUTH };
    private float posX, posZ;                 //移动前的初始x和z方向坐标
    private float moveLength;                  //移动的长度
    private float moveSpeed = 1.2f;            //移动速度
    private bool moveSign = true;              //是否到达目的地
    private Dirction dirction = Dirction.WEST;  //移动的方向
    private PatrolData data;                    //侦察兵的数据


    private PatrolAction() { }                      

    public static PatrolAction GetSSAction(Vector3 location)
    {
        PatrolAction action = CreateInstance<PatrolAction>();
        action.posX = location.x;
        action.posZ = location.z;

        //设定移动矩形的边长
        action.moveLength = Random.Range(3, 3);
        return action;
    }

    public override void Start()
    {
        this.gameobject.GetComponent<Animator>().enabled = true;
        data = this.gameobject.GetComponent<PatrolData>();
    }

    public override void Update()
    {
        //防止碰撞发生后的旋转
        if (transform.localEulerAngles.x != 0 || transform.localEulerAngles.z != 0)
        {
            transform.localEulerAngles = new Vector3(0, transform.localEulerAngles.y, 0);
        }
        if (transform.position.y != 0)
        {
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);
        }

        //如果侦察兵需要跟随玩家并且玩家就在侦察兵所在的区域,侦查动作结束
        if (data.wallSign == data.sign)    //由事件触发
        {
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this, 0, this.gameobject);
        }
        else
        {
            Patrol();
        }
    }
    

    private void Patrol()
    {
        if (moveSign)
        {
            //不需要转向则设定一个目的地,按照矩形移动
            switch (dirction)
            {
                case Dirction.EAST:
                    posX -= moveLength;
                    break;
                case Dirction.NORTH:
                    posZ += moveLength;
                    break;
                case Dirction.WEST:
                    posX += moveLength;
                    break;
                case Dirction.SOUTH:
                    posZ -= moveLength;
                    break;
            }
            moveSign = false;
        }
        this.transform.LookAt(new Vector3(posX, 0, posZ));
        float distance = Vector3.Distance(transform.position, new Vector3(posX, 0, posZ));

        //当前位置与目的地距离浮点数的比较决定是否转向
        if (distance > 0.9)
        {
            transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(posX, 0, posZ), moveSpeed * Time.deltaTime);
        }
        else
        {
            dirction = dirction + 1;
            if (dirction > Dirction.SOUTH)
            {
                dirction = Dirction.EAST;
            }
            moveSign = true;
        }
    }
}

Control/Action/SSAction

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

public class SSAction : ScriptableObject            //动作
{

    public bool enable = true;                      //是否正在进行此动作
    public bool destroy = false;                    //是否需要被销毁

    public GameObject gameobject;                   //动作对象
    public Transform transform;                     //动作对象的transform
    public ISSActionCallback callback;              //回调函数

    protected SSAction() { }                        //保证SSAction不会被new

    //子类可以使用下面的函数
    public virtual void Start()                    
    {
        throw new System.NotImplementedException();
    }

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

    public void Reset()
    {
        enable = false;
        destroy = false;
        gameobject = null;
        transform = null;
        callback = null;
    }
}

Control/Action/SSActionManager

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

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>();                              //等待删除的动作的key                

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

        foreach (KeyValuePair<int, SSAction> kv in actions)
        {
            SSAction ac = kv.Value;
            if (ac.destroy)
            {
                waitingDelete.Add(ac.GetInstanceID());
            }
            else if (ac.enable)
            {
                //运动学运动更新
                ac.Update();
            }
        }

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

    public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager)
    {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();
    }

    public void SSActionEvent(SSAction source, int intParam = 0, GameObject objectParam = null)
    {
        if (intParam == 0)
        {
            //侦查兵跟随玩家

            FollowAction follow = FollowAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().player);
            this.RunAction(objectParam, follow, this);
        }
        else
        {
            //侦察兵按照初始位置开始继续巡逻
            PatrolAction move = PatrolAction.GetSSAction(objectParam.gameObject.GetComponent<PatrolData>().startPosition);
            this.RunAction(objectParam, move, this);
            //玩家逃脱
            Singleton<GameEventManager>.Instance.Escape();
        }
    }


    public void DestroyAll()
    {
        foreach (KeyValuePair<int, SSAction> kv in actions)
        {
            SSAction ac = kv.Value;
            ac.destroy = true;
        }
    }
}

Control/Event/GameEventManager

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

public class GameEventManager : MonoBehaviour
{
    //分数变化
    public delegate void ScoreEvent();
    public static event ScoreEvent ScoreChange;
    //游戏结束变化
    public delegate void GameoverEvent();
    public static event GameoverEvent GameoverChange;

    //玩家逃脱
    public void Escape()
    {
        if (ScoreChange != null)
        {
            ScoreChange();  //玩家逃脱则加一分
        }
    }
    //玩家被捕
    public void Gameover()
    {
        if (GameoverChange != null)
        {
            GameoverChange();   //玩家被捕即游戏结束
        }
    }
}

Control/Event/PlayerCollide

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

public class PlayerCollide : MonoBehaviour
{
    void OnCollisionEnter(Collision other)
    {
        //当玩家与巡逻兵相撞
        if (other.gameObject.tag == "Player")
        {
            //游戏结束,发布消息
            Singleton<GameEventManager>.Instance.Gameover();
        }
    }
}

Control/FirstController

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

public class FirstController : MonoBehaviour, IUserAction, ISceneController
{
    public PatrolFactory patrolFactory;                               //巡逻者工厂
    public ScoreRecorder scoreRecorder;                               //记分员
    public PatrolActionManager actionManager;                         //动作管理器
    public UserGUI userGUI;                                           //用户图形界面
    public GameObject player;                                         //玩家
    public List<GameObject> patrols;                                  //巡逻兵队列

    private GameState gameState;                                      //游戏状态
    private readonly float playerSpeed = 5;                           //玩家移动速度

    void Start()
    {
        SSDirector director = SSDirector.GetInstance();
        director.CurrentScenceController = this;
        patrolFactory = Singleton<PatrolFactory>.Instance;
        actionManager = gameObject.AddComponent<PatrolActionManager>() as PatrolActionManager;
        userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;
        LoadResources();
        scoreRecorder = Singleton<ScoreRecorder>.Instance;
    }

    void Update()
    {
        int wallSign = 0;
        if (player.transform.position.x < -1 && player.transform.position.z > 1)
            wallSign = 3;
        if (player.transform.position.x > 1 && player.transform.position.z > 1)
            wallSign = 1;
        if (player.transform.position.x < -1 && player.transform.position.z < -1)
            wallSign = 4;
        if (player.transform.position.x > 1 && player.transform.position.z < -1)
            wallSign = 2;

        for (int i = 0; i < patrols.Count; i++)
        {
            patrols[i].gameObject.GetComponent<PatrolData>().wallSign = wallSign;
        }
        if (wallSign != 0)
            patrols[wallSign - 1].gameObject.GetComponent<PatrolData>().player = player;
    }

    public void LoadResources()
    {
        Instantiate(Resources.Load<GameObject>("Prefabs/Plane"));
        player = Instantiate(Resources.Load("Prefabs/player"), new Vector3(0, 0, -4), Quaternion.identity) as GameObject;
        player.GetComponent<Animator>().enabled = false;
        patrols = patrolFactory.GetPatrols();

        
        for (int i = 0; i < patrols.Count; i++)
        {
            patrols[i].GetComponent<Animator>().enabled = false;
        }        
    }

    //用户接口
    public void MovePlayer(float translationX, float translationZ)
    {
        //实际上移动玩家这个任务应该交给动作管理器完成,这里由于玩家动作简单,所以为了简化代码,就交给场景管理器代劳
        if (translationX != 0 || translationZ != 0)
        {
            player.GetComponent<Animator>().enabled = true;

            if (translationZ > 0)
            {
                player.transform.localEulerAngles = new Vector3(0, 0, 0);
                player.transform.Translate(0, 0, translationZ * playerSpeed * Time.deltaTime);
            }
            if (translationZ < 0)
            {
                player.transform.localEulerAngles = new Vector3(0, 180, 0);
                player.transform.Translate(0, 0, -translationZ * playerSpeed * Time.deltaTime);
            }
            if (translationX > 0.45)
            {
                player.transform.localEulerAngles = new Vector3(0, 90, 0);
                player.transform.Translate(0, 0, translationX * playerSpeed * Time.deltaTime);
            }
            if (translationX < -0.45)
            {
                player.transform.localEulerAngles = new Vector3(0, -90, 0);
                player.transform.Translate(0, 0, -translationX * playerSpeed * Time.deltaTime);
            }         
        }
        else
        {
            player.GetComponent<Animator>().enabled = false;
            player.transform.localEulerAngles = new Vector3(0, player.transform.localEulerAngles.y, 0);
        }

        //防止碰撞带来的移动
        if (player.transform.localEulerAngles.x != 0 || player.transform.localEulerAngles.z != 0)
        {
            player.transform.localEulerAngles = new Vector3(0, player.transform.localEulerAngles.y, 0);
        }
        if (player.transform.position.y != 0)
        {
            player.transform.position = new Vector3(player.transform.position.x, 0, player.transform.position.z);
        }
    }

    public void GameStart()
    {
        for (int i = 0; i < patrols.Count; i++)
        {
            actionManager.Patrol(patrols[i]);
            patrols[i].GetComponent<Animator>().enabled = true;
        }
    }

    public void Restart()
    {
        gameState = GameState.RUNNING;
        scoreRecorder.Reset();
        player.transform.position = new Vector3(0, 0, -4);
        player.transform.localEulerAngles = new Vector3(0, 0, 0);

        int[] pos_x = { 1, -4 };
        int[] pos_z = { 4, -1 };
        Vector3[] position = new Vector3[9];
        int index = 0;
        //生成不同的巡逻兵初始位置
        for (int i = 0; i < 2; i++)
        {
            for (int j = 0; j < 2; j++)
            {
                position[index] = new Vector3(pos_x[i], 0, pos_z[j]);
                index++;
            }
        }
        for (int i = 0; i < patrols.Count; i++)
        {
            patrols[i].transform.position = position[i]; 
        }
        

        GameStart();
    }

    //订阅者模式
    void OnEnable()
    {
        GameEventManager.ScoreChange += AddScore;
        GameEventManager.GameoverChange += Gameover;
    }



    void OnDisable()
    {
        GameEventManager.ScoreChange -= AddScore;
        GameEventManager.GameoverChange -= Gameover;
    }

    private void AddScore()
    {
        scoreRecorder.Add();
    }

    private void Gameover()
    {
        this.gameState = GameState.OVER;
        player.GetComponent<Animator>().enabled = false;
        for (int i = 0; i < patrols.Count; i++)
        {
            patrols[i].GetComponent<Animator>().enabled = false;
        }
        actionManager.DestroyAll();
    }

    public GameState GetGameState()
    {
        return gameState;
    }

    public int GetScore()
    {
        return scoreRecorder.score;
    }

    public void SetGameState(GameState gameState)
    {
        this.gameState = gameState;
    }

}

Control/SSDirector

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

public class SSDirector : System.Object
{
    //singlton instance
    private static SSDirector _instance;

    public ISceneController CurrentScenceController { get; set; }

    //get instance
    public static SSDirector GetInstance()
    {
        if (_instance == null)
        {
            _instance = new SSDirector();
        }
        return _instance;
    }
}

Model/PatrolFactory

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

public class PatrolFactory : MonoBehaviour
{
    private GameObject patrol = null;                              //巡逻兵
    private List<GameObject> used = new List<GameObject>();        //正在被使用的巡逻兵,该游戏巡逻兵不需要回收,所以不需要free表
    private Vector3[] position = new Vector3[9];                   //保存每个巡逻兵的初始位置

    public FirstController sceneControler;                         //场景控制器

    public List<GameObject> GetPatrols()
    {
        int[] pos_x = { 1, -4};
        int[] pos_z = { 4, -1};
        int index = 0;
        //生成不同的巡逻兵初始位置
        for (int i = 0; i < 2; i++)
        {
            for (int j = 0; j < 2; j++)
            {
                position[index] = new Vector3(pos_x[i], 0, pos_z[j]);
                index++;
            }
        }
        for (int i = 0; i < 4; i++)
        {
            patrol = Instantiate(Resources.Load<GameObject>("Prefabs/zombie"));
            patrol.transform.position = position[i];
            patrol.AddComponent<PatrolData>();
            patrol.GetComponent<PatrolData>().sign = i + 1;
            patrol.GetComponent<PatrolData>().startPosition = position[i];
            used.Add(patrol);
        }
        return used;
    }

    public void StopPatrol()
    {
        //切换所有侦查兵的动画
        for (int i = 0; i < used.Count; i++)
        {
            used[i].gameObject.GetComponent<Animator>().SetBool("run", false);
        }
    }
}

Model/Singleton

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

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));
                if (instance == null)
                {
                    Debug.LogError("An instance of " + typeof(T)
                        + " is needed in the scene, but there is none.");
                }
            }
            return instance;
        }
    }
}

效果展示:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值