MagicaVoxel OBJエクスポート時の設定について

OBJエクスポート時の設定について

設定をアレコレいじるには、MagicaVoxelのインストールフォルダにある config/config.txt ファイルを編集します。

最適化をやめる

同じ色毎に面をマージする設定のオン/オフを切り替えます。

最適化オン

最適化オン

最適化オフ

最適化オフ

やりかた

ファイル config/config.txt の file_obj -> optimize を’1’に設定するとオン、’0’にするとオフになります。

1
2
3
4
5
6
7
file_obj
(
(省略)
optimize = '1' // ←ここ
//optimize = '0' // こうするとオフ
)

中心点を決める

objデータの空間上の中心座標を決めます。

接地面を中心に

(0.5, 0.5, 0.0)

モデルの真ん中を中心に

(0.5, 0.5, 0.5)

やりかた

1
2
3
4
5
6
7
8
file_obj
(
(省略)
pivot = '0.5 0.5 0' // ←ここ
(省略)
)

その他

  • 出力時スケール
  • UV座標のオフセット
  • 面方向(頂点指定の周回方向)
  • 座標軸

などを設定することができます。

俺とphina.jsとGithub

本記事はphina.js Advent Calendar 2015の24日目です。
クリスマス当日になってしまいました。遅れて申し訳ないです。

omatoroさん
phiさん

俺とphina.js

思えばphina.js(の前身であるtmlib.js)との付き合いも4年目を迎えようとしています。
ずいぶん長いことJavaScriptブラウザゲーム作りを楽しませて頂きました。
改めてphiさんをはじめとしたJSゲーム界隈の皆様に感謝を捧げさせていただきます。

この記事は…?

さてさて、本記事は去る2015年の5月に行われた「tmlib.jsゆるふわ勉強会」にて私が発表したLTの資料をリライトしたものになります。

スライドはこちら

ゲーム開発を通じてphina.jsに貢献する方法

今回はゲーム開発を通じ、Github上のphina.jsプロジェクトにPullRequest貢献する方法を紹介します。

1. phina.jsを使ったゲームを作ることを決意する

まずは何はなくとも自分のゲームを作り始めます。

どんなゲームを作りたいかを考え、気合を入れて作業に入りましょう。

2. phina.jsをForkする

Forkボタン

phiさんがGithub上に公開されているphina.jsのプロジェクトをForkします。

3. プロジェクトの雛形を作る

開発マシン上に自分のゲームを作る準備をします。

git initでgitリポジトリ化します。

1
$ git init

次にgit submodule addコマンドでForkした自分のphina.jsをサブモジュールとして追加します。

1
$ git submodule add https://github.com/daishihmr/phina.js.git

そしてForkしたサブモジュールphina.js内に、自分のゲーム開発用のブランチを作成します。
以後、このブランチのことをゲームブランチと呼ぶことにします。

1
2
$ cd tmlib.js
$ git checkout -b mygame

ゲームで使うphina.jsはこのブランチでビルドします。

1
2
3
$ npm install
$ gulp
$ cp build/phina.js ../libs/

4. ゲーム開発開始!

いよいよゲーム開発スタートです。
魂の赴くまま、自分が面白いと思うゲームを作りましょう。

そんな中、ふとこういうことを思う時が来るかもしれません。

  • 「……あ、こんな機能欲しいな」
  • 「……あ、phina.jsのここんとこ、バグってるや」

そんな状況に遭ったら次のステップです。

5. 新たにブランチを切ってphina.jsに追加・修正

developブランチから新たにブランチを分岐させます。

1
2
$ git checkout develop
$ git checkout -b feature/physics

機能追加の場合は「feature/○○」、バグ修正の場合は「hotfix/××」というブランチ名にしましょう。

分岐したブランチ内で機能追加・修正が完了したら、ゲームブランチへマージします。

1
2
$ git checkout mygame
$ git merge feature/physics

マージ後もfeatureブランチは消さないでください!
変更履歴は大切な財産であるとともに、作成したブランチはのちのち使うことになります。

