HaxeFlixel デモから学ぶ

# HaxeFlixel 勉強
![nin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/8b21ae32-4a50-0c99-9428-f6f11f4a8f8c.png)

## 何故 HaxeFlixel を使うのか

皆さんご存知かと思いますが、他のゲームエンジンに比べて HaxeFlixel と Haxe の情報は少ないです。ですが、コードの記述だけでゲームを作成したいと考えている方にとっては数少ない選択肢では無いでしょうか？現在主流のゲームエンジンは、GUIを利用しシーンやオブジェクトをコード外で設定するものが多いのですが、HaxeFlixel はそういったものが一切なく（ogmo editor など外部のツールは利用可能だったりしますが）、直接記述するため、コードを見れば設定した数値が確認出来てあっちこっち見に行く必要が無く、「また新しいソフトを学習する必要があるのか...」とうんざりしなくて済むのでストレスは少ないです。
筆者はカラフルなロゴとlimeやnekoといったツールの名前に惹かれて使い始めました。

## 学習の進め方について
初心者向けの2Dゲームエンジンですがマイナーな言語を使用しているので、新たに学習する事は多いです。これまでにいくつかプログラミング言語に触れている人にはそこまでハードルは高くないと思うのですが、公式以外、一般ユーザーが投稿したWEB情報が少ないので、サクサクは進みませんでした。

この記事では筆者が学習するにあたって試行錯誤し、その中でも効率が良かった方法を紹介します。

:::note info
ここでは windows11 を使用して進めるので、使用環境に合わせてコマンドを修正して下さい。
:::

## デモを魔改造する
いきなり変なタイトルで申し訳ないのですが、その名の通りデモを弄って別のものにする学習をおすすめします。

言葉だけでは伝わらないと思うので、以下実際のゲームソースを触りながら説明します。
\
\
まずターミナルから、プロジェクトフォルダーを作成したいフォルダーへ移動します。

```ruby:terminal
cd .\HaxeProjects
```
以下でフォルダーを作成します。
```ruby:terminal
flixel tpl -n "ActionTestRoom" -ide vscode
```
ActionTestRoom というのがプロジェクト名（もちろん任意）で、使用する IDE は VScode です。

<code>Successfully created template</code> と表示されていれば作成されています。

次に VScode でプロジェクトを開きます。
```ruby:terminal
code "ActionTestRoom"
```
VScode が開いたので、ここからは VScode で進めていきます。
![2025-01-06-01:43:05-screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/eb290c01-0358-027c-ca93-05a8117fe5c2.png)

改造するには元となるオープンソースのデモが必要なので、公式から引っ張ってきます。

アクション要素のデモを見つけたのでこれを改造したいと思います。
![FlxFSMデモ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/df93e28a-c42d-3654-c0ec-98af70365112.png)

