Unity3d-巡逻兵游戏

  • 游戏内容参照这里
  • 这里我的游戏基本框架参照MokHoYin的博客,细节方面有些不同
  • 游戏效果展示:方块代表巡逻兵,圆球代表玩家,其中巡逻兵在自己对应的矩形中巡逻。

  • 部分代码    
  1. GameModel.cs   
这里定义的游戏对象PatrolInstance,PlayerInstance,backgroundInstance,uiInstance是我们做好的预制,分别用来实例化巡逻兵、玩家、背景以及UI。在实现巡逻兵的巡逻时,每次都让巡逻兵往向一个方向移动随机的距离。若撞到围栏或者这段距离移动结束,就转一个方向继续巡逻。每次Update时都要检测玩家在哪个区域上,一方面好通知这一区域的巡逻兵去追逐玩家,另一方面,若是玩家逃离了一个巡逻兵的追逐,则可以让玩家得分。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Patrols;

public class GameModel : SSActionManager, ISSActionCallback {
	//运行之前将预制拖入这些属性中
    public GameObject PatrolInstance, PlayerInstance, backgroundInstance, uiInstance;

    private SceneController scene;
    private GameObject zyzPlayer, background, gameText;
	//巡逻兵对象列表
    private List<GameObject> PatrolList;
	//巡逻兵巡逻的方向
    private List<int> PatrolDirection;
	//巡逻兵的巡逻速度
    private const float NORMAL_SPEED = 0.5f;
	//巡逻兵追逐玩家时的速度
    private const float CHASING_SPEED = 0.7f;

    void Awake() {
		//用一个预制初始化工厂中用于生产巡逻兵的对象
        PatrolFactory.getInstance().initPatrolInatance(PatrolInstance);
    }

    protected new void Start () {
        scene = SceneController.getInstance();
        scene.setGameModel(this);
		//生产玩家(同样是用之前做好的预制)
        createPlayer();
		//用工厂制作6个巡逻兵
        createPatrols();
		//背景
        background = Instantiate(backgroundInstance);
        gameText = Instantiate(uiInstance);
    }

    protected new void Update() {
        base.Update();
    }

    void createPlayer() {
        zyzPlayer = Instantiate(PlayerInstance);
    }

    void createPatrols() {
        PatrolList = new List<GameObject>(6);
        PatrolDirection = new List<int>(6);
        Vector3[] locations = PatrolFactory.getInstance().getPatrolLocations();
        for (int i = 0; i < 6; i++) {
			//使用工厂模式初始化游戏对象
            GameObject newPatrol = PatrolFactory.getInstance().getPatrol();
            newPatrol.transform.position = locations[i];
            newPatrol.name = "Patrol" + i;
			//初始化巡逻方向为空
            PatrolDirection.Add(-2);
            PatrolList.Add(newPatrol);
			//开始让巡逻兵随机移动
            moveRandomly(newPatrol, true);
        }
    }

    //玩家的移动
    public void movePlayer(int dir) {
		//欧拉角直接旋转90度
        zyzPlayer.transform.rotation = Quaternion.Euler(new Vector3(0, dir * 90, 0));
		if (dir == Diretion.UP)
			zyzPlayer.transform.position += new Vector3(0, 0, 0.15f);
		else if (dir == Diretion.DOWN)
			zyzPlayer.transform.position += new Vector3(0, 0, -0.15f);
		else if (dir == Diretion.LEFT)
			zyzPlayer.transform.position += new Vector3(-0.15f, 0, 0);
		else if (dir == Diretion.RIGHT)
			zyzPlayer.transform.position += new Vector3(0.15f, 0, 0);
    }

	
    public void SSActionEvent(SSAction source, SSActionEventType eventType = SSActionEventType.Completed, 
        SSActiontargetPositionType intParam = SSActiontargetPositionType.Normal, string strParam = null, object objParam = null) {
        //若是正常模式下就随机巡逻
		if (intParam == SSActiontargetPositionType.Normal)
            moveRandomly(source.gameObject, true);
		//否则就追逐玩家
        else
            moveToPlayer(source.gameObject);
    }

