Unity game example development collection of Car Racing 2D (2D racing) leisure games for rapid implementation

Unity game example development collection of Car Racing 2D (2D racing) leisure games for rapid implementation

catalogue

Unity game example development collection of Car Racing 2D (2D racing) leisure games for rapid implementation

1, Brief introduction

2, Car racing 2D game content and operation

3, Relevant description

4, Game code framework

5, Knowledge points

6, Game effect preview

7, Implementation steps

8, Project source code address

9, Extension

1, Brief introduction

Unity game example development collection, using a simple and understandable way to explain the development and implementation process of common games, so as to facilitate the reference and reuse of similar game development in the later stage.

This section introduces the fast implementation method of car racing 2D leisure game. I hope it can help you. If there is anything wrong, please leave a message.

This is a 2D game, which is mainly realized by using sprite map, 2D gravity and 2D collision body. The principle of game realization is as follows:

0. This is a 2D game developed based on vertical screen 1080x1920, and realizes screen adaptation;

1. The position of the player's car y direction remains unchanged, and the road and NPC car gold coins move from top to bottom, so as to realize the effect of the player's car moving forward

2. All objects in the scene have no gravity effect, but are mounted with Rigidbody2D. The Body Type is Kinematic. Through getcomponent < Rigidbody2D > () Add speed to the direction of velocity to achieve the effect of movement

3. The principle of adding points to the number of trips is to add points to the number of trips of the vehicle according to the moving speed of the road

4. The implementation principle of game pause is as follows: 1) Pause effect: set the Velocity of Rigidbody2D to 0 for all moving game objects to realize the stop effect; 2) Continue the game effect: restore all moving game objects to the original value of the Velocity setting of Rigidbody2D, so as to restore the scene and continue the game

5. Realization of infinite background: set the road in two copies (multiple copies can be set as needed), 1) two copies are spliced up and down

2) First, the background at the bottom is displayed. The background moves downward together. When it is invisible at the bottom, the invisible background at the bottom moves to the top of the upper background again. In this way, the infinite circular background is realized

2, Car racing 2D game content and operation

1. When the game starts, the background Road will automatically move downward, and the player's Car will be in a random position. Wait for clicking Play to start the game

2. Click Play to start the game and automatically generate NPC cars and gold coins. Click the left mouse button. When the position is on the left half of the screen, the car will turn left and move, and on the right, it will turn right and move (you can add keys as needed)

 

3. According to the number of trips, the corresponding score will increase. If you encounter gold coins, you will get extra points

4. The game ends when you encounter other NPC cars

5. In the middle of the game, you can click pause, continue to play or restart

3, Relevant description

1. The enumeration naming of audio corresponds to the name of the actual audio, which is convenient for loading and specifying the playing audio

2. For 2D games (all elements are on the same plane), set the Order in Layer of SpriteRenderer to control the display order. The larger the Order in Layer, the display will be in front. Therefore, the display rules of each Order in Layer are defined as - 5 for Road preform and 0 for car and gold coin

3. Rigidbody2D for Road, car and gold coin. The Body Type is Kinematic, and there is no downward effect of gravity

4. When the car turns left and right, if the assignment transform is used In the way of EulerAngles, note that if the value is assigned a negative value, the system will automatically change to the new value assigned 360 + value (making the rotation and weird), so pay attention to deal with it

private void RotateLerp(float target) {
			Vector3 curRot = transform.eulerAngles;
			if (curRot.z <= 90)
			{
				curRot.z = Mathf.Lerp(curRot.z, target, Time.deltaTime * m_RotateAnimationSpeed);
			}
			else { // Correct the right rotation assignment, and the assignment will be converted to the corresponding positive rotation value (for example, - 5, automatically converted to 360 + (- 5))
				curRot.z = Mathf.Lerp(curRot.z, 360+target, Time.deltaTime * m_RotateAnimationSpeed);
			}
			// Debug.Log(curRot.z);
			transform.eulerAngles = curRot;
		}

5. NPC car is generated at the position, which is set according to the percentage (1 +?%) of the screen height. Therefore, it can be guaranteed that the car will not be seen before generation; NPC car is a recycling location, which is also set according to the lower percentage (-?%) of the screen. It can ensure that the recycling car is invisible

 

