JumpJump (simple jump) of the Unity game instance development collection to quickly implement casual games

JumpJump (simple jump) of the Unity game instance development collection to quickly implement casual games

content

JumpJump (simple jump) of the Unity game instance development collection to quickly implement casual games

1. Brief introduction

2. JumpJump (simple jump) game content and operation

3. Game code framework

Four, knowledge points

Five, game effect preview

6. Implementation steps

7. Project source code address

Eight, extension


1. Brief introduction

Unity game instance development collection, using an easy-to-understand way to explain the development and implementation process of common games, to facilitate the reference and reuse of similar game development in the later stage.

This section introduces the quick implementation of JumpJump (simple jump) casual game. I hope it can help you. If there is something wrong, please leave a message.

2. JumpJump (simple jump) game content and operation

1. When the game starts, the platform will be automatically generated

2. Press the left button of the mouse and the character will automatically face the direction of the platform, long press the right button to charge

3. Release the left mouse button, and the character will perform a parabolic jump according to the amount of energy stored

4. If you land on the platform, the corresponding bonus points will be added. If you land on the platform, the game will end.

5. After the game is over, the game will automatically restart here

3. Game code framework

Four, knowledge points

1. MonoBehaviour life cycle functions: Awake, Start, Update, Destroy, OnGUI

2. Monitor the state of the mouse buttons for the Input button

3. Generation of GameObject.Instantiate objects, destruction of GameObject.Destroy objects

4. Camera follow management

5. Rigidbody2D gravity effect, add Collider for collision detection

6. GUIStyle GUI style, the function of adding text to GUI.Label

7. The use of Vector3.Lerp displacement vector interpolation, the use of Vector3.Distance position distance function

8. Unified constant management of some data, paths, etc.

9. Transform.Rotate is used for rotation

10. IEnumerator coroutine, StartCoroutine to start coroutine and StopAllCoroutines to stop the use of all coroutines

11. Use of simple parabolic motion of objects

12. The use of delegates in Action<int> OnChangeValue property changes

13. Use of Resources.Load<GameObject>() code to load prefabs

14. Simple use of Fog fog effect and simple implementation of gradient background

15. SceneManager.LoadScene loading, and SceneManager.GetActiveScene() current scene acquisition

16. Simple use of Lighting Settings scene lighting baking

17, and so on

Five, game effect preview

6. Implementation steps

This is a 3D game. It mainly uses resource components such as SpriteRenderer, 2D Collider, 2D Rigidbody, and TextMesh. All resources are native to Unity, and no other external texture model resources are imported.

1. First, make a simple gradient background, add a Plane, set as follows, and add a material

2. Open the settings and turn on the fog effect Fog, here is the key to the gradient background disconnection

3. Check Fog in Lighting's Other Settings, set the color, Mode is Liner, and set Start 10, End 13 (the details will be adjusted later)

3. Add a Cube and set the scale to (1,8,1) 

4. Set the Transform of Sky_Plane and the Main Camera (rotate the camera for the gradient from bottom to top (the color of Sky_Plane is displayed above)) The Transform is shown in the figure, the effect is as follows (set the vertical screen (800x1280))

5. Adjust the Rotation X of Sky_Plane again, and the Start and End of Lighting's Other Settings Fog. The final effect is as follows

6. We don't need Sky_Plane to receive projection and Collider, here we remove the Mesh Collider component

7. Create a new empty object GameObject, Reset its Transform, take MainCamera and Sky_Plane as its sub-objects, and change them to CameraGroup, which is convenient for moving with the protagonist Player later

8. According to the Cube, create Platforms with several colors of the platform, and cancel their cast shadow Cast Shadows to off (note: their child objects cancel the Collider component)

9. Create an empty object GameObject, rename it Player, add a Rigbody, XYZ of FreezeRotation

10. Player adds a Capsule, renamed Player_Capsule, Scale is adjusted according to the ratio of Platform, so here is adjusted to (0.5, 0.5, 0.5), here Y of Position is adjusted to 0.5 to make the bottom of Player_Capsule as the local coordinates of Player The origin is easy to change the Scale on Y (the base point of the change is scaled from the bottom) as shown in the figure, and finally the Sphere is used as the identification of the front direction (remove the Collider component)

