MacでAltseedのプロジェクトを用意する

Visual Studio for Mac を使います。


プロジェクトの作成

新しいプロジェクト -> その他 -> .NET -> コンソールプロジェクト(好きな言語を選択)
を選びます。

f:id:wraikny:20180601000002p:plain

プロジェクト名を入力。
gitを使う場合は、ここで.gitignoreを生成して置くと楽。

Altseedの追加

1. nuget経由でインストールする

楽に入れることができます。
ただし、最新版を使うには後述の手動で追加することが必要です。
2018/6/1現在では、nugetから最新版をインストールできます。

ソリューションエクスプローラからパッケージを右クリック -> パッケージの追加
f:id:wraikny:20180601000355p:plain

AltseedDotNetを検索して、チェックを入れて追加
f:id:wraikny:20180601000504p:plain

これで完了です。


2.手動で参照の追加

ダウンロードまたはコンパイルしたAltseedを手動で追加します。
ソリューションのディレクトリにAltseed.xml, Altseed.dll, libAltseed_core.dylibを置きます。
f:id:wraikny:20180601000925p:plain

Visual Studio上から
ソリューション -> 追加 -> ファイルの追加
を選択します。
f:id:wraikny:20180601001010p:plain

Altseed.dll, libAltseed_core.dylibを選択すると、ソリューションエクスプローラにファイルが表示されます。
f:id:wraikny:20180601001144p:plain

ソリューションエクスプローラ
参照 -> 参照の編集を選択し、
f:id:wraikny:20180601001241p:plain

.NET アセンブリの右下の参照を選択。
f:id:wraikny:20180601001241p:plain

Altseed.dllを選択すると、このように追加されます。
f:id:wraikny:20180601001430p:plain

ソリューションエクスプローラのAltseed.dllを右クリック -> プロパティ
f:id:wraikny:20180601001610p:plain

出力ディレクトリにコピー -> 新しい場合はコピーする
f:id:wraikny:20180601001616p:plain

出力ディレクトリにコピーの選択を、libAltseed_core.dylibに対しても同様に行います。

これで完了です。

.NET(Mono)上のexeをMac向けにする備忘録

実行時のMonoのインストールを不要にする



この記事

qiita.com

を教えてもらったので,やってみました.
実行したシェルコマンドは以下です.

export PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig
export AS="as -arch i386"
export CC="clang -arch i386 -mmacosx-version-min=10.6"

mkbundle -o Bar Foo.exe --deps --sdk /Library/Frameworks/Mono.framework/Versions/Current

otool -L Bar

元のFoo.exeという実行ファイルを,Mono無しに実行できるBarというファイルに変換できました.
パスに関するエラーが出たので,Mono Frameworkの場所を指定する--sdk以下を加えたらうまくいきました.
元のQiitaの記事ではotoolのエラーに関する記述がありましたが,そこは特に何事もなく通りました.
また,bundle化することで,*.dllが統合されるため、これらは不要になります。

僕の場合の実際のファイル構成です.

Cannon/
├── Cannon
├── Cannon.command
├── README.txt
├── Resources.pack
└── libAltseed_core.dylib

Cannonが,mkbundleによって作られたMac向けの実行ファイルです.
以下のようなシェルスクリプトに*.commandという名前で実行権限を与えれば,ダブルクリックで実行できます.

Cannon.command

#!/bin/sh
cd `dirname $0`
./Cannon

.app形式にする



しかし上記のように複数のファイルがあると,一見してどのファイルを実行すればいいのかわかりません.
全員がREADMEを読むとは限らないからです.
また,*.commandを実行する形式だと実行時にターミナルが開いてしまって,見た目も悪いです.
そのため,これらのファイルをまとめてapp形式にします..

こちらの記事
MacOSXでシェルスクリプトを.app形式のアプリケーションにするmkapp.app - maruko2 Note.
ほぼそのままです.

以下のようなディレクトリ構造を作成すれば,あとはMacが勝手にappと認識してくれます.

Cannon.app/
├── Contents
│   ├── Info.plist
│   ├── MacOS
│   │   └── script.sh
│   └── Resources
│       ├── Cannon
│       ├── Resources.pack
│       └── libAltseed_core.dylib
└── Icon\r

ライブラリやソースは,Resourcesディレクトリ内に配置しました.

追加したファイルの内容は以下です.
Info.plistは先ほどの記事のそのままです.
script.shは,元のCannon.commandをベースに書き換えました.

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>CFBundleExecutable</key>
    <string>script.sh</string>
  </dict>
