2D Unity射击游戏中的问题,玩家射击次数超过了应该允许的上限。

huangapple go评论53阅读模式
英文:

2d Unity Shooting Bug Where The Player Shoots More Than The Cap Should Allow

问题

这个Unity C# 2D玩家控制器脚本使玩家角色能够在必须站在地面上重新加载和射击之前连续射击两次。问题是玩家可以射击一次,等待片刻,然后连续射击三次,而上限应为两次,然后他们需要重新加载才能再次射击。任何见解或帮助将不胜感激。

using System.Collections;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public bool enableDebugLogs = false;
    public bool isGrounded;
    public bool isReloading;
    public bool isPlayingWindSound;
    public bool isFalling;
    public bool canMoveFreely;

    public float recoilForce = 10.0f;
    public float moveSpeed = 5.0f;
    public float maxSpeed = 10.0f;
    public float windSoundDelay = 1.0f;
    public float shotCooldown = 0.1f;
    public float timeFalling = 0.0f;
    public float groundedTime = 0.0f;
    public float groundedDuration = 0.2f;
    public float freeMoveDuration = 1.0f;
    public float idleTimeThreshold = 1.0f;
    public float reloadTime = 0.1f;

    public Camera mainCamera;
    public Transform groundCheck;
    public Vector2 groundCheckSize;
    public LayerMask groundLayer;
    public int maxShotsBeforeReload = 2;
    public int shotsFired;

    public AudioClip shootSound;
    public AudioClip windSound;
    public AudioSource audioSource;
    public AudioSource windAudioSource;
    public Texture2D crosshairTexture;
    private Vector3 savedPosition;

    private Rigidbody2D rb;
    private SpriteRenderer spriteRenderer;
    private Animator animator;

    private float lastShotTime;
    private float lastMouseMovementTime;
    private PlatformMovement currentPlatform;

    // ... 这里是其他函数,未包括在翻译中 ...
}

请注意,我只翻译了您提供的代码部分,没有包括其他内容。如果您需要更多帮助或有其他问题,请随时提出。

英文:

This Unity C# 2D Player Controller script has it so the player character is able to shoot twice before they have to be on the ground to reload and shoot again. The problem is that the player can shoot once, wait a few moments, and then shoot three times in a row when the cap should be two times and then they need to reload before they can shoot again. Any insight or help will be much appreciated.

