You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity C#问题:父物体旋转时LookAt函数产生异常结果

3D立方体表面贪吃蛇:蛇段旋转异常问题

我是编程新手,主要靠Unity和C#学习游戏开发,目前在做一款3D贪吃蛇——玩家不是在2D平面,而是在立方体表面移动。

我写了代码让蛇身段转向时自动旋转,保证模型朝向正确:蛇头脚本用LookAt函数,让视觉模型的背部朝向刚离开的点位。正常情况下功能没问题,但只要玩家转向新面导致立方体旋转,所有蛇段的角度就会变得异常,LookAt的目标Vector3和传入的点位置完全对不上。

我测试过,哪怕蛇段完全不动,只旋转立方体,也会出现同样的问题;后来试着用相机绕立方体移动替代立方体旋转,问题还是没解决。我希望蛇段能看向立方体前一面的上一个点,怀疑是角度计算用了局部空间而非世界空间,但一直没找到解决办法,而且我对Quaternions相关知识也不太熟悉。

以下是蛇头的代码:

public GameObject ourPoint;
public GameObject thisPoint;
public GameObject playerSegmentPrefab;
public List<GameObject> segments;
public float secondsSinceLastMovement;
public float timeBetweenMovements;
public int direction;
public bool pointsSet = false;

[SerializeField] private GameObject playerVisual;
[SerializeField] private Vector3 lookAtTarget;
[SerializeField] private GameObject a;
public bool test;


// Start is called before the first frame update
void Awake()
{
    References.player = this;
    direction = 4;
    lookAtTarget = new Vector3(0, -5, -1.5f);
}

void Start()
{
    GameObject firstSegement = Instantiate(playerSegmentPrefab, transform.position, transform.rotation);
    segments.Insert(0, firstSegement);
    firstSegement.transform.SetParent(gameObject.transform);
    GameObject secondSegment = Instantiate(playerSegmentPrefab, transform.position, transform.rotation);
    segments.Insert(1, secondSegment);
    secondSegment.transform.SetParent(gameObject.transform);
    Player_Segment_Behaviour firstSegmentScript = firstSegement.GetComponent<Player_Segment_Behaviour>();
    firstSegmentScript.follower = secondSegment;
}

void Move(int upDownRightLeft)
{
    int currentPeak = References.ground.peak;
    int currentFace = References.ground.face;
    Point_Script ourPointScript = ourPoint.GetComponent<Point_Script>();
    if(upDownRightLeft == 1)
    {
        thisPoint = ourPointScript.upPoint;
    }

    if(upDownRightLeft == 2)
    {
        thisPoint = ourPointScript.downPoint;
    }

    if(upDownRightLeft == 3)
    {
        thisPoint = ourPointScript.rightPoint;
    }

    if(upDownRightLeft == 4)
    {
        thisPoint = ourPointScript.leftPoint;
    }
    Point_Script thisPointScript = thisPoint.GetComponent<Point_Script>();
    if(thisPoint != null)
    {
    if(ourPointScript.ourCube == thisPointScript.ourCube)
    {
        References.ground.face = thisPointScript.compass;
    }
    }



    Player_Segment_Behaviour firstSegmentScript = segments[0].GetComponent<Player_Segment_Behaviour>();
    firstSegmentScript.Move(ourPoint, upDownRightLeft, thisPoint);
    lookAtTarget = ourPoint.transform.position;
    ourPoint = thisPoint;
    if(thisPointScript.ourCube == ourPointScript.ourCube)
    {
        References.ground.ChangeTarget(upDownRightLeft);
    } 

    secondsSinceLastMovement = 0;
    if(test == false)
    {
    playerVisual.transform.LookAt(lookAtTarget);
    }

}

// Update is called once per frame
void Update()
{
    playerVisual.transform.LookAt(lookAtTarget);

    if(test == true)
    {
    lookAtTarget = a.transform.position;
    }

    for(int i = 0; i < segments.Count; i ++)
    {
        if(segments[i] != null)
        {
        Player_Segment_Behaviour thisSegment = segments[i].GetComponent<Player_Segment_Behaviour>();
        thisSegment.test = test;
        thisSegment.a = a;
        }
    }

    if(References.ground.points.Count >= 149 && pointsSet == false)
    {
        Player_Segment_Behaviour firstSegmentScript = segments[0].GetComponent<Player_Segment_Behaviour>();
        Player_Segment_Behaviour secondSegmentScript = segments[1].GetComponent<Player_Segment_Behaviour>();
        Point_Script ourPointScript = ourPoint.GetComponent<Point_Script>();
        firstSegmentScript.ourPoint = ourPointScript.downPoint;
        firstSegmentScript.gameObject.transform.position = ourPointScript.downPoint.transform.position;
        Point_Script firstSegementPointScript = firstSegmentScript.ourPoint.GetComponent<Point_Script>();
        secondSegmentScript.ourPoint = firstSegementPointScript.downPoint;
        secondSegmentScript.gameObject.transform.position = firstSegementPointScript.downPoint.transform.position;
        pointsSet = true;
    }
    transform.position = ourPoint.transform.position;
    secondsSinceLastMovement += Time.deltaTime;

    if(References.ground.cycleActive == false)
    {
    if(Input.GetKeyDown(KeyCode.A) && direction != 3)
    {
        direction = 4;
        Move(direction);
    }

    if(Input.GetKeyDown(KeyCode.D) && direction != 4)
    {
        direction = 3;
        Move(direction);
    }

    if(Input.GetKeyDown(KeyCode.W) && direction != 2)
    {
        direction = 1;
        Move(direction);
    }

    if(Input.GetKeyDown(KeyCode.S) && direction != 1)
    {
        direction = 2;
        Move(direction);
    }

    if(secondsSinceLastMovement >= timeBetweenMovements)
    {
        Move(direction);
    }
    }
}

(test布尔值用于测试蛇段朝向,通过GameObject a作为目标调整模型对齐)

内容的提问来源于stack exchange,提问作者Matthew Brady

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 12:10:10