</plist>

script.sh

#!/bin/sh
cd `dirname $0`
cd ../Resources
./Cannon

元の記事にもありますが,シェルスクリプトには実行権限を与えてください.

$ chmod +x script.sh

appを作成したら,ダブルクリックで実行できることを確かめてください.

また,appにアイコンを設定する方法は以下の記事
support.apple.com
あるいは,こちらのサイトを使ってください.

*.dmgにしまう



こちらの記事
qiita.com
ほぼそのままなのですが,5.ディスクの作成は不要でした.OSのバージョンの違いでしょうか(2年前の記事なので).
一応,dmgを開いて,appをデスクトップにドラッグ&ドロップした後,ダブルクリックで実行できることを確かめてください.

最後に



今回僕がMac向けに作成したappは以下のページからダウンロードできるので,これを機に遊んでみてください(ダイレクトマーケティング
freegame-mugen.jp

また,ゲームエンジン - Altseed -もよろしくお願いします.

Kotlin on GradleからAltseedを使う

Altseedとは



言わずと知れたゲームエンジン
.Net Framework/JVMで動くすごいやつ.
ゲームエンジン - Altseed -

環境(ざっくりと)



IntelliJ IDEA
Gradle
JDK 1.8.0_162
注意:Macだと,現在のAltseedのJava版が若干古くて,エラーで起動時に終了しました.プロジェクト自体は作れます.

プロジェクトを作る



こちらの記事を読んでください.

biacco42.hatenablog.com

僕の場合はsrc/main/kotlin/wraiknyapp/Main.ktとしました.

AltseedをライブラリとしてIntelliJに追加する



こちらの記事を参考にしました.
qiita.com

Altseedの公式ページから,AltseedのJava版をダウンロードします.
IntelliJ左側のProject欄の一番上,「project_name ~/IdeaProjects/project_name」と表示されている部分,
ここに,Altseed.jar をドラッグ&ドロップしてプロジェクトに追加します.
Altseed.jarをIntelliJ上で右クリックし,Add as Libraryでライブラリに追加します.
build.gradleを開き,dependenciesの中を以下の様にします.

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile files('Altseed.jar')
}

あとは
Main.ktでasdと打つと,コード補完が働いて候補が表示されます.
IntelliJは予測の際に大文字と小文字の区別がデフォルトでされているので,オフにすることをお勧めします.
(Altseedの他言語版とは,先頭の大文字/小文字が異なる場合がある)

この状態で一度,先ほどの
20 分で IntelliJ IDEA と Gradle で Kotlin 開発環境を作って fatJar ビルドしてコマンドラインツールしたり Kotlin Playground したりする話 - たのしい人生
の記事にあるfatJarのタスクを実行することで,build/libs/以下に実行ファイルである.jarが生成されます.
この場所に
Altseed_code.dll (Windows)
libAltseed_code.dylib (Mac)
(自分のOSに合うもの,あるいは両方)をドラッグ&ドロップして追加します.

コード例


ウィンドウを表示する.

Main.kt

package hoge

fun main(args: Array<String>) {
    val isMac = System.getProperty("os.name").toLowerCase().startsWith("mac")
    val isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows")

    val path = System.getProperty("user.dir")

    when {
        isMac -> System.load(path + "/libAltseed_core.dylib")
        isWindows -> System.load(path + "/Altseed_core.dll")
        else -> {
            println("Unexpected OS: " + System.getProperty("os.name"))
            return
        }
    }

    asd.Engine.Initialize("Test", 640, 480, asd.EngineOption())

    while(asd.Engine.DoEvents()) {
        asd.Engine.Update()
    }
    asd.Engine.Terminate()
}

JVM言語では,ダイナミックリンクライブラリの読み込みを明示的に書く必要があるそうです.
以下の記事を参考にしました.
mocha-java.com

四角形を表示する.

Main.kt

package hoge

class Shikaku : asd.GeometryObject2D() {init {
    val size = asd.Vector2DF(100f, 100f)
    val rect = asd.RectangleShape()

    rect.drawingArea = asd.RectF(-size.X/2.0f, -size.Y/2.0f, size.X, size.Y)

    this.shape = rect
    this.position = asd.Vector2DF.DivideByScalar(asd.Engine.getWindowSize().To2DF(), 2.0f)
    this.color = asd.Color(255, 255, 255)
}
}

