Monthly Archives: 9月 2014

[Unity] [C#] クラス定義を複数ソースに分割する

UnityでC#のクラスを定義するとき、通常はひとつのソースファイル内で完結するのが普通でしょう。
しかし、そのクラスの定義が数千行になった場合はソースファイルを編集するのが大変になります。
また、複数人でひとつのクラスを実装するとき、ファイルが同一だと競合を起こしてしまいます。
SVNやGITなどのバージョン管理ツールを用いればマージである程度回避できますが、このマージ機能もあまり信用できるものではありません。

このような場合、ひとつのクラス定義を複数のソースファイルに分割できれば問題を解消できます。

C#で以下のクラスを定義していたとします。

Blinker.cs

Blinker.csにはBlinkerクラスが定義されています。
このクラス内にはメソッドが3つ定義されています。
このクラス定義を分割するにはpartialキーワードをclassの前に付けます。

これで以下のようにソースファイル分割できるようになります。

Blinker.cs

BlinkRoutine.cs

Blink()を別ファイルに分割できました。
別ファイルに定義したフィールドやメソッドは問題なく使えます。

また、上記BlinkクラスはMonoBehaviourを継承していますが、複数ファイルに分割する場合はどれかひとつだけ継承元を書いていればよいです。
したがって、以下のように片方の継承元を省略できます。

Blinker.cs

BlinkRoutine.cs

もちろん、各ファイルで異なったクラスから継承してしまうとコンパイルエラーとなります。

ぜひソース分割の機能を使ってソースファイルの管理を楽にしてみてはいかがでしょうか。

[Departure from the Void] プレイデータ保存機能実装中

ゲームのオープニング動作を実装してから今はゲームデータの保存機能を実装しているところです。

保存するデータには、ハイスコアやプレイ回数、キーコンフィグなどの情報を考えてます。
Webブラウザ上でのプレイとなるため、クッキーとして保存したいと考えてます。
全プレイヤーのハイスコアにも登録できる仕組みにするため、一部をサーバ側に送信する仕組みも考えてますが、実装は当分先になりそうです。

サーバと連携するため、不正に改造したデータを送信できないようにクッキーの暗号化も行わないといけないですね・・・

オンラインで連携するとなると色々と対策が大変になりますが、私自身の勉強も兼ねていずれは実現させたいと思います。

[Unity] 2D図形を指定した色で描画する

2Dゲームの制作などで単色の図形を描画する方法のメモ書きです。
主に塗りつぶし図形を表示させたい場合に使えます。

mesh-col

図形の描画色を変えるには専用のマテリアルを用意し、これにDiffuseシェーダーなどをセットして色を指定することで可能です。
しかし、この方法では異なる色の図形を用意するたびにその数分のマテリアルを用意せねばならず、多数の色のオブジェクトを描画したい場合には多大な労力がかかってしまいます。
また、動的に図形の色を変えるのも難しいです。
さらに、複数のマテリアルを用いるためDrawCallが増加してしまうこともデメリットです。

Unityで描画する図形はメッシュとして管理されています。
メッシュは頂点とそれを結ぶポリゴンによって構成されています。
頂点一つ一つには位置座標やテクスチャのUV座標、頂点色などが含まれます。

この頂点色を変更することで、ひとつのマテリアルだけでさまざまな塗りつぶし色の図形を描画することが可能です。
動的な色変えも可能です。

まず、メッシュ描画用のマテリアルを作成し、シェーダーをGUI/Text Shaderに設定します。

そして、以下の要領でメッシュオブジェクトを作成します。

 1.GameObjectをシーンに作成
 2.MeshFilter、MeshRendererをアタッチ
 3.MeshRendererのMaterialsを開き、Elementに前述のマテリアルを指定
 4.以下スクリプトをアタッチ

 5.SetMeshRendererのColorに指定したいメッシュの色を設定

これで5.のColorに指定した色でメッシュが描画されるようになります。

メッシュの色設定のポイントは以下の部分です。

自身のGameObjectのMeshFilterコンポーネントのcolorsメンバに指定したいメッシュの色を上書きしています。
これにより、メッシュの色が反映されます。
注意点として、colorsメンバの各要素に直接色を指定しても反映されないということです。
なので、mesh.colorsを一時的にコピーし、色をセットした後にmesh.colorsに丸ごと代入しています。

このようなメッシュの色指定を逐次行うと、徐々にメッシュの色を変化させたりできるようになります。

上記スクリプトではUpdate()内で色の指定を随時行っていますが、メッシュの頂点数が多くなるほど処理が劇的に重くなるので、メッシュ色の動的変更をしない限りは以下のようにAwake()内で行うようにすれば良いでしょう。

[Departure from the Void] オープニング完成

今日はゲーム制作の日記です。

最近は風使い(仮)の制作を一旦中断してDeparture from the Voidの制作を進めております。
風使い(仮)は根本的な設計部分から見直しているので、お見せできるものは特に無いです(泣)

ひとまずステージ1のオープニングから自機を操作できるようになるところまで実装しました。

dpv-opening

動作はWindows版のときとほぼ一緒です。

Windows版に無かった機能として、ゲームパッド操作への対応を行いました。
これまではキーボードのみの操作であったため、キーボードによっては同時押しできないなどで操作性に不満が残っている状況でした。

自機の移動はアナログスティックで行うようにして移動速度を微調整できるようにしました。
これにより、操作性は前より格段に良くなったと思います。
キーボード操作にも従来通り対応しています。

動作確認にはMicrosoft XB360 ワイヤレスコントローラーを使用しました。
Unityを使えばゲームパッドの認識も簡単に行えるので非常に便利ですね。

現在はキーアサインが固定なので、キーコンフィグでユーザから自由にアサインを変えられる仕組みも考えています。

[Unity] コンポーネントのNULL参照を防ぐ

以下のようなスクリプトをGameObjectにアタッチしたとします。

上記スクリプトでは同GameObject内のRigidbodyを参照しています。
しかし、RigidbodyがGameObjectにアタッチされていない場合はどうなるでしょうか?

Rigidbodyが無いため以下のような例外が発生してしまいます。

MissingComponentException: There is no ‘Rigidbody’ attached to the “Sphere” game object, but a script is trying to access it.

GetComponent()でコンポーネントを取得した場合はnullが返却されるため、この戻り値からメンバにアクセスしようとするとNullReferenceExceptionが発生します。

上記の問題はいずれも参照しようとしている型のコンポーネントが同GameObjectにアタッチされていれば問題ないですが、付け忘れた場合にはどうしようもありません。
このようなヒューマンエラーには以下の方法で対応できます。

・足りないコンポーネントを一緒に追加する
以下のようにスクリプトのクラス定義の前にRequireComponent属性を追加します。

typeof()の中に必要なコンポーネント型を指定します。
書き方についてはあまり深いことは考えなくても大丈夫でしょう。

これでAirResistanceコンポーネントをインスペクタから追加するときにRigidbodyも一緒に追加してくれます。

require-component

複数の型を指定したい場合は属性指定を以下のように書けばOKです。

必要なコンポーネント型を明示することで、スクリプト利用者にもこのことを知らせられるため何かと便利です。

■参考サイト
RequireComponentによるコンポーネントの追加忘れ防止 – Neareal
[RequireComponent]属性について ゴマちゃんフロンティア

[Unity] 「result == FMOD_OK」が表示されたときは…

Unityの無料版を使っているときに以下のようなエラーメッセージが起動時と終了時に表示されるようになってしまいました。

unity-error

result == FMOD_OK
An invalid object handle was used.

このエラーが表示される原因をネット上で調べてみましたが、有力な情報がありませんでした。

ひとまずUnityとスクリプトエディタを閉じた後にエラーが発生したプロジェクトフォルダ配下のLibraryobjフォルダを削除。

これでエラーは全く起きなくなりました。
もしタイトルのエラーが発生した場合は上記の方法を試してみるとよいかもしれません。

[Departure from the Void] タイトル画面完成

三連休中にDeparture from the VoidのWeb版への移植を進めておりました。

タイトル画面まで実装してやっとゲームの序盤の実装に移ったところです。

移植なので基本的な動作はWindows版と一緒です。
ゲーム中のキャラの動きや配置も基本的に変えないつもりです。

一方、Web版への移植ということで以下の機能追加を考えています。

 ・ハイスコア表示機能
 ・Twitterへのスコア投稿機能

ハイスコア表示機能はプレイヤーの上位スコアを表示するあの画面です。
プレイヤー名とスコア、あとは必要に応じてTwitter等のアカウントへのリンクを表示するようにしたいと考えています。
プレイヤー間での記録共有を狙った機能です。
これらの情報はMySQL等を用いてサーバ上のDBで管理しようと考えています。

Twitterへのスコア投稿機能はゲームを終了した時点のスコアをTwitterに投稿するものです。
別の自作ゲームのBlock Shooterでは既にこの機能を実装しているので、当ゲームもこれを踏襲するつもりです。

連休最後の日に行った作業スケジュールの実績です。

dpv-timeresult

途中で別なことをやりつつの作業でしたが、それでもかなりローペースになってしまいました…
未だにUnityで色々とはまっている部分があるので、まだまだ勉強が必要だと実感しています。
毎日30分だけでも良いので制作をコツコツと進めていこうと思います。

[Unity] オブジェクトを点滅させるスクリプト(コルーチン版)

以前こちら記事でGameObjectを点滅させるスクリプトについて紹介しました。

これはタイマーとUpdateメソッドを用いて点滅制御する方法でしたが、今回はコルーチンを用いた実現方法についてご紹介します。
コルーチンの利用の仕方によってはスクリプトが非常に簡潔になります。

以下、点滅のスクリプトです。

Blinker.cs

スクリプトの量自体は前回の記事と大差ないですが、タイマーの作業用変数とUpdate内での処理が省かれています。
その代わりにBlinkというコルーチンが加わっています。
コルーチンの中では無限ループを回してrendererをトグルさせた後にyield~で一定時間待機させています。
yield return~を記述するとここで一旦関数の処理を終了し、また呼び出すべきタイミングになったときにここから処理が開始されます。
今回の例ではinterval秒経過したら以降の処理を再開します。

コルーチンとWaitForSecondsを組み合わせることでアニメーション等の動作を簡潔に実装できるのでお勧めです。

[WordPress] アップデートで「Briefly unavailable for scheduled maintenance. Check back in a minute.」と出てしまう問題

WordPressで本体のアップグレード後、プラグインをアップグレードしたら以下の表示が出てしまいブログや管理ページにアクセスできなくなってしまいました。

wp-maintenance1

このような場合、ブログディレクトリ配下の「.maintenance」ファイルを削除すれば復活します。

wp-maintenance2

    ↓

wp-maintenance3

説明手順が書かれていないため戸惑うかもしれませんが、やり方は至って単純なので落ち着いて対処すれば問題ありません。

■参考サイト
WordPress › Support » Briefly unavailable for scheduled maintenance. Check back in a minute.
WordPressのアップグレード時に「Briefly unavailable for scheduled maintenance. Check back in a minute.」と出ても慌てない | WordPressで企業ウェブサイト作成・商用ホームページ制作 WordPress Go Go

[Unity] シーン切り替え時間を測定してみる

Unityでのシーン切り替えは重いという言葉をよく耳にします。
しかし、どこまで重いのかについては根拠となる情報が存在せず・・・

今回はひとつのGameObjectのみが存在したシーンを再読み込みすることで切り替えにかかる時間を計測してみました。

以下計測用スクリプトです。

シーンには以下のようにひとつのMainCameraオブジェクトだけが存在している状態です。

scene-time1

以下実行結果です。

・QualityをGoodにした場合
scene-time2

・QualityをFastestにした場合
scene-time3

このことから、シーン切り替えにかかる時間はTime.deltaTimeすなわちフレーム間の時間にほぼ等しいことがわかります。
今回はUpdateとAwakeメソッドの中で開始・終了を計測しているために1フレーム分の時間がかかっていると思われます。(あくまで推測です)
しかし、どのみち次にレンダリングされるタイミングは次回のUpdateが呼び出されるタイミングであることを考えると、1フレーム分という時間は許容範囲のように思えます。

フレーム間隔を除いたシーン切り替え時間は0.001msにも達していない結果となりました。

大量のGameObjectが存在している場合はもっと時間がかかるかもしれませんが、シーン切り替えとは別物と考えられるでしょう。
果たしてシーン切り替えとプレハブによる切り替えのどちらが速いのか・・・
これについてはまた後日比較検証を行いたいと思います。