6. Script reprint suggestion: reprint the scripts of Common and Tools folders, then the scripts of each entity folder, then the scripts of Manager (the order can be in the order of implementation steps), and finally GameManager and GameStart

4, Game code framework

(for reference only, you can re architecture, add a message center, manage some events, or better)

 

5, Knowledge points

1. Monobehavior life cycle function: wake, Start, Update, Destroy

2. Input button monitors the status of mouse buttons

3,GameObject. Generation of instantiate object, GameObject Destruction of destroy objects

4. Simple object pool management

5. Rigidbody gravity effect, add EdgeCollider2D, and conduct collision detection (Trigger)

6. Use of simple UGUI

7. 2D game screen adaptation (mainly UI, NPC generation location, screen adaptation, camera orthographic size)

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

9. Simple use of Animation and Animator

10. Use of Tag in game

11. IManager simple interface specification Manager class function

12. Action < int > onchangevalue attribute changes the use of delegates

13,Resources. Load < GameObject > () use of code loading preform

14. Simple tool class for converting screen coordinates to world coordinates

15, SceneManager.LoadScene, and SceneManager Getactivescene() get the current scene

16. Classified management of resource script folders for game development

17. Audio simple management playback

18. Wait
 

6, Game effect preview

 

7, Implementation steps

1. Open Unity, import relevant resources, and turn the pictures into sprites

 

2. Set the position of Main Camera to (0,0, - 10), Clear Flags to Solid Color and Projection to Orthofraphic, as shown in the figure

 

3. In the scene, add a GameObject, rename it World, pos(0,0,0), delete the Directional Light, drag the Main Camera under it, and set the screen to 1080x1920 as the width and height of game development (the later screen adaptation is based on 1080x1920)

 

4. Drag the Road into the scene, according to the existing Game viewport, adapt the Scale (here (1.25, 1.25, 1.25)), add Rigidbody2D, set the BodyType to Kinematic (no gravity effect, but Kinematic effect), and drag it into Resources as a preform

 

5. Drag Car1 into the scene, change its name to PCCar, add Rigidbody2D, set the BodyType to Kinematic (no gravity effect, but Kinematic effect), drag it into Resources as a preform, add BoxCollider2D, and adjust its size to suit the size of the car

 

6. Similarly, in step 5, complete other vehicles and make them into preforms

7. Take boundsGold_x several pieces are dragged into the scene together, and the animation will be automatically generated. Similarly, in step 5, make a preform

 

8. Similarly, in step 7, make car3 and car6 into animated preforms

 

9. Drag Sounds to the Resources folder and use resources to dynamically load audio files

 

10. Add multiple GameObject s under the World with positions of (0,0,0) and rename them as SpawnRoadPos, AudioSourceTrans, SpawnNPCPos and SpawnPCCarPos. The function is as its name. It is used to generate the parent object of Road, mount the audio source, generate the parent object of NPCPos and generate the parent object of PCCar

 

11. Under the UI, add a Canvas (automatically add EventSystem), set the UI Scale Mode of Canvas Scaler to Scale with Screen Size, Reference Resolution to 1080 x 1920, and Match to Height

 

12. Add PlayPanel, and the parameter settings and renderings are as follows

 

 

 

 

 

13. Add GamePanel. The parameter settings and renderings are as follows

 

 

 

 

14. Add PausePanel, and the parameter settings and renderings are as follows

 

 

 

 

15. Add GameOverPanel. The parameter settings and effects are shown below

 

 

16. Add Common to the project (generally, it can be written at the end of game development, extracted from the script, sorted and managed uniformly), manage some constants in the game, Enum manages all enumerations, GameConfig some game configurations, gameobjectpathinsecenedefine game object path definition in the scene, ResPathDefine preform path definition class and Tag tag definition class

 

17. Tag tag definition class, in which tag is defined as follows. Select a game object, select the tag drop-down menu, and click Add Tag Add tag, then select +, name a name and save. Here, we set the tag of NPCCarx of the preform to NPCCar (used for triggering the collision body later) and Coin to Coin

 

 

 

