40
by MAX NEET GAME

FarmFury! 技術資料

Embed Size (px)

DESCRIPTION

XBLIGとPSMで配信中の「FarmFury!」の簡単な技術資料です。

Citation preview

Page 1: FarmFury! 技術資料

by MAX NEET GAME

Page 2: FarmFury! 技術資料

サークルについて

ゲーム紹介

開発環境

技術解説

Page 3: FarmFury! 技術資料

活動概要 ゲーム作ってます

作ったゲームの資料も公開していく予定

ホームページ http://maxneet.web.fc2.com/

メンバー 大熊猫 : プログラム、惰眠担当

まる : アート、雑用担当

Page 4: FarmFury! 技術資料

プラットフォーム XBOX 360 : 100円で配信中 PlayStation Mobile (PSM) : 100円で配信中

プレイ人数 : 1~2人 (PSM版は1人限定)

ジャンル: 簡易RTS 対戦型タワーディフェンスっぽいらしいです

動画 http://youtu.be/hqBQ9WucfF8

配信先URL: http://marketplace.xbox.com/ja-JP/Product/FarmFury/66acd000-77fe-

1000-9115-d80258550deb

Page 5: FarmFury! 技術資料
Page 6: FarmFury! 技術資料

XBOX 360 XNA 4

PlayStation Mobile

PsmStudio MonoGame

全体

Tortoise svn, Audacity, Paint.Net, etc

ファイル管理 Dropbox上にsvnのリポジトリ作成し、Dropboxのフォルダを共有

まずはXNAでPC用に作り、そこからXBOX対応。その後に

PSM対応しました。

Page 7: FarmFury! 技術資料

ホームページ - http://monogame.net/

XNAのコードを様々なプラットフォームで動かせるライブラリ Windows, XBOX, WP8, ios, OSX, Android, Ouya, PSM

比較的簡単に移植出来る 数十分~1日ぐらい

でも特有の問題も色々ある

Page 8: FarmFury! 技術資料

導入方法 http://ookumaneko.wordpress.com/2013/10/15/psmメモ-monogamesの導入方法/

コンテンツ(画像、フォント、等)

“Content”というフォルダを作成し、その中にコンテントファイルを入れる 先に.xnbファイルに変換してから使用する必要がある FarmFury!ではコンバーターソフトを作った(ContentCompiler)

XML読み込みにIntermidiateSerializerを使っている場合、そのまま

Content.Load<classType>で読み込みが出来る

Effectクラスでpsmのシェーダーを扱えるかを試してみた所、一部の型が実装されていないらしい ちゃんと出来た方は教えてください m_ _m

そのままビルドして使用すると、MetaData内のTouch設定がtrueじゃないと落ちる。なので、タッチをオフにしたい場合は、MonoGame側でPsmのTouch APIを切る必要があります。

Page 9: FarmFury! 技術資料

.xnbファイルに変換したいファイルを追加して、吐き出す

現状はフォルダ単位での読み込みに対応していないので、未だ開発中(気が向いた時のみ)

dllが必要 Microsoft.Build.dll

Microsoft.Build.Framework.dll

XNA系

Page 10: FarmFury! 技術資料

ビルド用クラス生成時の処理 一時ファイルディレクトリを作る プロジェクトを作る プロジェクトにXNAのコンテンツファイルを作る方法記されているファイルを読み込む

開始ボタンが押された時、ビルドする用のファイルを追加してからビルド処理を行う

ビルド時の処理 BuildManagerとBuildSubmissionを使用してビルドする

Page 11: FarmFury! 技術資料

using Microsoft.Build.Construction; using Microsoft.Build.Evaluation; using Microsoft.Build.Execution; using Microsoft.Build.Framework; … Project m_buildProject; ProjectRootElement m_projectRootElement; BuildParameters m_buildParameters; List<ProjectItem> m_projectItems = new List<ProjectItem>(); string m_buildDirectory; … // パス設定 string projectPath = Path.Combine(m_buildDirectory, "content.contentproj"); string outputPath = Path.Combine(m_buildDirectory, "bin"); // ビルドプロジェクトを作成 m_projectRootElement = ProjectRootElement.Create(projectPath); //プロジェクトにXNAのコンテンツファイルを作る方法記されているファイルを読み込む、設定 m_projectRootElement.AddImport("$(MSBuildExtensionsPath)¥¥Microsoft¥¥XNA Game Studio¥¥" +