    //isSelfTurn说明是否主动变向
    public void moveRandomly(GameObject gameObj, bool isSelfTurn) {
        int index = getIndex(gameObj);
        int moveDir = getmoveDirection(index, isSelfTurn);
        PatrolDirection[index] = moveDir;

        gameObj.transform.rotation = Quaternion.Euler(new Vector3(0, moveDir * 90, 0));
        Vector3 targetPosition = gameObj.transform.position;
        
		if (movedir == Diretion.UP)
            targetPosition += new Vector3(0, 0, 1);     
        else if (movedir == Diretion.DOWN)
            targetPosition += new Vector3(0, 0, -1);         
        else if (movedir == Diretion.LEFT)
            targetPosition += new Vector3(-1, 0, 0);       
        else if (movedir == Diretion.RIGHT)
            targetPosition += new Vector3(1, 0, 0);
           
        addSingleMoving(gameObj, targetPosition, NORMAL_SPEED, false);
    }
	
	//根据巡逻兵的名字判断巡逻兵的编号
    int getIndex(GameObject gameObj) {
        string name = gameObj.name;
        return name[name.Length - 1] - '0';
    }
	
	//获取巡逻兵的巡逻方向,isSelfTurn表明是正常换方向还是撞围栏的情况
    int getmoveDirection(int index, bool isSelfTurn) {
        int moveDir = Random.Range(-1, 3);
        //如果要碰到墙
		if (!isSelfTurn) {
			//不能走相同的方向并且不能迈出界限
            while (PatrolDirection[index] == moveDir || isPatrolOut(index, moveDir)) {
                moveDir = Random.Range(-1, 3);
            }
        }
		//如果是正常的换巡逻方向,下一时刻的巡逻方向不能相同或相反
        else {    
		    /*      0
			 *      |
			 * -1---|--- 1
			 *      |
			 *      2
			 *若两个方向相反且不等,则和为2或0
			 */
			int sumOfMovingDirection = PatrolDirection[index] + moveDir;
            while ( PatrolDirection[index] == moveDir || sumOfMovingDirection == 2 || sumOfMovingDirection == 0
                || isPatrolOut(index, moveDir)) {
                moveDir = Random.Range(-1, 3);
            }
        }
        
        return moveDir;
    }
	
    //判断巡逻兵是否走出了自己的区域
    bool isPatrolOut(int index, int moveDir) {
        Vector3 patrolPos = PatrolList[index].transform.position;
        float x = patrolPos.x;
        float z = patrolPos.z;
		
		bool falg = false;
       
		if  (index == 0 && (moveDir == 1 && x + 1 > FenchLocs.left
			    || moveDir == 2 && z - 1 < FenchLocs.center))
			flag = true;
		else if (index == 1 && (x + 1 > FenchLocs.right
				|| moveDir == -1 && x - 1 < FenchLocs.left
				|| moveDir == 2 && z - 1 < FenchLocs.center))
			flag = true;   
        else if (index == 2 && (moveDir == -1 && x - 1 < FenchLocs.right
			    || moveDir == 2 && z - 1 < FenchLocs.center))
			flag = true;
        else if (index == 3 && (moveDir == 1 && x + 1 > FenchLocs.left
                || moveDir == 0 && z + 1 > FenchLocs.center))
			flag = true;
        else if (index == 4 && (moveDir == 1 && x + 1 > FenchLocs.right
                || moveDir == -1 && x - 1 < FenchLocs.left
                || moveDir == 0 && z + 1 > FenchLocs.center))
            flag = true;   
        else if (moveDir == -1 && x - 1 < FenchLocs.right
                || moveDir == 0 && z + 1 > FenchLocs.center)
            flag = true;
          
        
        return flag;
    }

    //追逐玩家
    public void moveToPlayer(GameObject gameObj) {
		//追逐之前先将巡逻方向置为空
        int index = getIndex(gameObj);
        PatrolDirection[index] = -2;

        gameObj.transform.LookAt(gameObj.transform);
		//计算追逐的方向
        Vector3 chasingDirection = zyzPlayer.transform.position - gameObj.transform.position;
		//计算移动的目标位置
        Vector3 targetPosition = new Vector3(chasingDirection.x , 0, chasingDirection.z);
        targetPosition += gameObj.transform.position;
        this.runAction(gameObj, CCMoveToAction.GetSSAction(targetPosition, CHASING_SPEED, true), this);
    }

    //获取玩家所在的区域
    public int getPlayerArea() {
        return zyzPlayer.GetComponent<PlayerStatus>().whichArea;
    }
}

2. GameEventManager.cs

