如何使物体在指定位置寻找并减速停止?
Posted
技术标签:
【中文标题】如何使物体在指定位置寻找并减速停止?【英文标题】:How to make an object seek and decelerate to a stop exactly on a specified position? 【发布时间】:2012-06-08 18:30:18 【问题描述】:简介
我目前正在尝试创建一个脚本(Unity 中的 C# 脚本)来控制 GameObject 的指向和单击行为。
本质上,玩家最终将通过简单地点击屏幕来控制一个热气球,由此对象将开始加速并朝着点击的位置移动。当在点击位置的特定距离处,热气球应该开始向相反方向加速(因此减速)并完全停止在点击位置。
我已经创建了一个功能齐全的注释脚本(在这篇文章的底部找到),它只是将一个游戏对象以恒定的速度移向点击的位置,然后在特定距离内开始减速直到停在该点。
我还创建了一个单独且功能齐全的脚本,该脚本在加速时向点击位置移动(获得那种小行星撞击行为)。这也可以在帖子底部找到。
问题
现在我面临的问题是,我已经工作了很长时间来找到一种解决方案,您可以将这两种行为作为一个工作脚本来实现,也就是说,热气球有加速行为,同时减速并停在目标位置,就像在此处找到的这个视觉示例:
Visual Arrival Behaviour Demonstration
问题
然后我的问题变成了:
你怎样才能使到达行为不仅使用恒定速度,而且还包含在方程中的加速度?我尝试研究这个问题并尝试使用自己的解决方案,但我所做的一切似乎都没有达到应有的效果。
脚本附件
指向和点击移动以恒定的速度与到达行为
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour
// Fields
Transform cachedTransform;
Vector3 currentMovementVector;
Vector3 lastMovementVector;
Vector3 currentPointToMoveTo;
Vector3 velocity;
int movementSpeed;
Vector3 clickScreenPosition;
Vector3 clickWorldPosition;
float slowingDistance = 8.0f;
Vector3 desiredVelocity;
float maxSpeed = 1000.0f;
// Use this for initialization
void Start ()
cachedTransform = transform;
currentMovementVector = new Vector3(0, 0);
movementSpeed = 50;
currentPointToMoveTo = new Vector3(0, 0);
velocity = new Vector3(0, 0, 0);
// Update is called once per frame
void Update ()
// Retrive left click input
if (Input.GetMouseButtonDown(0))
// Retrive the click of the mouse in the game world
clickScreenPosition = Input.mousePosition;
clickWorldPosition = Camera.main.ScreenToWorldPoint(new Vector3(clickScreenPosition.x, clickScreenPosition.y, 0));
currentPointToMoveTo = clickWorldPosition;
currentPointToMoveTo.z = 0;
// Calculate the current vector between the player position and the click
Vector3 currentPlayerPosition = cachedTransform.position;
// Find the angle (in radians) between the two positions (player position and click position)
float angle = Mathf.Atan2(clickWorldPosition.y - currentPlayerPosition.y, clickWorldPosition.x - currentPlayerPosition.x);
// Find the distance between the two points
float distance = Vector3.Distance(currentPlayerPosition, clickWorldPosition);
// Calculate the components of the new movemevent vector
float xComponent = Mathf.Cos(angle) * distance;
float yComponent = Mathf.Sin(angle) * distance;
// Create the new movement vector
Vector3 newMovementVector = new Vector3(xComponent, yComponent, 0);
newMovementVector.Normalize();
currentMovementVector = newMovementVector;
float distanceToEndPoint = Vector3.Distance(cachedTransform.position, currentPointToMoveTo);
Vector3 desiredVelocity = currentPointToMoveTo - cachedTransform.position;
desiredVelocity.Normalize();
if (distanceToEndPoint < slowingDistance)
desiredVelocity *= movementSpeed * distanceToEndPoint/slowingDistance;
else
desiredVelocity *= movementSpeed;
Vector3 force = (desiredVelocity - currentMovementVector);
currentMovementVector += force;
cachedTransform.position += currentMovementVector * Time.deltaTime;
使用加速但没有到达行为的指向和点击移动
using UnityEngine;
using System.Collections;
public class SimpleAcceleration : MonoBehaviour
Vector3 velocity;
Vector3 currentMovementVector;
Vector3 clickScreenPosition;
Vector3 clickWorldPosition;
Vector3 currentPointToMoveTo;
Transform cachedTransform;
float maxSpeed;
// Use this for initialization
void Start ()
velocity = Vector3.zero;
currentMovementVector = Vector3.zero;
cachedTransform = transform;
maxSpeed = 100.0f;
// Update is called once per frame
void Update ()
// Retrive left click input
if (Input.GetMouseButtonDown(0))
// Retrive the click of the mouse in the game world
clickScreenPosition = Input.mousePosition;
clickWorldPosition = Camera.main.ScreenToWorldPoint(new Vector3(clickScreenPosition.x, clickScreenPosition.y, 0));
currentPointToMoveTo = clickWorldPosition;
// Reset the z position of the clicking point to 0
currentPointToMoveTo.z = 0;
// Calculate the current vector between the player position and the click
Vector3 currentPlayerPosition = cachedTransform.position;
// Find the angle (in radians) between the two positions (player position and click position)
float angle = Mathf.Atan2(clickWorldPosition.y - currentPlayerPosition.y, clickWorldPosition.x - currentPlayerPosition.x);
// Find the distance between the two points
float distance = Vector3.Distance(currentPlayerPosition, clickWorldPosition);
// Calculate the components of the new movemevent vector
float xComponent = Mathf.Cos(angle) * distance;
float yComponent = Mathf.Sin(angle) * distance;
// Create the new movement vector
Vector3 newMovementVector = new Vector3(xComponent, yComponent, 0);
newMovementVector.Normalize();
currentMovementVector = newMovementVector;
// Calculate velocity
velocity += currentMovementVector * 2.0f * Time.deltaTime;
// If the velocity is above the allowed limit, normalize it and keep it at a constant max speed when moving (instead of uniformly accelerating)
if (velocity.magnitude >= (maxSpeed * Time.deltaTime))
velocity.Normalize();
velocity *= maxSpeed * Time.deltaTime;
// Apply velocity to gameobject position
cachedTransform.position += velocity;
【问题讨论】:
这不是人工智能,而是控制理论。我已经删除了标签。 【参考方案1】:改编第一个脚本:
引入一个变量velocity
,就像在第二个脚本中一样。将其设置为等于Start()
中的movementSpeed
,之后不要使用movementSpeed
。 在一切正常之前不要继续。
现在介绍加速:
if (distanceToEndPoint < slowingDistance)
velocity *= distanceToEndPoint/slowingDistance;
else
velocity += direction * 2.0f * Time.deltaTime;
【讨论】:
【参考方案2】:根据您希望运动的显示方式,您可能需要constant velocity equations 或these equations。恒速会更容易。
例如:您可以将起点和终点之间的距离除以 2。然后使用数学计算中途加速,然后减速。
【讨论】:
啊,是的,我之前正在研究其中的一些方程 :) 但我认为让我感到困惑的部分是,当你开始添加来自小行星的运动时(其中,当你改变速度时,你不仅停止了当前的方向,而是在一个新的方向上平稳地加速)。我似乎无法将它实现到第一个基本上可以工作的脚本中,它只是不考虑恒定加速度(我会使用它),而只是没有加速度的恒定速度。也许我现在只是盯着自己瞎了眼以上是关于如何使物体在指定位置寻找并减速停止?的主要内容,如果未能解决你的问题,请参考以下文章
为什么轴在执行主动回原点命令时,初始方向没有找到原点,当需要碰到限位开关掉头继续寻找原点开关时并没有掉头,而是直接报错停止轴,报错原因是由于轴碰到了限位开关?