Game (not fake game): Geometry Dash
In Geometry Dash, players control a square, guiding it to jump over obstacles and reach the end. If the square falls off the map or collides with obstacles, it disappears only to respawn at the starting point.
Screen Recording:
Play by others:
Development:
1. Basic Movement of the Cube: At first, I need to accomplish the basic movement of the cube, including the jump and the rotation. The jump function is not hard to realize, but the square rotation function needs some calculation formulas and detailed data. Then, I studied this tutorial and completed the basic jump rotation function according to the data given in the tutorial.
if (OnGround()) { Vector3 Rotation = Sprite.rotation.eulerAngles; Rotation.z = Mathf.Round(Rotation.z / 90) * 90; Sprite.rotation = Quaternion.Euler(Rotation); //jump if (Input.GetKeyDown(KeyCode.Space)) { rb.velocity = Vector2.zero; rb.AddForce(Vector2.up * 26.6581f * Gravity, ForceMode2D.Impulse); } } else { Sprite.Rotate(Vector3.back, 452.4152186f * Time.deltaTime * Gravity); }
2. Build collision logic: Cubes can move normally on the ground, but will collide with the side of the platform, resulting in death and respawn. I used a function to determine if it is colliding by detecting if it overlaps with the box area specified by the other colliders on the specified layer, and returns a boolean value.
bool OnGround() { return Physics2D.OverlapBox(GroundCheckTransform.position + Vector3.up - Vector3.up * (Gravity - 1 / -2), Vector2.right * 1.1f + Vector2.up * GroundCheckRadius, 0, GroundMask); } bool TouchingWall() { // 将盒子的位置稍微向上移动,以确保它与角色的侧面接触 Vector2 boxPosition = (Vector2)transform.position + (Vector2.right * 0.55f) + Vector2.up * 0.1f; return Physics2D.OverlapBox( boxPosition, new Vector2(GroundCheckRadius * 2, 1.0f), // Use GroundCheckRadius * 2 for the width of the box 0, GroundMask ); }
3. Map Design: To enhance the game’s challenge, I designed some intricate areas, including traps. This step involves creating maps that are both interesting and challenging, ensuring players experience a sense of challenge.
I referenced some of the official designs:
4. Integration of Sound: I added sound effects by creating a sound manager and binding relevant code to it. The death sound effect will be triggered when the square hits the obstacles or falls out of the map. Additionally, I added background music.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundManager : MonoBehaviour { public static AudioSource audioSrc; public static AudioClip die; public static AudioClip bgm; private static bool isBgmPlaying = false; // Start is called before the first frame update void Start() { audioSrc = GetComponent<AudioSource>(); die = Resources.Load<AudioClip>("game"); bgm = Resources.Load<AudioClip>("bgm"); PlayBgm(); } // Update is called once per frame void Update() { } public static void PlayClip() { audioSrc.PlayOneShot(die); } public static void PlayBgm() { if (!isBgmPlaying) { audioSrc.clip = bgm; audioSrc.loop = true; // 设置为循环播放 audioSrc.Play(); isBgmPlaying = true; } } public static void StopBgm() { // 停止背景音乐 audioSrc.Stop(); isBgmPlaying = false; } }
5. Deathzone, Endzone, and Text Display: I introduced “Deathzone”, “Endzone”, and used TextMeshPro to display time and attempts. At the end of the game, the player’s game time and attempts will be calculated and displayed on the interface. This allows players to see their performance.
void CheckDeathZoneTrigger() { // 使用 Collider2D 的方法检测当前角色是否与DeathZone相交 if (deathZoneCollider != null && deathZoneCollider.IsTouching(GetComponent<Collider2D>())) { // 如果角色与DeathZone相交,执行死亡操作 Die(); } } void CheckEndTrigger() { if (endTrigger != null && endTrigger.IsTouching(GetComponent<Collider2D>())) { EndGame(); } } void EndGame() { gameEnded = true; // 计算时间和尝试次数 float endTime = Time.time; float gameTime = endTime - startTime; // 显示游戏结束文本 SetGameOverTextVisibility(true); gameOverText.text = "Congratulations"; timeText.text = "Time: " + gameTime.ToString("F2") + "s"; // 保留两位小数 attemptText.text = "Attempts: " + attempts.ToString(); Time.timeScale = 0f; } void SetGameOverTextVisibility(bool isVisible) { gameOverText.gameObject.SetActive(isVisible); timeText.gameObject.SetActive(isVisible); attemptText.gameObject.SetActive(isVisible); } }
In this attempt, I learned how to implement basic player movement, including moving left and right and jumping; I understood some collision logic and how to detect the player’s interactions with the ground, platforms, and walls; I also constructed challenging level designs with traps and tricky sections to increase the difficulty of the game; and I learned to incorporate musical sound effects into the game.
Challenges:
1. Some mechanics: Adjust the parameters of rotation speed, gravity, movement speed, and jump height to make the game playable and look comfortable.
2. Collision detection: Ensuring accurate collision detection, especially when dealing with different platforms and walls, can be challenging.