Unity开发中导弹路径散射的原理与实现

Unity开发中导弹路径散射的原理与实现

前言

前面我们学习了导弹的追踪的效果,但是在动画或游戏中,我们经常可以看到导弹发射后的弹道是不规则的,扭扭曲曲的飞行,然后击中目标。

这期我们就讲一下不规则路径飞行的逻辑,在游戏中是如何实现的。

逻辑原理

首先迎面走来的是初级的散射效果原理图,在发射点和目标点之间有一个散射经过点,重点来了:**利用三维空间中球形公式,给定球心,随机返回球面上一点。**然后让导弹经过随机点再击打目标,就会形成随机散射的效果。

多点也是一样的道理,把路径点经过换算之后再赋值导弹路径点,然后形成不规则散射的效果。

这里可以发现,导弹的路径是折线效果,按标准应该是曲线效果。两者的区别就在于导弹在两点之间的过渡函数,折线是平滑过渡,曲线是贝塞尔曲线过渡,选的过渡函数不同实现的效果也不一样。由于贝塞尔曲线过渡较为复杂,这里就用平滑过渡演示原理

代码实现

导弹自身脚本

这里将散射的范围用变量表示,实现可控的效果,想大范围就大范围、想小范围就小范围。将脚本挂载到导弹的预制体上之后给相应的变量赋值,例如:散射半径、爆炸特效、子弹移动速度,其他变量通过外部脚本赋值。

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpherePoint : MonoBehaviour
{
    [Header("散射半径")]
    public float radius;
    
    public GameObject FX;//爆炸特效
    public Transform endPoint;   // 目标点  
    public List<Transform> wayPoints; // 中间点列表  
    public float speed = 10f;         // 子弹移动速度  

    public int currentWaypointIndex = 0; // 当前处理的中间点索引  
    public Vector3 currentTargetPosition; // 当前目标位置  

    // Start is called before the first frame update
    void Start()
    {
        if (wayPoints.Count > 0)
        {
            currentTargetPosition = GetRandomPointOnSphere(wayPoints[0].position, radius);
        }
        else
        {
            currentTargetPosition = endPoint.position;
        }


    }

    // Update is called once per frame
    void Update()
    {
    	BulletMovement(transform);
    }

    /// <summary>
    /// 随机获取中间点周围的散射经过点
    /// </summary>
    /// <param name="center">中间点坐标</param>
    /// <param name="r">散射半径</param>
    /// <returns></returns>
    public static Vector3 GetRandomPointOnSphere(Vector3 center, float r)
    {
        // 生成随机的经度和纬度  
        float u = UnityEngine.Random.value * 2 * Mathf.PI; // 经度 [0, 2*PI]  
        float v = UnityEngine.Random.value * Mathf.PI; // 纬度 [0, PI]  

        // 将球坐标转换为笛卡尔坐标  
        float x = center.x + r * Mathf.Sin(v) * Mathf.Cos(u);
        float y = center.y + r * Mathf.Sin(v) * Mathf.Sin(u);
        float z = center.z + r * Mathf.Cos(v);

		//返回指定球心的球面上随机一点
        return new Vector3(x, y, z);
    }

    private void BulletMovement(Transform bulletTran)
    {
        // 子弹朝向当前目标位置  
        bulletTran.LookAt(currentTargetPosition);

        bulletTran.position += bulletTran.forward * speed * Time.deltaTime;      //向前移动

        // 检查子弹是否到达当前目标位置  
        if (Vector3.Distance(bulletTran.position, currentTargetPosition) < 0.1f)
        {
            // 如果当前点不是最后一个中间点,则更新下一个目标位置为下一个中间点  
            if (currentWaypointIndex < wayPoints.Count)
            {
                currentWaypointIndex++;
                if (currentWaypointIndex < wayPoints.Count)
                {
                    currentTargetPosition = GetRandomPointOnSphere(wayPoints[currentWaypointIndex].position, radius);
                }
                else
                {
                    currentTargetPosition = endPoint.position; // 最后一个中间点后,目标位置是终点  
                }
            }
            // 如果已经到达终点,可以选择销毁子弹或其他操作  
            else if (currentTargetPosition == endPoint.position)
            {
                GameObject tempFX = Instantiate(FX, bulletTran.position, bulletTran.rotation);  //生成一个爆炸特效 并给予位置和旋转信息
                Destroy(gameObject);//销毁自己
                Destroy(tempFX, 0.3f);//销毁爆炸效果
                currentWaypointIndex = 0;//重置路径索引
            }
        }
    }

}

外部控制脚本

将导弹的击打目标和散射路径点通过脚本告诉导弹。

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InstantiateBullet : MonoBehaviour
{
    public GameObject bullet;//导弹预制体
    public Vector3 startPoint; // 导弹出生发射点  
    public Quaternion missileRotation;//导弹出生时方向
    public Transform endPoint;   // 目标点  
    public List<Transform> wayPoints; // 中间点列表  
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
    	//鼠标点击左键发射导弹
        if (Input.GetMouseButtonDown(0))
        {
            GameObject bu = Instantiate(bullet, startPoint, missileRotation);
            bu.GetComponent<SpherePoint>().endPoint = endPoint;
            bu.GetComponent<SpherePoint>().wayPoints = wayPoints;
        }
    }
}

外部脚本我挂载到了Main Camera相机上。

应用效果

先看个正面的:

再来个侧面的:

好了,结束。

结语

学会后要多尝试,变成自己的东西,为己所用,赶快自己尝试下吧。有什么问题可以评论区或私信留言,下期见,拜拜。

相关推荐
远程软件小帮手8 小时前
好用的云电脑!手机怎么用UU远程云电脑玩电脑游戏?
运维·服务器·游戏·电脑
yingxiao88810 小时前
挖掘百亿“数字热土”!解读印度游戏与媒体娱乐的高速增长
游戏·娱乐·媒体
一个小狼娃16 小时前
Android集成Unity避坑指南
android·游戏·unity
极客柒17 小时前
Unity 协程GC优化记录
java·unity·游戏引擎
黄思搏17 小时前
Unity SpriteRenderer 进度条 Shader 实现
unity·游戏引擎
猫屋小鱼丸19 小时前
手把手教你在unity中实现一个视觉小说系统(一)
unity
国服第二切图仔1 天前
Rust开发实战之简单游戏开发(piston游戏引擎)
开发语言·rust·游戏引擎
ii_best1 天前
安卓/IOS工具开发基础教程:按键精灵一个简单的文字识别游戏验证
android·开发语言·游戏·ios·编辑器
HahaGiver6661 天前
Unity与Android原生交互开发入门篇 - 打开Unity游戏的设置
android·unity·交互
wanhengidc1 天前
云手机的基本原理
运维·服务器·游戏·智能手机·云计算