はじめに
初めまして!
CYBIRD Advent Calendar 2021 21日目を担当します、@R_araiと申します。
20日目は@cy_seiyanさんの初めての負荷試験とパフォーマンスチューニングで得た苦戦・快感・理解でした!バックエンド側の苦労や工夫が知れて勉強になる記事でした!
自己紹介
ゲーム系専門学校を卒業後、新卒でCYBIRDに入社した社会人1年目のエンジニアです!
配属部署はゲーム開発系ではなくほぼ未経験の分野で記事に出来る事がまだあまりないので今回は新卒研修でゲームを作る機会がありその時勉強した事を記事にしたいと思います!
概要
ゲーム開発をしていると〇〇した瞬間を検知したくなる時が度々あると思います。
学生時代自分は変化があるたびに条件書いたりしていましたが流石に面倒になってきたので新卒技術研修を機に勉強したので自分なりの解釈で今回の実装についてまとめようと思います。
尚、今回の実装の仕方は自分が理解しやすい形で実装したので一般的なオブザーバーパターンとは違うところがあるかも知れませんがこういう考え方もあるのか程度で見て頂けたら嬉しいです。
目次
1.Obeserverってなに?
2.実装内容
3.最後に
1.Observerってなに?
Observerとは観察される者(Observable)と観察する者(Observer)が存在し、観察される側に変化があったら観察する側に通知を送るというものになります。
自分もこの説明で理解出来れば苦労しなかったのですが正直この説明でもよく分からなかったのでRPGの戦闘終了時の処理に例えて解説してみます。
作りたい仕様は、Enemyが存在し、EnemyのHPが0になったらGameManagerは戦闘を終了させたい。
この仕様の場合、Enemyが観察される者(Observable)でGameManagerが観察する者(Observer)になります。
Enemy(Observable)は体力が0になったという変化が起きたのでGameManager(Observer)に変化があった事を通知するという流れになります。
2.実装内容
では次にさっきの仕様を実装してみます。
※UnityC#を使っていきます。
//観察する側インターフェース
public class IObserver : MonoVehavior
{
//変更があった時に呼ばれる仮想関数
public virtual void ChangeUpdate()
{
}
}
//観察される側
public class Observable
{
private List<IObserver> observerList = new List<IObserver>();
//観察してくる者を追加する関数
public void Add(IObserver observer)
{
observerList.Add(observer);
}
//自分に変化があった時、観察している者達に通知する
public void ChangeUpdate()
{
foreach(var observer in observerList)
{
observer.ChangeUpdate();
}
}
}
public class GameManager : IObservar
{
//シングルトンもどき
public static GameManager instance { get; private set; }
void Awake()
{
//この実装法は危険なのでシングルトンで調べて実装してね
instance = this;
}
public override void ChangeUpdate()
{
//ゲーム終了処理
}
}
Public class Enemy : MonoBehaviour
{
private int health;
private Observable observable = new Observable();
void Start()
{
health = 100;
observable.Add(GameManager.instance);
}
//現在の体力をチェック
private void CheckStatus()
{
if(health <= 0)
{
observable.ChangeUpdate();
}
}
}
実装はこんな感じで、コツとしては観察される者は観察する者のインスタンスを持っている事にあります。自分が変化したタイミングで観察する者の関数を呼んで上げれば通知が出来ます。呼ばれた時の振る舞いはIObserverを継承したクラス毎にoverrideして実装する事によって別々の定義が出来ます。さらにこのObserverの特徴がObservable(観察される者)が観察している者のインスタンスを複数持てる所で複数持てる事によってGameManagerからゲーム終了処理を呼ぶと同時にScoreManagerなどからスコアアップ関数やEffectEmitterからエフェクト生成関数など同時に行う処理をAddで追加するだけで簡単に仕様変更ができ多様性も高く作れます。
3.最後に
実際に初めて勉強して実装したのでObserverパターンというものがどんなモノかは理解しましたが、う〜ん…あんまりスマートな実装じゃないかも。概念としては間違っていないはずなのですが使いやすいかと言われると微妙な感じ…3~4週間という短い期間にゲームを作る研修という事もあってあまりここだけに時間が割けなかったというのもありますが、気が向いたら作り直したいです。
明日のCYBIRDエンジニア Advent Calendar 22日目 の担当は、@cy-naullさんのUnity初心者がImageを発光させるです。Unityで手軽にビジュアルをこだわりたい方は勉強になりそうですね!