首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Unity3D:如何移动一个对象与另一个对象的关系?

Unity3D:如何移动一个对象与另一个对象的关系?
EN

Stack Overflow用户
提问于 2022-07-12 17:02:02
回答 1查看 62关注 0票数 1

在我的场景中,我有一个启用物理功能的球体,我可以用WASD来移动这个角色。现在,我想要的是,一旦球员击中球,它就不应该是物理激活的,并与球员一起前进,就像球员把球握在手中一样。

到目前为止,我尝试过的是:我能够做到这一点,但并不是我想要的那样完美。我尝试了OnCollisionEnter来检测碰撞,我让球体成为播放器的一个子级,一旦检测到碰撞,我就使用isKinematic = true,并且我使用Vector3.MoveTowards作为对象来跟踪播放机的位置。

我在参考剪辑下面附了两个参考视频(我想要的风格):https://www.youtube.com/watch?v=fi-GB0RwLr0

MyVersion(这就是我能做的):https://www.youtube.com/watch?v=JtV11KHY4pU

总的来说,如果你看了剪辑,你可以看到我的版本是如何非常严格,斯塔克,小马车,没有那么轻的感觉,在所有。如果我做错了什么,也要放我一马,就像上个月一样,我开始团结起来。

这是我的播放器脚本,通过它我可以控制一切。

代码语言:javascript
运行
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
    public float MoveSpeed;
    [SerializeField]private Rigidbody playerRig;
    [SerializeField] private Rigidbody ballRig;
    [SerializeField] private GameObject Ball;
    [SerializeField] private GameObject heldObj;

    private bool isTouching = false;
    private Vector3 offset = new Vector3(0, 1, 3);


    private Vector3 force;
    public float jump;  
    private bool isGrounded = true;

    private void Start()
    {
        Ball = GameObject.FindGameObjectWithTag("Ball");
        ballRig.GetComponent<Rigidbody>();
        playerRig.GetComponent<Rigidbody>();
    }
    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        playerRig.velocity = new Vector3(x*MoveSpeed, playerRig.velocity.y,z*MoveSpeed);

        Vector3 vel = playerRig.velocity;
        vel.y = 0;
        
        if (vel.x != 0 || vel.z != 0) 
        {
         
            transform.forward = vel;
        }
       if(transform.position.y < -10)
        {
            GameOver();
        }

        ReleaseTheBall();


        if (isTouching == true)
        {
            
           ballRig.transform.position = Vector3.MoveTowards(ballRig.transform.position, playerRig.transform.position, 5f);
           
        }
    }
    void Jump()
    {           
        force = new Vector3(0, jump, 0);
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
        {
            isGrounded = false;
            playerRig.AddForce(force, ForceMode.Impulse);          
        }
       
    }
    private void OnCollisionEnter(Collision collision)
    {
        
        if(collision.gameObject.tag == "Ball" && heldObj == null)
        {
            ballRig.isKinematic = true;
           // ballRig.constraints = RigidbodyConstraints.FreezeRotation;
            ballRig.transform.parent = playerRig.transform;
            isTouching = true;
            Debug.Log(" BALL PICKED UP AND MOVING ");
            heldObj = Ball;
        }
    }
    public void ReleaseTheBall()
    {
        if (Input.GetKeyDown(KeyCode.Space) && heldObj != null)
        {
            isTouching = false;
            heldObj = null;
            ballRig.transform.parent = null;
            //ballRig.constraints = RigidbodyConstraints.None;
            ballRig.isKinematic = false;

            //Vector3 forceDirection = new Vector3(playerRig.transform.position.x, 0, playerRig.transform.position.z);
            Vector3 rotationDirection = new Vector3(playerRig.transform.rotation.x, playerRig.transform.rotation.y, playerRig.transform.rotation.z);
            ballRig.AddForce(new Vector3(transform.position.x,0,transform.position.z) * 5, ForceMode.Impulse);
            ballRig.AddTorque(rotationDirection * 1);
            Debug.Log("BALL RELEASED");
           
           


        }
    }
    public void GameOver()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }
  
}

我知道这里可能有一些效率很低的代码行,也可以随意地调用这些行。所以,基本上,我想要的是,我希望我的球员一碰到球就能捡起球,而球的移动应该就像他手里拿着球一样,当我击中空格键时,我希望球被释放到我正在寻找的方向(这部分对我来说也很棘手),我想要做的是,我想要做的完全一样,在参考剪辑。提前谢谢。

还有一件事,当我停止按下任何移动键(WASD)时,我的玩家转换会不断地上下改变值,然后开始稍微移动。我的意思是,当我没有按任何键,它仍然有点移动。

EN

回答 1

Stack Overflow用户

发布于 2022-07-12 20:01:31

首先,您确实有相当多的行在这里没有用,而且可以进行优化。不管怎样,我希望这能做你想做的事:

代码语言:javascript
运行
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

[RequireComponent(typeof(Rigidbody))]
public class Player : MonoBehaviour {
    [Header("Movement Setup")]
    [Tooltip("Translation speed in m/s")]
    [SerializeField] float _TranslationSpeed;
    [Tooltip("Rotation speed in °/s")]
    [SerializeField] float _RotationSpeed;
    [Tooltip("Interpolation speed [0;1]")]
    [SerializeField] float _InterpolationSpeed;
    [Tooltip("Strength for jumps")]
    [SerializeField] float _JumpingStrength;
    [Tooltip("Strength for shoots")]
    [SerializeField] float _ShootingStrength;

