【问题标题】:Trigonometry + Angles - Object rotating around player and facing mouse directionTrigonometry + Angles - 围绕玩家旋转并面向鼠标方向的对象
【发布时间】:2021-12-02 22:05:56
【问题描述】:

我不明白这段代码是如何工作的,我正在寻求解释。此代码位于更新函数中,不断更新对象位置。

“面向鼠标方向”是指物体就像地球一样围绕太阳运行,但您可以选择它当前在绕太阳旋转线上的位置。

     public GameObject player;
     private Vector3 v3Pos;
     private float angle;
     private readonly float distance = 0.16f;
 
     private void Update()
     {
         v3Pos = Input.mousePosition;
         v3Pos.z = (player.transform.position.z - 
        Camera.main.transform.position.z);
         v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
         v3Pos -= player.transform.position;
         angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
         if (angle < 0.0f) { angle += 360.0f; }
         transform.localEulerAngles = new Vector3(0, 0, angle);
 
         float xPos = Mathf.Cos(Mathf.Deg2Rad * angle) * distance;
         float yPos = Mathf.Sin(Mathf.Deg2Rad * angle) * distance;
         transform.localPosition = new Vector3(player.transform.position.x + 
         xPos * 4, player.transform.position.y + yPos * 4, 0);
     }

我在一个视频中发现了这段代码,它可以让一个物体(比如枪)围绕播放器旋转并同时跟随鼠标,但我不明白它是如何工作的。它是如何工作的?另外,我不知道视频在哪里,但如果有必要我会找到它。

【问题讨论】:

    标签: c# unity3d trigonometry angle euler-angles


    【解决方案1】:

    它使附加的游戏对象沿鼠标光标方向从玩家(出于某种原因)扭曲这么多单位,并且还转向朝向该方向的右侧(出于某种原因)。

    下面的 cmets 中解释了各个部分:

    public GameObject player;
    private Vector3 v3Pos;
    private float angle;
    private readonly float distance = 0.16f;
    
    private void Update()
    {
        // mouse position in screen space 
        // current value = (mouse x, mouse y, 0) )
        Vector3 v3Pos = Input.mousePosition;
    
        // sets the z coordinate to be the difference from the camera to the player
        //   along the forward world axis.
        // current value = (mouse x, mouse y, camera->player distance along forward)
        v3Pos.z = (player.transform.position.z - Camera.main.transform.position.z);
    
        // v3Pos now means the position of the cursor, projected onto plane the player
        // is on parallel to camera plane
        // This means it's a world space positioning of the mouse
        v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
    
        // v3Pos now means the direction from the player to the mouse position 
        //   in world space.
        // Despite the name, now a direction, not a position!
        v3Pos -= player.transform.position;
    
        // finds the signed angle from right to the direction v3Pos represents.
        // in the range (-180, 180]. positive = counterclockwise
        angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
    
        // converts negative angle into an equivalent positive angle.
        if (angle < 0.0f) { angle += 360.0f; }
    
        // sets the forward axis angle of the transform this 
        //   MonoBehaviour is attached to as the same angle.
        // Since we measured from the right to the direction of the mouse, 
        //   this turns the right side to face the mouse.
        // This is done in local space for some reason, can't tell from code.
        transform.localEulerAngles = new Vector3(0, 0, angle);
     
        // finds x and y coordinates of a point in the same direction as 
        //   v3Pos the mouse from the player but at distance 
        // Could use v3Pos but with a z=0, normalized then * distance but 
        //   recalculating with trig works too.
        // basic trig refresher
        //   cos of angle from right gives unit circle x coordinate
        //   sin of angle from right gives unit circle y coordinate
        float xPos = Mathf.Cos(Mathf.Deg2Rad * angle) * distance;
        float yPos = Mathf.Sin(Mathf.Deg2Rad * angle) * distance;
    
        // sets the player's local position to be the position of the player 
        //   adjusted by the direction and distance of the point.
        // Also done in local space, can't tell why from code.
        // Weird to use something else's world position as the local position
        //   for something else.
        transform.localPosition = new Vector3(player.transform.position.x  
                 + xPos * 4, player.transform.position.y + yPos * 4, 0);
     }
    

    上面提到的替代计算可以这样完成:

        Vector3 v3Pos = Input.mousePosition;
        v3Pos.z = (player.transform.position.z - Camera.main.transform.position.z);
        v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
        v3Pos -= player.transform.position;
        angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
        if (angle < 0.0f) { angle += 360.0f; }
        transform.eulerAngles = new Vector3(0, 0, angle);
    
        Vector3 v3DirFlat = v3Pos;
        v3DirFlat.z = 0f;
        // keeping both * distance and * 4 
        v3DirFlat = v3DirFlat.normalized * distance * 4; 
        transform.position = player.transform.position + v3DirFlat;
    

    【讨论】:

    • 您好,您对本地位置问题的看法是正确的。当携带代码的枪是玩家的孩子时,使用 localpos 和 localeulerangles 不允许代码正常工作。我尝试使用没有 localposition 和 localeulerangles 的相同代码,但作为玩家的孩子,它仍然无法正常工作,但是,它比使用 local 更好。当枪不是玩家的孩子时,它可以完美地双向工作,所以我决定在本地停止使用它们。您能否解释一下 trigo 的替代计算方法以及 trigo 计算的工作原理?提前致谢。
    • @omoor 同样对于这个问题,请考虑在此处支持有用的答案,accepting 是最有帮助的答案,可以为回答者提供声誉积分,并让此问题在搜索结果中显示为已回答,这有助于人们有类似问题的找到有用的答案。
    • @omoor 我确实为主题内容添加了一些说明。请参阅上面的修改。
    • 非常感谢您的帮助,我将您的答案标记为正确答案
    【解决方案2】:

    步骤是

    // Get the mouse position on the screen
    v3Pos = Input.mousePosition;
    // Bring that point down until it is level with the player
    v3Pos.z = (player.transform.position.z - Camera.main.transform.position.z);
    // Find that point in world space coordinates
    v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
    // Find the vector from the player to that point
    v3Pos -= player.transform.position;
    // Calculate the angle between that vector and the X axis
    angle = Mathf.Atan2(v3Pos.y, v3Pos.x) * Mathf.Rad2Deg;
    // ensure the values are between 0 and 360
    if (angle < 0.0f) { angle += 360.0f; }
    // Set the item's rotation to that angle, so it faces the right direction
    transform.localEulerAngles = new Vector3(0, 0, angle);
    // Find the new position of the item on the orbit circle
    float xPos = Mathf.Cos(Mathf.Deg2Rad * angle) * distance;
    float yPos = Mathf.Sin(Mathf.Deg2Rad * angle) * distance;
    // Set the item to it's new position
    transform.localPosition = new Vector3(player.transform.position.x + xPos * 4, player.transform.position.y + yPos * 4, 0);
    

    我不确定为什么最后一步中的坐标乘以 4,它们应该已经定位在半径为 distance 的圆上

    【讨论】:

    • 谢谢你,上面的人给了我最充分的答案,但我感谢你的努力和解释。
    猜你喜欢
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    • 2020-02-09
    • 1970-01-01
    • 2023-04-01
    相关资源
    最近更新 更多