【问题标题】:FPS Projectile firing from the wrong placeFPS 弹丸从错误的地方发射
【发布时间】:2021-06-01 21:07:25
【问题描述】:

我正在尝试在 Unity 中制作一个基本的 FPS 游戏,但我遇到了一个问题,即我射击的弹丸无法在正确的位置实例化。据我所知,无论我在哪里看,弹丸都会在相对于玩家的大致相同位置实例化(该位置在玩家起始角度的左侧一点点)。

这是一个 20 秒的视频演示我在说什么。

https://youtu.be/WLVuqUtMqd0

即使我面对的方向与弹丸通常实例化的方向完全相反,它仍然会在同一个地方生成,这意味着弹丸最终会在玩家身后生成并击中玩家。

我尝试使用 Debug.DrawRay() 来查看火点本身是否错误(这将由从枪管以外的某处开始的射线显示)。然而,似乎光线的起点每次都是正确的。

我不确定这是否与上述问题有关,但我注意到如果我看向地平线以下一点,则光线方向是错误的。不管怎样,弹丸的方向似乎是正确的。

Ray directions when looking slightly above the horizon vs. lower

这是我的代码,用于实例化/射击射弹。我认为最相关的部分可能是 shootProjectile() 和 instantiateProjectile()。此脚本附加到玩家角色。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shooting : MonoBehaviour
{
    public Camera cam;
    public GameObject projectile;
    public Transform firePoint;//firePoint is set to the end of the barrel.
    public float projectileSpeed = 40;
    //private var ray;
    private Vector3 destination;
    // Start is called before the first frame update
    void Start()
    {
       
    }

    // Update is called once per frame
    void Update()
    {
        //var ray = cam.ViewportPointToRay(new Vector3(0.5f,0.5f,0));
        //Debug.DrawRay(ray.origin, ray.direction);
        if(Input.GetButtonDown("Fire1")) {
            //player is shooting
            ShootProjectile();
        }
    }

    void ShootProjectile() {
        Ray ray1 = cam.ScreenPointToRay(Input.mousePosition);
        
        //Debug.Log(ray.direction);
        RaycastHit hit;
        if(Physics.Raycast(ray1, out hit))//checking whether the player is going to hit something
        {
            destination = hit.point;
        }
        else {
            destination = ray1.GetPoint(1000);
        }
        Debug.DrawRay(firePoint.position, destination, Color.white, 10f);
        InstantiateProjectile(firePoint);

        
    }
    
    void InstantiateProjectile(Transform firePoint) {
        var projectileObj = Instantiate (projectile, firePoint.position, Quaternion.identity) as GameObject;//projectile is instantiated
        projectileObj.GetComponent<Rigidbody>().velocity = (destination - firePoint.position).normalized * projectileSpeed;//projectile is set in motion
    }
}

这里是firePoint的位置。

firePoint (i.e. where the projectile should instantiate)

我将不胜感激任何帮助,因为我已经尝试修复它(打开和关闭)好几天了,但真的不知道问题出在哪里。

编辑:这也是我的玩家移动脚本。第一个是 PlayerController.cs,它将玩家的输入转换为适当的运动矢量和相机旋转。然后它调用 PlayerMotor.cs 中的方法,实际执行动作。

播放器控制器

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
    [SerializeField]
    public float speed = 10f;
    [SerializeField]
    private float lookSens = 3f;

    private PlayerMotor motor;

    


    void Start() {
        motor = GetComponent<PlayerMotor>();
        //Debug.Log("PlayerControllerStart");
        Cursor.lockState = CursorLockMode.Locked;
    }

    void Update() {
        //Debug.Log("PlayerControllerUpdate");
        //calculate movement velocity as 3D vector.
        float xMov = Input.GetAxisRaw("Horizontal");
        float zMov = Input.GetAxisRaw("Vertical");
        Vector3 movHorizontal = transform.right * xMov;
        Vector3 movVertical = transform.forward * zMov;

        Vector3 velocity = (movHorizontal + movVertical).normalized * speed;
        motor.move(velocity);
        //speed*=(float)1.15;

        //rotation

        float yRot = Input.GetAxisRaw("Mouse X");
        Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSens;

        motor.rotate(rotation);

        float xRot = Input.GetAxisRaw("Mouse Y");
        Vector3 cameraRotation = new Vector3 (xRot, 0f, 0f) * lookSens;

        motor.rotateCamera(cameraRotation);

        if (Input.GetKeyDown(KeyCode.Space) == true && motor.isGrounded()) {
            
            motor.canJump=true;
        }
        if (Input.GetKey(KeyCode.W) == true) {
            
            motor.accel=true;
        }
        else{
            motor.accel=false;
        }
        
        
    }
}


