# About

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2Fx7JVzfUYyole8P7bV2XM%2FGAMEPANGIN.jpg?alt=media&#x26;token=58e58579-a1e3-40e9-bb08-74a96ea39e6a" alt=""><figcaption></figcaption></figure>

Gamepangin is a Unity Package which contains various needs and ready-to-use systems that are often used in video game development. It aim so you can focus on what's matter, make the FUN.

{% hint style="info" %}
Did you know Gamepangin is named after an Indonesian words 'Gampangin'? It's means 'Make it easier'
{% endhint %}

### Requirements

* Unity 2021.3 or newer
* [Odin Inspector and Serializer](https://assetstore.unity.com/packages/tools/utilities/odin-inspector-and-serializer-89041)
* [DOTween](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676)

### How to install (Unity 2020.2 and newer)

* In Unity, open **Project Settings** window (Edit/Project Settings) an go **Package Manager**
* Add new **Scoped Registry** with URL : <mark style="background-color:yellow;"><https://package.openupm.com></mark>
* Add a new scope in Scope(s) section : <mark style="background-color:yellow;">com.gamelokal</mark>
* Click **Save** to save changes
* Open **Package Manager Window** (Window/Package Manager) and choose **Packages : My Registries** in the top left toolbar
* Choose **Gamepangin** in the list, and then click **Install**

{% hint style="info" %}
There are many more components provided in Gamepangin which are not documented on this page because they are quite straightforward and too many. You are expected to be able to see for yourself the scripts contained in this package.
{% endhint %}


# Code Naming Convention

## Code Naming Convention

* Rather than simply answering "what" or "how," comments can fill in the gaps and tell us "why."
* Use the // comment to keep the explanation next to the logic.
* Use a Tooltip instead of a comment for serialized fields.
* Avoid Regions. They encourage large class sizes. Collapsed code is more difficult to read.
* Use a link to an external reference for legal information or licensing to save space.
* Use a summary XML tag in front of public methods or functions for output documentation/Intellisense.
* Rather than simply answering "what" or "how," comments can fill in the gaps and tell us "why."
* Use the // comment to keep the explanation next to the logic.
* Use a Tooltip instead of a comment for serialized fields.
* Avoid Regions. They encourage large class sizes. Collapsed code is more difficult to read.
* Use a link to an external reference for legal information or licensing to save space.
* Use a summary XML tag in front of public methods or functions for output documentation/Intellisense.

### Naming/Casing

* Use Pascal case (e.g. ExamplePlayerController, MaxHealth, etc.) unless noted otherwise
* Use camel case (e.g. examplePlayerController, maxHealth, etc.) for local/private variables, parameters.
* Avoid snake\_case, kebab-case, Hungarian notation

### Formatting

* Choose K\&R (opening curly braces on same line) or Allman (opening curly braces on a new line) style braces.
* Keep lines short. Consider horizontal whitespace. Define a standard line width in your style guide (80-120 characters).
* Use a single space before flow control conditions, e.g. while (x == y)
* Avoid spaces inside brackets, e.g. x = dataArray\[index]
* Use a single space after a comma between function arguments.
* Don’t add a space after the parenthesis and function arguments, e.g. CollectItem(myObject, 0);
* Don’t use spaces between a function name and parenthesis, e.g. DropPowerUp(myPrefab, 0);
* Use vertical spacing (extra blank line) for visual separation.

### Comments

* Rather than simply answering "what" or "how," comments can fill in the gaps and tell us "why."
* Use the // comment to keep the explanation next to the logic.
* Use a Tooltip instead of a comment for serialized fields.
* Avoid Regions. They encourage large class sizes. Collapsed code is more difficult to read.
* Use a link to an external reference for legal information or licensing to save space.
* Use a summary XML tag in front of public methods or functions for output documentation/Intellisense.

### Namespace

* Pascal case, without special symbols or underscores.
* Add using line at the top to avoid typing namespace repeatedly.\\
* Create sub-namespaces with the dot (.) operator, e.g. MyApplication.GameFlow, [MyApplication.AI](http://MyApplication.AI), etc.

```csharp
namespace Gamepangin.StyleExample { }
```

### Enums

* Use a singular type name.
* No prefix or suffix.

```csharp
public enum Direction
{
    North,
    South,
    East,
    West
}
```

### Flags Enums

* Use a plural type name
* No prefix or suffix.
* Use column-alignment for binary values

```csharp
[Flags]
public enum AttackModes
{
    // Decimal                         // Binary
    None = 0,                          // 000000
    Melee = 1,                         // 000001
    Ranged = 2,                        // 000010
    Special = 4,                       // 000100

    MeleeAndSpecial = Melee | Special  // 000101
}
```

### Interfaces

* Name interfaces with adjective phrases.
* Use the 'I' prefix.

```csharp
public interface IDamageable
{
    string DamageTypeName { get; }
    float DamageValue { get; }

    // METHODS:
    // - Start a methods name with a verbs or verb phrases to show an action.
    // - Parameter names are camelCase.
    bool ApplyDamage(string description, float damage, int numberOfHits);
}

public interface IDamageable<T>
{
   void Damage(T damageTaken);
}
```

### Classes / Structs

* Name them with nouns or noun phrases.
* Avoid prefixes.

```csharp
public class StyleExample : MonoBehaviour { }
```

### Fields

* Avoid special characters (backslashes, symbols, Unicode characters); these can interfere with command line tools.
* Use nouns for names, but prefix booleans with a verb.
* Use meaningful names. Make names searchable and pronounceable. Don’t abbreviate (unless it’s math).
* Use camelCase.
* Add an optional underscore (*) in front of private fields to differentiate from local variables*
* *You can alternatively use more explicit prefixes: m* = member variable, s\_ = static, k\_ = const
* Specify (or omit) the default access modifier; just be consistent with your style guide.

```csharp
public bool canJump;
private int elapsedTimeInDays;

// Use [SerializeField] attribute if you want to display a private field in Inspector.
// Booleans ask a question that can be answered true or false.
[SerializeField] private bool isPlayerDead;
```

### Properties

* Preferable to a public field.
* PascalCase, without special characters.
* Use the expression-bodied properties to shorten, but choose your preferred format. e.g. use expression-bodied for read-only properties but { get; set; } for everything else.
* Use the Auto-Implemented Property for a public property without a backing field.

```csharp
// the private backing field
private int maxHealth;

// read-only, returns backing field
public int MaxHealthReadOnly => maxHealth;

// equivalent to:
// public int MaxHealth { get; private set; }

// explicitly implementing getter and setter
public int MaxHealth
{
	  get => maxHealth;
    set => maxHealth = value;
}

// write-only (not using backing field)
public int Health { private get; set; }

// write-only, without an explicit setter
public void SetMaxHealth(int newMaxValue) => maxHealth = newMaxValue;

// auto-implemented property without backing field
public string DescriptionName { get; set; } = "Fireball";
```

### Events

* Name with a verb phrase.
* Present participle means "before" and past participle mean "after."
* Use System.Action delegate for most events (can take 0 to 16 parameters).
* Define a custom EventArg only if necessary (either System.EventArgs or a custom struct). OR alternatively, use the System.EventHandler; choose one and apply consistently.
* Choose a naming scheme for events, event handling methods (subscriber/observer), and event raising methods (publisher/subject) e.g. event/action = "OpeningDoor", event raising method = "OnDoorOpened", event handling method = "MySubject\_DoorOpened"

### Methods

* Start a methods name with a verbs or verb phrases to show an action.
* Parameter names are camel case.


# Singleton

## What's that?

The Singleton Design Pattern is a design pattern used to guarantee that a class has only one instance, as well as granting global access to that instance. This is useful when there is a need to ensure that only one instance of a class is used in the entire application.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2FnTYgI3TUFNpBVkqwc8fl%2Fimage.png?alt=media&#x26;token=1b7cab69-9ed8-4b71-ab12-4733d6dbda0a" alt=""><figcaption><p>Singleton illustration</p></figcaption></figure>

In video game development, the Singleton Design Pattern can be used to manage game loops, audio engines, or input systems. In addition, the Singleton Design Pattern can also be used to manage access to limited resources, such as databases or file systems. By using Singleton, we can ensure that there is only one instance of a class that manages the resource, so there are no access conflicts or race conditions when the resource is being used by more than one class.

However, there are some drawbacks to the Singleton Design Pattern. First, Singleton cannot be used in cases where a class must have more than one instance. Second, Singleton has tight coupling with other classes, so it will be difficult to change its implementation to other classes without changing the existing code.

### Pros

* Can be sure that a class has only one instance.
* Can grant global access to the instance.
* The singleton object is initialized only when it is requested for the first time.

### Cons

* Overuse worsens the architecture, for example, when program components know too much about each other.
* It can be difficult to use Unit Testing when using Singleton because many test frameworks rely on inheritance when creating mock objects.

### Implementation

To turn a class into a singleton, you can simply inherit from the Singleton class Singleton\<T>

```csharp
public class MyClass: Singleton<MyClass> { }
```

If you need a function that is executed when the singleton instance is created, you can override OnCreate(), likewise if you want something to happen when the singleton is destroyed you can override OnDestroy()

```csharp
public MyClass : Singleton<MyClass>
{ 
    protected override void OnCreate()
    {
        base.OnCreate();
        // This is executed only once when created automatically
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        // This is executed only once when destroyed
    }
}
```

By default, a singleton class will be a GameObject that persists when switching scenes. This means that the GameObject will always be there even if you switch scenes. If you don't want this behavior, you can override the IsPersistBetweenScenes Properties to false

```csharp
public MyClass : Singleton<MyClass>
{ 
    protected override bool IsPersistBetweenScenes => false;
}
```

{% hint style="info" %}
If the singleton class is not in the scene, then when another script calls the singleton reference, a new GameObject will be formed with the singleton component before finally returning the reference.
{% endhint %}


# Publisher -> Subscriber

## What's that?

Publisher-subscriber is a design pattern commonly used in game development. This pattern allows an object to publish information to other objects that subscribe to the object. Objects that publish information are called "publishers", while objects that receive information are called "subscribers".

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2FyMArgdi0agDkciGu2BcU%2Fimage.png?alt=media&#x26;token=cb5c8219-ab1a-46ae-b4eb-c8f4e54a316d" alt=""><figcaption><p>PubSub illustration</p></figcaption></figure>

Publisher-subscribers provide an advantage in game development because they allow communication between isolated objects. This is especially useful if the objects have dependencies on one another, but there is no need to know in detail how the other objects work.

A simple example is if in your game there is an event which if the event is executed, then many other elements in your game will react to that event. For example, when the player character dies, you want to play the game over audio, display the game over screen, submit the player's score to the leaderboard, etc. You can run all these methods in one script but it will create coupling and dependencies in your script. This is where this pattern is used.

You just need to send an event/message from your player script when the player dies, and you can just make the script that needs to react to the event to become a subscriber.

## Implementation

#### GameEvent.cs

Gamepangin has provided an event that accepts a string as a parameter in the GameEvent.cs script If you only need to send an event that only contains the string: eventName, you can immediately use this GameEvent. The following is the contents of GameEvent.cs

```csharp
namespace Gamepangin
{
    public struct GameEvent
    {
        public string eventName;

        public GameEvent(string newName)
        {
            eventName = newName;
        }

        private static GameEvent gameEvent;

        public static void Trigger(string newName)
        {
            gameEvent.eventName = newName;
            EventManager.TriggerEvent(gameEvent);
        }
    }
}
```

## Trigger an Event

There are 2 ways to send an event, namely by EventManager.TriggerEvent or directly via the static Trigger method of an event struct.

```csharp
private void Die()
{
    EventManager.TriggerEvent(new GameEvent("Player Dead"));
    // Same as this one
    GameEvent.Trigger("Player Dead");
}
```

## Subscribe to an Event

So that your script can find out what specific events are sent, you must subscribe to the event by adding the IEventListener interface and also don't forget to tell the EventManager to subscribe/unsubscribe this component.

<pre class="language-csharp"><code class="lang-csharp">public class AudioManager : MonoBehaviour, IEventListener&#x3C;GameEvent>
{
<strong>    private void OnEnable()
</strong>    {
        // Subscribe
        EventManager.AddListener&#x3C;GameEvent>(this);
    }

    private void OnDisable()
    {
	// Unsubscribe
	EventManager.RemoveListener&#x3C;GameEvent>(this);
    }

    public void OnEvent(GameEvent gameEvent)
    {
	// Game Event is received, filter it by eventName
	if(gameEvent.eventName == "Player Dead")
	{
	    // Do something when player dead
	}
    }
}
</code></pre>

## Create your own event type

You can see the GameEvent example above to create your own event that can receive the parameters you want, here is an example of ApplicationEvent.cs which is included in Gamepangin which you can also use to detect whether your game is running in the background or not

```csharp
namespace Gamepangin
{
    public enum AppEventType
    {
        OnApplicationBackground,
        OnApplicationFocus,
        OnApplicationQuit
    }
    public struct ApplicationEvent
    {
        public AppEventType appEvent;

        public ApplicationEvent(AppEventType newAppEvent)
        {
            appEvent = newAppEvent;
        }

        private static ApplicationEvent e;

        public static void Trigger(AppEventType newAppEvent)
        {
            e.appEvent = newAppEvent;
            EventManager.TriggerEvent(e);
        }
    }
}
```


# Object Pooling

## What's that?

Object pooling is a technique used in video game development to efficiently manage in-game objects. The basic concept of object pooling is to prepare a number of objects beforehand and store them in a "pool" or "pool" to be reused when needed. This is especially useful when games require lots of objects to be created and removed continuously, such as bullets in a shooter game.

Without object pooling, the game will continue to create and delete new objects whenever needed. This process can take up a lot of computer resources, especially if the game requires a lot of objects to be created and removed quickly. With object pooling, objects can be quickly retrieved from the pool without the need to create new objects, thereby saving computer resources.

However, object pooling also has drawbacks. Object pooling requires good planning and implementation in order to work properly and efficiently. Because usually it will require additional work to reset the condition of the objects in the pool where this is usually done automatically without using Object Pooling.

## Implementation

Change the use of Instantiate(prefab) to pool.Spawn(prefab) and Destroy(gameObject) to pool.Despawn(gameObject) in your project

```csharp
// Instantiate(bullet);
Gamepangin.Pool.Spawn(bullet);

// Destroy(bullet);
Gamepangin.Pool.Despawn(bullet);
```

If you use the method above, a new GameObject will be created automatically as the prefab pool provider with default settings to make it easier to use. However, if you want more advanced settings for the pool you need, you can create a new GameObject and add a GameObjectPool component. Then you drag and drop the Prefab object that will be pooled into the Prefab slot section. Here you can set several settings such as Preload, Capacity, etc

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2FoukuOwWKDEdGp7UCvHgh%2Fimage.png?alt=media&#x26;token=62f350a1-048e-49fd-a7fe-4bb48a742d8d" alt=""><figcaption><p>GameObject Pool Settings</p></figcaption></figure>

Objects in the pool will not reset to their original state when they are spawned again. For example, if you do object pooling for bullets in your game, and you use the Rigidbody.Velocity API to provide the movement of the bullet, the velocity will not reset when it is despawned. So when you spawn the bullet and add velocity again, the result of the velocity will be multiplied by the last velocity when the bullet was despawned. Then how to overcome it? For each object that you use in Object Pooling, add a method to reset the object's state to OnEnable / OnDisable

```csharp
public class Bullet : MonoBehaviour {

    public float bulletSpeed = 10f;
    private Rigidbody rigidbody;
		
    private void Awake() {
        rigidbody = GetComponent<Rigidbody>();
    }

    private void OnEnable() {
	// Reset velocity first when spawned
	rigidbody.velocity = 0f;

	// Move the bullet by changing the velocity
	rigidbody.velocity = Vector3.forward * bulletSpeed;
    }
}
```


# State Machine

## What's that?

State Machine is a programming pattern that groups the behavior of an object into a state or what is known as a state. The state can change according to the action performed by the object. This pattern is widely used in game development to manage the behavior of characters or objects in the game.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2Fo7NzDwsMc1tPdGzfHV08%2Fimage.png?alt=media&#x26;token=1a5a1848-3812-4609-8292-95336ef9570f" alt=""><figcaption><p>State Machine illustration</p></figcaption></figure>

One example of the use of State Machines in game development is the character movement system. In-game characters can move in different directions, such as walking, running or jumping. Each of these movements is a separate state. State Machines can be used to manage transitions from one state to another. For example, when a character is walking and the jump button is pressed, the character will enter a jump state which will perform a function when the state changes to jump, such as playing a jump animation for the character.

Apart from that, the State Machine Design Pattern can also be used to manage the behavior of other objects in the game, such as NPC (Non-Player Character) or enemies. NPCs can have various states, such as idle, chatting, or currently attacking. By using the State Machine Design Pattern, we can easily manage the transition from one state to another on the NPC.

However, there are a few things to consider when using State Machine. First, we have to make sure that each state has an implementation that fits that state. Second, we have to make sure that every state transition is done correctly, so that invalid state doesn't occur.

{% hint style="info" %}
State machines in Gamepangin are different from Finite State Machines. Where if in the Finite State Machine you determine the Transition from one state to another possible state so that you can prevent unwanted changes to the state from the previous state. In an ordinary State Machine, you are free to move from any state to any state, you are expected to manage the possibilities that occur in the state that you will create later.
{% endhint %}

## Implementation

Add the StateMachine component to the GameObject you want. Then create a new GameObject under the parent State Machine which will act as the State.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2Fj0eQT9PkVZVgcHleaaEj%2Fimage.png?alt=media&#x26;token=6b8fe6a7-2571-440f-8807-0c30f7c27b45" alt=""><figcaption></figcaption></figure>

After creating the GameObject, add the State component, then add the GameObject to the States field in the State Machines component.

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2Fxn1iduPBa0qkwTPTXawC%2Fimage.png?alt=media&#x26;token=22886fcb-c436-4cf4-8f42-bcb1576390a5" alt=""><figcaption></figcaption></figure>

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2FC2qI0jXq6pH9IvBnzX6s%2Fimage.png?alt=media&#x26;token=4aab41fd-68cf-4e01-9b8b-5358f173813e" alt=""><figcaption></figcaption></figure>

For the implementation of methods that will be executed when this State Machine enters/exits a certain State, you can fill in the UnityEvent directly through the inspector on the currently selected State component.

To change a State to another State, you can use the SetState() API

```csharp
public StateMachine myStateMachine;

void GoToStateB(){
    myStateMachine.SetState("State B")
}
```


# Audio Manager

Gamepangin has provided a system for your in-game audio needs easily. The following are the features provided:

* Play / Stop / Pause / Resume
* Play clip with full settings : loop, volume, pitch, pan, spatial blend, bypasses, priority, reverb, doppler level, spread, rolloff mode, distance
* 2D & 3D spatial support
* Provided Audio Mixer and Track (Master, Sfx, Music, UI)
* Stop / Pause / Resume all tracks
* Stop / Pause / Resume all audio
* Mute / Set volume each tracks
* Integrated with Object Pooling for maximum performance
* Integrated with Save Load for persistence settings
* and more...

### Audio Clip Settings

Before you can play audio, you must create an AudioClipSettings scriptable object by right clicking on the Project Window > Create > Gamepangin > Audio > Clip

<figure><img src="https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4z5bYhjCwt02AHS4praa%2Fuploads%2FqC39qf1I21Z39z9AsA1Q%2Fimage.png?alt=media&#x26;token=95d83710-47c0-41e2-b84f-7d2796cbb505" alt=""><figcaption><p>AudioClipSettings Inspector</p></figcaption></figure>

### Audio Manager Singleton

Before calling the API, make sure you have Audio Manager in your scene. To make it you can use the Gamepangin menu > Audio > Audio Manager

### Public API

#### Play Sound

```csharp
// Play sound via unique id
AudioManager.Instance.PlaySound(string id)

// Play sound via AudioClipSettings reference
AudioManager.Instance.PlaySound(AudioClipSettings clip)
```

#### Pause Sound

```csharp
AudioManager.Instance.PauseSound(string id)
```

#### Resume Sound

```csharp
AudioManager.Instance.ResumeSound(string id)
```

#### Stop Sound

```csharp
AudioManager.Instance.StopSound(string id)
```

#### Mute Track

```csharp
AudioManager.Instance.MuteTrack(AudioManagerTracks track)
```

#### Unmute Track

```csharp
AudioManager.Instance.UnmuteTrack(AudioManagerTracks track)
```

#### Pause Track

```csharp
AudioManager.Instance.PauseTrack(AudioManagerTracks track)
```

#### Play Track

```csharp
AudioManager.Instance.PlayTrack(AudioManagerTracks track)
```

#### Stop Track

```csharp
AudioManager.Instance.StopTrack(AudioManagerTracks track)
```

#### Set Track Volume

```csharp
AudioManager.Instance.SetTrackVolume(AudioManagerTracks track, float volume)
```

#### Pause All Sounds

```csharp
AudioManager.Instance.PauseAllSounds()
```

#### Play All Sounds

```csharp
AudioManager.Instance.PlayAllSounds()
```

#### Stop All Sounds

```csharp
AudioManager.Instance.StopAllSounds()
```


# ScriptableObject with Id

ScriptableObjectWithId is a class derived from ScriptableObject which has a UniqueId property which will be generated automatically when the ScriptableObject is created. The GUID that is generated must be unique from the others. But you can change the UniqueId as long as you can ensure that the value is unique from the others.


