Я строю довольно простую гоночную игру на мраморе в Unity3D. Шар - это трехмерный физический объект, который движется только по осям 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();
}
}
}
Моя последняя попытка состояла в том, чтобы попробовать прыжок - solidbody.velocity.magnitude * 50 , чтобы уменьшить силу прыжка на скорость, с которой движется мяч. Он почти решил проблему прыжок + прыжок, пропорционально уменьшив силу прыжка до нуля, когда скорость мяча достигла того, что казалось эквивалентным по скорости. Он работал с нуля, но проблема в том, что он также учитывает величину, когда мяч заземлен, не давая мячу катиться на полной скорости и прыгать. Я был близко, но не совсем там!
Я начинающий программист, и я в тупике. Может ли кто-нибудь помочь мне найти творческое решение этой проблемы? Пока игрок может непрерывно подпрыгивать и прыгать все выше и выше, я не могу проектировать какие-либо уровни, потому что все они будут в состоянии быть обманутыми. Я хотел бы двигаться дальше - эта проблема долго сдерживала меня, поэтому я был бы очень признателен за некоторые советы!
Ответы:
Прежде всего, я хочу сказать, что ваш вопрос очень хорошо написан, и это приятно :), вам просто нужно удалить то, что не нужно в коде (аудиоисточники и т. Д.), И это было бы идеально. Приветствия для этого.
Для ответа вы можете ограничить свою скорость при прыжке, что помешает вам достичь слишком высоких скоростей при нажатии кнопки прыжка.
источник
В то время как я лично люблю прыжки кролика ... В качестве отправной точки мы должны знать предполагаемую «скорость прыжка» как дельта-скорость. Эта цифра представляет увеличение скорости (в линии с «нормальным прыжком») в момент прыжка один раз.
Любая скорость, которую игрок уже имеет в соответствии с нормой прыжка, может рассматриваться как существующая «энергия прыжка». Это приводит к прямому решению: мгновенная дельта-скорость может быть ограничена так, что она никогда не приводит к ускорению игрока сверх целевой скорости.
Чтобы измерить вашу ранее существовавшую скорость прыжка, мы можем взять точечное произведение вашего нормализованного вектора прыжка и скорости вашего игрока:
«Существующая скорость» также здесь принудительно неотрицательна; Когда игрок падает, существующая отрицательная скорость прыжка компенсирует его падение, позволяя ему подпрыгивать на воздухе, если он запускает прыжок во время падения.
Теперь, когда мы знаем, насколько точно уменьшить дельта-скорость, мы можем вычислить эффективный «вектор скачка», масштабируя нормаль скачка до целевой дельта-скорости.
На этот раз скорректированная скорость прыжка принудительно неотрицательна; Если игрок уже поднимается быстрее, чем он должен быть в состоянии прыгнуть, он достигнет отрицательно скорректированной скорости, что позволяет ему использовать действие «прыжка» в качестве тормоза. (чтобы мгновенно замедлиться до намеченной скорости прыжка!)
Примечание: я считаю, что ваши контакты X и Y уже нормализованы как пара. Я включил явные детали для полноты ради хотя.
источник
Этот ответ, возможно, является скорее изменением дизайна, чем вы ожидаете, но как насчет этого - после нажатия на кнопку прыжка у мяча короткий промежуток времени, когда он твердо стоит на земле и отменяет любой вертикальный импульс вверх (может быть бит для обозначения пружинного сжатия), а затем прыгает вверх после окончания этого периода. Это решило бы проблему добавления импульса отскока к прыжку, хотя это также позволило бы игрокам контролировать, отскочили они или просто прыгнули. Это также добавляет задержку к функции прыжка, которая может рассматриваться как хорошая (кажется более естественной) или плохая (не дает игрокам достаточно времени для ответа).
источник