11. Add TrailRenderer to the Player, and add the trailing effect of the movement (the effect is adjusted according to the actual effect). Here, set the width to 0.5 to decrease the gradient, the time to 0.5, the color as shown, add the TrailRenderer material, and the material shader is Particles/Additive , the effect is as follows

12. Use the Player as a prefab and place it in the resources/Prefabs folder

13. Add a UI Text to display the score

14. Add an empty object GameObject, rename it to World, put CameraGroup under it, and set the PlayerSpawnPos and FirstPlatFormCubeSpawnPos positions of GameObject reasonably as the initial generation positions of Player and Platform

15. Add a Platform script to the project, the main function is to inherit MonoBehaviour, control the animation of Platform generation in Update, jump into and trigger OnCollisionEnter event with Player, generate the next Platform, and increase the score

16. The main functions in Platform, PlatformSpawnAniamtion and FirstOnCollisionEnter

		/// <summary>
		/// 平台的上升动画
		/// </summary>
		void PlatformSpawnAniamtion() {
			if (m_IsSpawnAnimation == true)
			{
				m_MoveDeltra += 1f / GameConfig.PLATFRM_SPAWN_ANIMATION_MOVE_SPEED * Time.deltaTime;
				transform.position = Vector3.Lerp(transform.position, m_TargetPos, m_MoveDeltra);
				if (Vector3.Distance(transform.position, m_TargetPos) <= 0.01f)
				{
					transform.position = m_TargetPos;

					m_IsSpawnAnimation = false;
				}
			}
		}

		/// <summary>
		/// 第一次碰撞进入平台,触发对应事件
		/// 这里事件主要是 生成下一个 Platform 和 增加分数
		/// </summary>
		private void FirstOnCollisionEnter()
		{
			if (m_IsOnCollisionEntered == false)
			{
				m_IsOnCollisionEntered = true;
				m_OnCollisionEnterAction?.Invoke(this.transform.position);

			}
		}

17. Add a PlatformManager script to the project, the main function is to load all types of Platform prefabs, initialize the first random Platform generation, and set the platform to generate the next Platform event, and control the total number of Platforms retained in the game, Many delete the first Platform

