unity导弹算法 预计目标点
关于导弹的飞行算法,网上有很多教程。简单算法无非是获取目标点的当前位置,然后导弹朝目标方向移动。高深点的,就是通过计算获取碰撞点然后朝着目标移动。如果你能看懂这个高深算法的话,可以去看原帖:http://game.ceeger.com/forum/read.php?tid=3919
需要注意的是,原帖存在错误。而且一些方法使用的不合理。下面是我整合后的代码,欢迎大家提出不同见解。
想要实现导弹的“拦截”功能,首先需要根据目标物体的速度,位置,导弹的速度,位置,计算出两者相交的预计点。然后导弹朝碰撞点移动。
因为目标可能做不规则运动,所以需要公式计算物体的平均速度。即速度=距离/时间。物体的方向,则是当前位置-上一位置。下面是计算物体的速度和方向的具体代码:

using UnityEngine;
using System.Collections; public class SpeedTest : MonoBehaviour {
private float lastTime;
private Vector3 lastPos;
private float dtime;
[HideInInspector]
public Vector3 CurrentVector;
[HideInInspector]
public float Speed; // Update is called once per frame
void OnEnable() {
lastTime = Time.time;
lastPos = transform.position;
}
void Update () {
dtime = Time.time - lastTime;
if (dtime > 0) {
lastTime = Time.time; Speed = PhycisMath.GetSpeed(lastPos, transform.position, dtime);
CurrentVector = PhycisMath.GetDir(lastPos, transform.position);
if (Mathf.Abs(Speed)<0.001f)
{
CurrentVector = transform.TransformDirection(Vector3.forward);
}
lastPos = transform.position;
}
}
}

上面是通过位移来算的速度和方向,与物理效果无关,所以拥有更好的适用性,可以用来不规则的平滑运动计算。为了代码的直观,将一些常用的方法封装于一个静态方法类中。

using UnityEngine;
using System.Collections; public class PhycisMath
{
public static float GetSpeed(Vector3 lastPos,Vector3 newPs,float time) {
if (time == 0) return 0;
return Vector3.Distance(lastPos, newPs) / time;
}
public static Vector3 GetDir(Vector3 lastPos, Vector3 newPs)
{
return (newPs - lastPos).normalized;
}
public static float GetDelta(float a,float b,float c) {
return b * b - 4 * a * c;
}
public static float GetRad(float dis, float angle)
{
return -(2 * dis * Mathf.Cos(angle * Mathf.Deg2Rad));
}
public static float GetPom(float a, float b)
{
return 1-Mathf.Pow(a,b);
}
public static float GetSqrtOfMath(float a,float b, float d) {
float a1 = (-b + Mathf.Sqrt(d)) / (2 * a);
float a2 = (-b - Mathf.Sqrt(d)) / (2 * a); return a1>a2?a1:a2;
}
public Vector3 GetHitPoint() {
return Vector3.zero;
}
}

接下来是写一个雷达,通过一系列“复杂”的运算获取碰撞点位置。

using UnityEngine;
using System.Collections; public class RadarOfRocket : MonoBehaviour {
//我们的导弹的轨道计算是基于Transform的,
//纯数学的计算,这样更精确,适用性更好
public Transform target;//目标
private SpeedTest rocketSpeed;//
private SpeedTest targetSpeed; private Vector3 targetDir;
private float angle;
private float distence; private bool isAim = false; public bool IsAim
{
get { return isAim; }
set { isAim = value; }
}
private Vector3 aimPos; public Vector3 AimPos
{
get { return aimPos; }
set { aimPos = value; }
}
void checkTarget() {
if (!(rocketSpeed=GetComponent<SpeedTest>()))
{
gameObject.AddComponent<SpeedTest>();
rocketSpeed = GetComponent<SpeedTest>();
}
if (target&&!(targetSpeed = target.GetComponent<SpeedTest>()))
{
target.gameObject.AddComponent<SpeedTest>();
targetSpeed = target.GetComponent<SpeedTest>();
}
}
void OnEnable() { checkTarget();
}
void Update() {
if (target)
TestAim();
}
public void TestAim() { if (Mathf.Abs(targetSpeed.Speed) < 0.01f)
{ //物体的速度过小,则默认物体是静止的。 isAim = true;
aimPos = target.position;
}
else {
targetDir = transform.position - target.position;
angle = Vector3.Angle(targetDir, targetSpeed.CurrentVector); distence = targetDir.magnitude; float a = PhycisMath.GetPom((rocketSpeed.Speed / targetSpeed.Speed), 2);
float b = PhycisMath.GetRad(distence, angle);
float c = distence * distence;
float d = PhycisMath.GetDelta(a, b, c);
isAim = d >= 0 && !float.IsNaN(d) && !float.IsInfinity(d); if (isAim)
{
float r = PhycisMath.GetSqrtOfMath(a, b, d);
if (r < 0) isAim = false;//如果得出的是负值,则代表交点有误
aimPos = target.transform.position + targetSpeed.CurrentVector * r;
} } }
}

