18.游戏场景-游戏主逻辑-子弹相关-逻辑处理
18.1 知识点
创建子弹对象BulletObject脚本,继承MonoBehaviour类。创建一个私有字段info用于存储子弹数据。定义三个公共方法InitInfo、DealyDestroy和Dead,分别用于初始化子弹数据、延迟销毁子弹对象和销毁场景上的子弹。在InitInfo方法中,初始化子弹数据并调用Invoke方法延迟销毁子弹对象,延迟的时间是从配置信息里面拿的。使用延迟函数更安全,因为延迟函数所在的脚本被删除了延迟函数就不会被执行,注意不怕Destroy的时候报错了。在DealyDestroy方法中,它调用Destroy方法销毁子弹对象。在Dead方法中,实例化死亡特效并设置特效位置,然后调用Destroy方法延迟销毁特效对象和销毁子弹对象。在OnTriggerEnter方法中,实现了碰撞逻辑。当碰撞到玩家对象时,获取玩家PlayerObject 脚本并调用Wound方法使玩家受伤。然后调用Dead方法销毁子弹对象。
public class BulletObject : MonoBehaviour
{
//子弹使用的数据
private BulletInfo info;
//用于曲线移动的 计时变量
private float time;
//初始化子弹数据的方法
public void InitInfo(BulletInfo info)
{
this.info = info;
//根据生命周期函数 决定自己什么时候 延迟移除
//Destroy(this.gameObject, info.lifeTime);
Invoke("DealyDestroy", info.lifeTime);
}
private void DealyDestroy()
{
Destroy(this.gameObject);
}
//销毁场景上的子弹
public void Dead()
{
//创建死亡特效
GameObject effObj = Instantiate(Resources.Load<GameObject>(info.deadEffRes));
//设置特效的位置 创建在当前子弹的位置
effObj.transform.position = this.transform.position;
//1秒后延迟移除特效对象
Destroy(effObj, 1f);
//销毁子弹对象
Destroy(this.gameObject);
}
//和对象碰撞时(触发)
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("Player"))
{
//得到玩家脚本
PlayerObject obj = other.GetComponent<PlayerObject>();
//玩家受伤减血
obj.Wound();
//销毁自己
Dead();
}
}
}
创建一个私有字段time,用于存储计时变量。在Update方法中,处理子弹对象的移动。首先根据子弹数据中的forwardSpeed字段沿着面朝向移动。然后根据子弹数据中的type字段处理其他移动逻辑。注意要把玩家脚本PlayerObject 设置成单例,好获取玩家的位置。
子弹不同type具体移动逻辑详解
- 直线运动。这种情况下,子弹只朝着自己的面朝向移动。
- 曲线运动。这种情况下,子弹会在直线运动的基础上进行左右摇摆。它使用Mathf.Sin函数和time变量来计算左右位移量,并使用Transform.Translate方法进行移动。
- 右抛物线。这种情况下,子弹会在直线运动的基础上向右旋转。它使用Quaternion.AngleAxis方法和info.roundSpeed字段来计算旋转角度,并使用Transform.rotation属性进行旋转。
- 左抛物线。这种情况下,子弹会在直线运动的基础上向左旋转。它使用Quaternion.AngleAxis方法和info.roundSpeed字段来计算旋转角度,并使用Transform.rotation属性进行旋转。
- 跟踪导弹。这种情况下,子弹会不断调整自己的朝向,以便朝着玩家对象移动。它使用Quaternion.LookRotation方法计算和PlayerObject的向量
子弹代码
//用于曲线移动的 计时变量
private float time;
void Update()
{
//所有移动的共同特点 都是朝自己的面朝向动
this.transform.Translate(Vector3.forward * info.forwardSpeed * Time.deltaTime);
//接着再来处理 其它的移动逻辑
//1 代表 只朝自己面朝向移动 直线运动
//2 代表 曲线运动
//3 代表 右抛物线
//4 代表 左抛物线
//5 代表 跟踪导弹
switch (info.type)
{
case 2:
time += Time.deltaTime;
//sin里面值变化的快慢 决定了 左右变化的频率
//乘以的速度 变化的大小 决定了 左右位移的多少
//曲线运动时 roundSpeed旋转速度 主要用于控制 变化的频率
this.transform.Translate(Vector3.right * Time.deltaTime * Mathf.Sin(time * info.roundSpeed) * info.rightSpeed);
break;
case 3:
//右抛物线 无非 就是 去改变 旋转角度
this.transform.rotation *= Quaternion.AngleAxis(info.roundSpeed * Time.deltaTime, Vector3.up);
break;
case 4:
//左抛物线 无非 就是 去改变 旋转角度
this.transform.rotation *= Quaternion.AngleAxis(-info.roundSpeed * Time.deltaTime, Vector3.up);
break;
case 5:
//跟踪移动 不停的计算 玩家和我之间的方向向量 然后得到四元数 然后自己的角度 不停的 变化为这个目标四元数
this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
Quaternion.LookRotation(PlayerObject.Instance.transform.position - this.transform.position),
info.roundSpeed * Time.deltaTime);
break;
}
}
拖一个子弹预制体到场景,子弹预制体添加子弹脚本。脚本中添加测试代码,开始时初始化数据。调整测试代码中的索引看看不同配置的效果,根据效果修改配置。测试完删除测试代码。
给各个子弹预制体的父对象的碰撞器设置为触发器。给每个玩家飞机对象设置标签为Player,也添加碰撞器并添加刚体。不使用重力。
18.2 知识点代码
BulletObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletObject : MonoBehaviour
{
private BulletInfo info;
public void InitInfo(BulletInfo info)
{
this.info = info;
Invoke("DealyDestroy", info.lifeTime);
}
private void DealyDestroy()
{
Destroy(this.gameObject);
}
public void Dead()
{
GameObject effObj = Instantiate(Resources.Load<GameObject>(info.deadEffRes));
effObj.transform.position = this.transform.position;
Destroy(effObj, 1f);
Destroy(this.gameObject);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
PlayerObject obj = other.GetComponent<PlayerObject>();
obj.Wound();
Dead();
}
}
private float time;
void Update()
{
this.transform.Translate(Vector3.forward * info.forwardSpeed * Time.deltaTime);
switch (info.type)
{
case 2:
time += Time.deltaTime;
this.transform.Translate(Vector3.right * Time.deltaTime * Mathf.Sin(time * info.roundSpeed) * info.rightSpeed);
break;
case 3:
this.transform.rotation *= Quaternion.AngleAxis(info.roundSpeed * Time.deltaTime, Vector3.up);
break;
case 4:
this.transform.rotation *= Quaternion.AngleAxis(-info.roundSpeed * Time.deltaTime, Vector3.up);
break;
case 5:
this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
Quaternion.LookRotation(PlayerObject.Instance.transform.position - this.transform.position),
info.roundSpeed * Time.deltaTime);
break;
}
}
}
PlayerObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerObject : MonoBehaviour
{
private static PlayerObject instance;
public static PlayerObject Instance => instance;
public int nowHp;
public int maxHp;
public int speed;
public int roundSpeed;
private Quaternion targetQ;
public bool isDead;
private Vector3 nowPos;
private Vector3 frontPos;
private void Awake()
{
instance = this;
}
public void Dead()
{
isDead = true;
GameOverPanel.Instance.ShowMe();
}
public void Wound()
{
if (isDead)
return;
this.nowHp -= 1;
GamePanel.Instance.ChangeHp(this.nowHp);
if (this.nowHp <= 0)
this.Dead();
}
private float hValue;
private float vValue;
void Update()
{
if (isDead)
return;
hValue = Input.GetAxisRaw("Horizontal");
vValue = Input.GetAxisRaw("Vertical");
if (hValue == 0)
targetQ = Quaternion.identity;
else
targetQ = hValue < 0 ? Quaternion.AngleAxis(20, Vector3.forward) : Quaternion.AngleAxis(-20, Vector3.forward);
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, targetQ, roundSpeed * Time.deltaTime);
frontPos = this.transform.position;
this.transform.Translate(Vector3.forward * vValue * speed * Time.deltaTime);
this.transform.Translate(Vector3.right * hValue * speed * Time.deltaTime, Space.World);
nowPos = Camera.main.WorldToScreenPoint(this.transform.position);
if (nowPos.x <= 0 || nowPos.x >= Screen.width)
{
this.transform.position = new Vector3(frontPos.x, this.transform.position.y, this.transform.position.z);
}
if (nowPos.y <= 0 || nowPos.y >= Screen.height)
{
this.transform.position = new Vector3(this.transform.position.x, this.transform.position.y, frontPos.z);
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com