例のピンボールゲームで使われてた言語を触ってみた

この記事は、[近畿大学AdventCalendar2019](https://qiita.com/advent-calendar/2019/kindai)の12/06(金)の記事になります。

## (蛇足)
皆さんは、「ぁぃぅぇぉ」といった日本語の小文字を入力する際は、xで入力しますか?
それともlでしょうか?
筆者はxで入力する派です。

ということで今回は「はぇ」こと、Haxeのお話です。

## はじめに
蛇足も程々にして、本記事では
静的型付きの高級言語**Haxe**と、
haxeのフレームワークである**OpenFL**の公式チュートリアルを触ってみた系初心者向け記事です。


## きっかけ
2019年11月27日に、某「空と古戦場の物語」などで有名な会社さんが、新規サービスとしてピンボールを題材にしたゲームを配信、リリースしました。

ゲームの中身のお話は置いておくとして、ふと興味本位で「権利表記」の頁を見てみた際に、このゲームがHaxeおよびOpenFLを中心に作成されていることを知り、ここから、Haxe・OpenFLに触ってみることにしました。


## Haxe って??

>Haxe（ヘックス、発音記号は heks）はオープンソースの高級プログラミング言語、もしくはそのコンパイラである。
>言語としてのHaxeは静的型付きのオブジェクト指向言語であり、構文はActionScript 3および標準化が中止されたECMAScript 4に似ている。Adobe FlashやJava仮想マシンおよび独自のNekoやHashLinkで実行可能なバイトコードにコンパイルされるほか、JavaScript、ActionScript 3、C++、Cppia、C#、Java、PHP 7、Python 3、Luaへのソースコードの変換が可能であるため、主にマルチプラットフォーム開発を目的として使用される。また、FlashからHTML5への移行にも適する。

wikipediaより引用

簡単に言ってしまえば、Haxe言語一つで、JavaScriptやPHP、Pythonといった動的言語や、 Java、C++をとった静的言語への変換が可能なスゴイヤツです。

```
class Main {
  static public function main():Void {
    trace("Hello World");
  }
}
```
基本的な文法はJavaやJavaScriptに近い体系をしているため、学ぶのは比較的簡単だと思われます。


## OpenFL って??

>OpenFL enables creative expression for the desktop, mobile and web. Enterprise applications and best-selling games are made with OpenFL, publishing native, Flash and HTML5 applications using one seamless toolset.

[]()
[公式サイトより](https://www.openfl.org/)
以下Google翻訳さんより

>OpenFLは、デスクトップ、モバイル、Webのクリエイティブな表現を可能にします。 エンタープライズアプリケーションとベストセラーゲームは、1つのシームレスなツールセットを使用して、OpenFL、パブリッシングネイティブ、FlashおよびHTML5アプリケーションで作成されます。

OpenFLでは一つのソースコードで様々な環境での動作が可能なのが魅力の一つです。先程話していた某ピンボールゲームの公式サイトで遊べる体験版も、OpenFLでの機能を用いて遊べるようになってると考えられます。

今回行う公式チュートリアルでも、2種類の環境で動作を確認する機会があります。

## 環境構築
では、公式チュートリアルに従ってあれこれする為の準備をします

### 筆者の開発環境
筆者は下記の環境で実施、動作させています。参考までに。

- macOS Mojave 10.14.6
- Homebrew(2.2.0) : Haxeのインストールで利用
- VisualStudioCode(1.40.2) : ソースコード編集で利用

- **Haxe**(4.0.3) これから導入
- **OpenFL**(8.9.5-LoqcFr) これから導入


HomebrewとVScodeに関しては各自での準備をお願いします。

### Haxeのインストール
今回はHaxeはHomebrewを介してインストールします。
下記のコードを各自のターミナルで実行してさい。

```shell

$ brew install haxe
```
Haxeと一緒にいくつか必要なものも自動でインストールされます。

```shell
$ haxe --version
```
にてhaxeのバージョンが出力されたらインストール完了です。


### OpenFLのインストール

OpenFLの導入にはHaxeのパッケージ管理機能であるhaxelibを利用します。npmやpipの用に多様なパッケージが存在し、[公式サイト](https://lib.haxe.org/)にて確認ができます。

初めてhaxelibを使う際は、初期設定が必要になります。
ターミナルにて

```shell
$ haxelib setup
```
と実行すると

```shell 
Please enter haxelib repository path with write access
Hit enter for default (/usr/local/lib/haxe/lib)
Path :
```
と返ってきます。ここで、ダウンロードするパッケージを保存する場所を聞かれます。デフォルトでは`/usr/local/lib/haxe/lib`となっており、そのままで良い場合は何も入力せずにエンターキーを押します。**このとき、指定するディレクトリは書き込み権限があるところを**指定してください。もしくは、デフォルト設定しているディレクトリに対して`chown`コマンドを利用して権限を追加するといったことをしてください。

続いてopenfl本体をインストールします。
ターミナルで下記を実行してください。

```shell
$ haxelib install openfl
```
必要なファイルがダウンロードされます。
その後、下記を実行することでさらに必要なパッケージを自動でダウンロードしてくれます。

```shell
$ haxelib run openfl setup
```

ダウンロードが完了したら、

```shell
$ openfl
```

と入力して下図の用にな文字がでてきたらインストール完了です。
![スクリーンショット 2019-12-06 22.40.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281151/94fe16f6-83d9-fd30-0789-3709e584f055.png)


**お疲れさまです!準備はできました!!**

## 実際に作ってみる
今回は、公式チュートリアルの[Adding Animation](https://www.openfl.org/learn/haxelib/tutorials/adding-animation/)を実施します。内容としては、指定した画像に動きをもたせる(フェードインや拡大縮小などの)操作をします。
公式の方では、先に[Displaying a Bitmap](https://www.openfl.org/learn/haxelib/tutorials/displaying-a-bitmap/)を実施しますが、今回は簡単に動くものをつくれるこちらを実施します。

### 0. プロジェクトの作成

下記のコマンドを入力することで、プロジェクトの雛形を生成してくれます。今回はプロジェクト名をAddingAnimationとしましたが、好きな名前に変えても大丈夫です。

```shell
$ openfl create project AddingAnimation
```

作られる雛形は、下図のようなディレクトリ構造をしています。
![スクリーンショット 2019-12-06 22.51.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281151/a40b1ab5-1ac5-626c-2b14-3462bacde0f5.png)

動作をつけたりする際は、基本的にSourceディレクトリ下のMain.hxを書き換えていきます。生まれたてのMain.hxは下記の様になってると思います。

```haxe:Main.hx
package;

import openfl.display.Sprite;

class Main extends Sprite
{
	public function new()
	{
		super();
	}
}
```


### 1. 動かす画像の用意

[こちら](https://raw.githubusercontent.com/openfl/openfl-samples/master/features/display/DisplayingABitmap/Assets/openfl.png)にて今回動かす画像を保存します。画像のファイル名はopenfl.pngとして、プロジェクトの中のAssetsディレクトリ下に保存します。


その後、Main.hxに、画像を読み込む機能を追加します。

```haxe:Main.hx
package;

import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.Assets;

class Main extends Sprite {
    
    public function new () {
        
        super ();
        
        var bitmap = new Bitmap (Assets.getBitmapData ("assets/openfl.png"));
        addChild (bitmap);
        
    }
    
}
```

画像データを読み込んで表示させるために、Bitmap型のインスタンスを利用します。そのためのimport文`import openfl.display.Bitmap;`を追加しています。また、読み込みたい画像データのあるAssetsディレクトリを`import openfl.Assets;`にて見れるようにしています。
new()関数内では、順番に、「openfl.pngファイルをビットマップ(点と色のデータの集まり)として読み込む」　「読み込んだビットマップデータをもとにBitmap型のインスタンスを生成」　「生成したビットマップを可視化する」という動作を追加しました。

### 2. 動かす為のパッケージ準備
OpenFL内で、オブジェクトの動きをつける際には、Actuateというパッケージを利用します。今回は環境構築の段階で、自動でhaxelib経由でダウンロードされています。そのActuateの機能を利用できるようにするためには、project.xmlにて、Actuateを利用するという情報を追記する必要があります。

```xml:project.xml
<?xml version="1.0" encoding="utf-8"?>
<project>
	
	<meta title="Simple SWF Layout" package="org.openfl.samples.simpleswflayout" version="1.0.0" company="OpenFL" />
	<app main="Main" path="Export" file="SimpleSWFLayout" />
	
	<source path="Source" />
	
	<haxelib name="openfl" />
	<haxelib name="layout" />
	
	<haxelib name="actuate" />
	
	<library path="Assets/layout.swf" preload="true" />
	
</project>
```

`<haxelib name="actuate" />`というのが今回追記したものになります。同様に、haxelib経由で入手したパッケージを使うはproject.xml内での宣言が必要となります。

Main.hxにも同様にimport文を追記します。

```haxe:Main.hx
package;

import motion.Actuate;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.Assets;

class Main extends Sprite {
    
    public function new () {
        
        super ();
        
        var bitmap = new Bitmap (Assets.getBitmapData ("assets/openfl.png"));
        addChild (bitmap);
        
    }
    
}
```

### 3. 動作を記述する(平行移動させる)
先の節でActuateを使う準備はできたので、実装します。Main.hxを下記のように実装してください(順番に進めているなら1行追加するだけ)

```haxe:Main.hx
package;

import motion.Actuate;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.Assets;

class Main extends Sprite {
    
    public function new () {
        
        super ();
        
        var bitmap = new Bitmap (Assets.getBitmapData ("assets/openfl.png"));
        addChild (bitmap);
        
        Actuate.tween (bitmap, 3, { x: 200 });
        
    }
    
}
```

` Actuate.tween (bitmap, 3, { x: 200 });`という文にて、tweenという関数によって平行移動する動きを追加しています。tweenとはbetweenから派生した単語で、2つの間のアニメーションを作るという意味になります。~~英字辞書の10代前半という意味ではありません~~
引数にて**bitmap**インスタンスを、4(**3**+1)秒で、bitmapの**x**座標を**200**へ動かす。という動作になっています。bitmapインスタンスは初期値で座標が(0,0)なので、**4秒で(0,0)から(200,0)へ移動する**という感じになります。

### 4.動作を追加する(だんだん見えるようにする)
bitmapインスタンスにある`alpha`というパラメータを0から1の間で調節することで、透過度を設定できます。今回は初期値を0として時間経過で1になる動作を追加します。

```haxe:Main.hx
package;

import motion.Actuate;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.Assets;

class Main extends Sprite {
    
    public function new () {
        
        super ();
        
        var bitmap = new Bitmap (Assets.getBitmapData ("assets/openfl.png"));
        addChild (bitmap);
        bitmap.alpha = 0;
        
        Actuate.tween (bitmap, 3, { alpha: 1, x: 200 });
        
    }
    
}
```

tweenを実行する前に、bitmapのalpha値を0にしておきます。
そして、tweenの引数で4秒後にalpha値が1になるようにすることで、4秒かけて**だんだんみえるようになる**動作が追加できました。

### 5. 動作を追加する(拡大)
Bitmapには`smoothing`というパラメータがあり、デフォルトではfalseとなっています。この場合、拡大縮小や回転の施されていない画像が綺麗に表示されますが、逆に拡大縮小を行う際は、`smoothing`をtrueに設定することで画像が綺麗に描画されます。

```haxe:Main.hx
package;

import motion.easing.Elastic;
import motion.Actuate;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.Assets;

class Main extends Sprite {
    
    public function new () {
        
        super ();
        
        var bitmap = new Bitmap (Assets.getBitmapData ("assets/openfl.png"));
        addChild (bitmap);
        bitmap.alpha = 0;
        bitmap.scaleX = 0;
        bitmap.scaleY = 0;
        bitmap.smoothing = true;
        
        Actuate.tween (bitmap, 3, { alpha: 1 });
        Actuate.tween (bitmap, 6, { scaleX: 1, scaleY: 1 }).ease (Elastic.easeOut);
        
    }
    
}
```

このソースコードでは、alpha値による透過度の変化に加えて、`scaleX``scaleY`パラメータを利用しての時間経過での拡大を表現しています。


## 動かす

実際に作成したソースコードを動作させるには
- **neko**と呼ばれる実行可能なバイトコード変換を用いた実行
- html5に変換しての実行
- Flash SWFでの実行

といった選択肢があり、プロジェクトのディレクトリ直下にてそれぞれ

```shell
$ openfl test neko
```

```shell
$ openfl test html5
```

```shell
$ openfl test flash
```
と実行すれば対応した環境での動作をしてくれます。

## おわりに

今回はOpenFLのチュートリアルをやってみた記事でした。
実際に触ってみて、自分の書いたものが複数の環境で動くことに少し感動を覚えました。言語自体もhaxeがjavascriptに近い形をしていて関わりやすい言語なので、もっと触れてみて、色々作ってみたい所存です。

---

## 参考

- [Haxe](https://haxe.org/)
- [OpenFL](https://www.openfl.org/)