[HaxeFlixel公式デモ FlxFSM ](https://haxeflixel.com/demos/FlxFSM/)

猫のロゴから git を開き、assets、source、Project.xmlを全て作成したプロジェクトにコピーします。
・assets は画像及び音声データをダウンロードして全て入れます。（ Slime.hx は新規プロジェクトには無いので作成します ）
・source と Project.xml はテキストをコピペします。

:::note info
最新のversionではアセットパスの記述が変更されているので、面倒ですがアセットは全て以下の新しい書式に書き換える必要があります。（ PlayState.hx と Slime.hx ）
:::
下記+のように <code>""</code> が無くなり、<code>assets/</code> が <code>AssetPaths.</code> 、 <code>.</code> が <code>__</code> へ変更されました。

```diff_ruby:VScode　例：
- FlxG.sound.play("assets/powerup.ogg");
+ FlxG.sound.play(AssetPaths.powerup__ogg);
```

次にProject.xml の７行目辺り、
```ruby:Project.xml
<app title="FlxFSM" file="FlxFSM" main="Main" version="0.0.1" company="HaxeFlixel" />
```
を
```ruby:Project.xml
<app title="ActionTestRoom" file="ActionTestRoom" main="Main" version="0.0.1" company="HaxeFlixel" />
```
に変更します。（ "ActionTestRoom" の箇所はプロジェクトフォルダーの名前にする必要があります。）

これで一旦テストします。
```ruby:terminal
cd .\ActionTestRoom
lime test neko
```
正常に起動されれば準備完了です。
![FlxFSMテスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/4ee23b96-b780-12bf-1c54-2a46b234b7a3.png)

ここからが本題なので勉強したい箇所を改造していきましょう！！
この中には学ぶべき事が盛り沢山ですが、折角なのでデモのタイトルにある FlxFSM から学習します。

では、改造していきます。例えば、主人公を変更します。（ アニメーションにはスプライトシートを利用 ）
![slime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/e002b543-faa4-ad66-1d30-5202d923c5ff.png)
デモではこの可愛らしいスライムが主人公ですが、オリジナルの忍者にしてみます。（ 左上から0～7です ）
![player.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/87a603eb-aa54-dd60-2b64-9b57be7f643a.png)
まずこの様なスプライトシートを自作して（asepriteなどで作成、長くなるので製作手順は省略しますがキャラクターの寸法は32×32pixelです。）、16×16のスライムと入れ替えます。
```ruby:Slime.hx
public function new(X:Float = 0, Y:Float = 0)
	{
		super(X, Y);

		loadGraphic(AssetPaths.slime__png, true, 16, 16);
		setFacingFlip(LEFT, true, false);
		setFacingFlip(RIGHT, false, false);
		facing = RIGHT;

		animation.add("standing", [0, 1], 3);
		animation.add("walking", [0, 1], 12);
		animation.add("jumping", [2]);
		animation.add("pound", [3]);
		animation.add("landing", [4, 0, 1, 0], 8, false);
  ```
これを、
```ruby:Slime.hx
public function new(X:Float = 0, Y:Float = 0)
	{
		super(X, Y);
        
        #次の１行を変更します。（作成したスプライトシートと入れ替えます）
		loadGraphic(AssetPaths.player__png, true, 32, 32);
  
		setFacingFlip(LEFT, true, false);
		setFacingFlip(RIGHT, false, false);
		facing = RIGHT;

        #次の２行を追加してキャラクターの位置を調整します。
        setSize(16, 32);
		offset.set(8, 0);

		animation.add("standing", [0]);
		animation.add("walking", [0, 1], 6);
		animation.add("jumping", [2, 3, 4],6);
		animation.add("pound", [0]);
		animation.add("landing", [0, 4], 12, false);
  ```
  こうすると、

  ![FlxFSMキャラ変.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/abf60ef9-7287-f56d-65ea-764691672192.png)
こんな感じです。楽しくなってきましたね。

では本題の FlxFSM を触っていきます。

##### アニメーションを追加
改造の例として剣を振るアクションを追加したいと思います。
Slime.hx の25行目辺りにある animation.add が記述されている下にコードを追加します。
```ruby:Slime.hx
    animation.add("standing", [0]);
	animation.add("walking", [0, 1], 2);
	animation.add("jumping", [2, 3, 4],6);
	animation.add("pound", [0]);
	animation.add("landing", [0, 4], 12, false);
    #ここに次の１行を記述
    animation.add("sword", [5, 6, 7, 4, 0],12, false);
 ```
<code>"sword"</code> がアニメーション名で、 <code>[5, 6, 7, 4, 0]</code> がスプライトシートの番号、 <code>12</code> がフレーム数、 <code>false</code> がリピート有無です。

##### FlxFSM の状態を追加
Slime.hx の35行目辺りにある fsm.transitions が記述されている下にコードを追加します。
```ruby:Slime.hx
    fsm = new FlxFSM(this);
	fsm.transitions.add(Idle,Jump,Conditions.jump);
    fsm.transitions.add(Jump,Idle,Conditions.grounded);
    
    #ここに次の４行を記述
    fsm.transitions.add(Sword, Jump, Conditions.jump);
    fsm.transitions.add(Idle,Sword,Conditions.sword);
    fsm.transitions.add(Jump,Sword,Conditions.sword);
    fsm.transitions.add(Sword, Idle, Conditions.animationFinished);
    
    fsm.transitions.start(Idle);
```
そして80行目辺りに記述されている Conditions クラスにその状態となる条件のコードを追加します。
```ruby:Slime.hx
class Conditions
{
	public static function jump(Owner:FlxSprite):Bool
	{
		return (FlxG.keys.justPressed.UP && Owner.isTouching(DOWN));
	}

	public static function grounded(Owner:FlxSprite):Bool
	{
		return Owner.isTouching(DOWN);
	}

	public static function groundSlam(Owner:FlxSprite):Bool
	{
		return FlxG.keys.justPressed.DOWN && !Owner.isTouching(DOWN);
	}

#次の４行を追加します
    public static function sword(Owner:FlxSprite):Bool
	{
		return FlxG.keys.justPressed.K;
	}

	public static function animationFinished(Owner:FlxSprite):Bool
	{
		return Owner.animation.finished;
	}
}
```

##### Sword クラスを作成

最後に Slime.hx の一番下に Sword クラスを作成します。
```ruby:Slime.hx
class Sword extends FlxFSMState<Slime>
{
	override function enter(owner:Slime, fsm:FlxFSM<Slime>):Void
	{
		owner.animation.play("sword");
	}
}
```

Slime.hx を <code>Ctrl + s</code> で上書き保存します。

ターミナルから <code>lime test neko</code> で実行。
```ruby:terminal
lime test neko
```

そしてキーボードの <code>K</code> を押すと、
![FlxFSMソード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957376/6a76ad08-9dc9-5bc6-5365-62617cb6b058.png)
無事にソードのアクションが実行されました。
\
\
HaxeFlixel は情報が少ないので、筆者は公式チュートリアルを行った後はこのように学習しています。
他にも良い方法があれば是非 Qiita の記事などで教えて下さい！！