unity3d开发巡逻兵游戏

游戏规则:

* 创建一个地图和若干巡逻兵(使用动画);
* 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
* 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
* 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
* 失去玩家目标后,继续巡逻;

程序设计要求:

* 必须使用订阅与发布模式传消息
* 工厂模式生产巡逻兵

UML图
UML
游戏截图
效果图

代码实现
巡逻兵创建
  1. 给巡逻兵添加两个预制体, Box Collider和Capsule Collider, BoxCollider使用trigger检测player进入巡逻兵的范围,Capsule Collider用来检测player与巡逻兵的碰撞
  2. PatrolData:巡逻兵数据
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public enum Dir { down, right, up, left}
public class PatrolData : MonoBehaviour {

    // Use this for initialization
    //巡逻兵的路线为一个正方形
    public Vector3 startPostion; //巡逻的起始位置
    public Vector3 endPostion;//正方形对角线位置
    public int sideLength; //正方形边长
    public int dir = 0;
    public GameObject player; //玩家
    public int sign; //巡逻兵在哪一块区域
}

PatrolFactory创建巡逻兵的工厂

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

public class PatrolFactory : MonoBehaviour {
    private List<GameObject> patrols = new List<GameObject>();
    // Use this for initialization
    public List<GameObject> GetPatrols()
    {
        int rectLength; //正方形边长
        int[] pos_x = { 5, -2, -9 };
        int[] pos_z = { 5, -2, -9 };
        int index = 1;
        for (int i = 0; i < 3; ++i)
        {
            for (int j = 0; j < 3; ++j)
            {
                Vector3 startPostion = new Vector3(pos_x[i], 0, pos_z[j]);
                rectLength = UnityEngine.Random.Range(3, 5);
                Vector3 endPostion = new Vector3(pos_x[i] + rectLength, 0, pos_z[j] + rectLength);
                GameObject monster =  Instantiate(Resources.Load<GameObject>("Prefabs/Monster"));
                monster.transform.position = startPostion;
                PatrolData data =  monster.AddComponent<PatrolData>();
                data.startPostion = startPostion;
                data.endPostion = endPostion;
                data.sideLength = rectLength;
                data.sign = index;
                patrols.Add(monster);
                ++index;
            }
        }
        return patrols;
    }
}

巡逻兵追捕与巡逻动作
PatrolGoAction

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

public class PatrolGoAction : SSAction {

    private Vector3 start; //巡逻兵的起始位置
    private Vector3 end;//巡逻兵起始位置的正方形对角线位置
    private Vector3 next;
    private int dir; //方向:0 x+, 1:z+, 2:x-,3:z-
    // Use this for initialization

   public static SSAction getPatrolGoAction()
    {
        PatrolGoAction action = ScriptableObject.CreateInstance<PatrolGoAction>();
        return action;
    }
    public override void Start () {
        PatrolData data = gameObject.GetComponent<PatrolData>();
        dir = 0;
        start = data.startPostion;
        end = data.endPostion;
       // transform.localEulerAngles =new  Vector3(0, 90, 0);
        next = new Vector3(end.x,0,start.z);
        transform.LookAt(next);
        this.enable = true;
        this.distroy = false;
    }

    // Update is called once per frame
    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);
        }

        //移动
        transform.position = Vector3.MoveTowards(transform.position, next, Time.deltaTime * 2f);
        gameObject.GetComponent<Animator>().SetBool("walk", true);
        GameObject player = gameObject.GetComponent<PatrolData>().player;
        if (player !=null && player.GetComponent<PlayerData>().area == gameObject.GetComponent<PatrolData>().sign )
        {
            this.callback.SSActionEvent(this, 0, this.gameObject);
        }
        if (Vector3.Distance(transform.position, next) < 0.1)
        {
            dir = (dir + 1) % 4;
            if (dir == 1)
            {
                next = new Vector3(end.x, 0, end.z);
            }
            else if (dir == 2)
            {
                next = new Vector3(start.x, 0, end.z);
            }
            else if (dir == 3)
            {
                next = new Vector3(start.x, 0, start.z);
            }
            else
            {
                next = new Vector3(end.x, 0, start.z);
            }
            transform.LookAt(next);
        }
    }
}

PatrolFollowAction

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

public class PatrolFollowAction : SSAction {
    public GameObject player;
    // Use this for initialization
    public override void Start () {
        this.distroy = false;
        this.enable = true;
    }

    // Update is called once per frame
    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);
        }
        transform.LookAt(player.transform.position);
        transform.position = Vector3.MoveTowards(transform.position, player.transform.position, Time.deltaTime * 1.5f);
        gameObject.GetComponent<Animator>().SetBool("walk", true);
        player = gameObject.GetComponent<PatrolData>().player;
        if(player == null || player.GetComponent<PlayerData>().area != gameObject.GetComponent<PatrolData>().sign)
        {
            this.callback.SSActionEvent(this, 1, this.gameObject);
        }
    }
    public static SSAction GetPatrolFollowAction(GameObject player)
    {
        PatrolFollowAction action = ScriptableObject.CreateInstance<PatrolFollowAction>();
        action.player = player;
        return action;
    }
}