using System.Collections;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public bool enableDebugLogs = false;
public bool isGrounded;
public bool isReloading;
public bool isPlayingWindSound;
public bool isFalling;
public bool canMoveFreely;
public float recoilForce = 10.0f;
public float moveSpeed = 5.0f;
public float maxSpeed = 10.0f;
public float windSoundDelay = 1.0f;
public float shotCooldown = 0.1f;
public float timeFalling = 0.0f;
public float groundedTime = 0.0f;
public float groundedDuration = 0.2f;
public float freeMoveDuration = 1.0f;
public float idleTimeThreshold = 1.0f;
public float reloadTime = 0.1f;
public Camera mainCamera;
public Transform groundCheck;
public Vector2 groundCheckSize;
public LayerMask groundLayer;
public int maxShotsBeforeReload = 2;
public int shotsFired;
public AudioClip shootSound;
public AudioClip windSound;
public AudioSource audioSource;
public AudioSource windAudioSource;
public Texture2D crosshairTexture;
private Vector3 savedPosition;
private Rigidbody2D rb;
private SpriteRenderer spriteRenderer;
private Animator animator;
private float lastShotTime;
private float lastMouseMovementTime;
private PlatformMovement currentPlatform;
public void Initialize(int shotsFired, bool isReloading)
{
this.shotsFired = shotsFired;
this.isReloading = isReloading;
}
private void Start()
{
rb = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
}
private void FixedUpdate()
{
isGrounded = Physics2D.OverlapBox(groundCheck.position, groundCheckSize, 0, groundLayer);
if (rb.velocity.y < 0)
{
timeFalling += Time.fixedDeltaTime;
if (timeFalling >= windSoundDelay && !isPlayingWindSound && !isFalling)
{
isFalling = true;
animator.SetBool("IsFalling", isFalling);
Debug.Log("IsFalling set to true");
if (!windAudioSource.isPlaying)
{
windAudioSource.clip = windSound;
windAudioSource.Play();
isPlayingWindSound = true;
}
}
if (isPlayingWindSound)
{
float volumeFactor = Mathf.Clamp(timeFalling / 10.0f, 0.0f, 1.0f);
windAudioSource.volume = volumeFactor;
}
}
else if (isGrounded)
{
timeFalling = 0.0f;
if (isFalling)
{
isFalling = false;
animator.SetBool("IsFalling", isFalling);
animator.SetBool("IsLayingDown", true);
}
if (isPlayingWindSound)
{
StartCoroutine(FadeOutWindSound(0.2f));
}
}
if (shotsFired >= maxShotsBeforeReload && !isReloading && isGrounded)
{
isReloading = true;
StartCoroutine(Reload());
}
if (isGrounded)
{
groundedTime += Time.fixedDeltaTime;
}
else
{
groundedTime = 0.0f;
}
Vector2 mousePosition = mainCamera.ScreenToWorldPoint(Input.mousePosition);
Vector2 shotDirection = (mousePosition - (Vector2)transform.position).normalized;
float facingDirection = 1.0f;
if (spriteRenderer.flipX)
{
facingDirection = -1.0f;
}
animator.SetFloat("LookHorizontal", shotDirection.x * facingDirection);
animator.SetFloat("LookVertical", shotDirection.y);
if (animator.GetBool("IsLayingDown") == false)
{
if (shotDirection.x > 0)
{
spriteRenderer.flipX = false;
}
else if (shotDirection.x < 0)
{
spriteRenderer.flipX = true;
}
}
float horizontalInput = Input.GetAxis("Horizontal");
Debug.Log("Horizontal Input: " + horizontalInput); // Debug code
animator.SetFloat("Speed", Mathf.Abs(horizontalInput));
if (Mathf.Abs(horizontalInput) > 0 && isGrounded) // if there is any horizontal input and the player is grounded
{
animator.SetBool("IsLayingDown", false); // set IsLayingDown to false
}
if (Input.GetMouseButtonDown(0) && shotsFired < maxShotsBeforeReload && !isReloading && !animator.GetBool("IsLayingDown") && Time.time - lastShotTime >= shotCooldown)
{
shotsFired++;
lastShotTime = Time.time; // Update the time of the last shot
rb.AddForce(-shotDirection * recoilForce, ForceMode2D.Impulse);
animator.SetBool("IsRecoiling", true);
StartCoroutine(StopRecoilAnimation());
audioSource.PlayOneShot(shootSound);
}
if ((isGrounded || canMoveFreely))
{
Vector2 horizontalForce = new Vector2(horizontalInput * moveSpeed, 0);
Debug.Log("Horizontal Force: " + horizontalForce); // Debug code
rb.AddForce(horizontalForce, ForceMode2D.Force);
}
if (rb.velocity.magnitude > maxSpeed)
{
rb.velocity = rb.velocity.normalized * maxSpeed;
}
animator.SetBool("IsGrounded", isGrounded);
// Check for mouse movement
if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
{
lastMouseMovementTime = Time.time;
animator.SetBool("MouseMoving", true);
}
else
{
animator.SetBool("MouseMoving", false);
}
// Check if the time since the last mouse movement exceeds the threshold
if (Time.time - lastMouseMovementTime > idleTimeThreshold)
{
animator.SetBool("IsIdle", true);
}
else
{
animator.SetBool("IsIdle", false);
}
Debug.Log("Player Velocity: " + rb.velocity); // Debug code
}
private IEnumerator FadeOutWindSound(float duration)
{
float startVolume = windAudioSource.volume;
float elapsedTime = 0.0f;
while (windAudioSource.volume > 0.0f)
{
elapsedTime += Time.fixedDeltaTime;
windAudioSource.volume = Mathf.Lerp(startVolume, 0.0f, elapsedTime / duration);
yield return null;
}
windAudioSource.Stop();
isPlayingWindSound = false;
}
public void EnableFreeMovement()
{
canMoveFreely = true;
StartCoroutine(DisableFreeMovement());
}
private IEnumerator DisableFreeMovement()
{
yield return new WaitForSeconds(freeMoveDuration);
canMoveFreely = false;
}
private IEnumerator Reload()
{
isReloading = true;
Debug.Log("Reloading started.");
yield return new WaitForSeconds(reloadTime);
shotsFired = 0;
isReloading = false;
Debug.Log("Reloading finished. Current shot count: " + shotsFired);
}
private IEnumerator StopRecoilAnimation()
{
yield return new WaitForSeconds(animator.GetCurrentAnimatorStateInfo(0).length);
animator.SetBool("IsRecoiling", false);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(groundCheck.position, groundCheckSize);
}
private void OnCollisionEnter2D(Collision2D collision)
{
PlatformMovement platformMovement = collision.gameObject.GetComponent<PlatformMovement>();
if (platformMovement)
{
currentPlatform = platformMovement;
}
}
private void OnCollisionExit2D(Collision2D collision)
{
PlatformMovement platformMovement = collision.gameObject.GetComponent<PlatformMovement>();
if (platformMovement && platformMovement == currentPlatform)
{
currentPlatform = null;
}
}
}