原博客中的解是获取较小的那个。但是据我测试,只有正解时目标点才正确。大家也可以进行测试。值得注意的是,导弹的速度必须要大于目标的速度,不然导弹无法靠近目标。
好,获取目标点的代码已经完成了。接着是导弹的飞行代码。关于这部分,一般的做法是通过移动+转向实现导弹的轨迹。代码很简单。距离和角度的过滤我就省略了,基本上新手都能写出来。

using UnityEngine;
using System.Collections;
[RequireComponent(typeof(RadarOfRocket))]
public class Missile : MonoBehaviour {
private RadarOfRocket radar;
public float Speed = 100;
public float RoteSpeed = 3;
public float Noise = 0;
void OnEnable() {
radar = GetComponent<RadarOfRocket>();
}
void Update() {
Fly();
if (radar.IsAim) {
FlyToTarget(radar.AimPos-transform.position);
}
}
private void FlyToTarget(Vector3 point) {
if (point != Vector3.zero) {
Quaternion missileRotation = Quaternion.LookRotation(point, Vector3.up); transform.rotation = Quaternion.Slerp(transform.rotation, missileRotation, Time.deltaTime * RoteSpeed);
} }
private void Fly() {
Move(transform.forward.normalized+transform.right*Mathf.PingPong(Time.time,0.5f)*Noise, Speed*Time.deltaTime);
}
public void Move(Vector3 dir,float speed){
transform.Translate(dir*speed,Space.World);
}
void OnTriggerEnter(Collider other)
{
print("hit");
} }