"v4.0¥¥Microsoft.Xna.GameStudio.ContentPipeline.targets"); m_buildProject = new Project(m_projectRootElement); m_buildProject.SetProperty("XnaPlatform", "Windows"); m_buildProject.SetProperty("XnaProfile", "Reach"); m_buildProject.SetProperty("XnaFrameworkVersion", "v4.0"); m_buildProject.SetProperty("Configuration", "Release"); m_buildProject.SetProperty("OutputPath", outputPath); m_buildParameters = new BuildParameters(ProjectCollection.GlobalProjectCollection);

Page 12: FarmFury! 技術資料

// 非同期のビルドリクエストを作る BuildManager.DefaultBuildManager.BeginBuild(m_buildParameters);

BuildRequestData request = new

BuildRequestData(m_buildProject.CreateProjectInstance(), new string[0]); BuildSubmission submission =

BuildManager.DefaultBuildManager.PendBuildRequest(request); // ビルド開始 submission.ExecuteAsync(null, null);

// ビルドが終わるまで待つ submission.WaitHandle.WaitOne();

// ビルド終了 BuildManager.DefaultBuildManager.EndBuild(); if (submission.BuildResult.OverallResult == BuildResultCode.Failure) { // ...エラー処理 }

Page 13: FarmFury! 技術資料
Page 14: FarmFury! 技術資料

このゲームはプログラムを始めてからあまりたっていない頃に作った物をそのまま使っている箇所が多いので、基本的に難しい事、新しい事、面白い事は特にありません。

ゲーム作り始めの方なら何か役に立つかもしれないです。

Page 15: FarmFury! 技術資料
Page 16: FarmFury! 技術資料

解像度 1280 x 720 or 1920 x 1080 (HD)

コントローラーが抜けたらゲームをポーズする必要がある

コントローラーが抜けた事を判定する方法

どのコントローラーからでもゲームを開始出来る必要がある タイトル画面と、対戦時の2P開始に「Press Start」表記をし、Startボタンを押したコ

ントローラーを記録している

XBOXメニュー画面でもポーズする必要がある

ゲームUIや操作キャラはセーフエリア(テレビサイズ関係無く表示される領域)に出す必要がある ゲーム内の外枠はその為にあります 今回は [1280 x 720]の85%をセーフエリア扱いして開発しました。

.Net 2 Compact Framework しか使えない

C#のバージョンが古い為(C# 2)、使用出来ない機能が沢山ある

Page 17: FarmFury! 技術資料

解像度 960 x544 (Vita), 800 x 480, 1280 x 800 エミュレーターで上記の設定をテスト出来る。 ちゃんと全ての機種の解像度に対応出来ないとリジェクトされます orz

Vita, SONY認定デバイスの両方で同じバイナリを使う

そのせいか、Vitaの背面タッチやアドホックが使えない・・・

コンテントをメインスレッド以外で読み込めない XBOXでは全て別スレッドで読み込んでいたが、PSMではリストを作り一つずつ読み込み、一つ終わる度に描画更新した。

サンプルではバイトデータに変換して別スレッドで読み込み、再度元に戻しているらしい

エラーメッセージが解り難い時がある

SDKのバージョンが古い時に出るメッセージが「ライセンスが切れました」

Page 18: FarmFury! 技術資料

解像度を考慮しないアホ過ぎる作りをした為、表示がかなり崩れ、作業量がかなり多くなりそう・・・

なので、手抜き実装として画面を解像度に合わせて引き伸ばしたり、縮めたりして表示しました。

とった実装手段はレンダーターゲットに画面を描画し、その画像を画面サイズに合わせて描画する。

この手法の問題はメモリを食うのと、処理が重い事です。PSMではどれぐらいか解りませんが、Gravity Dazeの人達もRenderTargetの切り替えが遅いから工夫したとCEDECで言っていた気がする。

Psm SDKに何時の間にか自動で黒枠を追加する機能があるらしいのを最近知りました・・・orz

Page 19: FarmFury! 技術資料

デバイスの解像度獲得 width = Sce.PlayStation.Core.Graphics.GraphicsContext.ScreenSizes[0].Width; height = Sce.PlayStation.Core.Graphics.GraphicsContext.ScreenSizes[0].Height;