这一文件实现了订阅发布模式,首先定义委托,在后面我们将其实例化。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Patrols;

//实现发布订阅模式
public class GameEventManager : MonoBehaviour {
    public delegate void ScoreAction();
    public static event ScoreAction zyzScoreAction;

    public delegate void OverAction();
    public static event OverAction zyzOverAction;

    private SceneController scene;

    void Start () {
        scene = SceneController.getInstance();
        scene.setGameEventManager(this);
    }
	
	void Update () {
		
	}
	
	//玩家逃离追捕并得分
    public void playerScore() {
        if (zyzScoreAction != null)
            zyzScoreAction();
    }
	//巡逻兵追到玩家,游戏结束
    public void gameOver() {
        if (zyzOverAction != null)
            zyzOverAction();
    }
}

3.SceneController.cs

这里对于接口的实现主要依赖于GameModel以及GameEventManager的帮助

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

namespace Com.Patrols {
	//巡逻兵进行巡逻的方向
    public class Diretion {
		public const int LEFT = -1;
        public const int UP = 0;
		public const int RIGHT = 1;
        public const int DOWN = 2;
    }
	
	//围栏的位置,这里的地图中没有设置这些围栏,但是我们可以通过位置判断巡逻兵是否碰到
    public class FenchLocs {
        public const float center = 12f;
        public const float left = -3.0f;
        public const float right = 3.0f;
    }
	
	//玩家移动的接口
    public interface IUserAction {
        void movePlayer(int dir);
    }
	
	//巡逻兵的移动模式
    public interface PatrolMove {
        void moveRandomly(GameObject gameObj, bool isSelfTurn);
        void moveToPlayer(GameObject gameObj);
    }

    public interface GameStatus {
        int getPlayerArea();
        void playerScore();
        void gameOver();
    }

    public class SceneController : System.Object, IUserAction, PatrolMove, GameStatus {
        private static SceneController instance;
        private GameModel zyzGameModel;
        private GameEventManager zyzGameEventManager;

        public static SceneController getInstance() {
            if (instance == null)
                instance = new SceneController();
            return instance;
        }

        internal void setGameModel(GameModel zyzGameModel) {
            if (zyzGameModel == null) {
                zyzGameModel = zyzGameModel;
            }
        }

        internal void setGameEventManager(GameEventManager zyzGameEventManager) {
            if (zyzGameEventManager == null) {
                zyzGameEventManager = zyzGameEventManager;
            }
        }

        public void movePlayer(int dir) {
            zyzGameModel.movePlayer(dir);
        }

        public void moveRandomly(GameObject gameObj, bool isSelfTurn) {
            zyzGameModel.moveRandomly(gameObj, isSelfTurn);
        }

        public void moveToPlayer(GameObject gameObj) {
            zyzGameModel.moveToPlayer(gameObj);
        }

        public int getPlayerArea() {
            return zyzGameModel.getPlayerArea();
        }

        public void playerScore() {
            zyzGameEventManager.playerScore();
        }

        public void gameOver() {
            zyzGameEventManager.gameOver();
        }
    }
}

4.PatrolFactory.cs

使用工厂模式来生产个巡逻兵

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Patrols;

//工厂模式生成巡逻兵
namespace Com.Patrols {
    public class PatrolFactory : System.Object {
        private static PatrolFactory instance;
        private GameObject PatrolInstance;
		
		//巡逻兵的初始位置
        private Vector3[] PatrolLocations = new Vector3[] { new Vector3(-4, 0, 10), new Vector3(-1, 0, 10),
            new Vector3(4, 0, 10), new Vector3(-4, 0, 4), new Vector3(0, 0, 4), new Vector3(4, 0, 4)};
	
		//单例
        public static PatrolFactory getInstance() {
            if (instance == null)
                instance = new PatrolFactory();
            return instance;
        }
	
		//初始化用于生产的模具
        public void initPatrolInatance(GameObject PatrolInstance) {
            this.PatrolInstance = PatrolInstance;
        }
		
		
        public GameObject getPatrol() {
            GameObject newPatrol = Camera.Instantiate(PatrolInstance);
            return newPatrol;
        }

        public Vector3[] getPatrolLocations() {
            return PatrolLocations;
        }
    }
}

 
 

关键的代码大概如此,其余的代码可以参见我的github

猜你喜欢

转载自blog.csdn.net/zyz1234544/article/details/80286624