Je construis un jeu de course de marbre assez simple dans Unity3D. La balle est un objet physique 3D qui se déplace uniquement sur les axes X et Y. Il a la capacité de rouler à gauche et à droite et de sauter. Assez basique, sauf que j'ai rencontré un problème révolutionnaire: en tombant et en frappant le sol, l'amplitude du rebond de la balle peut être combinée avec sa force de saut pour créer un saut extra-haut. Cela signifie que, avec des pressions de bouton bien synchronisées, le joueur peut faire rebondir la balle de manière exponentielle plus haut, atteignant des hauteurs involontaires. Je ne peux pas concevoir correctement les niveaux tant que ce problème n'est pas résolu. J'ai illustré cet exemple:
Cependant, le saut n'est pas aussi simple que de simplement tirer le ballon vers le haut. Afin de faciliter la complexité de la conception des niveaux, j'ai programmé l'angle de saut par rapport à la surface sur laquelle la balle roule.
La figure 3 , dans cette illustration, montre comment mon jeu fonctionne jusqu'à présent; pas la figure 4 . Cela rend la résolution du problème de rebond + saut beaucoup plus difficile, car je ne peux pas simplement mesurer et définir une force ou une vitesse exacte sur l'axe Y. Cela entraîne un comportement étrange, qui devient considérablement plus visible lorsque la balle se déplace sur des pentes plus raides.
Jusqu'à présent, j'ai été en mesure de concevoir une solution à tous les autres problèmes de conception de ce jeu et de découvrir comment les programmer, mais celui-ci m'a bloqué. J'ai essayé un certain nombre d'approches différentes, mais aucune n'a fonctionné.
Voici le script C # qui contrôle le saut de la balle:
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();
}
}
}
Ma dernière tentative a été d'essayer de sauter - rigidbody.velocity.magnitude * 50 , pour réduire la puissance de saut de la vitesse à laquelle la balle se déplace. Il a presque résolu le problème de rebond + saut, en réduisant proportionnellement la force de saut à zéro lorsque la vitesse de la balle a atteint ce qui semblait être l'équivalent en vitesse.magnitude. Il a fonctionné à l'arrêt, mais le problème est qu'il tient également compte de l'amplitude pendant que la balle est au sol, empêchant la balle de rouler à pleine vitesse et de sauter. J'étais proche, mais pas tout à fait là!
Je suis un programmeur novice et je suis perplexe ici. Quelqu'un peut-il m'aider à trouver une solution créative à ce problème? Tant que le joueur est capable de rebondir et de sauter de plus en plus haut, je ne peux concevoir aucun niveau, car ils pourront tous être trompés. J'adorerais continuer - ce problème me retient depuis longtemps, alors j'apprécierais grandement quelques conseils!