Unity3D homework_7

Unity3D homework_7

智能巡逻兵

一、要求

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

二、制作

1、 动画状态机

  • 将所使用的动画都拖入人物动画器的Base Layer中,实现人物动作:

  • 按WASD进行行走和转向

  • 站立不动时按下空格后跳一小步,行走时按下空格向前翻滚

  • 奔跑时按下空格向前跳跃,在空中跳跃完成后下落,下落到地面时翻滚

  • 按SHIFT奔跑

人物模型使用的是YBoy的
在这里插入图片描述


2、Animator的状态图在这里插入图片描述
3、ground动画混合树
ground由站立,走路,奔跑三个动画组成,将这三个动画拖进来。
在这里插入图片描述
修改混合树名字和参数名字,在Motion中新增三个状态,并拖入如图所示的三个动画,并调整阈值。拖动红色标尺能看到动画的渐变。
在这里插入图片描述
创建过渡与参数控制

右键->创建过渡,将所有状态都连接起来。状态之间的过渡通过参数来控制。

使用的所有参数如下:
在这里插入图片描述
forward为Float,用于控制ground混合树中行走奔跑的过渡;

OnGround为Bool,表示模型是否在地面上;

jump为Trigger,用于控制跳跃和后跳;

roll为Trigger,用于控制翻滚;

jabVelocity为Float,表示后跳的速度;

rollVelocity为Float,表示翻滚的速度。

下面是一个从ground到jump的过渡例子:
在这里插入图片描述
还有更多细节就不一一赘述了

三、脚本

1、脚本结构
在这里插入图片描述
分为四个部分,分别管理动作,场景,守卫和玩家
我们挑重要的部分讲

2、守卫追人范围实现GuardActionManager
当每个圈圈的范围的intParam=0的时候,就开始追人。如果是其他值就继续安装原来的路径走。

public class GuardActionManager : SSActionManager, ISSActionCallback {
    private GuardPatrolAction patrol;
    private GameObject player;
    public void GuardPatrol(GameObject guard, GameObject _player) {
        player = _player;
        patrol = GuardPatrolAction.GetSSAction(guard.transform.position);
        this.RunAction(guard, patrol, this);
    }

    public void SSActionEvent(
        SSAction source, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, GameObject objectParam = null) {
        if (intParam == 0) {
            //追逐
            GuardFollowAction follow = GuardFollowAction.GetSSAction(player);
            this.RunAction(objectParam, follow, this);
        } else {
            //巡逻
            GuardPatrolAction move = GuardPatrolAction.GetSSAction(objectParam.gameObject.GetComponent<GuardData>().start_position);
            this.RunAction(objectParam, move, this);
            Singleton<GameEventManager>.Instance.PlayerEscape();
        }
    }
}

3、
追人启停机制,当脱离该区域时候,便继续巡逻。

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

public class GuardFollowAction : SSAction {
    private GameObject player;        
    private GuardData data;
    private Animator anim;
    private Rigidbody rigid;
    private Vector3 planarVec; // 平面移动向量
    private float speed;

    private GuardFollowAction() {}

    public override void Start() {
        data = gameobject.GetComponent<GuardData>();
        anim = gameobject.GetComponent<Animator>();
        rigid = gameobject.GetComponent<Rigidbody>();
        speed = data.runSpeed;
        anim.SetFloat("forward", 2.0f);
    }

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

    public override void Update() {
        //保留供物理引擎调用
        planarVec = gameobject.transform.forward * speed;
    }

    public override void FixedUpdate() {
        transform.LookAt(player.transform.position);
        rigid.velocity = new Vector3(planarVec.x, rigid.velocity.y, planarVec.z);
        
        //如果玩家脱离该区域则继续巡逻
        if (data.playerSign != data.sign) {
            this.destroy = true;
            this.callback.SSActionEvent(this, SSActionEventType.Competeted, 1, this.gameobject);
        }
    }
}

4、玩家控制
可以设置行走的速度,并且按下空格,自动播放跳跃或者翻滚的动画,并且还可以按下shift加速。

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