18. In the Interface, add various basic interfaces to facilitate the function specification of specific classes

 

19. Tools tool class. At present, two function functions are added to convert screen coordinates into world coordinates and 2D game screen adaptation function

	public class Tools 
	{
		/// <summary>
		///Convert screen coordinates to world coordinates
		/// </summary>
		///< param name = "reftran" > corresponding reference object < / param >
		///< param name = "refcamera" > corresponding reference camera < / param >
		///< param name = "screenpos" > screen position < / param >
		///< returns > world position of screen position < / returns >
		public static Vector3 ScreenPosToWorldPos(Transform refTran, Camera refCamera, Vector2 screenPos)
		{
			//Replace object coordinates with screen coordinates
			Vector3 pos = refCamera.WorldToScreenPoint(refTran.position);
			//Make the screen coordinates of the mouse consistent with the object coordinates
			Vector3 mousePos = new Vector3(screenPos.x, screenPos.y, pos.z);
			//Change the correct mouse screen coordinates into world coordinates and give them to the object
			return refCamera.ScreenToWorldPoint(mousePos);

		}


		/// <summary>
		///2D game screen adaptation 
		/// vaildWidth =(Screen.width/Screen.height*2*orthographicSize)
		/// </summary>
		///< param name = "basescreenwidth" > reference screen width during development < / param >
		///< param name = "basescreenheight" > reference screen height during development < / param >
		///< param name = "orthographic camera2d" > orthogonal addition < / param >
		public static void AdaptationFor2DGame(int BaseScreenWitdh,int BaseScreenHeight,Camera orthographicCamera2D)
        {
            if (orthographicCamera2D.orthographic ==false)
            {
				Debug.LogError("AdaptationFor2DGame()/ Camera is not orthographic , Please Check !! ");
				return;
            }
			// Gets the size of the orthographic camera set by the development  
			float BaseOrSize = orthographicCamera2D.orthographicSize;
			 // Get effective visual width
            float vaildWidth = (BaseScreenWitdh * 1.0f / BaseScreenHeight) * 2 * BaseOrSize;
			// Aspect ratio of actual screen
            float aspectRatio = Screen.width * 1f / Screen.height;
			// According to the actual screen and effective visual width, the appropriate size is obtained and assigned to the camera
            float adapterOrthoSize = vaildWidth / aspectRatio / 2;
			orthographicCamera2D.orthographicSize = adapterOrthoSize;
        }
    }

20. IServer script is added to the project. Its main function is to define some basic function interfaces of service classes

22. Add reloadserver script in the project and inherit IServer. Its main function is to load preforms and audio files

        /// <summary>
        ///Load preform GameObject 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public GameObject LoadPrefab(string path)
        {
            if (m_PrefabsDict.ContainsKey(path) == true)
            {
                return m_PrefabsDict[path];
            }
            else
            {
                GameObject prefab = Load<GameObject>(path);
                if (prefab != null)
                {
                    m_PrefabsDict.Add(path, prefab);
                }

                return prefab;
            }
        }

        /// <summary>
        ///Loading preform AudioClip 
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public AudioClip LoadAudioClip(string path)
        {
            if (m_AudioClipsDict.ContainsKey(path) == true)
            {
                return m_AudioClipsDict[path];
            }
            else
            {
                AudioClip prefab = Load<AudioClip>(path);
                if (prefab != null)
                {
                    m_AudioClipsDict.Add(path, prefab);
                }

                return prefab;
            }
        }

