Estoy construyendo un juego de carreras de mármol bastante simple en Unity3D. La pelota es un objeto de física en 3D que se mueve solo en los ejes X e Y. Tiene la capacidad de rodar a izquierda y derecha, y saltar. Cosas bastante básicas, excepto que me he topado con un problema que rompe el juego: al caer y golpear el suelo, la magnitud del rebote de la pelota se puede combinar con su fuerza de salto para crear un salto extra alto. Esto significa que, al presionar los botones a tiempo, el jugador puede hacer que la pelota rebote exponencialmente más alto, alcanzando alturas no deseadas. No puedo diseñar niveles correctamente hasta que se solucione este problema técnico. He ilustrado este ejemplo:
Sin embargo, el salto no es tan simple como disparar la pelota hacia arriba. Para facilitar una mayor complejidad en el diseño del nivel, he programado que el ángulo de salto sea relativo a la superficie sobre la que rueda la pelota.
La Figura 3 , en esa ilustración, es cómo funciona mi juego hasta ahora; No figura 4 . Esto hace que resolver el problema de rebote + salto sea mucho más desafiante, porque no puedo simplemente medir y establecer una fuerza o velocidad exacta en el eje Y. Hacerlo da como resultado un comportamiento extraño, que se vuelve dramáticamente más notable a medida que la pelota viaja en pendientes más pronunciadas.
Hasta ahora, he sido capaz de concebir una solución para todos los demás problemas de diseño en este juego y luego descubrir cómo programarlos, pero este me tiene atrapado. He intentado varios enfoques diferentes, pero ninguno de ellos ha funcionado.
Aquí está el script de C # que controla el salto de la pelota:
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();
}
}
}
Mi último intento fue intentar saltar - rigidbody.velocity.magnitude * 50 , para reducir la potencia de salto por la velocidad con la que viaja la pelota. Casi resolvió el problema de rebote + salto, reduciendo proporcionalmente la fuerza de salto a cero cuando la velocidad de la pelota alcanzó lo que parecía ser el equivalente en velocidad.magnitud. Funcionó desde un punto muerto, pero el problema es que también explica la magnitud mientras la pelota está en tierra, evitando que la pelota ruede a toda velocidad y salte. Estaba cerca, ¡pero no del todo!
Soy un programador novato, y estoy perplejo aquí. ¿Alguien puede ayudarme a encontrar una solución creativa a este problema? Mientras el jugador pueda rebotar y saltar continuamente más y más alto, no puedo diseñar ningún nivel, porque todos podrán ser engañados. Me encantaría seguir adelante: este problema me ha estado frenando durante mucho tiempo, ¡así que agradecería mucho algunos consejos!
Respuestas:
En primer lugar, quiero decir que su pregunta está muy bien escrita y es un placer :), solo necesitaría eliminar lo que no es necesario en el código (recursos de audio, etc.) y sería perfecto. Saludos por eso.
Para la respuesta, podría reducir su velocidad al saltar, lo que le impediría alcanzar velocidades demasiado altas al presionar el botón de salto.
fuente
Aunque personalmente me encantan los saltos de conejo ... Como punto de partida, deberíamos conocer la "Velocidad de salto" prevista como velocidad delta. Esta cifra representa el aumento de velocidad (en la línea con el "Salto normal") durante el instante de saltar una vez.
Cualquier velocidad que el jugador ya tenga en línea con el Jump Normal se puede ver como una "Energía de salto" preexistente. Esto conduce a una solución sencilla: la velocidad delta instantánea puede limitarse de modo que nunca se acelere más allá de la velocidad objetivo.
Para medir su velocidad de salto preexistente, podemos tomar el producto de punto de su vector de salto normalizado y la velocidad de su jugador:
La "Velocidad existente" también es forzada no negativa aquí; Cuando el jugador está cayendo, una velocidad de salto negativa existente compensará su caída, permitiéndole rebotar en el aire si dispara el salto mientras cae.
Ahora que sabemos cuánto reducir con precisión la velocidad delta, podemos calcular el "vector de salto" efectivo al escalar el salto normal a la velocidad delta objetivo.
Esta vez, la velocidad de salto ajustada se fuerza no negativamente; Si el jugador ya está subiendo más rápido de lo que debería poder saltar, alcanzaría una velocidad ajustada negativa, lo que les permite utilizar la acción de "salto" como frenos. (¡para reducir la velocidad de salto deseada al instante!)
Nota: Creo que su contacto X e Y ya están normalizados como un par. Sin embargo, incluí detalles explícitos por completo.
fuente
Esta respuesta es quizás un cambio de diseño más de lo que estás buscando, pero ¿qué tal esto? La pelota tiene un breve período después de presionar el botón de salto, donde permanece firmemente en el suelo y cancela cualquier impulso vertical hacia arriba (tal vez aplastando un para indicar una compresión similar a un resorte), luego salta hacia arriba después de que ese período ha concluido. Esto resolvería el problema del impulso del rebote que se agrega al salto, aunque también permitiría a los jugadores controlar si rebotaron o simplemente saltaron. También agrega un retraso a la función de salto, que puede verse como buena (se siente más natural) o mala (no les da a los jugadores suficiente tiempo para responder).
fuente