Unity3D'de oldukça basit bir mermer yarış oyunu inşa ediyorum. Top, yalnızca X ve Y eksenlerinde hareket eden bir 3D fizik nesnesidir. Sola ve sağa dönme ve zıplama yeteneğine sahiptir. Oldukça basit şeyler, ancak bir oyun kırma problemine çarptığımda: Yere düştüğünde ve yere çarptığında, topun sıçrama büyüklüğü, ekstra yüksek bir sıçrama oluşturmak için atlama gücüyle birleştirilebilir. Bu, iyi zamanlanmış düğmeye basıldığında, oyuncunun topun katlanarak daha yüksek bir şekilde sıçramasına ve istenmeyen yüksekliklere ulaşmasına neden olabileceği anlamına gelir. Bu aksaklık giderilene kadar seviyeleri düzgün bir şekilde tasarlayamıyorum. Bu örneği gösterdim:
Ancak zıplama, topu yukarı doğru fırlatmak kadar basit değildir. Seviye tasarımında daha fazla karmaşıklık sağlamak için, atlama açısını topun yuvarlandığı yüzeye göre programladım.
Şekil 3 , bu örnekte, oyunumun şu ana kadar nasıl çalıştığı; Şekil 4 değil . Bu, sıçrama + atlama problemini çözmeyi çok daha zorlaştırır, çünkü Y ekseninde kesin bir kuvvet veya hız ölçüp ayarlayamıyorum. Bunu yapmak, top daha dik yamaçlarda ilerledikçe daha belirgin hale gelen garip davranışlarla sonuçlanır.
Şimdiye kadar, bu oyundaki diğer tüm tasarım sorunlarına bir çözüm tasarlayabildim ve sonra bunları nasıl programlayacağımı öğrendim, ama bu beni sıkıştı. Birkaç farklı yaklaşım denedim, ama hiçbiri işe yaramadı.
Topun zıplamasını kontrol eden C # betiği:
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();
}
}
}
En son denemem, atlama gücünü topun hareket hızıyla düşürmek için zıplamayı denemekti - rigidbody.velocity.magnitude * 50 . Topun hızı, hızdaki eşdeğeri gibi görünen şeye ulaştıkça, sıçrama kuvvetini orantılı olarak sıfıra düşürerek hemen hemen sıçrama + atlama problemini çözdü. Duruştan çalıştı, ancak sorun şudur, top topraklandığında büyüklüğün hesabını yapar, topun tam hızda yuvarlanmasını ve zıplamasını önler. Yakındım, ama tam olarak orada değil!
Ben acemi bir programcıyım ve burada güldüm. Herkes bu soruna yaratıcı bir çözüm bulmama yardımcı olabilir mi? Oyuncu sürekli zıplayabildiği ve daha yüksek ve daha yüksek zıplayabildiği sürece, herhangi bir seviye tasarlayamıyorum, çünkü hepsi sadece aldatılabilecek. Devam etmek isterdim - bu sorun beni uzun zamandır geri tutuyor, bu yüzden bazı tavsiyeleri çok takdir ediyorum!