Sto costruendo un gioco di corse in marmo abbastanza semplice in Unity3D. La palla è un oggetto fisico 3D che si muove solo sugli assi X e Y. Ha la capacità di rotolare a sinistra ea destra e di saltare. Roba piuttosto semplice, tranne per il fatto che ho riscontrato un problema di rottura del gioco: quando cadi e colpisci il terreno, l'entità di rimbalzo della palla può essere combinata con la sua forza di salto per creare un salto extra-alto. Ciò significa che, con una pressione dei pulsanti tempestiva, il giocatore può far rimbalzare esponenzialmente la palla, raggiungendo altezze non intenzionali. Non riesco a progettare correttamente i livelli fino a quando questo problema tecnico non viene risolto. Ho illustrato questo esempio:
Il salto, tuttavia, non è così semplice come sparare la palla verso l'alto. Per facilitare una maggiore complessità nella progettazione del livello, ho programmato che l'angolo di salto sia relativo alla superficie su cui sta rotolando la palla.
La figura 3 , in quella illustrazione, mostra come funziona il mio gioco finora; non figura 4 . Questo rende la risoluzione del problema bounce + jump molto più impegnativa, perché non riesco semplicemente a misurare e impostare una forza o velocità esatta sull'asse Y. In questo modo si ottiene un comportamento strano, che diventa notevolmente più evidente quando la palla viaggia su pendenze più ripide.
Finora sono stato in grado di concepire una soluzione a tutti gli altri problemi di progettazione in questo gioco e poi scoprire come programmarli, ma questo mi ha bloccato. Ho tentato una serie di approcci diversi, ma nessuno di loro ha funzionato.
Ecco lo script C # che controlla il salto della palla:
using UnityEngine;
using System.Collections;
public class BallJumping : MonoBehaviour {
public System.Action onJump;
public Rigidbody objRigidbody; // Set this to the player
public bool isGrounded; // Determines whether or not the ball is on the ground
public Transform groundChecker; // A child object that's slightly larger than the ball
public float groundRadius = 0.6f;
public LayerMask whatIsGround; // Determines what layers qualify as ground
public AudioClip jumpSFX;
public AudioClip stickyJumpSFX;
private float p_WillJumpTimeRemaining; // Grace periods before/after hitting the ground to trigger jump
private float p_CanJumpTimeRemaining;
public float earlyJumpToleranceDuration = 0.2f;
public float lateJumpToleranceDuration = 0.2f;
public float jump = 500f; // Jumping power
private float halfJump = 250f; // Used for the sticky puddles
public bool stuck = false; // Used for sticky materials
private float contactX;
private float contactY;
// Input for jumping
void Update () {
if (Input.GetButtonDown ("Jump") && isGrounded == true) {
ProcessJump();
}
}
// Continuously checks whether or not the ball is on the ground
void FixedUpdate () {
if (Physics.CheckSphere (groundChecker.position, groundRadius, whatIsGround) == true) {
isGrounded = true;
} else {
isGrounded = false;
}
}
// Sets a grace period for before or after the ball contacts the ground for jumping input
void ProcessJump () {
bool boolGetJump = Input.GetButtonDown("Jump");
if (boolGetJump && isGrounded == false) {
p_WillJumpTimeRemaining = earlyJumpToleranceDuration;
} else {
if (p_WillJumpTimeRemaining > 0) {
p_WillJumpTimeRemaining -= Time.fixedDeltaTime;
}
}
if (isGrounded) {
p_CanJumpTimeRemaining = lateJumpToleranceDuration;
}
if (isGrounded || p_WillJumpTimeRemaining > 0) {
Jump();
}
if (p_CanJumpTimeRemaining > 0) {
p_CanJumpTimeRemaining -= Time.fixedDeltaTime;
}
}
// Sticky puddles script -- hinders jumping while in the puddle
void OnTriggerEnter (Collider collision) {
if (collision.gameObject.tag == "Sticky") {
stuck = true;
}
}
void OnTriggerExit (Collider collision) {
if (collision.gameObject.tag == "Sticky") {
stuck = false;
}
}
// Calculates the normals for the jump angle
void OnCollisionStay (Collision collision) {
Debug.Log ("Collision.");
foreach (ContactPoint contact in collision.contacts) {
contactX = contact.normal.x;
contactY = contact.normal.y;
}
}
// Controls jumping
void Jump() {
Debug.Log ("Jump.");
p_WillJumpTimeRemaining = 0.0f;
p_CanJumpTimeRemaining = 0.0f;
halfJump = jump * 0.5f; // Cuts jumping force in half while in a sticky puddle
GetComponent<AudioSource>().volume = 1;
GetComponent<AudioSource>().pitch = Random.Range (0.9f, 1.1f);
if (stuck == false) {
objRigidbody.AddForce (contactX * jump, contactY * jump, 0);
GetComponent<AudioSource>().clip = jumpSFX;
GetComponent<AudioSource>().Play ();
}
else if (stuck == true) {
objRigidbody.AddForce (contactX * halfJump, contactY * halfJump, 0);
GetComponent<AudioSource>().clip = stickyJumpSFX;
GetComponent<AudioSource>().Play ();
}
if (onJump != null) {
onJump();
}
}
}
Il mio ultimo tentativo è stato quello di provare a saltare - rigidbody.velocity.magnitude * 50 , per ridurre la potenza di salto della velocità con cui la palla sta viaggiando. Ha quasi risolto il problema di rimbalzo + salto, riducendo proporzionalmente la forza di salto fino a zero quando la velocità della palla ha raggiunto quello che sembrava essere l'equivalente in velocità. Ha funzionato da fermo, ma il problema è che spiega anche la grandezza mentre la palla è messa a terra, impedendo alla palla di rotolare a tutta velocità e saltare. Ero vicino, ma non del tutto lì!
Sono un programmatore alle prime armi, e sono perplesso qui. Qualcuno può aiutarmi a trovare una soluzione creativa a questo problema? Finché il giocatore è in grado di rimbalzare continuamente e saltare sempre più in alto, non posso progettare alcun livello, perché saranno tutti in grado di essere imbrogliati. Mi piacerebbe andare avanti - questo problema mi ha trattenuto per molto tempo, quindi apprezzerei molto alcuni consigli!