好,上面就是导弹的所有代码了。谢谢观看。
考虑到可能有小白拿到代码可能完全不知道怎么弄,故增加以下注释。
将Radar.cs脚本和Missile.cs脚本托给你做好的导弹。然后将目标Transform赋值给Radar的target即可完成拦截导弹的演示。
关于目标怎样的移动,你可以自己定义,像直线移动或者圆周移动,不规则平滑移动等等都可以进行拦截。具体的效果由参数控制,但是一定要注意导弹的速度一定要大于目标的
速度,拦截导弹才能发挥作用!
本文的链接是:http://www.cnblogs.com/jqg-aliang/p/4768101.html 转载请申明出处谢谢!
unity导弹算法 预计目标点的更多相关文章
- [UE4]记录瞬移目标点
1.判定射线是否击中一个物体:LineTraceByChannel的Return Value返回值 2.击中的目标点:LineTraceByChannel.Out Hit.Location,如图提示文 ...
- Unity三消算法
消除算法图文详解 三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分.可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多 ...
- [Unity A*算法]A*算法的简单实现
写在前面:之前看过一点,然后看不懂,也没用过. 最近正好重构项目看到寻路这块,想起来就去查查资料,总算稍微理解一点了,下面记录一下自己的成果(哈哈哈 :> ) 下面分享几篇我觉得挺不错的文章 A ...
- ros机器人导航设置原点,目标点
之前利用movebase导航定位都是通过rviz用鼠标指来指去,实验时非常方便,但实际应用总不能也人工指来指去吧,这怎么体现智能呢 启动导航后,用以前使用的rviz设设置目标点来获取map坐标系下的位 ...
- 基于Unity的A星寻路算法(绝对简单完整版本)
前言 在上一篇文章,介绍了网格地图的实现方式,基于该文章,我们来实现一个A星寻路的算法,最终实现的效果为: 项目源码已上传Github:AStarNavigate 在阅读本篇文章,如果你对于里面提到的 ...
- Unity实现A*寻路算法学习1.0
一.A*寻路算法的原理 如果现在地图上存在两点A.B,这里设A为起点,B为目标点(终点) 这里为每一个地图节点定义了三个值 gCost:距离起点的Cost(距离) hCost:距离目标点的Cost(距 ...
- Unity实现A*寻路算法学习2.0
二叉树存储路径节点 1.0中虽然实现了寻路的算法,但是使用List<>来保存节点性能并不够强 寻路算法学习1.0在这里:https://www.cnblogs.com/AlphaIcaru ...
- unity A*寻路 (三)A*算法
这里我就不解释A*算法 如果你还不知道A*算法 网上有很多简单易懂的例子 我发几个我看过的链接 http://www.cnblogs.com/lipan/archive/2010/07/01/1769 ...
- Unity Lighting - The Precompute Process 预计算过程(二)
The Precompute Process 预计算过程 In Unity, precomputed lighting is calculated in the background - eith ...
随机推荐
- myDate97用法
myDate97用法 CreateTime--2017年5月12日11:00:32Author:Marydon 一.基本用法 官网链接:http://www.my97.net/index.asp ...
- Zmodem transfer canceled by remote side问题的解决办法!
在使用跳转机跳转到另外一台机器的时候,上传一个安装包,此时使用rz命令上传文件,例如:resin-pro-4.0.44.tar.gz,结果出现如下错误提示: 点击确定之后,界面出现乱码,并退回到了跳转 ...
- IIS自定义404错误不能生效的原因
通过IIS自定义错误信息的功能,来自定义的404错误页面. 先制作显示错误信息的htm文件404.htm(随便什么名都行),我把文件入在根目录下. 使用Url类型,设置“/404.htm ”,可以成功 ...
- 摘:数据结构各种算法实现(C++模板)
目 录 1.顺序表. 1 Seqlist.h 1 Test.cpp 6 2.单链表. 8 ListNode.h 8 SingleList.h 10 test.cpp 20 3.双向链表. 22 No ...
- NPN/PNP和N沟道/P沟道负载的接法
N沟道mos管和p沟道mos管负载的接法不一样,随意接的话导致VGS不满足条件:如下图N沟道接法,下拉电阻R2必须接,否则电路状态不稳定. 三极管原理类似如下图(满足三极管导通条件) NPN型三极管: ...
- android.graphics(1) - Paint, Canvas, drawLine, drawPoint, drawRect, drawRoundRect, drawCircle, drawOval, drawArc
一.Paint与Canvas 像我们平时画图一样,需要两个工具,纸和笔.Paint就是相当于笔,而Canvas就是纸,这里叫画布. 所以,凡有跟要要画的东西的设置相关的,比如大小,粗细,画笔颜色,透明 ...
- ENGINE_API CXSroll
#ifndef __XSROLL_H__ #define __XSROLL_H__ #include "CocoHead.h" #include "XWindow.h&q ...
- error while loading shared libraries *.so.*
转自 http://my.oschina.net/u/561492/blog/192341 ubuntu12.04-64位编译Android4.2时出现问题:error while loading s ...
- RCC—使用 HSE/HSI 配置时钟 ---时钟树
本章参考资料:< STM32F4xx 中文参考手册> RCC 章节.学习本章时,配合< STM32F4xx 中文参考手册> RCC 章节一起阅读,效果会更佳,特别是涉及到寄存器 ...
- WebService或HTTP服务端接收请求转发消息到另一个服务端-实现思路
1.需求结构(WebService) A客户端<->B服务端<->C服务端 说明: a.在B服务端上面添加配置项(1.是否转发消息到C服务端:2.C服务端IP和端口): b.A ...