Я будую досить просту мармурову гоночну гру в Unity3D. М'яч - це об'єкт фізики 3D, який рухається лише по осях X і Y. Він має здатність котитися вліво і вправо і стрибати. Досить основні речі, за винятком того, що я зіткнувся з проблемою розриву гри: При падінні та ударі об землю величину відскоку м'яча можна поєднувати зі своєю стрибковою силою для створення надзвичайно високого стрибка. Це означає, що при чіткому натисканні кнопок гравець може призвести до того, що м'яч підстрибує експоненціально вище, досягаючи ненавмисних висот. Я не можу правильно розробити рівні дизайну, поки ця проблема не буде виправлена. Я проілюстрував цей приклад:
Стрибки, однак, не такі прості, як просто вистріл м'яча прямо вгору. Щоб полегшити більш складність в дизайні рівнів, я запрограмував кут стрибка таким чином, щоб він був відносно поверхні, на яку котиться м'яч.
На малюнку 3 на цій ілюстрації показано, як працює моя гра до цих пір; не Рисунок 4 . Це робить рішення проблеми відскоку + стрибка набагато складнішим, оскільки я не можу просто виміряти та встановити точну силу чи швидкість на осі Y. Це призводить до дивної поведінки, яка стає помітно помітнішою, коли м'яч рухається крутішими схилами.
Поки що мені вдалося розібратися у вирішенні всіх інших проблем із дизайном у цій грі, а потім дізнатися, як їх запрограмувати, але ця мене застрягла. Я спробував декілька різних підходів, але жоден з них не спрацював.
Ось сценарій C #, який керує стрибками м'яча:
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();
}
}
}
Моєю останньою спробою було спробувати стрибок - rigidbody.velocity.magnitude * 50 , щоб зменшити силу стрибка на швидкість, з якою рухається м'яч. Це майже вирішило задачу відскоку + стрибка, пропорційно зменшивши силу стрибка до нуля, оскільки швидкість кулі досягла того, що здавалося еквівалентним у швидкості. Це спрацьовувало з затримки, але проблема полягає в тому, що він також враховує величину, коли м'яч заземлений, не даючи кульці котитися на повній швидкості і стрибати. Я був поруч, але не зовсім там!
Я початківець програміст, і я тут спотикаюся. Чи може хтось допомогти мені знайти творче рішення цієї проблеми? Поки гравець може постійно підстрибувати і стрибати все вище і вище, я не можу створити жодних рівнів, тому що всі вони просто зможуть пройти обман. Я хотів би рухатись вперед - ця тема вже давно стримує мене, тому я дуже вдячний за пораду!