山寨小小军团开发笔记 之 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字段)? 原先调 ...
随机推荐
- StreamWriter和StremReader简单的用法
string str = "中国";//写入的内容 string path = @"e:\1.txt";//文件路径 StreamWriter sw = new ...
- java springmvc Log4j filter等(稍微完善一下项目)
仅供参考-接上文 springmvc 1.设置Log4jConfigListener日志监听(可以为开发调试.发布后运行的意外调试.等) 在src/main/resources目录下新建log4j. ...
- 方法:一个简单的读取配置文件.properties的工具类 JAVA
import java.util.ResourceBundle; public class ConfigHelper { private static ConfigHelper instance; p ...
- JAVA泛型? T K V E含义
? 表示不确定的java类型,类型是未知的. T 表示java类型. K V 分别代表java键值中的Key Value. E 代表Element,特性是枚举.
- Python实现Linux下文件查找
import os, sys def search(curpath, s): L = os.listdir(curpath) #列出当前目录下所有文件 for subpath in L: #遍历当前目 ...
- 【Qt】Qt之进程间通信(共享内存)【转】
简述 上一节中,我们分享下如何利用Windows消息机制来进行不同进程间的通信.但是有很多局限性,比如:不能跨平台,而且必须两个进程同时存在才可以,要么进程A发了消息谁接收呢? 下面我们来分享另外一种 ...
- WPF 绑定一(数据源为控件)
xaml: <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.co ...
- php获取系统信息的方法
php获取系统信息的方法. 用 getenv函数进行处理: <?php $root = getenv('DOCUMENT_ROOT'); ////服务器文档根目录 $port = getenv( ...
- TextView中gravity属性值测定
Attributes Explain top 不改变控件大小,对齐到容器顶部 bottom 不改变控件大小,对齐到容器底部 left 不改变控件大小,对齐到容器左侧 right 不改变控件大小,对齐到 ...
- Python开发【第一篇】Python基础之正则表达式补充
正则表达式 一简介:就其本质而言,正则表达式(或RE)是一种小型的.高度专业化的标称语言,(在Python中)它内嵌在Python中,并通过re模块实现.正则表达式模式被编译成一系列的字节码,然后由用 ...