unity3D-learning: factory mode for playing flying saucers

homework and exercises

1. Write a simple mouse hit UFO (Hit UFO) game

  • Game content requirements:
    1. The game has n rounds, and each round includes 10 trials;
    2. The color, size, launch position, speed, angle, and number of UFOs appearing at the same time may be different for each trial. They are controlled by the round's ruler;
    3. The flying saucer of each trial is random, and the overall difficulty increases with the round;
    4. Points are scored by the mouse, and the scoring rules are calculated according to different colors, sizes, and speeds, and the rules can be set freely.
  • Game requirements:
    • Use the factory mode with cache to manage the production and recycling of different flying saucers. The factory must be a single instance of the scene! For the specific implementation, see the reference resource Singleton template class
    • It is possible to use the previous MVC structure to realize the separation of human-computer interaction and game model

The content of this week's study is the interaction with the game world, and also learned the factory mode, combined with the action separation mode and the director's scene mode we learned before, we are going to experiment with such a flying saucer game, the game is still very fun. Let's first have a general understanding of the factory pattern, because we have already talked about action separation and field recording, so in fact our other two are easy to understand.

The design patterns of UFO factories are as follows: single-instantiated factories, fractional control and scene control, and the separation and use of various presets.


Let's start by stating the general pattern of the game we want to implement:

The advancement of such a mode is conducive to increasing the fun of the game. The difficulty is getting higher and higher, and the completion is getting harder and harder. But the score will also increase. We mainly change the difficulty by controlling the flying frequency of the flying saucer, the flying speed and the size of the flying saucer. We will talk about the specific implementation below.

1. The first is the realization of the flying saucer factory, which should implement two functions: getDisk(ruler) and FreeDisk(disk):

* getDisk(ruler) //pseudocode   
IF (free list has disk)   
THEN      
 a_disk = remove one from list   
ELSE      
 a_disk = clone from Prefabs   
ENDIF   
Set DiskData of a_disk with the ruler  
Add a_disk to used list   
Return a_disk    

FreeDisk(disk) //pseudocode  
Find disk in used list   
IF (not found)   
THEN THROW exception   
Move disk from used to free list
 */

At the same time, the rounds of the flying saucer have also been changed and the difficulty has been increased.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*game rules:
 * The game is divided into three rounds in total, and each round changes the size, speed and frequency of the flying saucer.
 * Adopt points promotion system
 * 3 points for hitting the plate in the first round
 * 5 points for hitting the plate in the second round
 * 8 points for hitting the plate in the third round
 * A total of 20 plates fly out each round
 * The cumulative score in the first round reaches 30 points to advance,
 * The cumulative score in the second round reaches 100 points to advance,
 * The cumulative score in the third round reaches 200 points to win!
 * A bit similar to our shot in the playground
 * Difficulty gradually increases
 */
public class DiskFactory : System.Object
{
   private static DiskFactory _instance;
   public SceneController sceneControler { get; set; }
   public List<GameObject> used;
   public List<GameObject> free;
    // Use this for initialization
    private static List<GameObject> diskList;

   public static DiskFactory getInstance()
   {
       if (_instance == null)
       {
           _instance = new DiskFactory();
           _instance.used = new List<GameObject>();
           _instance.free = new List<GameObject>();
       }
       return _instance;
   }