18. The main functions of the PlatformManager script: LoadPlatformPrefabs() loads the Platform prefab, SetOnPlatformCubeEnterAction() sets the platform callback event, SpawnNext(Vector3 curPos, int score, Transform parent = null) randomly generates the next Platform direction and generates the next Platform, Spawn(Vector3 pos, int score, Transform parent = null, bool isMoveAnimation = false) Randomly generate a Platform, JudgePlatformQueueCount() controls the number of Platforms in the scene, if too many, delete the original Platform

		/// <summary>
		/// 加载 Platform 预制体
		/// </summary>
		void LoadPlatformPrefabs() {
            foreach (string resPath in ResPathDefine.PLATFORM_RES_PATH_LIST)
            {
				GameObject prefab = Resources.Load<GameObject>(resPath);
				if (prefab != null)
				{
					m_PlatformPrefabList.Add(prefab);
				}
				else {
					Debug.LogError(GetType()+ "/LoadPlatformPrefabs()/ prefab is null, resPath = " + resPath );
				}
            }
		}

		/// <summary>
		/// 设置平台回调事件(这个主要是分数事件)
		/// </summary>
		/// <param name="onPlatformEnterAction"></param>
		void SetOnPlatformCubeEnterAction(Action<int> onPlatformEnterAction)
		{
			m_OnPlatformEnterAction = onPlatformEnterAction;
		}

		/// <summary>
		/// 随机生成下一个 Platform 方向,并 生成下一个 Platform
		/// </summary>
		/// <param name="curPos">位置</param>
		/// <param name="score">增加的分数</param>
		/// <param name="parent">附载的父物体</param>
		/// <returns></returns>
		GameObject SpawnNext(Vector3 curPos, int score, Transform parent = null)
		{
			int rand = UnityEngine.Random.Range(0, (int)Dir.ENUM_COUNT);
			m_CurDir = (Dir)rand;
			switch (m_CurDir)
			{
				case Dir.Right:
					curPos.x += GameConfig.PLATFRM_CUBE_DISTANCE;

					break;
				case Dir.Forword:
					curPos.z += GameConfig.PLATFRM_CUBE_DISTANCE;
					break;
				case Dir.ENUM_COUNT:
					break;
				default:
					break;
			}

			return Spawn(curPos, score,parent, true);

		}

		/// <summary>
		///  随机生成一个 Platform
		/// </summary>
		/// <param name="curPos">位置</param>
		/// <param name="score">增加的分数</param>
		/// <param name="parent">附载的父物体</param>
		/// <param name="isMoveAnimation">是否进行上升动画</param>
		/// <returns></returns>
		GameObject Spawn(Vector3 pos, int score, Transform parent = null, bool isMoveAnimation = false)
		{
			int randValue = UnityEngine.Random.Range(0, m_PlatformPrefabList.Count);
			GameObject go = GameObject.Instantiate(m_PlatformPrefabList[randValue], parent);
			m_PlatformsQueue.Enqueue(go);
			Platform platform = go.GetComponent<Platform>();
            if (platform==null)
            {
				platform = go.AddComponent<Platform>();
			}

			platform.Init(
				(curPos) => {
					m_CurPlatformCube = m_NextPlatformCube;
					m_NextPlatformCube = SpawnNext(curPos, score, parent);

                    if (m_OnPlatformEnterAction!=null)
                    {
						m_OnPlatformEnterAction.Invoke(score);
                    }
				},
				pos,
				isMoveAnimation);

			return go;
		}

		/// <summary>
		/// 控制场景中 Platform 的数量
		/// 过多则删除最初的 Platform
		/// </summary>
		void JudgePlatformQueueCount() {
            if (m_PlatformsQueue.Count> GameConfig.PLATFORM_EXIST_COUNT)
            {
				GameObject.Destroy(m_PlatformsQueue.Dequeue());
            }
		}

19. Add a Player script to the project. The main function is to monitor Jump related events (left mouse button press, lift, etc.), generate a motion trajectory according to the duration of pressing the power, and monitor whether the Player falls to the Platform, inheriting Monobehaviour, Monitor collision events and other related functions

20. The main function of the Player script: UpdateJumpOperation() ump jumps the relevant mouse monitoring event, OnCollisionEnter(Collision collision) collision event, the jump can only be done on the platform

		/// <summary>
		/// Jump 跳一跳相关鼠标监听事件
		/// </summary>
		public void UpdateJumpOperation()
		{
			if (m_IsFallen == true)
			{
				return;
			}

			JudgeFallen();

			if (m_IsCanJump == false)
			{
				return;
			}

			if (Input.GetMouseButtonDown(0))
			{

				UpdatePlayerRotate();
				m_PressTime = 0;

			}
			if (Input.GetMouseButton(0))
			{

				m_PressTime += Time.deltaTime;
				if (m_PressTime >= GameConfig.MOUSE_PRESSING_TIME_LENGTH)
				{
					m_PressTime = GameConfig.MOUSE_PRESSING_TIME_LENGTH;

				}

				SmallScaleYAnimation();
			}
			if (Input.GetMouseButtonUp(0))
			{

				StartCoroutine(Jump());
				BackOriScale();
				m_IsCanJump = false;
			}

		}


        #region Unity Functions

		/// <summary>
		/// 碰撞事件,在平台才能 Jump
		/// </summary>
		/// <param name="collision"></param>
        private void OnCollisionEnter(Collision collision)
		{
			m_IsCanJump = true;

			// 第一碰撞平台的基础数据设置
			if (m_IsInitCollisionEnter == false)
			{
				m_IsInitCollisionEnter = true;
				m_ModelOriPos = this.transform.position;

			}

		}

		#endregion