23. Add AudioServer script in the project and inherit IServer. Its main functions are to load specified audio, add audio source, and play background music and specified audio files

        /// <summary>
        ///Play the specified background music
        /// </summary>
        /// <param name="audioName"></param>
        public void PlayBG(AudioClipSet audioName,bool isLoop=true)
        {
            if (m_AudioClipDict.ContainsKey(audioName) == true)
            { 
                m_AudioSource.Stop();
                m_AudioSource.clip = m_AudioClipDict[audioName];
                m_AudioSource.loop = isLoop;
                m_AudioSource.Play();
            }
            else
            {
                Debug.LogError(GetType() + "/PlayAudio()/ audio clip is null,audioName = " + audioName);
            }
        }

        /// <summary>
        ///Stop background music
        /// </summary>
        public void StopBG() {
            m_AudioSource.Stop();
        }

        /// <summary>
        ///Play specified audio
        /// </summary>
        /// <param name="audioName"></param>
        public void PlayAudio(AudioClipSet audioName)
        {
            if (m_AudioClipDict.ContainsKey(audioName) == true)
            {
                m_AudioSource.PlayOneShot(m_AudioClipDict[audioName]);
            }
            else
            {
                Debug.LogError(GetType() + "/PlayAudio()/ audio clip is null,audioName = " + audioName);
            }
        }

        /// <summary>
        ///Load audio
        /// </summary>
        private void Load()
        {
            for (AudioClipSet clipPath = AudioClipSet.Bonus; clipPath < AudioClipSet.SUM_COUNT; clipPath++)
            {
                AudioClip audioClip = m_ResLoadServer.LoadAudioClip(ResPathDefine.AUDIO_CLIP_BASE_PATH + clipPath.ToString());
                m_AudioClipDict.Add(clipPath, audioClip);
            }
        }

24. Add IManager script in the project. Its main function is to define some basic function interfaces of management class

 

25. Add the RoadManager script in the project. The main function is to load the Road, generate two Road splices (the splicing distance is recorded in GameConfig here), add velocity to make it move, move the specified distance, move to the top, and realize circular Road

        /// <summary>
        ///Loading preform
        /// </summary>
        private void LoadPrefab()
        {
            GameObject prefab = m_ResLoadServer.LoadPrefab(ResPathDefine.PREFAB_ROAD_PATH);
            for (int i = 0; i < GameConfig.ROAD_TILE_COUNT; i++)
            {
                GameObject road = GameObject.Instantiate(prefab, m_SpawnSkyTilePosTrans);
                Vector3 curPos = road.transform.position;
                road.transform.position = new Vector3(curPos.x, curPos.y+(i*GameConfig.ROAD_SPRITE_INTERVAL_Y),curPos.z);
                m_RoadTransformList.Add(road.transform);
                m_RoadRigidbodyList.Add(road.GetComponent<Rigidbody2D>());
            }
        }

        /// <summary>
		///Update Road location
		///When the position reaches the specified position, move the position to the left, so as to realize infinite cycle
		/// </summary>
		private void UpdatePosOperation()
        {

            foreach (var item in m_RoadTransformList)
            {
                Vector3 curPos = item.position;

                if (curPos.y <= m_TargetPosY)
                {
                    // Move to the right (think it's gone, the right is the right, so add 2 * BACKGROUND_SPRITE_INTERVAL_X)
                    curPos = new Vector3( curPos.x, (curPos.y+ m_ResetMoveDistanceY), curPos.z);
                    item.position = curPos;
                }
            }
            
        }

26. Add a Model script to the project. Its main function is to define a basic data Model, including values and events triggered by value changes

	/// <summary>
	///Data model
	/// </summary>
	public class Model
	{
		private int m_Value;
		public int Value
		{
			get { return m_Value; }
			set
			{
				if (m_Value != value)
				{
					m_Value = value;

					if (OnValueChanged != null)
					{
						OnValueChanged.Invoke(value);

					}
				}
			}
		}

		/// <summary>
		///Numerical change event
		/// </summary>
		public Action<int> OnValueChanged;
	}

27. Add a DataModelManager script to the project. Its main function is to define the data involved in the game. Here, the data of Score (both Model class type parameters) is defined

 

28. Add the DrivingDistanceScoreManager script in the project. The main function is to increase the score according to the journey (actually, increase the score per second according to the road speed)

        /// <summary>
        ///Travel bonus
        /// </summary>
        void UpdateDistanceScore()
        {
            m_Timer += Time.deltaTime;
            if (m_Timer>= (1.0f/GameConfig.ROAD_MOVEVELOCITY_Y))
            {
                m_Timer -= (1.0f / GameConfig.ROAD_MOVEVELOCITY_Y);
                m_DataModelManager.Score.Value += GameConfig.DRIVING_DISTANCE_SCORE;

            }
        }

 