public class ActorController : MonoBehaviour {
    public GameObject model;
    public PlayerInput pi;
    public float walkSpeed = 1.5f;
    public float runMultiplier = 2.7f;
    public float jumpVelocity = 4f;
    public float rollVelocity = 1f;

    [SerializeField]
    private Animator anim;
    private Rigidbody rigid;
    private Vector3 planarVec; // 平面移动向量
    private Vector3 thrustVec; // 跳跃冲量

    private bool lockPlanar = false; // 跳跃时锁死平面移动向量

    void Awake() {
        pi = GetComponent<PlayerInput>();
        anim = model.GetComponent<Animator>();
        rigid = GetComponent<Rigidbody>();
    }

    //刷新每秒60次
    void Update() {
        //修改动画混合树
        /*1.从走路到跑步没有过渡*/
        /*anim.SetFloat("forward", pi.Dmag * (pi.run ? 2.0f : 1.0f));*/
        /*2.使用Lerp加权平均解决*/
        float targetRunMulti = pi.run ? 2.0f : 1.0f;
        anim.SetFloat("forward", pi.Dmag * Mathf.Lerp(anim.GetFloat("forward"), targetRunMulti, 0.3f));
        //播放翻滚动画
        if (rigid.velocity.magnitude > 1.0f) {
            anim.SetTrigger("roll");
        }
        //播放跳跃动画
        if (pi.jump) {
            anim.SetTrigger("jump");
        }
        
        //转向
        if(pi.Dmag > 0.01f) {
            /*1.旋转太快没有补帧*/
            /*model.transform.forward = pi.Dvec;*/
            /*2.使用Slerp内插值解决*/
            Vector3 targetForward = Vector3.Slerp(model.transform.forward, pi.Dvec, 0.2f);
            model.transform.forward = targetForward;
        }
        if(!lockPlanar) {
            //保存供物理引擎使用
            planarVec = pi.Dmag * model.transform.forward * walkSpeed * (pi.run ? runMultiplier : 1.0f);
        }
        
    }

    //物理引擎每秒50次
    private void FixedUpdate() {
        //Time.fixedDeltaTime 50/s
        //1.修改位置
        //rigid.position += movingVec * Time.fixedDeltaTime;
        //2.修改速度
        rigid.velocity = new Vector3(planarVec.x, rigid.velocity.y, planarVec.z) + thrustVec;
        //一帧
        thrustVec = Vector3.zero;
    }

    /// <summary>
    /// Message processing block
    /// </summary>
    public void OnJumpEnter() {
        pi.inputEnabled = false;
        lockPlanar = true;
        thrustVec = new Vector3(0, jumpVelocity, 0);
    }

    public void OnRollEnter() {
        pi.inputEnabled = false;
        lockPlanar = true;
    }

    public void OnRollUpdate() {
        thrustVec = model.transform.forward * anim.GetFloat("rollVelocity") * 1.0f;
    }

    public void OnGround() {
        anim.SetBool("OnGround", true);
    }

    public void NotOnGround() {
        anim.SetBool("OnGround", false);
    }

    public void OnGroundEnter() {
        pi.inputEnabled = true;
        lockPlanar = false;
    }

    public void OnFallEnter() {
        pi.inputEnabled = false;
        lockPlanar = true;
    }

    public void OnJabEnter() {
        pi.inputEnabled = false;
        lockPlanar = true;
    }

    public void OnJabUpdate() {
        thrustVec = model.transform.forward * anim.GetFloat("jabVelocity")*1.4f;
    }
}

5、检测被抓住
用两者的collision来判断,如果撞上了则代表玩家被抓住,游戏结束

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

public class PlayerCollide : MonoBehaviour {
    void OnCollisionEnter(Collision other) {
        //当玩家与侦察兵相撞
        if (other.gameObject.tag == "Guard") {
            Singleton<GameEventManager>.Instance.PlayerGameover();
        }
    }
}

四、展示

1、初始页面,绿色的为自己,黑色的为守卫者。左上角有分数,每躲过一个守卫者则加一分
在这里插入图片描述

2、被抓到游戏结束
在这里插入图片描述
3、跳跃和翻滚
在这里插入图片描述

在这里插入图片描述
童鞋们也快去试一试吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是zp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值