21. The main functions of the Player script: IEnumerator Jump() coroutine, to implement jumping, JumpMoving(float jumpLength) to generate a jump trajectory according to the charging result, YParabola(float x, float k, float top) to calculate the Y value of the parabola, here Simple parabolic knowledge is required, and some transformations are required. Interested students can also realize it by themselves.

		/// <summary>
		/// 协程,进行跳跃实现
		/// </summary>
		/// <returns></returns>
		IEnumerator Jump()
		{
			float jumpLength = m_PressTime * GameConfig.PLAYER_MODEL_JUMP_LENGTH_SMOOTH_VALUE;
			oriPos = this.transform.localPosition;
			Vector3 nextPos = oriPos + transform.forward * jumpLength;
			movePos = nextPos - oriPos;
			m_JumpTime = m_JumpTime_Length;

			while (true)
			{
				if (m_JumpTime < 0)
				{
					break;
				}
				JumpMoving(jumpLength);
				yield return new WaitForEndOfFrame();
			}
		}
		
		/// <summary>
		/// 根据蓄力结果,生成跳跃轨迹
		/// </summary>
		/// <param name="jumpLength"></param>
		void JumpMoving(float jumpLength)
		{
			m_JumpTime -= Time.deltaTime;

			float deltra = (m_JumpTime_Length - m_JumpTime) / m_JumpTime_Length;
			var x = oriPos.x + movePos.x * deltra;
			var y = oriPos.y + YParabola(jumpLength * deltra, jumpLength / 2, GameConfig.PLAYER_MODEL_JUMP_TOP_DISTANCE);
			var z = oriPos.z + movePos.z * deltra;
			this.transform.localPosition = new Vector3(x, y, z);

		}

		/// <summary>
		/// 计算抛物线的 Y 值
		/// </summary>
		/// <param name="x"></param>
		/// <param name="k"></param>
		/// <param name="top">抛物线最高的点高度</param>
		/// <returns></returns>
		float YParabola(float x, float k, float top)
		{
			if (k == 0)
			{
				k = 1;
			}

			return top - (top * (x - k) * (x - k) / (k * k));
		}

22. The main functions of the Player script: UpdatePlayerRotate() according to the Platform position, the Player rotates, SmallScaleYAnimation() charges the Player's animation, BackOriScale() returns to the charge animation, JudgeFallen() judges whether the Player falls to the Platform

		/// <summary>
		/// 根据 Platform 位置,Player 进行转向
		/// </summary>
		void UpdatePlayerRotate()
		{
			float angle = 0;

			switch (m_PlatformManager.CurDir)
			{
				case Dir.Right:
					angle = Vector3.Angle(transform.forward, Vector3.right);
					this.transform.Rotate(Vector3.up, angle);
					break;
				case Dir.Forword:
					angle = Vector3.Angle(transform.forward, Vector3.forward);
					this.transform.Rotate(Vector3.up, -angle);
					break;

				default:
					break;
			}
		}

		/// <summary>
		/// 蓄力 Player 的动画
		/// </summary>
		void SmallScaleYAnimation()
		{
			if (this.transform.localScale.y <= m_ModelMinScaleY)
			{
				return;
			}

			this.transform.localScale = Vector3.Lerp(this.transform.localScale, 
				m_ModelMinScale, 
				Time.deltaTime * GameConfig.PLAYER_MODEL_SCALE_Y_SAMLL_SPEED);
		}

		/// <summary>
		/// 回到蓄力动画前
		/// </summary>
		void BackOriScale()
		{
			this.transform.localScale = m_ModelOriScale;
		}

		/// <summary>
		/// 判断 Player 是否坠落 Platform 
		/// </summary>
		void JudgeFallen()
		{
			if (this.transform.position.y < m_ModelOriPos.y - GameConfig.PLAYER_MODEL_FALL_DISTANCE_FROM_PLATFORM)
			{
				m_IsFallen = true;
			}
		}

23. Add the PlayerManager script to the project, the main function is to obtain the Player prefab and generate the Player in the scene

