我是Unity3d的新手。我正在创建一个画廊射击游戏,我有一个只能沿x轴移动的枪对象。我想将移动限制在屏幕边缘。一旦它到达屏幕的边缘,我就用硬编码将其移回屏幕几个像素。但它看起来很粗糙,因为当它碰到屏幕边缘时会闪烁。我已经尝试将transforms.position.x设置为等于transform.position.x一旦它到达屏幕边缘但枪支对象将继续移出屏幕。
目前这是代码:
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour
{
public float maxStrafeSpeed = 0.01f; // max move speed, recommend a very low float, will move too fast if too high
public float maxMouseSpeed = 3.0f; // max speed the gun will rotate to where the mouse is pointing
private float h; // horizontal axis
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
PlayerMovementStrafing ();
PlayerMovementMouseAim ();
}
void PlayerMovementStrafing()
{
// get input
h = Input.GetAxis ("Horizontal") * maxStrafeSpeed;
Vector3 pos = Camera.main.WorldToViewportPoint(transform.position);
if (pos.x < 0.0f)
{
transform.position = new Vector3(-0.6f, transform.position.y, transform.position.z);
Debug.Log("Left edge of view");
}
else if (pos.x > 1.0f)
{
transform.position = new Vector3(0.6f, transform.position.y, transform.position.z);
Debug.Log("Right edge of view");
}
this.transform.Translate (new Vector3 (h, 0.0f, 0.0f));
}
void PlayerMovementMouseAim ()
{
transform.Rotate(Vector3(Input.GetAxis("Mouse Y"), Input.GetAxis("Mouse X"), 0) * (Time.deltaTime * maxMouseSpeed));
}
}
答案 0 :(得分:1)
你的逻辑就在那里,当你移动时,你只是在中犯了一个微妙的错误。
主要问题是你在移动之前就已经紧张了:
void PlayerMovementStrafing()
{
// Getting Input
h = ...
//Getting the viewport location for clamping
Camera.main.Worl...
//Clamping the position
if (pos.x < 0.0f) ...
else if (pos.x > 1.0f) ...
// Changes the position after we just clamped (so each turn clamping is one frame behind)
this.transform.Translate (new Vector3 (h, 0.0f, 0.0f));
}
但除此之外,你应该在LateUpdate
中应用这样的钳制代码。如果您的游戏非常简单,Update
应该工作,但是从文档开始,“在调用所有更新函数后调用LateUpdate。”。 order of execution的文档还显示每个帧在动画和物理后调用LateUpdate
,并且是渲染前的最后一个事件。
成为渲染之前的最后一个事件使LateUpdate
成为理想之处,我定义了一个在那里调用的方法,并缩小了扫描方法。
我还使用ViewportToWorldPoint
来限制值而不是使用硬编码值。使用硬编码值,如果摄像机不在您现在所处的确切位置,则夹紧将失败(即使它在编辑器中移动)。
如果相机永远无法移动并且您担心性能问题,那么___to___
个来电都可以移至Start
并且其值已缓存,但非常可能是此时过早优化(并打开你的微妙错误):
我还在扫射方法中添加了对Time.delta
的调用。目前,如果游戏未以完全 60fps运行,则移动速度会有所不同,因为Update
每帧仅调用一次。换句话说,您的移动速度是每个帧的X个单位。乘以Time.delta
(自上一帧起的时间)将其更改为每秒的X个单位。
这意味着即使FPS变化(例如在慢速机器上),您的移动速度也不会。这也意味着您需要提高速度值,因为Time.delta
通常会小于1.
作为“规则”,如果您处于更新状态,并且您正在拨打电话,这会导致随时间移动乘以Time.deltaTime
(因此它包含Translate
电话[您已经让他们进行Rotate
通话])。请注意,在FixedUpdate
中,您仍然可以乘以Time.deltaTime
(在该方法中返回Time.fixedDeltaTime
,但您不必这样做,因为它不会受到FPS的影响。
void PlayerMovementStrafing()
{
// get input
h = Input.GetAxis ("Horizontal") * maxStrafeSpeed;
transform.Translate(new Vector3 (h, 0.0f, 0.0f) * Time.delta); //Multiply by delta time in
}
void LateUpdate()
{
PlayerMovementClamping();
}
void PlayerMovementClamping()
{
var viewpointCoord = Camera.main.WorldToViewportPoint(transform.position);
if (viewpointCoord.x < 0.0f)
{
Debug.Log("Left edge of view");
viewpointCoord.x = 0.0f;
transform.position = Camera.main.ViewportToWorldPoint(viewpointCoord);
}
else if (viewpointCoord.x > 1.0f)
{
Debug.Log("Right edge of view");
viewpointCoord.x = 1.0f;
transform.position = Camera.main.ViewportToWorldPoint(viewpointCoord);
}
}
还有一点小问题,如果您不使用这些块进行调试,可以使用Mathf.Clamp01
缩短钳位代码:
void PlayerMovementClamping()
{
var viewpointCoord = Camera.main.WorldToViewportPoint(transform.position);
viewpointCoord.x = Mathf.Clamp01(viewpointCoord.x);
transform.position = Camera.main.ViewportToWorldPoint(viewpointCoord);
}