【发布时间】:2020-06-08 18:27:59
【问题描述】:
我正在使用 Unity 开发 3d FPS 游戏。目前,我正在实施一个穿墙机制。这背后的逻辑非常简单——如果玩家向前推进,但没有接地,并且接触到墙壁,我会限制 Y/Z 方向(但玩家仍然可以向前跑,因为我忽略了 X 方向)并关闭重力。它似乎工作正常,有点笨拙但对我来说还可以。除非,当墙被抛在身后时,玩家仍然可以在半空中奔跑,直到他失去惯性(这里是示例:https://imgur.com/a/LtbWs9J)。代码如下:
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(AudioSource))]
public class WallRunning : MonoBehaviour
{
public AudioClip audioClip;
private CharacterMovement cm;
private Rigidbody rb;
private bool isJumping;
public bool isWall;
private bool playAudio;
private AudioSource audioSource;
public float energyLimit = 3.5f;
private void Start()
{
//Get attached components so we can interact with them in our script.
cm = GetComponent<CharacterMovement>();
rb = GetComponent<Rigidbody>();
audioSource = GetComponent<AudioSource>();
}
private void FixedUpdate()
{
bool jumpPressed = Input.GetButtonDown("Jump");
float verticalAxis = Input.GetAxis("Vertical");
//Check if the controller is grounded.
if (cm.Grounded)
{
isJumping = false;
isWall = false;
}
//Has the jump button been pressed.
if (jumpPressed)
{
StartCoroutine(Jumping());
}
//If we are pushing forward, and not grounded, and touching a wall.
if (verticalAxis > 0 && isJumping && isWall)
{
StartCoroutine(Energy());
//We constrain the Y/Z direction to defy gravity and move off the wall.
//But we can still run forward as we ignore the X direction.
rb.useGravity = false;
rb.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezeRotation;
//We also telegraph to the player by playing a sound effect on contact.
if (audioClip != null && playAudio == true)
{
audioSource.PlayOneShot(audioClip);
//We block more audio being played while we are on the wall.
playAudio = false;
}
}
else
{
StopCoroutine(Energy());
//We need to make sure we can play audio again when touching the wall.
playAudio = true;
rb.useGravity = true;
rb.constraints = RigidbodyConstraints.FreezeRotation;
}
}
void OnCollisionEnter(Collision other)
{
//Are we touching a wall object?
if (other.gameObject.CompareTag("Walls"))
{
isWall = true;
}
}
void OnCollisionExit(Collision other)
{
//Did we stop touching the wall object?
if (!other.gameObject.CompareTag("Walls"))
{
isWall = false;
}
}
IEnumerator Jumping()
{
//Check for 5 frames after the jump button is pressed.
int frameCount = 0;
while (frameCount < 5)
{
frameCount++;
//Are we airbourne in those 5 frames?
if (!cm.Grounded)
{
isJumping = true;
}
yield return null;
}
}
IEnumerator Energy()
{
yield return new WaitForSeconds(energyLimit);
isWall = false;
}
}
注意:墙壁上有盒子碰撞器(“Is Trigger”复选框未选中),并且玩家连接了非运动刚体和胶囊碰撞器。墙没有标记为“静态”并分配给默认层,而玩家被分配给玩家层。
我做错了什么?我确定我搞砸了代码,但无法找出问题所在。
【问题讨论】:
标签: c# unity3d game-development