行う処理の順番は: 描画先にレンダーターゲットを指定 ゲーム画面を描画 描画先を元に戻す レンダーターゲットの内容を描画。サイズ指定は上記で獲得した解像度

PSM版MonoGameでのRenderTarget2Dの問題 上記を試してみた所、180度回転した上に左右引っくり返って表示されました なので、SpriteBatch.Draw()のrotationに180度の指定と、SpriteEffectに

SpriteEffects.FlipHorizontallyを設定 ついでに原点(origin)には解像度の半分の大きさを指定しました

Page 20: FarmFury! 技術資料

基本的な円と円を使った判定を使用 public bool CollisionCheck(Circle obj1, Circle obj2) { float distance = Vector2.DistanceSquared(obj1.Position,

obj2.Position); float radius = (obj1.Radius * obj1.Radius) + (obj2.Radius *

obj2.Radius); return (distance <= radius); } DistanceSquaredを使用しているのはsqrt()が結構負荷が高い計算の為です。実際に処理速度の違いは微々たる物ですが、計算回数が多いゲームの為、取り合えず削れる所で削っています。

Page 21: FarmFury! 技術資料

最初はfor文を使ったブルートフォース的なチェックを行っていた

ただ、負荷が高過ぎた為、簡単な空間分割を使う事にした(Uniform Grid)

当たり判定の管理に含まれるのは動物、牧場、肉、忍者、手裏剣、火柱

Page 22: FarmFury! 技術資料
Page 23: FarmFury! 技術資料

ゲーム画面を一定の大きさのマス目に分裂する。

各オブジェクトはどれかのマスに配置され、移動した際には別のマスに配置を移す。

各移動系オブジェクトは、自分のマスとその周りのマスに配置されているオブジェクトだけ当たり判定の確認を行う。

オブジェクトのサイズによっては確認するマスの範囲は変わる。

Page 24: FarmFury! 技術資料

目標は一定範囲内に居る一番近い敵 居ない時は直進

これの距離計算にもVector2.DistanceSquared()を使用

最初は検索に敵全てを見ていたが重すぎるので変更。

当たり判定で使用したグリッドを使って同じような方法で距離を測り対象を設定

Page 25: FarmFury! 技術資料
Page 26: FarmFury! 技術資料

当たり判定、移動先検索同様グリッドを使用。

保存するのは死骸のみ

掃除機のAIは一番多いマスに向けて移動する

これの難点はAIの方が人間より集めるのが上手い確立がかなり高い

Page 27: FarmFury! 技術資料

結構適当に作ってますw

基本的な動作は: 次に使いたい物選択 金があれば使用、無ければ必要金額を保存し、金を集める 一定金額が集まれば使おうとしていた物を選択 アイコンを選択後に置ける場所を探す 場所へ移動後、置けなくなっていたら再度場所を探す。置けるまで移動->検索を繰り返す

置いたら最初に戻る

キャラによって選択出来る物が違ったり、比重を置く物が変わります。

Page 28: FarmFury! 技術資料

パーティクル 擬似3D 追尾(Trail) 常時(Persistent)

フェードイン・アウト

フェードアウト・フェードインの作り方

振動 どちらかの事務所が破壊された時のエフェクト

雷っぽいもの

タイトルのメニューで選択中の項目に出ているやつ

Page 29: FarmFury! 技術資料

基本的には小さい画像を沢山飛ばしているだけ

使っているのは右の画像達: これらの色、大きさ、速度、α値、時間、移動方向、数、を操作する事でエフェクトを作っています

擬似3DのエフェクトはZ値によって大きさを変える事でそれっぽくしています。

追尾方エフェクトはオブジェクトの位置を把握し、指定された時間毎にエフェクトを出しています。細かい指定は生成時に行われ、くっ付いている先のオブジェクトが生きている限りは残ります。

Page 30: FarmFury! 技術資料

使用出来る頂点数が少ない為、PC, XBOXと同じ用にやろうとすると、直ぐ落ちる

更に、凄く処理落ちする

解決策は特に思いつかなかったので、単純にVitaに合わせてエフェクトの量やスケールを変える事で調整。

え?あんどろいど?ナンデスカソレ?・・・

Page 31: FarmFury! 技術資料
Page 32: FarmFury! 技術資料

ブログでも紹介しています

振動エフェクトの作り方

ゲーム画面をレンダーターゲットに描画。保存した画像を複数回描画し、描画が増える毎に大きく表示する。

