---
# System prepended metadata

title: 'Find Me Bitch (2D Party Game):'
tags: [遊戲製作]

---

---
tags: 遊戲製作
---

# Find Me Bitch (2D Party Game):

## how to play:
This game is divided into black and white to fight against each other, the white is the brave, there are several players, and the black is the BOSS, there is only one person; the main game goal of the game is that the BOSS has to find the players hidden in many NPC; the way to win the players is to occupy the red area for a few seconds and then Successful occupation, or the number of BOSS attacks runs out, the player wins; while the BOSS attack destroys all players or the time runs out, the BOSS wins.

<font color="#f00">Player1: </font> 
move: WASD

<font color="#f00">Player2: </font> 
move: GVBN

<font color="#f00">BOSS: </font> 
move: arrow-Up arrow-Left arrow-Down arrow-Right 
attack: Space

<font color="#f00">Return to Home: </font> H

<font color="#f00">Quit Game: </font> ESC

---

## production experience:
This is the first game I wrote and completed myself from beginning to end. Many APIs I wrote later were learned at this time, how to tie animations for characters, how to time
timing, how to change scenes, etc. When I finished, I felt a sense of accomplishment, and finally I felt like I was working on a game by my self.

## Codes

Programs worth reviewing

### ChangeScene.cs

When I wrote this code for the first time, I opened a script every time I changed a screen. The program was very lengthy. When I organized the portfolio this time, I organized the code by the way, and it felt very good.

this code can also be used on other project.

```cpp=
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//changeScene must included
using UnityEngine.SceneManagement;

//This script changes Scene, return to start and finish game 
public class ChangeScene : MonoBehaviour
{
    //"Scene in build" number array
    public int[] SceneNumber;

    //i is the 'i'th one in SceneNumber array 
    public void OnButtonClick(int i)
    {
        SceneManager.LoadScene(SceneNumber[i]);
    }

    // Update is called once per frame
    void Update()
    {
        
        if (Input.GetKeyDown(KeyCode.H))
        {
            //print H return to the Scene "Home" 
            SceneManager.LoadScene(0);
        }

        if (Input.GetKeyDown("escape"))
        {
            //print ESC to quit the game      
            Application.Quit();
        }
    }
}
```

### NPC Manager

When I was writing the program, I created NPCs in a simple way of directly copying a total of 7 NPCs in unity Hierarchy; but when I came back recently, I felt that such a program was difficult to control, so I modified it.

Singleton will be used here, and here I am citing the creation of Singleton Generics taught by my seniors:
```cpp=
namespace HD.Singleton{
    public class TSingletonMonoBehavior<T>: MonoBehaviour where T : MonoBehaviour{

        static T instance = null;

        public static T Instance{
            get { return instance ??= (FindObjectOfType(typeof(T))as T);}
            set {instance = value; }
        }

        protected virtual void Awake(){
            if(instance == null) instance = this as T;
            if(instance == this) DontDestroyOnLoad(this);
            else DestroyImmediate(this);
        }

        protected virtual void OnDestroy() => instance = null;
    }
}
```
---

Next is the pool, where you can use it directly as long as you hang the GameObject and set the initial number:

(This can also be used directly in other projects)

```cpp=
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HD.Singleton;

public class ObjectPool : TSingletonMonoBehavior<ObjectPool>
{
    public List<GameObject> pooledObjects;
    public GameObject objectToPool;
    //the number you need to generate
    public int amountToPool;

    public GameObject GetPooledObject(){
        for ( int i = 0; i < amountToPool; i++ ) {
            //Use it if you are not using it
            if(!pooledObjects[i].activeInHierarchy){
                return pooledObjects[i];
            }
        }
        return null;
    }

    void Awake()
    {
        pooledObjects = new List<GameObject>();
        GameObject tmp;
        //create Objects and add into  pooledObjects
        for(int i = 0; i < amountToPool; i++)
        {
            tmp = Instantiate(objectToPool);
            tmp.SetActive(false);
            pooledObjects.Add(tmp);     
        }              
    }
}
```

Since objectToPool is not initialized, it cannot be placed in your own commonly used namespace

---
Quoting the above code to randomly generate several NPC
```cpp=
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NPCManager : MonoBehaviour
{
    public int amountToPool;
    //put in randomly generated boundaries
    public Transform Up;
    public Transform Left;
    public Transform Down;
    public Transform Right;
    //l is in order to prevent the generated object from
    // hitting the wall, it needs to be generated inside
    //  the wall
    float l = 1.0f;
    Vector3 StartPosition;
 
    // Start is called before the first frame update
    void Start()
    {      
        for (int i = 0; i < amountToPool; i++)
        {
            StartPosition = new 
            Vector3(Random.Range(Left.position.x + l , 
            Right.position.x - l), 
            Random.Range(Down.position.y+l, Up.position.y-
            l), 0);
            GameObject NPC = 
            ObjectPool.Instance.GetPooledObject();            
            NPC.transform.position  = StartPosition;            
            NPC.SetActive(true);
        }
    }
}

```

## UIText

reference: https://codingnote.cc/zh-tw/p/238497/

Update the UI by passing the boss's attack status to UIText through event delegation

Boss
```cpp=
public delegate void OnAttack(); //設定攻擊委託
public static event OnAttack onAttack; //建立攻擊事件

if (AttackKey)
            isAttackedKeyPressed = true;
        if (isAttackedKeyPressed && Input.GetAxis(BOSSH) < 0)
        {
            weapon.SetActive(true);
            audiosource.PlayOneShot(impact);
            timer += Time.deltaTime;
            if (timer >= beat)
            {
                weapon.SetActive(false);              
                onAttack();
                timer = 0;
                isAttackedKeyPressed = false;
            }
        }

```

UIText
```cpp=
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIText : MonoBehaviour
{
    public int bossAttackTime = 25;
    public Text BossAttackTime;
    public Text BossLose;

    public void UpdateText()
    {
        bossAttackTime --;
        BossAttackTime.text = bossAttackTime + "";
        if (bossAttackTime <= 0)
        {
            BossLose.text = "Chanllengers Win!";
        }
    }

    public void OnEnable()
    {
        Boss.onAttack += UpdateText;
    }
}

```





## Responsible for:
1. Planning (total 2 people)
2. Coding (total 1 people) all code by my self



## More Information
Video: https://www.youtube.com/watch?v=2DZn3IxZn70&ab_channel=-WEI-JHESHU
Github: https://github.com/andy091045/FindMeBitch
HackMD: https://hackmd.io/@andy091045/HkcmgP1dc