29. Add ObjectPool and ObjectPoolContainer scripts in the project. The main function is to establish object pool (object preloading, acquisition, release and emptying) and manage object usage status (used and unused) of object pool

 

30. Add ObjectPoolManager script in the project. The main function is to manage each object pool, preload, obtain, release and delete objects in each object pool

 

        /// <summary>
        ///Incubator incubates specified number of objects pool objects
        /// </summary>
        ///< param name = "prefab" > preform < / param >
        ///< param name = "count" > object pool to be pre generated < / param >
        public void WarmPool(GameObject prefab,Transform parent, int count)
        {
            if (m_PrefabPoolDictinary.ContainsKey(prefab))
            {
                Debug.Log("Pool for prefab " + prefab.name + " has already been created");
            }

            ObjectPool<GameObject> pool = new ObjectPool<GameObject>(() => {
                return InstantiatePrefab(prefab, parent);

            }, DestroyClone, count);

            // Add to dictionary
            m_PrefabPoolDictinary[prefab] = pool;

            // Update usage data flag
            m_Dirty = true;

        }

        /// <summary>
        ///Take out the specified object from the object pool and use it
        /// </summary>
        ///< param name = "prefab" > object to use < / param >
        ///< returns > available objects returned by the object pool < / returns >
        public GameObject SpawnObject(GameObject prefab, Transform parent)
        {
            return SpawnObject(prefab, parent, Vector3.zero, Quaternion.identity);
        }


        public GameObject SpawnObject(GameObject prefab,Transform parent, Vector3 position, Quaternion rotation)
        {
            // If the preform is not incubated, incubate one first
            if (m_PrefabPoolDictinary.ContainsKey(prefab) == false)
            {
                WarmPool(prefab, parent,1);
            }

            // Get object from object pool
            ObjectPool<GameObject> pool = m_PrefabPoolDictinary[prefab];
            GameObject clone = pool.GetObjectPoolContainerItem();

            // Set the position rotation of the object and display the object
            clone.transform.position = position;
            clone.transform.rotation = rotation;
            clone.SetActive(true);

            // Add the extracted object to the used dictionary
            m_UsedPoolObjectbDictinary.Add(clone, pool);

            // Update usage data flag
            m_Dirty = true;

            return clone;
        }

        /// <summary>
        ///Release used object pool objects
        /// </summary>
        ///< param name = "clone" > object < / param >
        public void ReleaseObject(GameObject clone)
        {
            clone.SetActive(false);

            // In used Dictionaries
            if (m_UsedPoolObjectbDictinary.ContainsKey(clone))
            {
                m_UsedPoolObjectbDictinary[clone].ReleaseItem(clone);
                m_UsedPoolObjectbDictinary.Remove(clone);

                // Update usage data flag
                m_Dirty = true;
            }
            else
            {

                Debug.Log("No pool contains the object: " + clone.name);

            }
        }

31. Npcmmanager script is added to the project. Its main function is to load NPC preform, generate NPC regularly (random NPC, some data of random position, determined on the lane and uniformly defined in GameConfig), judge the position and recover NPC

        /// <summary>
        ///Loading preform
        /// </summary>
        private void LoadPrefab() {

            for (NPCType npc = NPCType.Coin; npc < NPCType.SUM_COUNT; npc++)
            {
                m_NPCPrefabDict.Add(npc,m_ResLoadServer.LoadPrefab(ResPathDefine.PREFAB_NPC_BASE_PATH + npc.ToString()));
            }
        }

        /// <summary>
        ///Timing generates tubes, initializes tubes, and sets events to recycle tubes
        /// </summary>
        void UpdateSpawnNPC()
        {
            m_SpawnTimer += Time.deltaTime;
            if (m_SpawnTimer >= GameConfig.NPC_SPAWN_TIME_INTERVAL)
            {
                m_SpawnTimer -= GameConfig.NPC_SPAWN_TIME_INTERVAL;

                int rand = Random.Range((int)NPCType.Coin, (int)NPCType.SUM_COUNT);
                GameObject npc = m_ObjectPoolManager.SpawnObject(m_NPCPrefabDict[(NPCType)rand],m_SpawnNPCPosTrans);
                npc.transform.position = m_SpawnPosArray[Random.Range(0, m_SpawnPosArray.Length)];
                Rigidbody2D rb = npc.GetComponent<Rigidbody2D>();
                rb.velocity = m_NPCMoveVelocity;
                m_ShowNPCRigidbodyList.Add(rb);
                m_ShowNPCTransformList.Add(npc.transform);
            }
        }

        /// <summary>
        ///Judge the location and recycle the object
        /// </summary>
        void UpdateNPCPosRecycle() {
            if (m_ShowNPCTransformList!=null)
            {
                foreach (Transform npc in m_ShowNPCTransformList)
                {
                    if (npc.position.y<=m_TargetMovePosY)
                    {
                        npc.GetComponent<Rigidbody2D>().velocity = Vector2.zero;
                        m_ObjectPoolManager.ReleaseObject(npc.gameObject);
                        npc.position = m_SpawnPosArray[0];
                    }
                }
            }
        }

 