24. The main functions of the PlayerManager script are: IsFallen() Whether the Player has fallen, SpawnPlayer(Vector3 pos, Transform parent) generates the Player at the specified position

		/// <summary>
		/// Player 是否坠落
		/// </summary>
		/// <returns></returns>
		public bool IsFallen() {
			return m_Player.IsFallen;
		}
		

		/// <summary>
		/// 指定位置生成 Player
		/// </summary>
		/// <param name="pos">位置</param>
		/// <param name="parent">父物体</param>
		/// <returns></returns>
		Player SpawnPlayer(Vector3 pos,Transform parent) {
			Player player = null;

			if (m_PlayerPrefab==null)
            {
				GameObject prefab = Resources.Load<GameObject>(ResPathDefine.PLAYER_RES_PATH);
				if (prefab != null)
				{
					m_PlayerPrefab = (prefab);
				}
				else
				{
					Debug.LogError(GetType() + "/LoadPlatformPrefabs()/ prefab is null, resPath = " + ResPathDefine.PLAYER_RES_PATH);
				}
			}

			player = GameObject.Instantiate<GameObject>(m_PlayerPrefab, pos, Quaternion.identity).AddComponent<Player>();
			player.transform.SetParent(parent);

			return player;
		}

25. Add the CameraManager script to the project. The main function is to make the Camera follow the Platform that the Player jumps to, move, follow the Player, and SetOffSet() the position difference between the Camera and the Platform.

26. The main function of the CameraManager script: SetCameraTransPos() Camera animation moves to the specified Platform

		/// <summary>
		/// Camera 动画移动到指定 Platform 
		/// </summary>
		void SetCameraTransPos()
		{
			if (m_PlatformManager.CurPlatformCube != null)
			{
				m_CameraTrans.position = Vector3.Lerp(m_CameraTrans.position, 
					m_PlatformManager.CurPlatformCube.transform.position - m_OffsetPos, 
					Time.deltaTime * GameConfig.CAMERA_FOLLOW_PLAYER_SPEED);

			}
		}

		/// <summary>
		/// Camera 和 Platform 的位置差值
		/// </summary>
		void SetOffSet()
		{
			m_OffsetPos = m_PlatformManager.CurPlatformCube.transform.position - m_CameraTrans.position;
		}

27. Add ScoreManager script to the project, the main function is to perform score statistics and trigger score change events

28. Add the GameManager script to the project. The main function is to obtain some game objects in the scene, manage the initialization of each Manager, Update, Destroy, etc., determine whether the game is over, and restart the game when it ends.

29. The main functions of GameManager script are: Awake(), Start(), Update(), OnDestroy() to manage the relevant initialization of the corresponding Manager, Update, Destroy functions, OnGUI() to set simple operation instructions

		public void Awake()
		{
			PlatformManager = new PlatformManager();
			PlayerManager = new PlayerManager();
			CameraManager = new CameraManager();
			ScoreManager = new ScoreManager();
		}

		public void Start()
		{
			FindGameObjectInScene();

			PlatformManager.Init(OnPlatformEnterAction, m_FirstPlatFormCubeSpawnPosTrans.position, GameConfig.PLATFORM_ADD_SCORE, m_FirstPlatFormCubeSpawnPosTrans);
			PlayerManager.Init(m_PlayerSpawnPosTrans, PlatformManager);
			CameraManager.Init(m_CameraGroupTrans,PlatformManager);

			ScoreManager.Score = 0;
			ScoreManager.OnValueChanged += (socre) => { m_ScoreText.text = ScoreManager.Score.ToString(); };
		}

		public void Update()
		{
			JudgeGameOver();

			PlatformManager.Update();
			PlayerManager.Update();
			CameraManager.Update();
		}

		public void OnDestroy()
		{
			PlatformManager.Destroy();
			PlayerManager.Destroy();
			CameraManager.Destroy();

			m_WorldTrans = null;
			m_UITrans = null;
			m_FirstPlatFormCubeSpawnPosTrans = null;
			m_PlayerSpawnPosTrans = null;
			m_CameraGroupTrans = null;
			m_ScoreText = null;
			m_IsGameOver = false;

			PlatformManager = null;
			PlayerManager = null;
			CameraManager = null;
			ScoreManager = null;
		}

		public void OnGUI()
		{
			// 游戏操作说明
			GUIStyle fontStyle = new GUIStyle();
			fontStyle.normal.background = null;    //设置背景填充
			fontStyle.normal.textColor = new Color(1, 0, 0);   //设置字体颜色
			fontStyle.fontSize = 32;       //字体大小
			GUI.Label(new Rect(10, 10, 200, 200),
				"操作说明:\n1、按下鼠标左键蓄力;\n2、松开鼠标左键起跳;\n3、坠落,重新开始;",
				fontStyle);

		}