   public GameObject getDisk(int round)
   {
       //
       if (sceneControler.num == 21)
       //A total of 20 launches per round, if the score reaches a certain requirement, enter the next round, otherwise GameOver
       {
            
            if (sceneControler.round == 1 && sceneControler.score >= 30)
            {
                sceneControler.round++;
                sceneControler.num = 0;
            }
            if (sceneControler.round == 2 && sceneControler.score < 30)
            {
                sceneControler.game = 2; // lost the game
            }

            if (sceneControler.round == 2 && sceneControler.score >= 100)
            {
                sceneControler.round++;
                sceneControler.num = 0;
            }
            if (sceneControler.round == 3 && sceneControler.score < 100)
            {
                sceneControler.game = 2; // lost the game
            }

            if (sceneControler.round == 3 && sceneControler.score >= 200)
            {
                sceneControler.round++;
                sceneControler.num = 0;
            }
            if (sceneControler.round == 4 && sceneControler.score < 200)
            {
                sceneControler.game = 2; // lost the game
            }
        }
       if (sceneControler.round == 4)
       {
           sceneControler.game = 4;//Win the game
       }
       GameObject newDisk;
       if (free.Count == 0)
       {
           newDisk = GameObject.Instantiate(Resources.Load("prefabs/Disk"), new Vector3(0, 0, -10), Quaternion.identity) as GameObject;
       }
       else
       {
           newDisk = free[0];
           free.Remove(free[0]);
       }
       switch (round)
       // Make the color and size of the flying saucer according to the number of rounds
       {
           case 1:
               newDisk.transform.localScale = new Vector3(1.5f, 0.2f, 1.5f);
               newDisk.GetComponent<Renderer>().material.color = Color.blue;
               break;
           case 2:
               newDisk.transform.localScale = new Vector3(1.2f, 0.2f, 1.2f);
               newDisk.GetComponent<Renderer>().material.color = Color.gray;
               break;
           case 3:
               newDisk.transform.localScale = new Vector3(1.0f, 0.2f,1.0f);
               newDisk.GetComponent<Renderer>().material.color = Color.yellow;
               break;
       }
       used.Add(newDisk);
       return newDisk;
   }

   public void freeDisk(GameObject disk1)
   {
       for (int i = 0; i < used.Count; i++)
       {
           if (used[i] == disk1)
           {
               used.Remove(disk1);
               disk1.SetActive(true);//The disk hit by the mouse is set to false, so all are activated here
               free.Add(disk1);
           }
       }
   }
}

2. Add the general game themes, how to score, how to control, and the basis of various games.

void Awake()
    //Create director instance and load resources
    {
        SSDirector director = SSDirector.getInstance();
        DiskFactory DF = DiskFactory.getInstance();
        DF.sceneControler = this;
        director.currentScenceController = this;
        director.setFPS(60);
        director.currentScenceController.LoadResources();
    }
    void Start()
    {
        round = 1;
    }
    public void LoadResources()
    {
        explosion = Instantiate(Resources.Load("prefabs/Explosion"), new Vector3(0, 0, -20), Quaternion.identity) as GameObject;
        plane = Instantiate(Resources.Load("prefabs/Plane"), new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
    }

    // Update is called once per frame
    void Update()
    {
        Score.text = "Score:" + score.ToString();
        Round.text = "Round:" + round.ToString();
        if (Input.GetMouseButtonDown(0) && game == 1)//游戏中
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                if (hit.transform.tag == "Disk")
                {
                    if (round == 1 && game == 1)
                    {
                        score += 3;
                    }
                    if (round == 2 && game == 1)
                    {
                        score += 5;
                    }
                    if (round == 3 && game == 1)
                    {
                        score += 8;
                    }
                    explosion.transform.position = hit.collider.gameObject.transform.position;
                    explosion.GetComponent<Renderer>().material = hit.collider.gameObject.GetComponent<Renderer>().material;
                    explosion.GetComponent<ParticleSystem>().Play();
                    hit.collider.gameObject.SetActive(false);
                }
            }
        }
        if (game == 2)
        {
            GameOver();
        }
        if (game == 4)
        {
            Win();
        }
    }
    public IEnumerator waitForOneSecond()
    {
        while (StartTimes >= 0 && game == 3)
        {
            Time.text = StartTimes.ToString();
            Time.color = Color.red;
            yield return new WaitForSeconds(1); //One second counts down by 1
            StartTimes--;
        }
        Time.text = "";
        game = 1;
    }
    public void ReStart()
    {
        SceneManager.LoadScene("task1");
    }

3. Realize the flight path and speed of the flying saucer

flight path:

public override void Update()
    {
        Vector3 targetPos = target.transform.position;

        // make it always towards the goal  
        gameobject.transform.LookAt(targetPos);
        float angle = Mathf.Min(1, Vector3.Distance(gameobject.transform.position, targetPos) / distanceToTarget) * 45;
        gameobject.transform.rotation = gameobject.transform.rotation * Quaternion.Euler(Mathf.Clamp(-angle, -42, 42), 0, 0);
        float currentDist = Vector3.Distance(gameobject.transform.position, target.transform.position);
        gameobject.transform.Translate(Vector3.forward * Mathf.Min(speed * Time.deltaTime, currentDist));
        if (this.transform.position == target.transform.position)
        {
            DiskFactory.getInstance().freeDisk(gameobject);
            Destroy(target);
            this.enable = false;
            this.destroy = true;
        }
    }

Flight speed:

public override void Start()
    {
        speed = 5 + sceneControler.round * 5;//Make the speed change with the number of rounds
        startX = 5 - Random.value * 10;//Make the launch position random at (-5,5)
        targetY = -5;
        this.transform.position = new Vector3(startX, 0, -6);
        target = new GameObject();//Create endpoint
        target.transform.position = new Vector3(targetX, targetY, 30);
        //calculate the distance between the two  
        distanceToTarget = Vector3.Distance(this.transform.position, target.transform.position);
    }

Change the firing frequency of the flying saucer

protected new void Update()
    {
        if (sceneController.round == 1 && sceneController.game == 1)
        {
            count++;
            if (count == 70)//Emit one at 70 frames, the transmission speed is different, the transmission is slower
            {
                DiskMove = Emit2.GetSSAction();
                this.addAction(diskFactory.getDisk(sceneController.round), DiskMove);
                sceneController.num++;//Record the number of launches
                count = 0;
            }
            base.Update();
        }
        if (sceneController.round ==2 && sceneController.game == 1)
        {
            count++;
            if (count == 60)//Emit one at 60 frames, the speed of the transmission is different
            {
                DiskMove = Emit2.GetSSAction();
                this.addAction(diskFactory.getDisk(sceneController.round), DiskMove);
                sceneController.num++;//Record the number of launches
                count = 0;
            }
            base.Update();
        }
        if (sceneController.round ==3 && sceneController.game == 1)
        {
            count++;
            if (count == 50)//Emit one at 60 frames, the speed of the transmission is different
            {
                DiskMove = Emit2.GetSSAction();
                this.addAction(diskFactory.getDisk(sceneController.round), DiskMove);
                sceneController.num++;//Record the number of launches
                count = 0;
            }
            base.Update();
        }
    }

Implementation of UI:

void OnGUI ()
    {
        GUIStyle fontstyle1 = new GUIStyle();
        fontstyle1.fontSize = 50;
        if (GUI.Button(new Rect(10, 10, 120, 40), "Start game"))
        {
            action.StartGame();
        }
        if (GUI.Button(new Rect(140,10 , 120, 40), "start over"))
        {
            action.ReStart();
        }
        if (GUI.RepeatButton(new Rect(750, 10, 120, 40), "Game Rules"))
        {
            action.ShowRule();
        }
    }

Points rules:

if (Physics.Raycast(ray, out hit))
            {
                if (hit.transform.tag == "Disk")
                {
                    if (round == 1 && game == 1)
                    {
                        score += 3;
                    }
                    if (round == 2 && game == 1)
                    {
                        score += 5;
                    }
                    if (round == 3 && game == 1)
                    {
                        score += 8;
                    }
                    explosion.transform.position = hit.collider.gameObject.transform.position;
                    explosion.GetComponent<Renderer>().material = hit.collider.gameObject.GetComponent<Renderer>().material;
                    explosion.GetComponent<ParticleSystem>().Play();
                    hit.collider.gameObject.SetActive(false);
                }
            }
Then just implement the director and the scene record, so I won't paste it here, and the complete code will be moved to github. This time the factory model still needs to be strengthened. The link to the demo video of the game is: https://pan.baidu.com/s/1dMO82DvbrXyfnUEodvmPOw .



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325473842&siteId=291194637