32. Npcmmanager script is added to the project. Its main function is to control the car's Lane cutting and turning (here, take the screen as the center, turn the left half screen to the left, and turn the right half screen to the right), including the position restriction of left and right movement, turning animation, and the entrusted triggering of collision NPC car and gold coin events

 

		/// <summary>
		///The car cuts and turns
		/// </summary>
		public void UpdateChangeLaneRotation() {

			if (Input.GetMouseButtonDown(0)
				   && EventSystem.current.IsPointerOverGameObject() == false)// Not click UI
			{
				if (Input.mousePosition.x <= m_HalfWidth)  // Turn left
				{
					m_CurCarRoateDir = CarRoateDir.Left;
					Rigidbody2D.velocity = m_MoveLeftVelocity;
				}
				else {									// Turn right
					m_CurCarRoateDir = CarRoateDir.Right;
					Rigidbody2D.velocity = m_MoveRightVelocity;
				}
			}
			else if(Input.GetMouseButtonUp(0)) {
				m_CurCarRoateDir = CarRoateDir.Normal;
				Rigidbody2D.velocity = Vector2.zero ;
			}

			RotateSelf(m_CurCarRoateDir);
			UpdateLimitPos();
		}

33. Add npcmmanager script in the project. Its main function is to obtain UI elements, add button events, and update events with scores on the UI

        private void OnRestartButton()
        {
            m_AudioServer.PlayAudio(AudioClipSet.ButtonClick);
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }

        private void OnPlayButton() {
            m_AudioServer.PlayAudio(AudioClipSet.ButtonClick);
            if (m_OnGameResume != null)
            {
                m_OnGameResume.Invoke();
            }
        }

        private void OnPauseButton()
        {
            m_AudioServer.PlayAudio(AudioClipSet.ButtonClick);
            if (m_OnGamePause != null)
            {
                m_OnGamePause.Invoke();
            }
        }
        private void UpdateScoreText(int score) {
            m_ScoreText.text = score.ToString();
        }

34. Add the BaseGameManager script in the project. Its main function is to define and register multiple interfaces and the unified processing function of Update Destroy

        /// <summary>
        ///Register Manager
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="manager"></param>
        protected void RegisterManager<T>(T manager) where T : IManager
        {
            Type t = typeof(T);
            if (m_ManagerDict.ContainsKey(t) == true)
            {
                m_ManagerDict[t] = manager;
            }
            else
            {
                m_ManagerDict.Add(t, manager);
            }
        }
        
        /// <summary>
        ///Register Server
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="server"></param>
        protected void RegisterServer<T>(T server) where T : IServer
        {
            Type t = typeof(T);
            if (m_ServerDict.ContainsKey(t) == true)
            {
                m_ServerDict[t] = server;
            }
            else
            {
                m_ServerDict.Add(t, server);
            }
        }

        /// <summary>
        ///Gets the specified Manger 
        ///(it may be more appropriate to set public)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        protected T GetManager<T>() where T : class
        {
            Type t = typeof(T);
            if (m_ManagerDict.ContainsKey(t) == true)
            {
                return m_ManagerDict[t] as T;
            }
            else
            {
                Debug.LogError("GetManager()/ not exist ,t = "+t.ToString());
                return null;
            }
        }

        /// <summary>
        ///Get the specified Server 
        ///(it may be more appropriate to set public)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        protected T GetServer<T>() where T : class
        {
            Type t = typeof(T);
            if (m_ServerDict.ContainsKey(t) == true)
            {
                return m_ServerDict[t] as T;
            }
            else
            {
                Debug.LogError("GetServer()/ not exist ,t = " + t.ToString());
                return null;
            }
        }

