将对象限制为沿x轴的屏幕边缘 - Unity3d

时间:2014-09-24 01:16:00

标签: c# unity3d

我是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));
    }
}

1 个答案:

答案 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);
}