26.移动的敌人

26.敌人-移动的敌人


26.1 知识点

明确移动的敌人需求

移动的敌人需要实现以下功能:

  1. 在多个点之间来回巡逻。
  2. 敌方坦克始终盯着玩家坦克移动。
  3. 当玩家坦克距离移动的敌人坦克较近时,按一定攻速开火。
  4. 敌人坦克死亡时需要加分。

拖拽移动的敌人资源做成预制体


将移动的敌人资源拖拽到场景中,并调整其属性以符合游戏需求。然后将其制作成预制体,以备后续使用。

创建移动的敌人脚本,要让敌方坦克在多个点之间来回的巡逻,让坦克一直看向一个随机点后往前移动,当距离小于一个很小值的时候更新随机点,实现巡逻。Update内要让地方坦克炮口一直盯着玩家坦克。重写死亡函数,移动敌人坦克死亡时需要加分。

using UnityEngine;

// 移动的敌人
public class MonsterObj : TankBaseObj
{
    // 当前的目标点
    private Transform targetPos;
    // 多个巡逻点
    public Transform[] randomPos;
    // 坦克要一直盯着的目标
    public Transform lookAtTarget;
    // 开火距离
    public float fireDis = 5f;
    // 开火时间间隔
    public float fireOffsetTime = 1f;
    private float nowTime = 0f;

    void Start()
    {
        RandomPos();
    }

    void Update()
    {
        // 多个点之间的随机移动
        this.transform.LookAt(targetPos);
        this.transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
        if (Vector3.Distance(this.transform.position, targetPos.position) < 0.05f)
        {
            RandomPos();
        }

        // 看向自己的目标
        if (lookAtTarget != null)
        {
            tankHead.LookAt(lookAtTarget);
            // 当自己和目标对象的距离小于等于配置的开火距离时
            if (Vector3.Distance(this.transform.position, lookAtTarget.position) <= fireDis)
            {
                nowTime += Time.deltaTime;
                if (nowTime >= fireOffsetTime)
                {
                    Fire();
                    nowTime = 0;
                }
            }
        }
    }

    // 随机选择巡逻点
    private void RandomPos()
    {
        if (randomPos.Length == 0)
            return;
        targetPos = randomPos[Random.Range(0, randomPos.Length)];
    }

    // 开火
    public override void Fire()
    {
        for (int i = 0; i < shootPos.Length; i++)
        {
            GameObject obj = Instantiate(bulletObj, shootPos[i].position, shootPos[i].rotation);
            // 设置子弹的拥有者,用于之后进行伤害计算
            BulletObj bullet = obj.GetComponent<BulletObj>();
            bullet.SetFather(this);
        }
    }

    // 重写死亡函数
    public override void Dead()
    {
        base.Dead();
        // 移动怪物死亡时需要加分
        GamePanel.Instance.AddScore(10);
    }
}

26.2 知识点代码

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

//移动的敌人
public class MonsterObj : TankBaseObj
{
    //1.要让坦克 在两个点之间 来回的移动
    //当前的目标点
    private Transform targetPos;
    //随机用的点 外面去关联
    public Transform[] randomPos;

    //2.坦克要一直盯着自己的目标
    public Transform lookAtTarget;

    //3.当目标到达一定范围内过后 间隔一段时间 攻击一下目标
    //开火距离  当小于这个距离时  就会主动攻击
    public float fireDis = 5;
    //为了避免 太难 加一个 攻击间隔时间
    public float fireOffsetTime = 1;
    private float nowTime = 0;

    //开火点
    public Transform[] shootPos;
    //子弹预设体
    public GameObject bulletObj;

    //两张 血条的图 外面关联
    public Texture maxHpBK;
    public Texture hpBK;

    //显示血条计时用时间
    private float showTime = 0;

    //之所以没有new 是因为是结构体 可以不用new 直接在下面赋值
    private Rect maxHpRect;
    private Rect hpRect;
    
    void Start()
    {
        RandomPos();
    }
    
    void Update()
    {
        #region 多个点之间的随机移动
        //看向自己的目标点
        this.transform.LookAt(targetPos);
        //不停的向自己的面朝向位移
        this.transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);

        //知识点 Vector3里面有一个得到两个点之间距离的方法
        //当距离过小时 认为到达了目的地 重新随机一个点
        if (Vector3.Distance(this.transform.position, targetPos.position) < 0.05f)
        {
            RandomPos();
        }
        #endregion

        #region 看向自己的目标
        if( lookAtTarget != null )
        {
            tankHead.LookAt(lookAtTarget);
            //当自己和目标对象的距离 小于等于 配置的 开火距离时
            if( Vector3.Distance(this.transform.position, lookAtTarget.position) <= fireDis)
            {
                nowTime += Time.deltaTime;
                if( nowTime >= fireOffsetTime )
                {
                    Fire();
                    nowTime = 0;
                }
            }
        }
        #endregion

    }

    //随机点
    private void RandomPos()
    {
        if (randomPos.Length == 0)
            return;
        targetPos = randomPos[Random.Range(0, randomPos.Length)];
    }

    //开火
    public override void Fire()
    {
        for (int i = 0; i < shootPos.Length; i++)
        {
            GameObject obj = Instantiate(bulletObj, shootPos[i].position, shootPos[i].rotation);
            //设置子弹的 拥有者 用于之后 进行伤害计算
            BulletObj bullet = obj.GetComponent<BulletObj>();
            bullet.SetFather(this);
        }
    }

    //重写死亡函数
    public override void Dead()
    {
        base.Dead();
        //移动怪物死亡时 需要加分
        GamePanel.Instance.AddScore(10);
    }

    //在这里进行血条UI的绘制
    private void OnGUI()
    {
        if(showTime > 0)
        {
            //不停计时
            showTime -= Time.deltaTime;

            //画图 画血条
            //1.把怪物当前位置 转换成 屏幕位置
            //摄像机里面提供了API 可以将 世界坐标 转为 屏幕坐标
            Vector3 screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
            //2.屏幕位置 转换成 GUI位置
            //知识点:如何得到当前屏幕的分辨率高
            screenPos.y = Screen.height - screenPos.y;

            //然后再绘制
            //知识点:GUI中的 图片绘制
            //底图
            maxHpRect.x = screenPos.x - 50;
            maxHpRect.y = screenPos.y - 50;
            maxHpRect.width = 100;
            maxHpRect.height = 15;
            //画底图
            GUI.DrawTexture(maxHpRect, maxHpBK);

            hpRect.x = screenPos.x - 50;
            hpRect.y = screenPos.y - 50;
            //根据血量和最大血量的百分比 决定画多宽
            hpRect.width = (float)hp / maxHp * 100f;
            hpRect.height = 15;
            //画血条
            GUI.DrawTexture(hpRect, hpBK);
        }
    }

    public override void Wound(TankBaseObj other)
    {
        base.Wound(other);
        //设置显示血条的时间
        showTime = 3;
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