fun main(args: Array<String>) {
    val isMac = System.getProperty("os.name").toLowerCase().startsWith("mac")
    val isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows")

    val path = System.getProperty("user.dir")

    when {
        isMac -> System.load(path + "/libAltseed_core.dylib")
        isWindows -> System.load(path + "/Altseed_core.dll")
        else -> println("Unexpected OS: " + System.getProperty("os.name"))
    }

    asd.Engine.Initialize("Test", 640, 480, asd.EngineOption())

    val shikaku = Shikaku()
    asd.Engine.AddObject2D(shikaku)

    while(asd.Engine.DoEvents()) {
        asd.Engine.Update()
    }
    asd.Engine.Terminate()
}

Kotlinには演算子オーバーロードがあるのですが,Javaにはありません.
その影響で,演算子オーバーロードは使えません.
不便ですね,拡張できたらしてみようかなとも思います.

また,JavaではプロパティがないのでgetXX(), setXX()形式でメソッドが定義されています.
しかしKotlinにはプロパティがあり,その様な形式に対応していたため,C#と同じ様に書けました.
ただし,asd.Engine.WindowSizeに関しては,getWindowSize() / setWindowSize()の形で書く必要がありました.
内部でSwigがどういった変換を施しているのでしょうね.

まとめ

Kotlinからも簡単にAltseedを扱えたので,この機会に使ってみてはどうでしょうか.
今回のレポジトリは
github.com
に置いてあります.
.gitignoreは参考にでもしてください.

AltseedとF#ゲーム製作入門

AltseedでF#を使う入門をした,という記事です.

初めに



Altseedというゲームエンジンがあります.
複数のプログラミング言語に対応しており,C++や.NET (Mono)やJVMから使うことができます.
詳しくはこちらの公式ページをご覧ください.
ゲームエンジン - Altseed -

F#Microsoftの開発している関数型言語です.C#と同様に.Net Frameworkプログラミング言語です.

この記事は秋津早苗さんのこちらの記事を受けて,もう少し発展した内容を扱います.
akitsu-sanae.hatenablog.com


Altseedは,どの言語でもほとんど同じ記述で書けます.
言語間のオブジェクト指向パラダイムにおける文法の違いがわかれば,簡単に他の言語でもゲームを作ることができます.

開発環境はVisual Studio Community 2017 for Macを使っています.

今回のプロジェクトのソースコードはこちらです.説明が不要な方はどうぞ.
github.com

導入


プロジェクトの作成

開発環境はVisual Studioを使います.

  1. 新しいプロジェクトから,その他→.NETのコンソールプロジェクト F# を選んでください.
  2. プロジェクト名(以下Solution)を入力して作成を押すと,新しいプロジェクトが作成されます.
  3. ソリューションエクスプローラーからパッケージを右クリック.
  4. パッケージの追加を選び,Altseedを検索して,AltseedDotNetを追加します.

注:Windows Form Applicationへの変更