玩家数据

PlayerData

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

public class PlayerData : MonoBehaviour {

    public int area = 1; //玩家位于地图那一块区域
}
SSActionManager与PatrolActionManager

SSActionManager

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

public class SSActionManager : MonoBehaviour,ISSActionCallback {

    protected Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
    protected List<SSAction> waitingAdd = new List<SSAction>();
    protected List<int> waitingDelete = new List<int>();
    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.distroy)
            {

                waitingDelete.Add(ac.GetInstanceID());
            }
            else if (ac.enable)
            {
                ac.Update();
            }
        }
        foreach (int key in waitingDelete)
        {
            SSAction ac = actions[key];
            actions.Remove(key);
            DestroyObject(ac);
        }
        waitingDelete.Clear();
    }
    public void DestroyAllAction()
    {
        foreach (KeyValuePair<int, SSAction> kv in actions)
        {
            SSAction ac = kv.Value;
            ac.gameObject.GetComponent<Animator>().SetBool("walk", false);
            ac.distroy = true;
        }
    }
    public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager)
    {
        action.gameObject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();
    }

    protected void Start()
    {

    }

    public void SSActionEvent(SSAction source, int intParam = 0, GameObject objectParam = null)
    {
        if (intParam == 0)
        {
            //跟踪玩家
            source.distroy = true;
            GameObject player = objectParam.GetComponent<PatrolData>().player;
            SSAction follow= PatrolFollowAction.GetPatrolFollowAction(player);
            this.RunAction(objectParam,follow, this);
        }else if(intParam == 1) {
            //继续巡逻
            source.distroy = true;
            objectParam.GetComponent<PatrolData>().player = null;
            SSAction go = PatrolGoAction.getPatrolGoAction();
            this.RunAction(objectParam, go, this);
        }
    }
}

PatrolActionManager

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

public class PatrolActionManager : SSActionManager {

    // Use this for initialization
    public void StartGoAction(GameObject gameObject)
    {
        SSAction action = PatrolGoAction.getPatrolGoAction();
        this.RunAction(gameObject, action, this);
    }

}
事件发布器EventPublisher
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventPublisher : MonoBehaviour {
    //分数实践
    public delegate void ScoreEvent();
    public static event ScoreEvent ScoreAddEvent;

    public delegate void GameEvent();
    public static event GameEvent GameOverEvent;
    // Use this for initialization
    public void ScoreAdd()
    {
        if(ScoreAddEvent!=null)
        {
            ScoreAddEvent();
        }
    }

    public void GameOver()
    {
        if(GameOverEvent!=null)
        {
            GameOverEvent();
        }
    }
}
基本代码

FirstSceneController

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

public class FirstSceneController : MonoBehaviour, SceneController,IUserAction {
    private PatrolActionManager actionManger;
    public bool game_over;
    private ScoreRecorder recorder;
    private UserGUI userGUI;
    public EventPublisher publisher;
    public GameObject player;
    public GameObject map;
    private List<GameObject> patrolsList;
    public int area;
    public void loadResources()
    {
        map = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/map"));
        player = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/Player"));
        player.AddComponent<PlayerData>();
        actionManger = gameObject.AddComponent<PatrolActionManager>();
        recorder = gameObject.AddComponent<ScoreRecorder>();
        publisher = gameObject.AddComponent<EventPublisher>();
        userGUI = gameObject.AddComponent<UserGUI>();
        Director.getInstance().currentSceneController = this;
        PatrolFactory patrols = gameObject.AddComponent<PatrolFactory>();
        patrolsList = patrols.GetPatrols();
    }
    private void Awake()
    {
        loadResources();
    }
    public void StartGame()
    {
        for (int i = 0; i < patrolsList.Count; ++i)
        {
            actionManger.StartGoAction(patrolsList[i]);
        }
    }
    void Start () {

    }

    void Update () {
        player.GetComponent<PlayerData>().area = area;
    }
    private void OnEnable()
    {
        EventPublisher.ScoreAddEvent += AddScore;
        EventPublisher.GameOverEvent += GameOver;
    }
    public void MovePlayer()
    {
        if(!game_over)
        {
            float horizontal = Input.GetAxis("Horizontal"); //A D 左右
            float vertical = Input.GetAxis("Vertical"); //W S 上 下
            player.transform.Translate(Vector3.forward * vertical * 3 * Time.deltaTime);//W S 上 下
            if (vertical != 0)
            {
                player.GetComponent<Animator>().SetBool("run", true);
            }
            else
            {
                player.GetComponent<Animator>().SetBool("run", false);
            }

            player.transform.Rotate(0, horizontal * 50 * Time.deltaTime, 0);
        }

    }

    void AddScore()
    {
        recorder.addRecord();
    }

    void GameOver()
    {
        game_over = true;
        actionManger.DestroyAllAction();
    }

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

猜你喜欢

转载自blog.csdn.net/qq_36297981/article/details/80283975