    [Header("Other Settings")]
    [Tooltip("Where the helded item will be placed")]
    [SerializeField] Transform _ContactPoint;
    [Tooltip("Which layers should be considered as ground")]
    [SerializeField] LayerMask _GroundLayer;

    // The player's rigid body
    Rigidbody _Rigidbody;

    // Is the player on the ground
    bool _IsGrounded;

    // Rigidbody of what's the player is helding. Null if the player isn't holding anything
    Rigidbody _HeldedItemRigidbody;

    // Getter to _IsGrounded, return true if the player is grounded
    public bool IsGrounded { get { return _IsGrounded; } }

    private void Start() {
        _Rigidbody = GetComponent<Rigidbody>(); // The player's rigidbody could be serialized
    }

    void FixedUpdate() {
        float horizontalInput, verticalInput;

        // Getting axis
        horizontalInput = Input.GetAxis("Horizontal");
        verticalInput = Input.GetAxis("Vertical");

        // Moving toward the x
        Vector3 moveVect = transform.forward * _TranslationSpeed * Time.fixedDeltaTime * verticalInput;
        _Rigidbody.MovePosition(_Rigidbody.position + moveVect);

        // Rotating the player based on the horizontal input
        float rotAngle = horizontalInput * _RotationSpeed * Time.fixedDeltaTime;
        Quaternion qRot = Quaternion.AngleAxis(rotAngle, transform.up);
        Quaternion qRotUpRight = Quaternion.FromToRotation(transform.up, Vector3.up);
        Quaternion qOrientationUpRightTarget = qRotUpRight * _Rigidbody.rotation;
        Quaternion qNewUpRightOrientation = Quaternion.Slerp(_Rigidbody.rotation, qOrientationUpRightTarget, Time.fixedDeltaTime * _InterpolationSpeed); // We're using a slerp for a smooth movement
        _Rigidbody.MoveRotation(qRot * qNewUpRightOrientation);

        // This prevents the player from falling/keep moving if there is no input
        if (_IsGrounded) _Rigidbody.velocity = Vector3.zero;
        _Rigidbody.angularVelocity = Vector3.zero;

        if (transform.position.y < -10) GameOver();

        if (Input.GetKey(KeyCode.Mouse0) && _HeldedItemRigidbody != null) ShootTheBall();

        if (!_IsGrounded) return; // What's below this won't be executed while jumping
        if (Input.GetKey(KeyCode.Space)) Jump();
    }

    void Jump() {
        _IsGrounded = false;
        _Rigidbody.AddForce(_JumpingStrength * transform.up, ForceMode.Impulse);
    }

    private void OnCollisionEnter(Collision collision) {
        // Checking if the player encountered a ground object
        if ((_GroundLayer & (1 << collision.gameObject.layer)) > 0) _IsGrounded = true;

        if (collision.gameObject.tag == "Ball") { // this can be improved as tags are error prone
            // Setting the item position to contact point
            collision.gameObject.transform.position = _ContactPoint.position;

            // Getting the rigidbody
            _HeldedItemRigidbody = collision.gameObject.GetComponent<Rigidbody>();

            // Setting the parent
            _HeldedItemRigidbody.transform.parent = transform;

            // Setting the body to be kinematic
            _HeldedItemRigidbody.isKinematic = true;

            // Stopping any movement or rotation
            _HeldedItemRigidbody.velocity = Vector3.zero;
            _HeldedItemRigidbody.angularVelocity = Vector3.zero;
        }
    }

    public void ShootTheBall() {
        // Reverting what's done in OnCollisionEnter
        _HeldedItemRigidbody.transform.parent = null;
        _HeldedItemRigidbody.isKinematic = false;

        // Adding force for the shoot
        _HeldedItemRigidbody.AddForce(transform.forward * _ShootingStrength, ForceMode.Impulse);

        // Resetting helding item to null
        _HeldedItemRigidbody = null;
    }

    public void GameOver() {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }
}

您必须添加一个层,并为这个新层设置基础。根据您的喜好设置变量,不要犹豫,用它来找适合您的东西(也不要忘记设置玩家的质量(在刚体中)!) 播放器脚本设置示例

最后一件事,你必须添加一个空的游戏对象到你的球员,这将是球将被放置的地方。我知道它有点脏,但把它放在离球员有点远(超过球的半径),否则它会出错。我们可以用编程的方法把球固定在一个位置上,并根据球的半径来调整这个点。这是玩家的一个例子

正如你所看到的,我有一个空的" player“游戏对象,它有刚体、对撞机和播放器脚本。GFX项目,这只是胶囊。如果你不知道这一点:玩家的游戏对象实际上是在地板上(在玩家的脚),所以它是更好的运动。如果你这样做,不要忘记调整玩家的胶囊对撞机,以适应GFX。我也有联系人。忘记鼻子的东西,这只是一种方法,看看球员面对的地方,当你只有一个胶囊。

如果你有什么问题,可以随便问。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72955939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档