30. The main functions of the GameManager script are: FindGameObjectInScene() to get the game objects in the scene, JudgeGameOver() to judge whether the game is over, OnPlatformEnterAction(int score) to increase the score

		/// <summary>
		/// 获取场景中的游戏物体
		/// </summary>
		private void FindGameObjectInScene()
		{
			m_WorldTrans = GameObject.Find(GameObjectPathInSceneDefine.WORLD_PATH).transform;
			m_UITrans = GameObject.Find(GameObjectPathInSceneDefine.UI_PATH).transform;
			m_FirstPlatFormCubeSpawnPosTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.FIRST_PLATFORM_CUBE_SPAWN_POS_PATH);
			m_PlayerSpawnPosTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.PLAYER_SPAWN_POS_PATH);
			m_CameraGroupTrans = m_WorldTrans.Find(GameObjectPathInSceneDefine.CAMERA_GROUP_PATH);
			m_ScoreText = m_UITrans.Find(GameObjectPathInSceneDefine.CANVAS_SCORE_TEXT_PATH).GetComponent<Text>() ;
		}

		/// <summary>
		/// 判断游戏是否结束
		/// </summary>
		void JudgeGameOver()
		{
			if (PlayerManager.IsFallen() == true)
			{
				if (m_IsGameOver == false)
				{
					m_IsGameOver = true;
					SceneManager.LoadScene(SceneManager.GetActiveScene().name);
				}
			}
		}

		/// <summary>
		/// 分数增加委托
		/// </summary>
		/// <param name="score"></param>
		void OnPlatformEnterAction(int score) {
			ScoreManager.Score += score;
		}

31. Add the GameStart script to the project. The main function is to manage the corresponding functions of Awake(), Start(), Update(), OnDestroy() and OnGUI() corresponding to GameManager, the entrance of the entire game.

32. Add Enum, GameConfig, GameObjectPathInSceneDefine, ResPathDefine scripts to the project, Enum manages all enumerations, GameConfig defines some game configuration constants that control game effects, GameObjectPathInSceneDefine manages the path constant definitions of game objects in the scene, and ResPathDefine is Resources to manage prefabs path constant definition

33. Add a GameObject empty object to the scene, change its name to GameStart, and mount the GameStart script

34. Run the scene, the scene will automatically generate Platform, Player and score display, etc., you can operate correspondingly through the mouse

35. Because automatic lighting processing is performed here, here, the lighting effect of the scene is baked

36. After baking, the effect is as follows, obviously brighter and more beautiful

7. Project source code address

github address: GitHub - XANkui/UnityMiniGameParadise: Unity game development collection code set

The MGP_003JumpJump project

Eight, extension

The quality of the game, fun, visualization and many other factors affect the game. The following is a brief introduction to the direction of expanding the game in several aspects, for reference only.

1. You can modify game resources, skin, etc. according to your needs

2. You can add extra special effects, sound effects, more detailed changes in the background as needed, etc.

3. Add UI panels, etc. to beautify the game

4. It is not necessary to set different platforms except for the special events of the basic score, how long the ratio stays on the platform, triggering special scores or events, etc.

5. The spacing of the platform is now fixed each time, and the random spacing can be within the range;

6. Add the highest score reservation, and game leaderboards, etc.;

7. Optimize Platform management, use object pool management to optimize performance, etc.;

Guess you like

Origin blog.csdn.net/u014361280/article/details/122478869