【游戏开发】unity教程6 巡逻兵小游戏

github传送门:https://github.com/dongzizhu/unity3DLearning/tree/master/hw6/Patrol

视频传送门:https://space.bilibili.com/472759319

要求

  • 游戏设计要求:
    • 创建一个地图和若干巡逻兵(使用动画);
    • 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址。即每次确定下一个目标位置,用自己当前位置为原点计算;
    • 巡逻兵碰撞到障碍物,则会自动选下一个点为目标;
    • 巡逻兵在设定范围内感知到玩家,会自动追击玩家;
    • 失去玩家目标后,继续巡逻;
    • 计分:玩家每次甩掉一个巡逻兵计一分,与巡逻兵碰撞游戏结束;
  • 程序设计要求:
    • 必须使用订阅与发布模式传消息
      • subject:OnLostGoal
      • Publisher: ?
      • Subscriber: ?
    • 工厂模式生产巡逻兵

 

订阅与发布模式

为什么需要订阅与发布模式

就像我们订阅报刊,有什么时事新闻出现,报社(发布者)可以第一时间印刷数百份乃至数千份报纸(传播媒介),发到各个订阅了该报纸的人(订阅者)手上,这样就完成了信息传播。

与观察者模式的区别

在观察者模式中,观察者需要直接订阅目标事件;在目标发出内容改变的事件后,直接接收事件并作出响应,往往发布者需要对所有的观察者维持一个列表,从而在每次发生变化时通知所有观察者。在发布订阅模式中,发布者和订阅者之间多了一个发布通道;一方面从发布者接收事件,另一方面向订阅者发布事件;订阅者需要从事件通道订阅事件,以此避免发布者和订阅者之间产生依赖关系,从而降低代码的耦合性。

在本次游戏中的应用

我们通过订阅与发布模式,让巡逻兵将自己的状态传递展示出来,然后由EventManager观察并做出反应。

 

代码

其他的模式如工厂模式产生士兵,以及MVC架构这里就不再赘述了,感兴趣的读者可以看之前的博客。

这里主要讲一下订阅与发布的模式以及巡逻兵的行动逻辑。

    void Update () {
		//Debug.Log("here1");
        if (Vector3.Distance(gameStatusOp.getHeroPosition().position, gameObject.transform.position) <= 10f)
        {   
            if (!isCatching)
            {
                isCatching = true;                
            }
            
            addAction.addDirectMovement(this.gameObject);
        }
        else
        {
            if (isCatching)
            {
                //stop catching 
                gameStatusOp.heroEscapeAndScore();
                isCatching = false;
				addAction.addRandomMovement(this.gameObject, false);     
				        
            }
            else
				addAction.addRandomMovement(this.gameObject, true);        
        }
    }

在PatrolControl中,如果hero出现在当前patrol的附近,那么开始追逐;如果hero离开了,那么停止追逐,同时将hero逃跑的信息通过firstController也就是之类的gameStatusOp发布。然后在决定当前状态后,和之前一样(MVC模式),调用actionManager来控制移动。

void OnCollisionStay(Collision e)
    {
        if (e.gameObject.name.Contains("Patrol"))
        {
            isCatching = false;
            addAction.addRandomMovement(this.gameObject, false);
            gameStatusOp.heroEscapeAndScore();
        }

        if (e.gameObject.name.Contains("hero"))
        {
            gameStatusOp.patrolHitHeroAndGameover();
            Debug.Log("Game Over!");
        }
    }

当与物体相撞时,如果是和其他巡逻兵撞在一起,那么同样停止追逐,同时发布逃跑状态;如果撞到了hero,则发布游戏结束的状态。

public class GameEventManager : MonoBehaviour {
    public delegate void GameScoreAction();
    public static event GameScoreAction myGameScoreAction;

    public delegate void GameOverAction();
    public static event GameOverAction myGameOverAction;

    private FirstControl scene;

    void Start () {
        scene = (FirstControl)Director.getInstance().sceneCtrl;
        scene.gameEventManager = this;
    }
	
	void Update () {
		
	}

    //hero escape
    public void heroEscapeAndScore() {
        if (myGameScoreAction != null)
            myGameScoreAction();
    }

    //hero gets caught
    public void patrolHitHeroAndGameover() {
        if (myGameOverAction != null)
            myGameOverAction();
    }
}

而每次发布的状态都有eventManager订阅,在被调用相应的函数后实现对游戏状态和分数的调整。

至于巡逻兵的巡逻轨迹则主要由下一个方向决定。我将每个巡逻兵上一次行动的方向保存在PatrolLastDir中,将行动的距离保存在PatrolMoveLength中,然后在非追逐状态下,巡逻兵会走一个一定距离的矩形。

int getRandomDirection(int index, bool isActive) {
        int randomDir;
		
		if (!isActive) {    
            if(PatrolLastDir[index] < 2)
				randomDir = PatrolLastDir[index] + 1;
			else
				randomDir = -1;
			PatrolLastDir[index] = randomDir;
			PatrolMoveLength[index] = 0;
        }
        else {              
			PatrolMoveLength[index]++;
			Debug.Log(PatrolMoveLength[index]);
			if(PatrolMoveLength[index] > 1000f){
				if(PatrolLastDir[index] < 2)
					randomDir = PatrolLastDir[index] + 1;
				else
					randomDir = -1;
				PatrolLastDir[index] = randomDir;
				PatrolMoveLength[index] = 0;
			}
			else{
				randomDir = PatrolLastDir[index];
			}	
				
        }
        return randomDir;
    }

其他具体的代码就不贴上来了,感兴趣的请移步github。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值