まえがき
現在、私は自分のゲームエンジンに取り組んでいます。 最小限の数のサードパーティライブラリを使用して、ゲームループ(ゲームループ)の実装、フレームのレンダリング、「更新」機能、テクスチャのロードなどを行うと、エンジンの主な「充填」の準備が整いました。 もう1つの重要なコンポーネント-シーン(シーン)を実装するときが来ました。
はじめに
この記事では、エンジンにはすでに「コールバック」機能を備えたゲームループが装備されていると想定しています。 すべてのコードはJavaで記述されますが、 ガベージコレクションをサポートする他の言語に簡単に移植できます。 さあ、始めましょう。
すでにそこにあるもの
前述のように、すでにゲームループがあります。 次のようにします。
void awake() { RenderUtil.init(); // OpenGL run(); } void run() { // game loop // ... // input, frame rate . . // if (Window.isCloseRequested()) { // stop(); return; } update(); render(); }
後でrender()およびstop()メソッドの実装を提供します。
シーンを定義する
シーンのクラスを書き始める前に、それがどうなるかを決める必要があります。 私の場合、これは多くのゲームオブジェクトを含むオブジェクトです。 少し読んで休憩して、あなたの周りを見てみましょう。私たちはあなたが見る(ほぼ)ゲームオブジェクト、そしてあなたがいる場所をすべてシーンと呼びます。
ゲームオブジェクトとはどういう意味ですか? これは、ゲームループの「コールバック」機能を実装するオブジェクトです。 Unity3Dに精通している人向け :クラスがMonoBehaviourを実装するオブジェクトとの類推。
この同じゲームオブジェクトをインターフェイス(または目的の機能に応じて抽象クラス)で表し、 GameListenerを呼び出します (この記事でも、このクラスは既に何らかの方法で実装されています)。
プリミティブインターフェイスの実装は次のようになります。
public interface GameListener { void start() ; // , void update(); // void draw(); // update() void destroy(); // , "" }
機能の数は、望ましい制御の程度に依存します 。たとえば、Unity3D には多くの機能があります 。
クラスSceneを実装します
シーンのアーキテクチャと構造を定義したら、最終的にその実装に進むことができます。
public abstract class Scene implements GameListener { ArrayList<GameListener> gameListeners = new ArrayList<>(); public abstract void initializeScene(); public final void AddToScene(GameListener gameListener) { gameListeners.add(gameListener); } public final void onInitializeScene() { if (gameListeners.isEmpty()) initializeScene(); } @Override public final void start() { for (GameListener gameListener : gameListeners) gameListener.start(); } @Override public final void update() { for (GameListener gameListener : gameListeners) gameListener.update(); } @Override public final void draw() { for (GameListener gameListener : gameListeners) gameListener.draw(); } public final void onDestroy() { for (GameListener gameListener : gameListeners) gameListener.destroy(); gameListeners.clear(); } @Override public final void destroy() {}
私はアイテムにコメントを書きます:
- シーンは、ArrayListコレクションにゲームオブジェクトを格納します。
- initializeScene()メソッドは抽象です。 その中で、特定のシーンクラスのAddToScene()メソッドを使用して、ゲームオブジェクトをシーンに追加します。
- シーンの変更/再起動、またはゲームの終了後にonDestroy()メソッドを呼び出します。 その中で、ゲームオブジェクトのシーンをクリアし、ガベージコレクターが残りを処理します(System.gc()を呼び出すことでJVMにクリーンアップするようにヒントを与えることができます)。
すべてのメソッド(自然にinitializeScene()を除く)がfinalキーワードでマークされているため、Sceneクラスではエンジンのユーザーは自分のゲームオブジェクトのみを追加できます(この制限はこれまでのところ適しています)。
ゲームサイクルの変革
ここで、ゲームループで変換を実行する必要があります。 実際、それらはすべて直感的です。
Scene runningScene; void awake() { RenderUtil.init(); runningScene = SceneManager.getScene(0); run(); } void run() { if (Window.isCloseRequested()) { stop(); return; } runningScene.update(); runningScene.render(); } void stop() { runningScene.onDestroy(); } void render() { runningScene.draw(); }
作成したすべてのシーンを、たとえばSceneManagerというクラスに含まれる配列に追加できます。 その後、シーンシステムによってコントローラーとして機能し、 getScene() 、 setScene()メソッドなどを提示します。
この段階では、システムの実装は「ステータス」パターンに非常に似ています。 そうです。
シーンチェンジ
シーンを変更するには、SceneManagerでSceneクラスの同様のインスタンスを定義できます。
private static Scene currentScene;
次に、 setter setCurrentScene(Scene)を記述します。
public static void setCurrentScene(Scene scene) { currentScene = scene; }
次に、ゲームループでrunningSceneとcurrentSceneを比較し、一致しない場合はシーンを変更します。
void run() { if (Window.isCloseRequested()) { stop(); return; } runningScene.update(); if (runningScene != SceneManager.getCurrentScene()) { runningScene.onDestroy(); runningScene = SceneManager.getCurrentScene(); } runningScene.render(); }
現在のシーンのonDestroy()メソッドを呼び出してゲームオブジェクトを削除することを忘れないことが重要です。
添加剤添加の実施
同じUnity3D には、 「追加の」読み込みシーンの可能性があります。 このメソッドでは、「古い」シーンのオブジェクトは削除されず(この場合、 onDestroy()メソッドは呼び出されません)、新しいシーンは古いシーンの「上」にロードされます。
これは、たとえば、追加的にロードされたシーンのリストを保存するコンテナを作成することで実現できます。 その後、挑戦とともに
runningScene.update();
あなたは次のようなことを言う必要があります
for (Scene additive : additives)
additive.update();
などなど。
OnDestroy()は、 メインシーンの再起動/変更(runningScene)またはゲームを閉じる場合に呼び出す必要があります。
アーキテクチャ、ゲームオブジェクトを追加する手順、およびシーン自体は同じままです。