山寨小小军团开发笔记 之 Arrow Projectile
好久没怎么更新博客了,今天抽空来一篇,讨论一下弓箭的轨迹生成。
一、原理
弓箭的轨迹本质就是一个数学问题,使用一个 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的更多相关文章
- 山寨小小军团开发笔记 之 GamePool
很多时候我们对于物体(比如弓箭)大量的生成与销毁,这个时候可以把弓箭放在内存池中进行管理,加快体验.自己Copy了一个简易版的. 一.代码 GameObjectPoolManager.cs using ...
- ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring
接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...
- [开发笔记]-未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService...匹配的导出【转载自:酷小孩】
原文地址:http://www.cnblogs.com/babycool/p/3199158.html 今天打算用VisualStudio2012做一个js效果页面测试的时候,打开VS2012新建项目 ...
- EasyUI 开发笔记(二)
接上篇 :EasyUI 开发笔记(一) (http://www.cnblogs.com/yiayi/p/3485258.html) 这期就简单介绍下, easyui 的 list 展示, 在easy ...
- EasyUI 开发笔记(一)
由于某些原因,在公司做的后台需要改成类似于Ext.js 形式的后台,主要看好其中的 框架布局,以及tab开页面和弹出式内部窗体. 后来看看,改成EasyUI,较Ext.js 库小很多,也便于公司的初级 ...
- [Openwrt 项目开发笔记]:Openwrt平台搭建(一)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 最近开始着手进行Openwrt平台的物联网网关设 ...
- Android移动APP开发笔记——Cordova(PhoneGap)通过CordovaPlugin插件调用 Activity 实例
引言 Cordova(PhoneGap)采用的是HTML5+JavaScript混合模式来开发移动手机APP,因此当页面需要获取手机内部某些信息时(例如:联系人信息,坐标定位,短信等),程序就需要调用 ...
- Android移动APP开发笔记——最新版Cordova 5.3.1(PhoneGap)搭建开发环境
引言 简单介绍一下Cordova的来历,Cordova的前身叫PhoneGap,自被Adobe收购后交由Apache管理,并将其核心功能开源改名为Cordova.它能让你使用HTML5轻松调用本地AP ...
- 开发笔记:基于EntityFramework.Extended用EF实现指定字段的更新
今天在将一个项目中使用存储过程的遗留代码迁移至新的架构时,遇到了一个问题——如何用EF实现数据库中指定字段的更新(根据UserId更新Users表中的FaceUrl与AvatarUrl字段)? 原先调 ...
随机推荐
- python基础:自定义函数
一.背景 在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下 ...
- GForms开发平台
1. 开发平台概述 1.1. 产品概述 GForms开发平台让开发人员甚至非技术人员在短短几分钟内创建全功能的展现服务,让开发团队更加适应客户和市场的需求,从而提高客户服务和速度实现收益. GForm ...
- Nginx集群(转)
转自:http://hi.baidu.com/xingyuanju/blog/item/779a2a23b7ebb749935807f1.html http://hi.baidu.com/dianhu ...
- Change http port in bitnami stack
My case goes like this. I installed bitnami redmine first with port 80 for http service, but got pro ...
- iPhone Tableview分批显示数据
//非原创 iPhone Tableview分批显示数据是本文要介绍的内容,主要讲解的是数据的显示.iPhone屏幕尺寸是有限的,如果需要显示的数据很多,可以先数据放到一个table中,先显示10 ...
- el表达式获取cookie
${cookie.name}将获得对应cookie的对象,比如我们用jsp将一段cookie发送给客户端. Cookie cookie = new Cookie("username" ...
- 如何解决win7系统访问共享服务器慢的问题
最近重新装了win7系统,但发现当访问共享服务器的时候很慢,后来在网上搜索了相关解决办法,在此和大家分享下: 1. 通过“windows键”+“R键”快捷打开“运行”窗口,然后输入cmd命令敲回车,进 ...
- Zencart 国家排序及中文名称的扩展
最终实现效果如上 具体步骤: 1. 手动或SQL修改数据表,增加2个字段 ) ) '; 2. 修改admin/countries.php文件,增加表单插入编辑功能, 共计7处,此处忽略具体代码. 3. ...
- Noppoo choc mini 84 @XUbuntu13.10 compatibility setting
Months ago, I bought the keyboard Noppoo Choc Mini 84keys for using under XUbuntu12.10, and I have f ...
- java之javadoc命令
[javadoc命令的用法] 1.java源文件里,注释以/**开始 并以*/结束,里面可以包含普通文件,HTML标记和javaDoc标记.这些将构成javaDoc文档. 2.javadoc命令只能处 ...