答案1

得分: 1

总体而言,逻辑似乎是正确的,但有一些地方可以显著改进。虽然您的问题涉及技术方面,但似乎主要问题在于您的代码组织。

首先,我想提出一个小问题。在FixedUpdate函数内处理输入可能会导致帧之间的不一致性和不精确性。有些帧会处理输入,而其他帧则不会。因此,建议考虑使用Update()。有时仅仅通过更改它就可以解决这个问题。

以下是一些增强您代码的提示:

清理和简化

仔细查看您的代码,以逻辑方式进行简化。不要使用shotsFiredmaxShotsBeforeReload,而是考虑使用更具描述性的变量名称,如magazineCountmagazineCap,或者甚至更简单的选项,如bulletsLeftbulletsMax。采用这种方法将导致更一致的逻辑。

组织您的代码

通过引入方法并在必要时修改其中的代码来减少复杂的逻辑。从逻辑上讲,首先检查shotsFired >= maxShotsBeforeReload是否有意义?也许在玩家射击后立即检查他们是否达到了最大子弹数更合乎逻辑。否则,他们将不得不等待另一个固定的更新。

引入局部变量

表达式如Time.time - lastShotTime >= shotCooldown可能难以阅读和维护。考虑引入一个局部布尔变量,如onCooldown = (Time.time - lastShotTime <= shotCooldown)。这将提高可读性并使您的代码更易管理。

希望这些建议能帮助您在代码的复杂结构中找到合适的解决方案。如有需要,请随时提出进一步的问题。

英文:

Overall, the logic appears to be sound, but there are several areas where it could be significantly improved. While your question pertains to technical aspects, it seems that the main issue lies in the organization of your code.

Firstly, I want to address a minor concern. Processing input inside the FixedUpdate function can lead to inconsistencies and imprecisions across frames. Some frames will process input, while others won't. Therefore, it is advisable to consider Update(). It can sometimes work just by changing that.

Here are some tips to enhance your code:

Clean up and simplify

Take a closer look at your code and aim to simplify it logically. Instead of using shotsFired and maxShotsBeforeReload, consider using more descriptive variable names like magazineCount and magazineCap, or even simpler options like bulletsLeft and bulletsMax. Adopting this approach will lead to more consistent logic.

Organize your code

Reduce complex logic by introducing methods and modifying the code within them if necessary. Logically, does it make sense to check if shotsFired &gt;= maxShotsBeforeReload first? It may be more logical to check if the player has reached the maximum number of bullets right after they shoot. Otherwise, they would have to wait for another fixed update.

Introduce local variables

Expressions like Time.time - lastShotTime &gt;= shotCooldown can be difficult to read and maintain. Consider introducing a local boolean variable like onCooldown = (Time.time - lastShotTime &lt;= shotCooldown). This will improve readability and make your code more manageable.

I hope these suggestions help you navigate through the complex structure of your code and find a suitable solution. Don't hesitate to ask further questions if needed.

huangapple
  • 本文由 发表于 2023年6月1日 02:37:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376415.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定