描画回数が多いほど濃いエフェクトになる

エフェクト開始時にエフェクトの濃度設定し、大きさ、α値はこの設定を使って計算。

濃度は毎フレーム減らし、0になればエフェクト終了

設定や計算はそれっぽく見えるように適当にやりましたw

Page 33: FarmFury! 技術資料

半球の画像と線の画像を用意する

開始地点と終了地点を指定し、両方に半球の画像を表示する

開始と終了の間に小刻みに線の画像を描画する

線の画像は前回の線、または開始地点から描画を初め、ランダムな角度と長さで描画される

角度の範囲は開始地点と終了地点の位置から設定する

α値は徐々に下がる

Page 34: FarmFury! 技術資料

オブジェクトプール

処理負荷計測

FPS (Frames per Second) カウンター

プロファイラー

Page 35: FarmFury! 技術資料

オブジェクトプールはオブジェクトを一定数最初に生成し、破棄した時に消さずにプールに戻す事で生成を1回するだけで使いまわす物

動物、牧場、死骸、パーティクル等の生成と破棄が頻繁に行われるオブジェクトで使用

メモリは最大数分取るが、最初に生成し、破棄がない分インスタンスの生成コストや、ガベージコレクタによる処理負荷が発生しにくくなるので、便利。

作り方は、Pool<T>クラスでT型と使用状態の情報を持ったリストを作り、コンストラクタで最大数分T型オブジェクトを生成してリストに追加する。

使用したい時にはリストの中で開いているオブジェクトを引っ張り、戻す時はそのオブジェクトの使用状態をリセットする

Page 36: FarmFury! 技術資料

ブロック内の処理にどれくらい時間が掛かっているかを計る

処理としては計測開始時にStopWatchクラスで計測開始し、終了時に経過時間を獲得する

double m_elapsed; Stopwatch m_stopwatch; public void Start() { m_stopwatch = Stopwatch.StartNew(); }

public void Stop() { m_elapsed += m_stopwatch.Elapsed.TotalSeconds; }

一定時間(1秒等)を計る時はアウトプットする時に経過時間をリセットする

ゲーム起動時全体の場合は、リセットしない

Page 37: FarmFury! 技術資料

計測時間をブロック内に限定する為の構造体を用意し、ブロックの先頭でusingでインスタンスを作り、計測する

public struct ProfileStarter: IDisposable { Profiler m_profiler; public ProfileStarter(Profiler profiler) { m_profiler = profiler; profiler.Start(); }

public void Dispose() { m_profiler.Stop(); } } #if DEBUG Profiler m_profiler; using (new ProfileStarter( m_profiler) ) #endif { // …計測する処理 }

Page 38: FarmFury! 技術資料

実機用にデバッグ表示付きのReleaseビルドを作成 名前は何か適当につけた

ログ表示

単純にList<T>に文字列を保存し、画面に表示。ファイルにも保存

デバッグコマンド 3倍速 (更新に渡す経過時間を3倍にしただけ) 1ボタンで敵即死

AI vs AI モード

エキシビジョンとしても使えた(自分たちで手を動かす必要が無いので) 処理負荷の計測に便利

入力記録

記録をxmlに保存し、それを再生する処理を作りバグを再現出来るようにした ただ、乱数を考慮していなかった為、毎回同じ結果にはならない orz AI は移動や選択する度に入力した体にし、ボタン等を保存 ロケテゲームショウで試合終了時に重かったのはその影響です(言い訳)

Page 39: FarmFury! 技術資料

他の細かい物は一部ブログに乗っています メニューの作り方

メニューの作り方 メニューの作り方3:サイズが変わるメニュー

ゲームステート(シーン遷移)の作り方 ゲームの状態変更の実装方法2 (クラス編) ゲームの状態変更の実装方法3 (クラスの再利用化)

チュートリアルテキスト系 流れるテキストの作り方 自動改行するテキストボックスの作り方

FPSカウンターの作り方 マルチスレッドでコンテントの読み込み xmlの読み込み & 書き込み(xna 4) コントローラーの振動機能に時間設定を付ける方法 HPゲージの実装方法

Page 40: FarmFury! 技術資料

紹介されていない物で知りたい事や、質問、疑問、ツッコミ、等があればご連絡ください

Twitter: @ookumaneko_XD

ブログ: http://ookumaneko.wordpress.com/