Unity如何实现在球表面移动并朝向一目标点 (二)
2017-10-10 19:45
1031 查看
上一次我们讲述了如何在球上运动并且始终朝向一点,其实之前的代码是有BUG的,因为我们点击的方向不同,他的转向也会不同,所以我们可能会+angle,也可能-angle。我会在这一章的例子中把之前的问题顺便阐述清楚。
我们之前做的是始终朝向一点运动,那么,我们是否能朝向我们所运动的方向呢?似乎这样更符合我们的认知。还有,之前在球上的操作是鼠标长按,鼠标在哪小人就在哪,那么我们是否可以实现点击球上一点,让小人自己走过去呢?今天就来解决这些问题。
首先,我们解决简单的鼠标点击问题,以前我们通过射线碰撞获取碰撞点,直接把碰撞点的位置赋给小人,这样显然有些操作上的不方便,那么我们现在点击一点,小人在球面上运动到目标点。如何实现呢?我们有这样一种思路:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/12/03b23612439e51b80b7d686a9cb8a8d3)
如图,我们正常是从直线的一端走向另一端,但是我们现在可以先计算出从起始点到目标点的直线移动坐标变化,每帧记录下这些坐标,然后每帧发射射线指向这些坐标,与球面碰撞的位置就是我们要在曲面上运动的轨迹,有了这个思路,我们的移动问题就解决了。
接下来就是文章一开头提到的转向问题:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202004/12/9911e391422331a50d1749b9bb56be0f)
如图,我们之前只考虑到一种转向问题,就是如图曲线的方向,这只是在面朝自己的这一面向下走时应该转的方向。
首先我们必须明确的一点是小人是有父对象的,并且父对象的正方向始终不变,为的就是和正确方向计算得出正确转向,那么我们的问题就来了,既然父物体对象正方向一直不变,怎么可能始终让子物体朝着一个方向转动呢,我们的角度一直都是非负的!不可能自动调整。所以我们就必须分情况讨论:
首先我们确定一个前提,就是父物体的x轴始终朝向我们,这样方便我们描述方向
1.面朝我们的球的一面:
面朝我们,就拿刚才第二个图来说,此时我们看到的球就是面朝着我们的一面。在这一面上,如果我们点击让小人往下走,就必须让小人顺时针旋转;如果往上走,就必须让小人逆时针旋转。
2.背朝我们这面:
与面朝我们这一面刚好相反,往下走逆时针,往上走顺时针。
这样,我们上一章的问题也理清了,知道了解决的方案,代码也就一起给上:
using
System.Collections;
using
System.Collections.Generic;
using
UnityEngine;
public
class
MoveOnSphere
:
MonoBehaviour
{
private
Vector3
desPos;
private
bool
isMove;//是否移动
private
Vector3
currentPos;
private
RaycastHit
hit;
public
GameObject
sphere;
void
Update () {
if
(Input.GetMouseButtonDown(0))
{
Ray
ray =
Camera.main.ScreenPointToRay(Input.mousePosition);
if
(Physics.Raycast(ray,
out
hit, 1000, 1 << 8))
{
desPos = hit.point;
isMove =
true;
Debug.Log("开始移动");
}
}
if
(isMove)
{
//获取每帧移动时当前的点
currentPos =
Vector3.MoveTowards(transform.position,desPos,0.1f);
Debug.Log(currentPos);
//每帧发射的射线
Ray
rayEveryFrame =
new
Ray(Camera.main.transform.localPosition,
(currentPos -
Camera.main.transform.localPosition).normalized);
//发射射线
if
(Physics.Raycast(rayEveryFrame,
out
hit, 1000, 1 << 8))
{
//求当前点的法线
Vector3
normal = (transform.position - sphere.transform.position).normalized;
//次切线
Vector3
binormal =
Vector3.Cross(normal,desPos-sphere.transform.position).normalized;
//切线
Vector3
tangent =
Vector3.Cross(binormal,normal).normalized;
transform.parent.position = hit.point;
transform.parent.up = normal;
//计算父级物体正方向和切线的夹角
float
angle =
Vector3.Angle(transform.parent.forward, tangent);
//将子物体的方向矫正
//要分在物体上方点击还是下方点击来判断子物体应该往那边偏移
if
(transform.position.x > sphere.transform.position.x)
{
if
(desPos.y > transform.position.y)
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y - angle, 0);
}
else
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y + angle, 0);
}
}
else
{
if
(desPos.y > transform.position.y)
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y + angle, 0);
}
else
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y - angle, 0);
}
}
}
if
(Vector3.Distance(transform.position, desPos) < 0.1f)
{
isMove =
false;
}
}
}
}
如果还有BUG,或者有什么疑问,可以留言;我会在第一时间与大家讨论!感谢大家的关注:)
我们之前做的是始终朝向一点运动,那么,我们是否能朝向我们所运动的方向呢?似乎这样更符合我们的认知。还有,之前在球上的操作是鼠标长按,鼠标在哪小人就在哪,那么我们是否可以实现点击球上一点,让小人自己走过去呢?今天就来解决这些问题。
首先,我们解决简单的鼠标点击问题,以前我们通过射线碰撞获取碰撞点,直接把碰撞点的位置赋给小人,这样显然有些操作上的不方便,那么我们现在点击一点,小人在球面上运动到目标点。如何实现呢?我们有这样一种思路:
如图,我们正常是从直线的一端走向另一端,但是我们现在可以先计算出从起始点到目标点的直线移动坐标变化,每帧记录下这些坐标,然后每帧发射射线指向这些坐标,与球面碰撞的位置就是我们要在曲面上运动的轨迹,有了这个思路,我们的移动问题就解决了。
接下来就是文章一开头提到的转向问题:
如图,我们之前只考虑到一种转向问题,就是如图曲线的方向,这只是在面朝自己的这一面向下走时应该转的方向。
首先我们必须明确的一点是小人是有父对象的,并且父对象的正方向始终不变,为的就是和正确方向计算得出正确转向,那么我们的问题就来了,既然父物体对象正方向一直不变,怎么可能始终让子物体朝着一个方向转动呢,我们的角度一直都是非负的!不可能自动调整。所以我们就必须分情况讨论:
首先我们确定一个前提,就是父物体的x轴始终朝向我们,这样方便我们描述方向
1.面朝我们的球的一面:
面朝我们,就拿刚才第二个图来说,此时我们看到的球就是面朝着我们的一面。在这一面上,如果我们点击让小人往下走,就必须让小人顺时针旋转;如果往上走,就必须让小人逆时针旋转。
2.背朝我们这面:
与面朝我们这一面刚好相反,往下走逆时针,往上走顺时针。
这样,我们上一章的问题也理清了,知道了解决的方案,代码也就一起给上:
using
System.Collections;
using
System.Collections.Generic;
using
UnityEngine;
public
class
MoveOnSphere
:
MonoBehaviour
{
private
Vector3
desPos;
private
bool
isMove;//是否移动
private
Vector3
currentPos;
private
RaycastHit
hit;
public
GameObject
sphere;
void
Update () {
if
(Input.GetMouseButtonDown(0))
{
Ray
ray =
Camera.main.ScreenPointToRay(Input.mousePosition);
if
(Physics.Raycast(ray,
out
hit, 1000, 1 << 8))
{
desPos = hit.point;
isMove =
true;
Debug.Log("开始移动");
}
}
if
(isMove)
{
//获取每帧移动时当前的点
currentPos =
Vector3.MoveTowards(transform.position,desPos,0.1f);
Debug.Log(currentPos);
//每帧发射的射线
Ray
rayEveryFrame =
new
Ray(Camera.main.transform.localPosition,
(currentPos -
Camera.main.transform.localPosition).normalized);
//发射射线
if
(Physics.Raycast(rayEveryFrame,
out
hit, 1000, 1 << 8))
{
//求当前点的法线
Vector3
normal = (transform.position - sphere.transform.position).normalized;
//次切线
Vector3
binormal =
Vector3.Cross(normal,desPos-sphere.transform.position).normalized;
//切线
Vector3
tangent =
Vector3.Cross(binormal,normal).normalized;
transform.parent.position = hit.point;
transform.parent.up = normal;
//计算父级物体正方向和切线的夹角
float
angle =
Vector3.Angle(transform.parent.forward, tangent);
//将子物体的方向矫正
//要分在物体上方点击还是下方点击来判断子物体应该往那边偏移
if
(transform.position.x > sphere.transform.position.x)
{
if
(desPos.y > transform.position.y)
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y - angle, 0);
}
else
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y + angle, 0);
}
}
else
{
if
(desPos.y > transform.position.y)
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y + angle, 0);
}
else
{
transform.localEulerAngles =
new
Vector3(0, transform.parent.localEulerAngles.y - angle, 0);
}
}
}
if
(Vector3.Distance(transform.position, desPos) < 0.1f)
{
isMove =
false;
}
}
}
}
如果还有BUG,或者有什么疑问,可以留言;我会在第一时间与大家讨论!感谢大家的关注:)
相关文章推荐
- Unity如何实现在球表面移动并朝向一目标点(一)
- //实现思路:鼠标点击,产生目标点,计算角色和目标点的夹角,旋转角色朝向目标点,然后移动角色。
- [Unity&Photon]在Unity&Photon基础上如何实现简单的右键移动
- Unity入门系列||Unity中如何用脚本实现物体的循环移动和旋转
- Unity 3d 如何实现点击屏幕,npc自动移动到点击位置
- Unity如何实现网络通讯(三):观察者模式以及在网络模块的应用
- 如何实现动易官方网站内容页的移动菜单效果?
- unity 如何实现脱卡功能
- Retina屏的移动设备如何实现真正1px的线?
- [Web]如何利用js库dom-drag.js最简单化实现移动图层和点击实现div居上问题
- 我的Unity(3)一点一滴 实现物体移动和旋转的方法总结(1)
- Unity资源打包学习笔记(二)、如何实现高效的unity AssetBundle热更新
- Unity实现缓慢的LookAt (缓慢旋转对着目标)
- unity数据持久化-如何保存多个帐号密码并切换任意用户实现登陆
- 汇总:unity中弹道计算和击中移动目标计算方法
- unity中如何实现文本输入字符串?
- 游戏的物理和数学:Unity中的弹道和移动目标提前量计算
- 方法:如何解决用MFC实现的ping功能中把目标主机不可到达的当成ping通的问题
- 采用移动加权平均计算商品成本,如何实现已入账商品单价修改
- 移动平台化进程加速 网秦如何实现战略转型?