好久没怎么更新博客了,今天抽空来一篇,讨论一下弓箭的轨迹生成。

一、原理

弓箭的轨迹本质就是一个数学问题,使用一个 bezier 曲线公式就可以插值生成。得到轨迹后,做一个lookAt就可以了。

二、Bezier 曲线原理

2015-5-15 :相关原理介绍,我就不重复了

  http://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A

  http://devres.zoomquiet.io/data/20110728232822/index.html

我这里贴一下应用代码

 public class Bezier
{
public Vector3 p0 = Vector3.zero;
public Vector3 p1 = Vector3.zero;
public Vector3 p2 = Vector3.zero; public Bezier(Vector3 v0, Vector3 v1, Vector3 v2)
{
this.p0 = v0;
this.p1 = v1;
this.p2 = v2;
} public void UpdateTargetPos(Vector3 v2)
{
p2 = v2;
} public Vector3 GetPointAtTime(float t)
{
float x = (1 - t) * (1 - t) * p0.x + 2 * t * (1 - t) * p1.x + t * t * p2.x;
float y = (1 - t) * (1 - t) * p0.y + 2 * t * (1 - t) * p1.y + t * t * p2.y;
float z = (1 - t) * (1 - t) * p0.z + 2 * t * (1 - t) * p1.z + t * t * p2.z;
return new Vector3(x, y, z);
}
}

三、例子分析

搭建一个测试场景,从中心点发射弓箭诡异

  

Center上挂载一个脚本  

BezierTest.cs

    public GameObject arrowPrefab;

    public Transform left;

    public Transform right;

    void Test(bool fireRight)
{
Transform end = fireRight ? right : left; ///在中心点生成弓箭
GameObject curArrow = arrowPool.Spawn(transform.position, Quaternion.Euler(Vector3.zero)); ///计算LookTarget的点 与 贝塞尔曲线的第三个控制点
Vector3[] points = Re_LookTarget_MiddlePerpendicularPoint(curArrow.transform, end); ///初始化发射
ArrowControl arrowControl = curArrow.GetComponent<ArrowControl>();
arrowControl.Init(
points[0],
points[1],
end.position,
3.0f,
delegate()
{
arrowPool.Unspawn(curArrow);
});
} Vector3[] Re_LookTarget_MiddlePerpendicularPoint(Transform self, Transform enemy)
{
Vector3 direction = (enemy.position - self.position).normalized; float segment = Vector2.Distance(enemy.position, self.position) / 2.0f; Vector3 lookTarget = (self.position + enemy.position) / 2.0f; Vector3 perpendicular_direction;
if (direction.x > 0)
{
perpendicular_direction = new Vector3(-direction.y, direction.x, 0);
}
else
{
perpendicular_direction = new Vector3(direction.y, -direction.x, 0);
} ///perpendicular line
Vector3 middle_pendicular = lookTarget + perpendicular_direction * segment; return new Vector3[] { lookTarget, middle_pendicular };
} void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 150, 100), "Fire Left")) Test(false);
if (GUI.Button(new Rect(160, 10, 150, 100), "Fire Right")) Test(true);
}

 

预设上挂载的控制脚本

ArrowControl.cs

    float alltimer;

    Util.Bezier bezier = null;

    float timer = 0f;

    Callback recycleFunction;

    Vector3 lookAtTarget;

    //bool defaultRightNeedTurn = false;;

    public void Init(Vector3 lookAtTarget, Vector3 middle, Vector3 end, float alltimer, Callback recycleFunction)
{
this.lookAtTarget = lookAtTarget; this.bezier = new Util.Bezier(transform.position, middle, end); this.alltimer = alltimer; Flip(end.x, transform.position.x); this.recycleFunction = recycleFunction;
} void Flip(float end_X, float self_X)
{
Transform pic = transform.Find("pic"); if (end_X < self_X) {
pic.localScale = new Vector3(-1.0f, 1.0f, 1.0f);
}
else {
pic.localScale = new Vector3( 1.0f, 1.0f, 1.0f);
}
} public void Clear()
{
this.bezier = null; timer = 0f;
} void Update()
{
if (this.bezier != null)
{
timer += Time.deltaTime; float t = timer / alltimer; //Debug.Log("timer" + timer + " t " + t); if (t >= 1.0f) { Clear(); if (recycleFunction != null) recycleFunction(); }
else {
transform.LookAt(lookAtTarget, Vector3.forward); transform.position = bezier.GetPointAtTime(t);
} }
}

  

这里注意,对于LookAt这个行为,我没有很好的数学方法,所以用了U3D的API。

但是这个API 只能保证Z轴始终指向target, 所以图片的旋转预先是这样。

四、结果

