【发布时间】:2021-06-01 21:07:25
【问题描述】:
我正在尝试在 Unity 中制作一个基本的 FPS 游戏,但我遇到了一个问题,即我射击的弹丸无法在正确的位置实例化。据我所知,无论我在哪里看,弹丸都会在相对于玩家的大致相同位置实例化(该位置在玩家起始角度的左侧一点点)。
这是一个 20 秒的视频演示我在说什么。
即使我面对的方向与弹丸通常实例化的方向完全相反,它仍然会在同一个地方生成,这意味着弹丸最终会在玩家身后生成并击中玩家。
我尝试使用 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 增加速度,从而产生加速效果。不过,这似乎不太可能导致问题,因为即使静止不动也会发生。