PlayerMotor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{
    [SerializeField]
    private Camera cam;



    private Vector3 velocity = Vector3.zero;
    private Vector3 rotation = Vector3.zero;
    private Vector3 cameraRotation = Vector3.zero;
    private Vector3 jumpVector = new Vector3 (0f, 5f, 0f);
    private PlayerController pc;
    private Rigidbody rb;
    public bool canJump;
    public bool accel;
    public float acceleration;
    int jumpCount;

    void Start() {
        rb = GetComponent<Rigidbody>();
        pc = GetComponent<PlayerController>();
        canJump=false;
        jumpCount=0;
        accel=false;
        //acceleration = 1.0;
        //distToGround = collider.bounds.extents.y;
        //Debug.Log("PlayerMotorStart");
    }
    //sets velocity to a given movement vector.
    public void move(Vector3 _velocity) {
        velocity = _velocity;
    }
    public void rotate(Vector3 _rotation) {
        rotation = _rotation;
    }
    public void rotateCamera(Vector3 _cameraRotation) {
        cameraRotation = _cameraRotation;
    }
    public bool isGrounded() {
        return Physics.Raycast(transform.position, -Vector3.up, (float)2.5);
        
    }
    public void jump() {
        rb.AddForce(transform.up * 250f);
        //Debug.Log("Jump"+jumpCount);
        jumpCount++;
        canJump=false;
    }
    void FixedUpdate() {
        performMovement();
        performRotation();
        if (canJump) {
            
            jump();
        }
        //Debug.Log("PlayerMotorUpdate");
        if(accel&&pc.speed<20f&&isGrounded())
        {
            //Debug.Log("W Pressed");
            pc.speed*=(float)1.005;
        }
        else if(!accel) {
            pc.speed=7f;
            
        }
    }

    void performMovement() {
        if(velocity != Vector3.zero) {
            rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
            //Debug.Log("Movement");
        }
    }
    void performRotation() {
        
            rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
            if(cam != null) {
                cam.transform.Rotate(-cameraRotation);
            }
    }
    
}

这里还有一些我的弹丸预制件的图片。

【问题讨论】:

  • 我实际上将它添加到我的项目中,一切都对我有用。这意味着它一定不是移动脚本的问题。所以,别担心。这很可能与您的移动脚本、玩家设置或您的层次结构有关。
  • 我建议尝试查看火点的位置是否发生变化。我的意思是,你可以进入场景视图,同时打开游戏视图。玩游戏并在场景视图中选择火点。开始环顾四周,看看火点是否在不应该出现的地方。告诉我你得到了什么,并编辑你的原始帖子以显示你的运动脚本和弹丸预制件的图片。确保弹丸预制图片包含组件值。
  • 我在运行游戏时尝试观察火点,它固定在枪管的末端,似乎没有任何关闭。我在主帖中添加了额外的上下文,希望对您有所帮助。我不确定这将如何导致问题,但我所做的可能与其他运动脚本有相当大的偏差,那就是让它保持 w 增加速度,从而产生加速效果。不过,这似乎不太可能导致问题,因为即使静止不动也会发生。

标签: c# unity3d


【解决方案1】:

解决第一个困惑:Debug.DrawRay 方法作为参数

  • 开始位置
  • 射线方向(!)

你正在传递另一个位置,这不是你想要的。

只要您站在0,0,0 上,这可能只会“意外”起作用,所以也许它并不那么引人注目,但债务射线肯定指向错误的方向。

宁可做例如

Debug.DrawRay(firePoint.position, destination - firePoint.position, Color.white, 10f);

或者宁可使用Debug.DrawLine,它实际上需要

  • 开始位置
  • 结束位置

那你就不用先计算方向了

Debug.DrawLine(firePoint.position, destination, Color.white, 10f);

然后我怀疑发生了以下情况:生成的 projectileObj 实际上被正确放置但是它是该射弹预制件内的视觉效果与父预制件根有一个局部偏移。

由于您总是在世界旋转Quaternion.identity 中生成射弹,因此无论您在哪里看,偏移量都保持不变。

我想一个简单的解决方法已经是应用相同的旋转

var projectileObj = Instantiate (projectile, firePoint.position, firePoint.rotation);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多