相对于线的长度向 LineRenderer 添加力?
Adding force to LineRenderer relative to the length of the line?
我在这里潜伏了很长时间,通过其他人的问题找到了很多帮助。但是经过大量搜索,我找不到 post 来帮助我找到解决我遇到的问题的方法,所以我决定 post 在这里提出我自己的问题,如果它得到回答,它可能会以类似的方式帮助其他人!
我在为 linerenderer 增加力时遇到了一些问题。基本思想是我有一个物体,我通过向相反方向拖动一条线来向前射击。现在所缺少的是射击具有相对于“拉索”长度的力,就像物体被拉动的“强度”一样。我在这方面遇到了一些麻烦,所以我想我应该问问比我更聪明、更有经验的人!
这是我绘制吊索的脚本:
public class DragIndicatorScript : MonoBehaviour
{
Vector3 startPos;
Vector3 endPos;
Camera camera;
LineRenderer lineRenderer;
Vector3 camOffset = new Vector3(0, 0, 10);
[SerializeField] AnimationCurve animCurve;
// Start is called before the first frame update
void Start()
{
camera = Camera.main;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (lineRenderer == null)
{
lineRenderer = gameObject.AddComponent<LineRenderer>();
}
lineRenderer.enabled = true;
lineRenderer.positionCount = 2;
startPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
lineRenderer.SetPosition(0, startPos);
lineRenderer.useWorldSpace = true;
lineRenderer.widthCurve = animCurve;
lineRenderer.numCapVertices = 10;
lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer.startColor = Color.magenta;
lineRenderer.endColor = Color.cyan;
}
if (Input.GetMouseButton(0))
{
endPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
lineRenderer.SetPosition(1, endPos);
}
if (Input.GetMouseButtonUp(0))
{
lineRenderer.enabled = false;
}
}
}
这是我控制物体射击的脚本:
public class Shoot : MonoBehaviour
{
Rigidbody2D rigidigidy;
Vector2 startpos;
Vector2 endpos;
[SerializeField] float power = 10f;
void Start()
{
rigidigidy = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
endpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Launch();
}
}
void OnMouseDown()
{
startpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void Launch()
{
Vector2 direction = (startpos - endpos).normalized;
rigidigidy.AddForce(direction * power, ForceMode2D.Impulse);
}
}
提前致谢!我已经连续使用 Google 数小时并编写了几行代码,但我觉得我就是找不到我要找的东西。
附加问题 1)
如何将 linerenderer 固定在可拉物体所在的位置?我希望让玩家可以在可玩区域的任何地方拖动,但是 linerenderer 总是在有问题的对象上实例化(它总是同一个对象,因为它是“玩家模型”)。
附加问题 2)
我知道如何在脚本中更改 linerenderer 的 material,但我还没有真正找到从我的资产中调用 material 的正确方法(我制作了一个 material想用作牵引线),所以作为占位符我只是使用:
Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer.startColor = Color.magenta;
lineRenderer.endColor = Color.cyan;
因为我想要一些比默认的粉红色更赏心悦目的东西。
主要问题我有点不清楚。您已经拥有 startpos-endpos
。这不就是包含您要查找的幅度的矢量吗?
我可能宁愿合并你的两个脚本,而不是让它们独立处理输入和位置。
我会让你的 Shoot
处理输入并只将它转发给 DragIndicatorScript
因为顾名思义:它应该只是一个指标,而不应该是决定最终拍摄的组件实力.
因此 Shoot
应该计算输入向量,将其固定并仅将其传递给指标,然后指标可以根据锚点(见下文)和向量更新其结束位置。
附加问题 1:
我会简单地记住锚点和 startPos 之间的偏移量。然后你可以稍后通过简单地考虑这个偏移量来计算端点。
为了能够在屏幕上的任何位置拖动,您不应该使用 OnMouseDown
,它仅在鼠标实际位于对撞机上方时才有效,而是按照您在 DragIndicatorScript
中所做的方式使用 GetMouseButtonDown(0)
.
听起来你还想要线的最大长度,并将这个最大长度也用作最大射击功率。多了一个论点,如前所述,为什么我会让拍摄控制一切。
附加问题 2:
您可以简单地在检查器的一个槽中引用您的 material。但总的来说,我建议事先添加 LineRenderer
并完全设置它。那么你甚至不需要通过代码来完成!
所以看起来有点像
public class Shoot : MonoBehaviour
{
[SerializeField] private DragIndicatorScript _dragIndicator;
[SerializeField] private Rigidbody2D _rigidBody;
[SerializeField] private float power = 10f;
[SerializeField] private Camera _camera;
// This script should clamp the input
[SerializeField] private float maxLength;
private Vector2 inputStartPosition;
private void Awake()
{
if(!_rigidBody) _rigidBody = GetComponent<Rigidbody2D>();
if(!_camera) _camera = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
// store the initial input position
inputStartPosition = camera.ScreenToWorldPoint(Input.mousePosition);
// Enable the indicator and for now set the endpoint also on the anchor since there wasn't any input yet
_dragIndicator.SetIndicator(Vector2.zero);
}
if (Input.GetMouseButton(0))
{
// Get the current position
Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
// Get the input delta between the current and initial position
var input = inputCurrentPosition - inputStartPosition;
// Now clamp this vector to the max length
input = Vector2.ClampMagnitude(input, maxLength);
_dragIndicator.SetIndicator(input);
}
if (Input.GetMouseButtonUp(0))
{
// Just to be sure recalculate from the current position
Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
var input = inputCurrentPosition - inputStartPosition;
// Now clamp this to the max length
input = Vector2.ClampMagnitude(input, maxLength);
_dragIndicator.HideIndicator();
// Directly pass in the final input vector, this way you don't need to store it in a field
Launch(input);
}
}
private void Launch(Vector2 input)
{
// Input already contains the direction and magnitude of the user input
_rigidBody.AddForce(-input * power, ForceMode2D.Impulse);
}
}
而 DragIndicatorScript
只接收这些命令:
public class DragIndicatorScript : MonoBehaviour
{
[SerializeField] private LineRenderer _lineRenderer;
// For the EXTRA QUESTION 1
[SerializeField] private Transform _lineAnchor;
// For EXTRA QUESTION 2
[SerializeField] private Material _lineMaterial;
[SerializeField] private AnimationCurve animCurve;
private void Awake()
{
if(!TryGetComponent<LineRenderer>(out _lineRenderer))
{
_lineRenderer = gameObject.AddComponent<LineRenderer>();
}
// Setup your Line ONCE
_lineRenderer.positionCount = 2;
_lineRenderer.useWorldSpace = true;
_lineRenderer.widthCurve = animCurve;
_lineRenderer.numCapVertices = 10;
_lineRenderer.material = _lineMaterial;
_lineRenderer.startColor = Color.magenta;
_lineRenderer.endColor = Color.cyan;
_lineRenderer.SetPosition(0, _lineAnchor.position);
_lineRenderer.enabled = false;
}
public void HideIndicator()
{
_lineRenderer.enabled = false;
}
public void SetIndicator(Vector3 input)
{
lineRenderer.SetPosition(1, _lineAnchor.position + input);
_lineRenderer.enabled = true;
}
}
我在这里潜伏了很长时间,通过其他人的问题找到了很多帮助。但是经过大量搜索,我找不到 post 来帮助我找到解决我遇到的问题的方法,所以我决定 post 在这里提出我自己的问题,如果它得到回答,它可能会以类似的方式帮助其他人!
我在为 linerenderer 增加力时遇到了一些问题。基本思想是我有一个物体,我通过向相反方向拖动一条线来向前射击。现在所缺少的是射击具有相对于“拉索”长度的力,就像物体被拉动的“强度”一样。我在这方面遇到了一些麻烦,所以我想我应该问问比我更聪明、更有经验的人!
这是我绘制吊索的脚本:
public class DragIndicatorScript : MonoBehaviour
{
Vector3 startPos;
Vector3 endPos;
Camera camera;
LineRenderer lineRenderer;
Vector3 camOffset = new Vector3(0, 0, 10);
[SerializeField] AnimationCurve animCurve;
// Start is called before the first frame update
void Start()
{
camera = Camera.main;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (lineRenderer == null)
{
lineRenderer = gameObject.AddComponent<LineRenderer>();
}
lineRenderer.enabled = true;
lineRenderer.positionCount = 2;
startPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
lineRenderer.SetPosition(0, startPos);
lineRenderer.useWorldSpace = true;
lineRenderer.widthCurve = animCurve;
lineRenderer.numCapVertices = 10;
lineRenderer.material = new Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer.startColor = Color.magenta;
lineRenderer.endColor = Color.cyan;
}
if (Input.GetMouseButton(0))
{
endPos = camera.ScreenToWorldPoint(Input.mousePosition) + camOffset;
lineRenderer.SetPosition(1, endPos);
}
if (Input.GetMouseButtonUp(0))
{
lineRenderer.enabled = false;
}
}
}
这是我控制物体射击的脚本:
public class Shoot : MonoBehaviour
{
Rigidbody2D rigidigidy;
Vector2 startpos;
Vector2 endpos;
[SerializeField] float power = 10f;
void Start()
{
rigidigidy = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetMouseButtonUp(0))
{
endpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Launch();
}
}
void OnMouseDown()
{
startpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void Launch()
{
Vector2 direction = (startpos - endpos).normalized;
rigidigidy.AddForce(direction * power, ForceMode2D.Impulse);
}
}
提前致谢!我已经连续使用 Google 数小时并编写了几行代码,但我觉得我就是找不到我要找的东西。
附加问题 1) 如何将 linerenderer 固定在可拉物体所在的位置?我希望让玩家可以在可玩区域的任何地方拖动,但是 linerenderer 总是在有问题的对象上实例化(它总是同一个对象,因为它是“玩家模型”)。
附加问题 2) 我知道如何在脚本中更改 linerenderer 的 material,但我还没有真正找到从我的资产中调用 material 的正确方法(我制作了一个 material想用作牵引线),所以作为占位符我只是使用:
Material(Shader.Find("Hidden/Internal-Colored"));
lineRenderer.startColor = Color.magenta;
lineRenderer.endColor = Color.cyan;
因为我想要一些比默认的粉红色更赏心悦目的东西。
主要问题我有点不清楚。您已经拥有
startpos-endpos
。这不就是包含您要查找的幅度的矢量吗?我可能宁愿合并你的两个脚本,而不是让它们独立处理输入和位置。
我会让你的
Shoot
处理输入并只将它转发给DragIndicatorScript
因为顾名思义:它应该只是一个指标,而不应该是决定最终拍摄的组件实力.因此
Shoot
应该计算输入向量,将其固定并仅将其传递给指标,然后指标可以根据锚点(见下文)和向量更新其结束位置。附加问题 1:
我会简单地记住锚点和 startPos 之间的偏移量。然后你可以稍后通过简单地考虑这个偏移量来计算端点。
为了能够在屏幕上的任何位置拖动,您不应该使用
OnMouseDown
,它仅在鼠标实际位于对撞机上方时才有效,而是按照您在DragIndicatorScript
中所做的方式使用GetMouseButtonDown(0)
.听起来你还想要线的最大长度,并将这个最大长度也用作最大射击功率。多了一个论点,如前所述,为什么我会让拍摄控制一切。
附加问题 2:
您可以简单地在检查器的一个槽中引用您的 material。但总的来说,我建议事先添加
LineRenderer
并完全设置它。那么你甚至不需要通过代码来完成!
所以看起来有点像
public class Shoot : MonoBehaviour
{
[SerializeField] private DragIndicatorScript _dragIndicator;
[SerializeField] private Rigidbody2D _rigidBody;
[SerializeField] private float power = 10f;
[SerializeField] private Camera _camera;
// This script should clamp the input
[SerializeField] private float maxLength;
private Vector2 inputStartPosition;
private void Awake()
{
if(!_rigidBody) _rigidBody = GetComponent<Rigidbody2D>();
if(!_camera) _camera = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
// store the initial input position
inputStartPosition = camera.ScreenToWorldPoint(Input.mousePosition);
// Enable the indicator and for now set the endpoint also on the anchor since there wasn't any input yet
_dragIndicator.SetIndicator(Vector2.zero);
}
if (Input.GetMouseButton(0))
{
// Get the current position
Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
// Get the input delta between the current and initial position
var input = inputCurrentPosition - inputStartPosition;
// Now clamp this vector to the max length
input = Vector2.ClampMagnitude(input, maxLength);
_dragIndicator.SetIndicator(input);
}
if (Input.GetMouseButtonUp(0))
{
// Just to be sure recalculate from the current position
Vector2 inputCurrentPosition = camera.ScreenToWorldPoint(Input.mousePosition);
var input = inputCurrentPosition - inputStartPosition;
// Now clamp this to the max length
input = Vector2.ClampMagnitude(input, maxLength);
_dragIndicator.HideIndicator();
// Directly pass in the final input vector, this way you don't need to store it in a field
Launch(input);
}
}
private void Launch(Vector2 input)
{
// Input already contains the direction and magnitude of the user input
_rigidBody.AddForce(-input * power, ForceMode2D.Impulse);
}
}
而 DragIndicatorScript
只接收这些命令:
public class DragIndicatorScript : MonoBehaviour
{
[SerializeField] private LineRenderer _lineRenderer;
// For the EXTRA QUESTION 1
[SerializeField] private Transform _lineAnchor;
// For EXTRA QUESTION 2
[SerializeField] private Material _lineMaterial;
[SerializeField] private AnimationCurve animCurve;
private void Awake()
{
if(!TryGetComponent<LineRenderer>(out _lineRenderer))
{
_lineRenderer = gameObject.AddComponent<LineRenderer>();
}
// Setup your Line ONCE
_lineRenderer.positionCount = 2;
_lineRenderer.useWorldSpace = true;
_lineRenderer.widthCurve = animCurve;
_lineRenderer.numCapVertices = 10;
_lineRenderer.material = _lineMaterial;
_lineRenderer.startColor = Color.magenta;
_lineRenderer.endColor = Color.cyan;
_lineRenderer.SetPosition(0, _lineAnchor.position);
_lineRenderer.enabled = false;
}
public void HideIndicator()
{
_lineRenderer.enabled = false;
}
public void SetIndicator(Vector3 input)
{
lineRenderer.SetPosition(1, _lineAnchor.position + input);
_lineRenderer.enabled = true;
}
}