マージしたら再びビルドし、自分のゲームに組み込んで引き続き開発しましょう。

1
2
$ gulp
$ cp build/phina.js ../libs/

追加した機能にバグがあったり修正自体が間違っていた場合は、もう一度featureブランチに戻って再度修正→ゲームブランチにマージ→ビルドします。

6. ゲーム完成!

ついにあなたのゲームが完成しました!
公開したり友達に自慢したりストアで販売したりして大いに楽しんでください。

さて、リポジトリをみるとfeatureブランチがたくさん出来ているはずです。
もしその中に「この機能はみんなに使ってもらいたい!」「他にもこの機能を欲しがっている人がいるはず!」と思えるようなfeatureブランチがあったなら、ぜひプルリクエストしましょう!

Github上でfeatureブランチからpull request作成! 追加した機能についてわかりやすくコメントを書こう!

7. まとめ

今回紹介した流れをまとめると以下のようになります。

  1. 自分のゲームのために欲しい機能を作る
  2. ゲーム開発の中で機能をテストし、バグを取る
  3. 完成した段階で機能をphina.js本体にマージしてもらう

この方法の利点は、

  • 確実に需要がある機能が出来る(少なくとも一人は使ってる!
  • 実際に使うことで十分にテストできる

ということだと思います。
単なる机上の空論ではない、実戦で「磨き上げた」コードをプルリクすることができます。

今回はここまで

今回はゲーム開発を通じてphina.jsへ貢献する私なりの方法を紹介しました。
これからphina.jsを使ってゲームを作ってみようという方はぜひ参考にしてください。

みんなで育てようphina.js!!

せっかくだから俺も3Dやってみた

phina.js Advent Calendar 2015の20日目です。

emadurandalさん
minimoさん

3Dのゲームを作るよ!

@emadurandal さんが昨日の記事でご紹介されていたとおりphina.jsにはThreeLayerというものがあり、three.jsと連携して3Dゲームを作ることが出来ます。

というわけでさっそくやってみました。

バトルシップ!

おふね~

私が過去に作った大海戦!ヤマトさんというゲームを3D化したものを開発しています。

まだ作成途中ですが、three.jsのExampleフォルダに入っているWaterShader丸パクリ利用してみました。

また、MagicaVoxelのvoxファイルをjsで使うためのライブラリvox.jsを使い、20分でモデリングした大和型戦艦を登場させています。

今回の記事ではphina.jsとthree.jsを連携する上でいくつか気づいたことをまとめてみます。

phina.asset.AssetManagerでテクスチャをロード

three.jsではテクスチャに画像ファイルを使う際、ImageUtils.loadTexture()メソッドなどを使い画像をロードします。

1
2
3
4
var texture = THREE.ImageUtils.loadTexture( "textures/water.jpg" );
var material = new THREE.MeshPhongMaterial({
map: texture
});

phina.jsにはアセットを一括管理するしくみがありますので、3D用のテクスチャもこちらでロードしたいところです。

そこでこのようにしてみました。

  • ロード時
1
2
3
4
5
6
7
var loadingScene = phina.game.LoadingScene({
assets: {
image: {
"curescarlet": "./assets/curescarlet.png",
}
}
});
  • 利用時
1
2
3
4
var texture = new THREE.Texture(phina.asset.AssetManager.get("image", "curescarlet").domElement);
var material = new THREE.MeshPhongMaterial({
map: texture
});

ロード時は2Dスプライト用のテクスチャとまったく同じです。

利用時は画像アセット(phina.asset.Texture)のdomElementプロパティからimg要素を取得できるので、それをTHREE.Textureのコンストラクタに渡してあげればテクスチャオブジェクトを作ることが出来ます。

Tweenerでアニメーション

phina.accessory.Tweenerを使ったアニメーションは簡単かつ見栄えのする演出方法です。ゲームを作る上ではぜひ利用していきたいしくみですね。

phina.js Advent Calendar 2015でも @simiraaaa さんが記事を書いていらっしゃいます。

Tweenerを使いこなそう!

THREE.Mesh等の3Dオブジェクトでトゥイーンアニメーションを実現するには、phinaのエレメントでラップしてしまうと手っ取り早いです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
phina.define("ThreeElement", {
superClass: "phina.app.Element",
// THREE.Object3Dオブジェクトを受け取る
init: function(threeObject) {
this.superInit();
this.$t = threeObject;
},
// _accessorで座標のgetter/setterを定義する
_accessor: {
x: {
get: function(){ return this.$t.position.x },
set: function(v){ this.$t.position.x = v }
},
y: {
get: function(){ return this.$t.position.y },
set: function(v){ this.$t.position.y = v }
},
z: {
get: function(){ return this.$t.position.z },
set: function(v){ this.$t.position.z = v }
}
}
});
...
// three.jsのメッシュ
var shipThree = new THREE.Mesh(geometory, material);
// phina.jsのエレメントでラップ
var shipPhina = ThreeElement(_ship);
// アニメーション
shipPhina.tweener.to({
x: 1000,
y: 200
}, 3000, "easeOutBack");

カメラなどをスムーズに移動させたい場合に便利ですね。

今回はここまで

というわけで簡単ではありますが、phina.jsとthree.jsを連携する際に覚えておくと便利な使い方でした。

MagicaVoxelで作ったプリキュアをUnityで動かす

つよく! やさしく! うつくしく!
真のゲームクリエイターを目指すおじさんの物語!
夢へ向かって…

当記事はプリキュアAdvent Calendar 2015の13日目です。

前→ プリキュア放送中に今誰が活躍してるかわかるやつ作ろうとした by 100_200さん

次→ rubicureでプリキュアの誕生日を手軽に調べる by sue445さん

お手軽モデルデータ工場としてのMagicaVoxel

個人でゲームを作る場合に強力な味方!

世の中にはMagicaVoxelというボクセルエディタがあって、わりと簡単にプリキュアの3Dモデルデータを作ることが出来ます。

のぞみ&マナ

こいつを使ってUnityゲームの素材を作り、みんなニコニコ自家発電で楽しみましょうというのが本記事の趣旨です。

素材配布

素体をベースにプリキュアをモデリング

上記にリンクしたMagicaVoxel用素体をベースにしてプリキュアを作成していきます。

準備

MagicaVoxelをインストールし、素体をインポートしましょう。

素体

(本当に最低限の)基本操作

あとはパレットから好きな色を取り、思うままボクセルを置いたり色を変えたり消したりしてプリキュアをモデリングしていきます。

画面左上の「Brush」の下、「V」「F」「B」のボタンをのうち「V」をオンにしましょう。

その状態で「Attach」モードにすると、3Dビューのカーソル位置にボクセルを置くことができます。

「Erase」モードにすると、カーソル位置のボクセルを消すことができます。

「Paint」モードではボクセルの色を変えます。

とりあえずそれだけ出来れば、あとはなんとかなるなる!

色にこだわれ!

プリキュアの皆さんは実にカラフルで個性的なデザインをしていらっしゃいます。

ボクセルアートという表現力に乏しい世界であっても、「色」さえ原作に忠実に再現すれば、多少形がイビツでもプリキュアに見えるモデルデータを作ることが出来ます(断言)。

オールスターズ

ちがうパーツをくっつけてはならない

今回は最終的に、Unity上でSkinnedMeshアニメーションをさせることを目標としています。

よって、髪や服とくっつけずにモデリングしないと、腕や脚が自由に動かせないモデルになってしまいます。

この部分の髪と腕がくっついてる!

上図のアンラブリーは髪と腕のボクセルがくっついて(隣接して)ますね。

これをそのままアニメーションさせるとこんな感じになります。

もちーん

腕と髪の頂点が共有されてしまうのでこのようになってしまうわけですね。

Blender上でうまく編集して離れさせることも出来ますが、なかなか面倒です。

面倒な目に遭う前に、気をつけてモデリングしましょう。

修正しました

特に注意が必要なのは、下図のような状態です。

1頂点を共有するボクセル

一見離れているようなのですが、こういう場合も同一頂点なのでうまくいきません。気をつけましょう。

Blenderでプリキュアにボーンを入れる

さてさて、ボクセルプリキュアが完成したら、今度はBlenderにインポートしてボーンを入れていきます。

objで出力

MagicaVoxel右下の「Export」-「obj」をクリックし、obj形式でモデルデータを出力します。

出力先は、UnityプロジェクトのAssetsフォルダ内にするとのちのち楽です。

おぶじぇ

素体用アーマチュアを読み込む

Blenderを起動し、さきほど配布した素体用アーマチュアを開きます。

ぼ~ん

objをインポート

つづいて「File」-「Import」-「Wavefront (.obj)」でobjファイルを読み込みます。

読み込んだー

拡大縮小&移動でモデルをアーマチュアのサイズ・位置に合わせます。

あわせたー

メッシュの編集

メッシュを編集します。

MagicaVoxelはobj出力時に同一頂点の最適化を行いませんので、「Remove Doubles」コマンドで重複頂点を削除します。

また、関節を入れたい位置に頂点を追加するなどしていい感じに編集します。

私の場合は面倒なので、「Subdivide」で適当に頂点を増やしています。

アーマチュアの編集

アーマチュアの各ボーンをいい感じにモデルに合わせて編集します。

素体からプロポーションを大きく変えていなければ、特に編集の必要はないと思います。

親子にする

メッシュ→アーマチュアの順に選択して「Make Parent」-「Armature Deform With Automatic Weights」でメッシュをボーンに関連付けます。

ポーズモードで意図したとおりにボーンが入ったか確認してください。.

かくにーん

FBX形式でエクスポート

「File」-「Export」-「FBX (.fbx)」でエクスポートします。

出力先はUnityプロジェクトのAssetsフォルダ内にしましょう。

UnityにFBXをインポート

Unityを起動し、出力したFBXを選択します。

インスペクタの「Rig」タグ-「Animation Type」を「Humanoid」に設定し、「Apply」ボタンを押します。

ひゅー

「Configure…」ボタンを押し、ボーンが正しく認識されていることを確認します。

「Done」ボタンを押してアセットのメタ情報を確定します。

アニメーションをつける

Asset Storeにある「Unityちゃん」(無料)のモーションなど、配布されているモーションを付けて楽しみましょう。

DAMAGED01をつけてみた

参考リンク

むすび

MagicaVoxelは非常に簡単に可愛らしいキャラクターを作ることが出来ます。

作ったキャラクターを動かすのも、Blenderを使えば非常に簡単です。

さらに、それを使ったゲームもUnityを使えば簡単に作ることが出来ます。

みなさんもぜひオリジナルプリキュアゲームを作って楽しいプリキュアライフを送ってください。

phina.jsでレイヤーと仲良くなろう

phina.js Advent Calendar 2015の10日目です。

グループ管理の基本テクニック by alkn203さん←前 次→physicalクラスを使ってみよう by alkn203さん

レイヤー!

プログラマーたるものたくさんのレイヤーと仲良くしていきたいものです。複数のレイヤーをとっかえひっかえというのも夢のある話です。

シーンは自分用のCanvas要素を持つ

ご存知の通り、phina.jsの前身にあたるライブラリにtmlib.jsというものがあります。

tmlib.js

tmlib.jsと比べてphina.jsでは、SceneクラスがCanvasSceneクラスという名前に変わり、Canvas APIを利用するアプリケーションへ特化した形に再構成されています。

このCanvasSceneは内部にCanvas要素を持っています。

以前(tmlib.js時代)はカレントのシーンがアプリケーション固有のCanvasへ直接描き込んでいたのに対し、phina.jsではシーンが自前のCanvasに描画した後、その結果をアプリケーションのCanvasへ転写します。

  • tmlib.jsの描画方式
tmlib.js
  • phina.jsの描画方式
phina.js

phina.display.ThreeLayer

この「自分固有のCanvas要素を持ち、それへの描画をしたのち、本命のCanvas要素へ転写する」という方式。実はCanvasScene特有のものではなく、どんな要素でも実現することが出来ます。

このしくみをうまく応用しているのがphina.display.ThreeLayerです。

ThreeLayerサンプル

ThreeLayer

ThreeLayerはThree.jsとphina.jsをゆるく連携する機能です。Three.jsを使って固有のCanvasへの描画を行い、その描画結果を親要素のCanvasに転写しています。

  • phina.display.ThreeLayerのソース(抜粋)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
init: function(params) {
...
// Three.jsのレンダラー
this.renderer = new THREE.WebGLRenderer();
...
// 毎フレームでThree.jsの描画処理を行う
this.on('enterframe', function() {
this.renderer.render( this.scene, this.camera );
});
},
draw: function(canvas) {
// Three.jsによって描画された結果をcanvasに転写
var domElement = this.renderer.domElement;
canvas.context.drawImage(domElement, 0, 0, domElement.width, domElement.height);
},

自分でレイヤーを作ってみる

このようなレイヤーを独自に実装することも出来ます。

ポイントは以下の2つ。

phina.display.CanvasRendererクラス

要素ツリーをスキャンし、各要素をCanvasに描く機能を持ったクラスです。

HTMLCanvasElementを内包しています。

phina.display.CanvasSceneクラスやphina.display.Layerクラスはこのクラスのオブジェクトをメンバに持っています。

renderChildBySelfプロパティ

「子孫要素の描画は自身で行う」という宣言です。

trueが設定されている場合、CanvasRendererはその要素の子孫を描画しません。

デフォルトではfalseが設定されています。

描画スキップレイヤー - 描画スキップによる高速化

大量の子孫要素を持つ要素の場合、描画処理を数フレームに1回だけ行うなどしてアプリケーション全体のフレームレートを改善できる場合があります。

自前の非表示Canvasへの描画結果をキャッシュしておき、描画処理を行わないフレームではキャッシュを使用します。

手元の環境では上記「スキップなし」で20FPSほどであるのに対し、「スキップあり」版では30FPSほどに向上させることが出来ました。

もちろん、描画を省略するぶん見た目がカクカクしてしまうわけですが、弾幕系シューティングゲームの背景など特にプレイヤーが注意を払う必要のないものについては検討する価値があるかもしれません。

画像フィルタ処理レイヤー - WebGLを使った画像処理

phina.display.GLFilterLayer

セピアとズームブラー

子孫要素を非表示Canvasに描画した後、WebGLのテクスチャとして使用して画像にフィルタをかけ、その結果をシーンのCanvasに転写する実装です。

まとめ

特殊な描画処理をレイヤーとして切り出すことで、汎用的なエフェクト機能として実装することが出来ます。

MagicaVoxelで背景透過画像を出力する

本記事はMagicaVoxelアドベントカレンダーの7日目の記事です(嘘)。

MagicaVoxelで作ったボクセルモデルをレンダリングし、透明な背景のPNG画像として出力する方法を紹介します。

レンダリングモードに入る

Switch Between Editor / Renderer

Renderボタン(Switch Between Editor / Renderer)を押してRenderモードへ。

Renderモード

画像サイズを設定

上記画像のような状態になる。

まず出力したい画像のサイズを設定する。

「出力画像のサイズ」欄(Image Size [16 - 2048])に「<幅> <高さ>」の形式で数値を入力する。

地面の表示/非表示

「地面の表示/非表示」ボタン(GD : Display Ground [CTRL+R])をオフにして地面を消す。

背景の透過/非透過

「背景の透過/非透過」ボタン(A : Toggle Alpha Channel of Screenshot)をオンにする。

png画像で出力

「png画像で出力」ボタン(Screenshot [6])を押す。「名前をつけて保存」ダイアログが表示されるので、保存先を選択する。

できたー!

できたー!

ManagerSceneでゲームの流れを管理しよう

phina.js Advent Calendar 2015の2日目です。

phiさん 前 ←→ 次 emadurandalさん

シューティングゲーム作るよ!

新進気鋭の国産JavaScriptゲームエンジン「tmlib.js」の後継である「phina.js」がリリースされました

さっそくですが、phina.jsの紹介+サンプル提供を兼ねてシューティングゲームを開発中です。

PhinaShooter

PhinaShooter

まだまだ開発途上ですが、phina.jsの新機能をふんだんに盛り込んでいきたいと考えています。

ManagerSceneを使ってシーン遷移をスッキリ管理

本ゲームはたくさんのシーンを次々に遷移しながら実行されます。

開発にあたる際、たとえばステージ3の道中中盤をデザインしている時に、テストのためにわざわざタイトル画面から実際にプレイするのは大変ですよね。

シーンごとに独立して製作し、あとで組み合わせる方法をとるのがスマートです。

そんな時に役立つのがphina.game.ManagerSceneです。

ManagerSceneの基本的な使い方

シーンAからシーンBへ遷移し、その後再びシーンAに戻ってくるような流れを作りたい場合、以下のようなコードになります。

  • SceneSequence.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// SceneSequenceクラス
phina.define("SceneSequence", {
// phina.game.ManagerSceneを継承します
superClass: "phina.game.ManagerScene",
// 初期化
init: function() {
this.superInit({
scenes: [
// A
{
label: "シーンA", // ラベル。参照用
className: "SceneA", // シーンAのクラス名
},
// B
{
label: "シーンB",
className: "SceneB",
nextLabel: "シーンA" // シーン終了時に次に遷移するシーンのラベル
}
]
});
}
});
  • SceneA.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// シーンクラス
phina.define("SceneA", {
// phina.display.CanvasSceneを継承します
superClass: "phina.display.CanvasScene",
// 初期化
init: function() {
this.superInit();
console.log("これはシーンAです");
},
// 毎フレーム行う処理
update: function(app) {
// クリックされたら
if (app.pointing.getPointingEnd()) {
// exitメソッドでシーンを終了させます
this.exit();
}
}
});

(SceneB.jsは省略)

Sceneクラス内で exit() メソッドを呼び出すことにより、そのシーンを終了させることが出来ます。

終了後は、

  • nextLabelで指定されたシーン

nextLabel指定がなければ

  • ManagerScene内で次に書かれているシーン

に遷移します。

条件分岐

特定の条件を満たす場合のみ遷移先を変えたい時もありますね。

たとえば、ゲーム中に3回ミスをしてしまったら次のステージではなくゲームオーバーシーンに遷移させたい場合などです。

そういった時は以下のように記述します。

  • SettingScene.js
1
2
3
4
5
6
7
8
9
...
scenes: [
...
// ゲームオーバーシーンを追加
{
label: "ゲームオーバー",
className: "GameOverScene"
}
...
  • SceneA.js
1
2
3
4
5
6
7
8
9
10
11
12
...
// ミスをした時の処理
miss: function() {
this.missCount += 1;
if (this.missCount >= 3) {
// ManagerScene側で設定したラベルを指定します
this.exit("ゲームオーバー");
}
}
...

exit() メソッドに引数としてラベル名を渡すことで、ManagerSceneで設定したラベルを指定してジャンプすることが出来ます。

シーンに引数を渡す

ManagerSceneでは次のシーンへの遷移時、シーンクラスをインスタンス化します。

その際にシーンクラスのコンストラクタへ引数を渡すことが出来ます。

  • SceneSequence.js
1
2
3
4
5
6
7
8
9
10
...
{
label: "ゲームオーバー",
className: "GameOverScene",
// GameOverSceneクラスのコンストラクタに渡すパラメータ
arguments: { message: "死んでしまった!" }
}
...
  • GameOverScene.js
1
2
3
4
5
6
7
8
9
10
11
12
13
phina.define("GameOverScene", {
// phina.display.CanvasSceneを継承します
superClass: "phina.display.CanvasScene",
// 初期化
init: function(param) { // 引数を受け取ります
this.superInit();
// 引数内のmessageプロパティを表示します
console.log(param.message);
},
});

次のシーンに値を渡す

遷移前のシーンから次のシーンに情報を渡すことが出来ます。

ゲームシーン中に獲得したスコアをリザルトシーンで表示する時などに使えますね。

  • SceneA.js
1
2
3
4
5
6
7
8
9
10
11
12
...
// ミスをした時の処理
miss: function() {
this.missCount += 1;
if (this.missCount >= 3) {
// exitの第2引数にオブジェクトを渡します
this.exit("ゲームオーバー", { score:this.score });
}
}
...
  • GameOverScene.js
1
2
3
4
...
// 引数内のmessageプロパティとscoreプロパティを表示します
console.log(param.message, param.score);
...

exit()メソッドの第2引数に渡したオブジェクトとManagerSceneで設定したargumentsオブジェクトはマージされます。

入れ子構造

ManagerScene自体もまたSceneのサブクラスですので、ManagerSceneから別のManagerSceneを呼び出すことも可能です。

ステージ1から最後までプレイするアーケードモードと、ステージを選んでプレイする練習モードを実装したい場合などに利用できます。

サンプル

  • ゲーム全体の流れ
PhinaShooter-SceneSequence.svg
  • アーケードモードの流れ
PhinaShooter-SceneSequenceArcade.svg
  • 練習モードの流れ
PhinaShooter-SceneSequencePractice.svg
  • PhinaShooter.js(抜粋)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* メインシーケンス */
phina.define("ps.MainSequence", {
superClass: "phina.game.ManagerScene",
init: function() {
this.superInit({
scenes: [
{
label: "load",
className: "ps.LoadingScene",
arguments: { stageId:0 },
},
{
label: "title",
className: "ps.TitleScene",
},
// アーケードモード
{
label: "arcadeMode",
className: "ps.ArcadeModeSequence",
nextLabel: "title",
},
// 練習モード
{
label: "practiceMode",
className: "ps.PracticeModeSequence",
nextLabel: "title",
},
{
label: "tutorial",
className: "ps.TutorialScene",
nextLabel: "title",
},
{
label: "setting",
className: "ps.SettingScene",
nextLabel: "title",
},
{
label: "ranking",
className: "ps.RankingScene",
nextLabel: "title",
},
],
});
}
});
/* アーケードモード */
phina.define("ps.ArcadeModeSequence", {
superClass: "phina.game.ManagerScene",
init: function() {
this.superInit({
scenes: [
{
label: "stage1preload",
className: "ps.LoadingScene",
arguments: { stageId:1 },
},
{
label: "stage1",
className: "ps.GameScene",
arguments: { stageId:1 },
},
{
label: "stage1result",
className: "ps.ResultScene",
},
{
label: "stage2preload",
className: "ps.LoadingScene",
arguments: { stageId:2 },
},
{
label: "stage2",
className: "ps.GameScene",
arguments: { stageId:2 },
},
{
label: "stage2result",
className: "ps.ResultScene",
},
{
label: "stage3preload",
className: "ps.LoadingScene",
arguments: { stageId:3 },
},
{
label: "stage3",
className: "ps.GameScene",
arguments: { stageId:3 },
},
{
label: "stage3result",
className: "ps.ResultScene",
},
{
label: "ending",
className: "ps.EndingScene",
},
{
label: "gameover",
className: "ps.GameoverScene",
},
{
label: "nameEntry",
className: "ps.NameEntryScene",
},
],
});
},
onfinish: function() {
this.exit();
}
});
/* 練習モード */
phina.define("ps.PracticeModeSequence", {
superClass: "phina.game.ManagerScene",
init: function() {
var sharedData = {};
this.superInit({
scenes: [
{
label: "stageSelect",
className: "ps.StageSelectScene",
arguments: sharedData,
},
{
label: "preload",
className: "ps.LoadingScene",
arguments: sharedData,
},
{
label: "stage",
className: "ps.GameScene",
arguments: sharedData,
},
{
label: "result",
className: "ps.ResultScene",
},
],
});
},
onfinish: function() {
this.exit();
}
});

まとめ

今回紹介したように、ManagerSceneを使ってシーン管理をすることで、アプリケーション全体をシンプルでスマートかつ変更に強い構造にすることが出来ます。

ぜひ使ってみてください。

MagicaVoxelの使い方(4) - シェイプ編

Shapeメニュー

Shapeモードへの切り替え

左上の「Brush」ボタンを押す。再度押すとBrushモードに戻る。

切り替え

シェイプ編集

  • 「+」ボタン…Attach Mode。シェイプを追加する。
  • 「-」ボタン…Erase Mode。シェイプ状にボクセルを削除する。
  • 「>」ボタン…Paint Mode。シェイプ状にボクセルを着色する。

Line

直線を描く。

Line

Cube

立方体を描く。

Cube

Sphere

球体を描く。

Sphere

Circle

円を描く。

Circle

Pattern

保存済みのボクセルモデルを読み込み、編集中のモデルデータに追加する機能。

1.「Pattern」ボタンをONにする。

  1. 左上のタブを「Model」から「Pattern」に切り替える。
  2. 表示したいモデルデータを選択する。

以降は左クリックでカーソル位置に選択したモデルデータを追加できるようになる。

Pattern

Patternモード中はキーボードの「+」と「-」で貼り付けデータの回転が可能。

Pattern

キーボードのカーソルキーで貼り付け位置の修正が可能。

Pattern

MagicaVoxelの使い方(3) - ブラシの基本編2

ブラシパネル(2)

ミラー

ミラー編集

モデルに対する編集が、選択した軸に対して対称に反映されるようになる。


ミラー編集

軸編集

軸編集

モデルに対する編集が、選択した軸上のすべてのボクセルに対して反映されるようになる。


軸編集

Editorのレンダリング設定

編集画面の描画に関する設定。

地面の表示・非表示

GD 地面の表示・非表示

背景の表示・非表示

BG 背景の表示・非表示

グリッドの表示・非表示

GRID グリッドの表示・非表示

フレームの表示・非表示

FRAME フレームの表示・非表示




MagicaVoxelの使い方(2) - ブラシの基本編1

ブラシパネル(1)

ボクセルを置く(Attach)

attach.png

空間にボクセルを置く操作。

ショートカットキーはTが割り当てられている。

エディットモードが「V」の時、カーソルのある位置に1つのボクセルを生成する。

tv.gif

エディットモードが「F」の時、カーソルのある平面全体にボクセルを生成する。

tf.gif

エディットモードが「B」の時、カーソルをドラッグして形成されるボックス内にボクセルを生成する。

tb.gif

ボクセルを消す(Erase)

erase.png

ボクセルを消す操作。

ショートカットキーはR

エディットモードが「V」の時、カーソルのある位置に1つのボクセルを削除する。

rv.gif

エディットモードが「F」の時、カーソルのある平面のボクセルを削除する。

rf.gif

エディットモードが「B」の時、カーソルをドラッグして形成されるボックス内のボクセルを削除する。

rb.gif

ボクセルを塗る(Paint)

paint.png

パレットなどで選択した色でボクセルを塗る操作。

着色はボクセル単位で行われる。ボクセルのある一面だけを塗るといったことは不可能

エディットモードが「V」の時、カーソルが指すボクセルを着色する。

gv.gif

エディットモードが「F」の時、カーソルのある平面のボクセルを着色する。

gf.gif

エディットモードが「B」の時、カーソルをドラッグして形成されるボックス内のボクセルを着色する。

gb.gif

編集中のモデルを動かす

move.png

編集中のモデルをXYZのいずれかの軸に沿って平行移動する。

移動先がフレーム外の場合、逆側から現れる(空間がループしている)。

m.gif

ボクセルから色を選択(スポイト)

color1.png

スポイト機能。

Alt+左クリックでもOK。

spoit.gif

同じ色のボクセルをすべて削除

color2.png

カーソルが指すボクセルと同じ色のボクセルをすべて削除する操作。

deletebycolor.gif

同じ色のボクセルをすべて変更

color3.png

カーソルが指すボクセルと同じ色のボクセルをすべて選択中の色で着色する。

allpaint.gif