35. Add GameManager script (single example) to the project and inherit BaseGameManager. Its main functions are: 1) obtain relevant game objects or UI root objects in the scene, 2) new related Manager management classes, initialize Init, Update, and Destroy, and 3) judge the game state, whether to pause, continue, and end

        protected override void InitServer(Transform rootTrans, params object[] objs) {

            m_ResLoadServer.Init(null);
            m_AudioServer.Init(m_WorldTrans, m_ResLoadServer);
        }

        protected override void InitManager(Transform rootTrans, params object[] objs)
        {
            m_DataModelManager.Init(null);
            m_DrivingDistanceScoreManager.Init(null, m_DataModelManager);
            m_UIManager.Init(m_UITrans, m_AudioServer, m_DataModelManager);
            m_ObjectPoolManager.Init(null);
            m_RoadManager.Init(m_WorldTrans, m_ResLoadServer);
            m_NPCManager.Init(m_WorldTrans, m_ResLoadServer, m_ObjectPoolManager);
            m_PCCarManager.Init(m_WorldTrans, m_ResLoadServer, m_ObjectPoolManager,m_AudioServer,m_DataModelManager);

            m_UIManager.SetOnGamePause(GamePause);
            m_UIManager.SetOnGameResume(GameResume);
            m_PCCarManager.SetPCCarColliderNPCCarAction(GameOver);

        }

        public void GamePause()
        {
            m_RoadManager.GamePause();
            m_NPCManager.GamePause();
            m_PCCarManager.GamePause();
            m_UIManager.GamePause();
            m_DrivingDistanceScoreManager.GamePause();
        }

        public void GameResume()
        {
            m_RoadManager.GameResume();
            m_NPCManager.GameResume();
            m_PCCarManager.GameResume();
            m_UIManager.GameResume();
            m_DrivingDistanceScoreManager.GameResume();
        }

        public void GameOver()
        {
            m_RoadManager.GameOver();
            m_NPCManager.GameOver();
            m_PCCarManager.GameOver();
            m_UIManager.GameOver();
            m_DrivingDistanceScoreManager.GameOver();
        }

36. GameStart script, the entrance of the whole game, manages the corresponding functions of wake(), Start(), Update(), OnDestroy() of the corresponding GameManager

	public class GameStart : MonoBehaviour
	{
        private void Awake()
        {
            GameManager.Instance.Awake(this);
        }

        // Start is called before the first frame update
        void Start()
		{
            GameManager.Instance.Start();

        }

		// Update is called once per frame
		void Update()
		{
            GameManager.Instance.Update();
        }

        private void OnDestroy()
        {
            GameManager.Instance.Destroy();
        }
    }

37. Add a GameObject empty object in the scene, rename it GameStart, and mount the GameStart script

 

38. When running the scene, the scene will be automatically generated. Click play to start generating NPC cars and gold coins. The car crash game is over

 

 

8, Project source code address

github address: https://github.com/XANkui/UnityMiniGameParadise

MGP of_ 007carracing2d project

9, Extension

Many factors such as the playfulness, interest and visualization of the game. The following briefly introduces several aspects to expand the direction of the game for reference only

1. You can modify game resources and skin changes according to your needs

2. You can add bonus effects, sound effects, more details of the background, etc. as needed

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

4. Car score effect added

5. Different states, skin or speed of the car under different scores;

6. Add the highest score reservation, game leaderboard, etc;

7. Add button operation or voice operation to the control mode of the car

8. Different groups of Road cars, such as spring, summer, autumn and winter, different styles of China, Japan and Egypt, to increase novelty

9. Wait
 

Added by kundan on Thu, 27 Jan 2022 06:31:07 +0200