Mac
  1. 適当なエディタでVisualStudioProjects/Solution/Solution/Solution.fsprojを開きます.
  2. 7行目あたりにあるOutputTypeのExeをWinExeに変更します.(Windowアプリケーションへの変更
Windows

上述の方法でもできますが、Visual StudioからGUIで変更できるはずです。

コード


ウィンドウを表示する.

Program.fs

namespace test

module Program = 
    [<EntryPoint>]
    let main argv = 
        asd.Engine.Initialize ("test", 640, 480, new asd.EngineOption ())
            |> ignore

        let rec loop () =
            if asd.Engine.Keyboard.GetKeyState asd.Keys.Escape = asd.KeyState.Push then ()
            elif asd.Engine.DoEvents () then
                asd.Engine.Update ()
                loop ()
        loop ()

        asd.Engine.Terminate ()
        0

上述の秋津さんの記事を参考にしました.実行するとウィンドウを表示するコードです.
ESCキーを押したら終了します.
F#ではbreak文がありません.途中でループを抜けるためには,while文ではなく再帰関数(rec)を用いる必要があります.

qiita.com

シーンを作る.

Game.fs

namespace test

type Game() =
    inherit asd.Scene()

    let layer = new asd.Layer2D()

    override this.OnRegistered () =
        base.OnRegistered ()
        this.AddLayer layer

asd.Sceneクラスを継承したGameクラスです.
inheritで継承,letでフィールドを宣言します.

bleis-tift.hatenablog.com

Program.fsの一部を以下の様に書き換え,Gameシーンに遷移する様にします.
省略されている部分は適宜読み替えてください.

Program.fs

    and.Engine.Initialize ...
        ...

    let scene = new Game ()
    asd.Engine.ChangeScene scene

    let rec loop () =
        ...

F#ではファイルの順序が大切で,先に定義したものしか使えません.

F# プロジェクトでは、ファイルの順序が重要になります。 F# プロジェクトのファイルは、F# コンパイラによって順番に処理されます。 F# コンパイラでは、すべての構成要素が、使用される前に定義されている必要があります。したがって、F# の構成要素の定義が含まれているファイルは、プロジェクトのファイル リストで、その構成要素を使用するファイルより前にある必要があります。
Visual Studio による F# プログラムの作成

そのため,ソリューションエクスプローラーで,Game.fsをProgram.fsの上に持ってきてくださ.

グローバルな関数を用意する.

Altseedのボタン入力はコードが長いので,関数定義をします.
Global.fs

namespace test

module Global =
    let KeyPush key =
        asd.Engine.Keyboard.GetKeyState key = asd.KeyState.Push
    
    let KeyHold key =
        asd.Engine.Keyboard.GetKeyState key = asd.KeyState.Hold
    
    let KeyRelease key =
        asd.Engine.Keyboard.GetKeyState key = asd.KeyState.Release
    
    let KeyFree key =
        asd.Engine.Keyboard.GetKeyState key = asd.KeyState.Free

これをソリューションエクスプローラで*.fsのファイルの先頭に持ってきてください.

プレイヤーを作る.

Player.fs

namespace test

open Global

type Player() as this = 
    inherit asd.GeometryObject2D()

    let speed = 4.0f
    let size = new and.Vector2DF(50.0f, 50.0f)

    do
        this.Shape <- 
            new asd.RectangleShape (DrawingArea=new asd.RectF (-this.size / 2.0f, this.size))
        this.Color <- new asd.Color(255uy, 255uy, 255uy)
        this.Position <- 0.5f * asd.Engine.WindowSize.To2DF ()

    member private this.UpdatePosition dx dy  =
        this.Position <- new asd.Vector2DF (this.Position.X + dx, this.Position.Y + dy)

    member private this.ClampPosition () =
        let pos = this.Position
        let win = asd.Engine.WindowSize.To2DF ()
        let x = asd.MathHelper.Clamp (pos.X, win.X - size.X / 2.0f, size.X / 2.0f)
        let y = asd.MathHelper.Clamp (pos.Y, win.Y - size.Y / 2.0f, size.Y / 2.0f)
        this.Position <- new asd.Vector2DF (x, y)

    member this.Move ()  =
        if KeyHold asd.Keys.Up then
            this.UpdatePosition 0.0f -speed
        
        if KeyHold asd.Keys.Down then
            this.UpdatePosition 0.0f speed
        
        if KeyHold asd.Keys.Right then
            this.UpdatePosition speed 0.0f
        
        if KeyHold asd.Keys.Left then
            this.UpdatePosition -speed 0.0f
        
        this.ClampPosition ()

    override this.OnUpdate () =
        base.OnUpdate ()
        this.Move ()

memberがメンバー関数を示します.
コンストラクタで処理を行うには,doの後につなげます.

F#では,値の代入には<-演算子を用います.
Altseedでは,get_XX, set_XXという形でgetter/setterが用意されています.

また,Geme.fsを以下の様に書き換え,layerにPlayerクラスのインスタンスを追加します.
Game.fs

namespace test

type Game() =
    inherit asd.Scene()

    let layer = new asd.Layer2D()
    let player = new Player()

    override this.OnRegistered () =
        base.OnRegistered ()
        this.AddLayer layer
        layer.AddObject player

実行する.

現在のファイル順序は

  • Global.fs
  • Player.fs
  • Game.fs
  • Program.fs

である必要があります.
この状態で実行すると,十字キーで操作可能な白い矩形が表示されていると思います.

終わりに

F#はインデントを用いるので,コードの見た目がスッキリしています.
F#でゲームを作るための,オブジェクト指向の基本的な部分がわかったので,簡単なゲームを一つ作ってみたいと思います.

(* 2018/04/21追記 *)
作りました。
freegame-mugen.jp


次の新歓に向けて,ドキュメントと初心者講座の整備もできたら嬉しいですね.

Amusement Creatorsの皆さんは是非,この機会にF#でゲームを作ってみてもらいたいと思います.

では,AltseedとF#ゲーム製作入門でした.