山寨小小军团开发笔记 之 Arrow Projectile的更多相关文章

  1. 山寨小小军团开发笔记 之 GamePool

    很多时候我们对于物体(比如弓箭)大量的生成与销毁,这个时候可以把弓箭放在内存池中进行管理,加快体验.自己Copy了一个简易版的. 一.代码 GameObjectPoolManager.cs using ...

  2. ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring

    接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...

  3. [开发笔记]-未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService...匹配的导出【转载自:酷小孩】

    原文地址:http://www.cnblogs.com/babycool/p/3199158.html 今天打算用VisualStudio2012做一个js效果页面测试的时候,打开VS2012新建项目 ...

  4. EasyUI 开发笔记(二)

    接上篇 :EasyUI 开发笔记(一)  (http://www.cnblogs.com/yiayi/p/3485258.html) 这期就简单介绍下, easyui 的 list 展示, 在easy ...

  5. EasyUI 开发笔记(一)

    由于某些原因,在公司做的后台需要改成类似于Ext.js 形式的后台,主要看好其中的 框架布局,以及tab开页面和弹出式内部窗体. 后来看看,改成EasyUI,较Ext.js 库小很多,也便于公司的初级 ...

  6. [Openwrt 项目开发笔记]:Openwrt平台搭建(一)

    [Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 最近开始着手进行Openwrt平台的物联网网关设 ...

  7. Android移动APP开发笔记——Cordova(PhoneGap)通过CordovaPlugin插件调用 Activity 实例

    引言 Cordova(PhoneGap)采用的是HTML5+JavaScript混合模式来开发移动手机APP,因此当页面需要获取手机内部某些信息时(例如:联系人信息,坐标定位,短信等),程序就需要调用 ...

  8. Android移动APP开发笔记——最新版Cordova 5.3.1(PhoneGap)搭建开发环境

    引言 简单介绍一下Cordova的来历,Cordova的前身叫PhoneGap,自被Adobe收购后交由Apache管理,并将其核心功能开源改名为Cordova.它能让你使用HTML5轻松调用本地AP ...

  9. 开发笔记:基于EntityFramework.Extended用EF实现指定字段的更新

    今天在将一个项目中使用存储过程的遗留代码迁移至新的架构时,遇到了一个问题——如何用EF实现数据库中指定字段的更新(根据UserId更新Users表中的FaceUrl与AvatarUrl字段)? 原先调 ...

随机推荐

  1. PHP的接口(interface)

    接口声明了函数和字段,但不会给出实现的细节 规则: 1.类全部为抽象方法(不需要声明abstract) 2.接口抽象方法必须是public 3.成员(字段)必须是常量 interface Comput ...

  2. (转)在Windows上以服务方式运行 MSOPenTech/Redis

    ServiceStack.Redis 使用教程里提到Redis最好还是部署到Linux下去,Windows只是用来做开发环境,现在这个命题发生改变了,在Windows上也可以部署生产环境的Redis, ...

  3. HDU1070 Milk 细节决定成败

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1070 注意:1.喝到第五天,第六天就不喝了  2.相同花费的,优先考虑容量大的  3.注意强制类型转换 ...

  4. OpenGL第15,16,17讲小结

    这三讲没有什么特别的感觉,15讲把纹理贴到3D字体上,16讲讲了雾的生成,17讲是通过以事先保存好的纹理贴图的字体来显示2D文字,这样子不用调用windows的字体,而是使用纹理中的字体.这样也在一定 ...

  5. 简单解析依赖注入(控制反转)在Spring中的应用

    IoC——Inversion of Control  控制反转DI——Dependency Injection   依赖注入 大家都知道,依赖注入是Spring中非常重要的一种设计模式.可能很多初学者 ...

  6. HttpWebResponse取不到Cookie?原来是因为被跳转了

    今天做模拟登陆的时候,发现HttpWebResponse的Cookie都为空,但是Fiddler看是有的...后来看见是302状态,才知道请求这个的时候,Response回来已经是跳转了...这样Co ...

  7. ajax对一些没有接口的数据进行分析和添加方法

    对于一些没有接口的数据进行分析和添加方法: <script src="ajax.js"><script>//插入ajax文件 <script> ...

  8. 简单方便的在线客服展示插件 jQuery.onServ

    onServ jQuery.onServ 是一款简单方便的在线客服jQuery 插件,可以使任意html实现弹出展示在线客服效果, 可以自定义内容,简单配置出多个弹出动作特效,设置位置和样式. git ...

  9. 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)

    AsyncTask使用方法详情:http://www.cnblogs.com/zzw1994/p/4959949.html 下拉开源框架PullToRefresh使用方法和下载详情:http://ww ...

  10. #include< > 和 #include” ” 的区别

    一.#include< > #include< > 引用的是编译器的类库路径里面的头文件. 假如你编译器定义的自带头文件引用在 C:\Keil\c51\INC\ 下面,则 #i ...