デジゲー博お疲れさまでした&SleepWalkerデモ版配布
どうも、かせです。
本日、デジゲー博にSleepWalkerのデモ版を出展させていただきました。
会場から閉会まで絶え間なくプレイしていただき、デジゲー博の熱量の高さを思い知りました。
また、夏から開発しはじめ、初めて人前でプレイをしていただけたので、様々なフィードバックを得ることができました。
この場を借りて
デジゲー博準備会様
各出展者様
来場者様
に深く感謝の意を述べさせていただきたく思います。
また、ゲームライターコミュニティ様にて記事を書いていただきました。
【デジゲー博2016】SleepWalker – ゲームライターコミュニティ
ありがとうございました。
SleepWalkerについて
夏から開発をしている「オープンワールド3DアクションRPG」です。
世界の体験をコンセプトとして、開発をしています。
また、プレイ感覚としてリアルな感覚を追求するのではなく
より爽快、かつなめらかなアクションを目指しています。
今回のデモは、アクション部分のコンセプトモデルでした。
このデモ版の配布をさせていただきます。
操作方法
「移動」左スティック
「視点移動」右スティック
「会話」Bボタン
「ジャンプ」Aボタン
「飛行」ジャンプ中にAボタンを再度押す、押しっぱなしで持続
「弱攻撃」地上・空中でXボタン
「強攻撃」地上・空中でYボタン
「打ち上げ」地上でRトリガーをおしながらXボタン
「追撃」地上・空中でRトリガーをおしながらYボタン
「回避」Rトリガーボタン
打ち上げ、追撃はすべての行動をキャンセルすることができます。
かっこいいコンボができると気持ちいいです。
動作環境
そこそこのグラフィックスカードがあれば、ラップトップでも30FPSで動作すると思います。
また、ゲームパッドはXInput対応のもののみのサポートになります。
Xbox360コントローラ、XboxOneコントローラの動作は確認済みです。
ご意見などございましたら、気軽にTwitterの方でお声がけください。
今後について
冬コミに当選しました。
1日目・西"ひ"-13a
でSleepWalkerの
オープンワールドになってる(する)
ボス戦とか実装した(する)
体験版を頒布予定です。
少しでも魅力を感じていただけましたら、ぜひご来場くだされば幸いです。
よろしくお願い致します。
最後に
ゲームを面白くするために努力してまいりますので、ぜひSleepWalkerの完成をお楽しみに!
UniRxを紐解く「Take(1)とFirst()の違い」
UniRxとは
大変便利なReactiveExtensionsのUnity版ライブラリ。
最近、業務でも業務外でもこちらを触ることが多く、色々な地雷を踏み倒してきました。
備忘録の意味も兼ねて今回は
- 「Take(1)とFirst()」の違い
をまとめようと思います。
入門者向きではないです、ご了承ください。
あとかなり長いです。
ソースコードなどはこちらの
を参考にさせていただいています。
TakeとかFirstってなんですか?という方は、こちらをまず読まれると良いと思います。
その他にも様々な分かりやすいサンプルがあり、入門に最適です。
Take(n)
nに指定した分だけ、OnNextを発行するオペレータです。
using UnityEngine; using System.Collections; using UniRx; using UniRx.Triggers; public class TakeSample : Base { // Use this for initialization void Start () { gameObject.transform.position = new Vector2(0, 0.5f); //Takeで最初の100回以外はカット this.UpdateAsObservable() .Take(100) .Subscribe(l => Move(0.01f, 0)); } }
このソースコード上で書かれたObservableを分解すると
- this.UpdateAsObservable()
毎フレーム、次のオペレータ[Take(100)]に対してOnNextを発行する
- .Take(100)
OnNextを100回だけ次のオペレータに発行する
- Subscribe(l => Move(0.01f,0));
OnNextが来たら、Move(0.01f,0)を叩く
という記述がされています。
ここでさらに、記述されていない中身を付け足したソースコードがこちらです
using UnityEngine; using System.Collections; using UniRx; using UniRx.Triggers; public class TakeSample : Base { // Use this for initialization void Start () { gameObject.transform.position = new Vector2(0, 0.5f); //Takeで最初の100回以外はカット this.UpdateAsObservable() .Take(100) .Subscribe(l => Move(0.01f, 0),
() => OnCompleted()); } }
() => OnCompleted()がSubscribeに追加されています。
これは、Subscribeまでのストリームで、OnCompletedが発行された際に実行されます。
そして、今回のObservableでOnCompletedを発行するのは
Take(100)が100回OnNextを通した時です。
つまるところ、100回Move()したら、OnCompletedが呼ばれるということです。
ちなみに、OnCompletedはだいたいどのオペレータでも
- try { observer.OnCompleted() } finally { Dispose(); } ;
という処理になっていますので、OnCompletedを発行してエラーを吐いてもDisposeされるようになっています。
まとめ
Take(n)はnに指定した回数だけOnNextを通して、終了時にOnCompletedを発行する
First(Func),First()
OnNextが発行された最初の一度だけOnNextを発行します
using UnityEngine; using System.Collections; using UniRx; using UniRx.Triggers; public class First : Base { // Use this for initialization void Start() { gameObject.transform.position = new Vector2(0, 1f); //クリックされたら右に1.5動かす(但し1回だけ) this.UpdateAsObservable() .First(l => Input.GetMouseButton(0)) .Subscribe(l => Move(1.5f, 0));
//こっちもやってること同じ
this.UpdateAsObservable()
.Where(_ => Input.GetMouseButton(0))
.First()
.Subscribe(l => Move(1.5f, 0));
} }
このソースコード上で書かれたObservableをまた分解していきます
- this.UpdateAsObservable()
毎フレーム、次のオペレータ[First(Func)]に対してOnNextを発行する
- .First(Func) .First()
OnNextをFuncがtrueの時に、一度発行する
FuncがないFirst()は、OnNextを無条件で発行する
- Subscribe(l => Move(0.01f,0));
OnNextが来たら、Move(0.01f,0)を叩く
という記述がされています。
First()は一度OnNextを発行すると、OnCompletedを発行します
単体では、Take(1)と同じ挙動をします
まとめ
First(),First(Func)は一回OnNextを発行し、その後OnCompletedを発行する
Take(1)とFirst()の違い
ここまで読んで
「Take()は回数指定できる、First()は条件指定できるのね、へ〜」
と思ったことでしょう。
それだけではないです、というかここからが重要です
端的に言うと
OnCompletedをオペレータ内で通す際の挙動に明確な違いがあります
TakeとFirstのOnCompletedメソッドをごらんください
- Take
public class Take : OperatorObserverbase<T,T>{
public override void OnCompleted(){
try {observer.OnCompleted();} finally { Dispose(); }
}
}
- First
public class First : OperatorObserverbase<T,T>{
public override void OnCompleted(){
if(notPublished){
try { observer.OnError(new InvalidOperationException("Sequence is empty"));}
finally { Dispose(); }
}
else{
try {observer.OnCompleted();} finally { Dispose(); }
}
}
}
こうなってます、全然違いますね。
一目見てなんだこれとなるのは、First()の方にあるnotPublishedというboolだと思います。
これはFirst()でOnNextが発行された時にfalseになるbool値です。
OnNextメソッドでもこれを使用していて、notPublishedの状態の時のみOnNextが次のオペレータに発行されるようになっています。
一度だけしか発行しない処理の中身はこうなっていました。
つまり
OnNextが一度も通っていないFirstオペレータはOnCompletedを通しません
こういう明確な差があるわけですね。
例として
public class First : Base { // Use this for initialization void Start() { gameObject.transform.position = new Vector2(0, 1f); //クリックされたら右に1.5動かす(但し1回だけ) this.UpdateAsObservable()
.TakeWhile(_ => isEnabled)
.Where(_ => Input.GetMouseButton(0)) .First() .Subscribe(l => Move(1.5f, 0));
} }
このコードで
一度もGetMouseButton(0)がtrueにならないまま、isEnabledがfalseになり
OnCompletedが発行されると、FirstくんはErrorを吐きます。
まとめ
OnNextが発行されていなくてもOnCompletedを次のオペレータに通知できるのが
Take(1)
OnNextが発行されていないと、OnCompletedを次のオペレータに通知できないのが
First()
です。
もしOnCompletedを発行できるオペレータが複数あるストリームを組むときは
Take(1)を使用することをオヌヌメします。
終わり。
間違いなどがあったら@YutaDevelopまでお願いします。
unirxすげー
C#でpartialを使ってクラスの中身を分割する
こんにちは。
開発が進んでいくと、一つのクラスの中身が膨大な行数になることがあると思います。
その理由は様々あり、解決策もまた様々あると思います。
その中で、今回はpartialを使ってクラスを分割するということを行います。
どのような時にpartialを使うのか
まず、クラスの中身が膨大な行数になっていく場面はいつなのかを考えます。
- クラスの役割を明確に分けられておらず、なんでもできる神クラスになっている
- 役割は明確だが、メソッドなどが抽象化できていないので同じ処理を複数回書いている
- 役割も明確で抽象化もできているが、仕様が多い
1の場合はまずクラスの役割を定めましょう。partialで分けるとさらに可読性が低くなります。
2の場合はまず同じメソッドを呼び出していないか、同じ計算を書いていないかを探して最適化しましょう。DRY原則を守れの一言に尽きます。
3の場合。お待たせしました、partialの出番です。
そもそもpartialってなんぞ
これ(投げやり)
クラスの定義を、複数ファイルにまたいで行うことができます。
例として、ある特定のクラス内で使用するStateの中身をpartialで追加していきます。
gist3c692f67badadfc5e98a8f8abd8480a1
こんな感じです。
これだけだと分かりづらいかもしれませんが、このStateを継承したState1やState2というクラスはこのソースに帰属しているということがわかるので、メンテナンス性や拡張性も向上します。
最後
使用方法を間違えると、スパゲッティになりがちなので要注意です。
適切な場所で使いましょう。
おわり
UnityのStateMachineBehaviourについてのメモ
こっちを読んでください
MonoBehaviourと呼び出される順番
最初の1F
Awake()
Start()
FixedUpdate()
Update()
OnStateEnter()
OnStateMove()
LateUpdate()
それ以降
FixedUpdate()
Update()
OnStateExit()
OnStateUpdate()
OnStateMove()
OnStateIK()
LateUpdate()
各コールバックが呼ばれるタイミング
OnStateEnter()
そのStateに移行した時一番最初に呼ばれる
OnStateUpdate()
OnStateEnter()の次のフレームから最後のExitを除いた毎フレーム呼ばれる
Stateがトランジションしてる時でも呼ばれる
OnStateMove()
Stateが切り替わるまで最初のフレームから最後のフレームまでずっと呼ばれる
Stateがトランジションしてる時でも呼ばれる
OnStateIK()
アニメーションがIKを更新した際だけ呼ばれる
OnStateExit()
Stateの最後の1Fで呼ばれる
UnityのAnimatorでアニメーション遷移するときの自分なりの解
こっちも読んでください
設計の指標なので、なんとなくUnityできる人向けな感じする
AnimatorController
アニメーションアセットを登録してトランジション作ったり、パラメータを色々持てる
Animatorの管理
アニメーションのトランジション制御をパラメータで行うのはトランジション設定を毎回やらないといけないし、矢印が量産されすぎてつらい
矢印量産をめんどくさがって減らすと、一回Exitを経由させてアニメーション遷移させたりしなければいけない
スクリプトでアニメーションの制御を行うと
スクリプト上で保存してるキャラクターの現在のStateと
アニメーションのパラメータがズレる自体が頻出して拡張性が低くなる
スクリプトを使わない(使えない)なら
トランジション制御をぽちぽち頑張って作るしかない
矢印の量産は必要経費として割り切る
スクリプトを使えるなら
AnimatorにStateを作って、State名をScriptableObjectに登録する
(Enumで定義して、Enum名をStateに合わせてもいい)
Animator.CrossFadeInFixedTime(StateName,duration);で制御すると良い
動的にトランジション制御を作成してくれるので、とても楽
ただ、レイヤー内を総当たりで検索してるらしいので、アニメーションの数が膨大になるとパフォーマンス的に厳しくなるのかも
ちなみにCrossFade(StateHash,duration);だとdurationが実時間分の遷移ではないので、意図した動作にならない
CrossfadeInFixedTimeおすすめ
EnumでState名を管理していた場合は
Animator.CrossFadeInFixedTime(Enum.State.ToString(),duration);
で矢印一個分の働きをしてくれる
制御の詰まりポイント
CrossFadeInFixedTimeのdurationが0よりも大きい時(主に3Dで、モーションブレンドさせたい時)
CrossFadeInFixedTimeを呼ぶと、前のStateからCrossFade先のStateに移動するまでにduration分の時間がかかる
CrossFade中は、Animatorから取得できるStateInfoは遷移が完全に終わらないと、遷移先のStateではなく、遷移前のStateのままになる
つまり
if(CurrentStateName == NextStateName) return;
みたいな形で
同じステートの時アニメーションが最初から再生される動作を弾くチェックしようとしても弾けない
他にも、遷移中に同じStateに遷移が行われてしまう要因にもなる
解決方法として、アニメーションの遷移を行った時は、コルーチンなりを使って
yield return new WaitForSeconds(duration);などアニメーション制御を待機させてあげると良いと思う
結果
Animatorぽちぽち地獄から解放されて、設定弄るだけでアニメーション制御の書き換えもできるようになる
今の所問題はないけどあったら追記予定
2016/8/25 追記
こんなものがあった。
併用してアニメーション遷移の汎用コンポーネント作りたい
2017/4月の追記
制御コンポーネントを作成して適用してみた(年明け前くらい)
いい感じだけど、NormalizedTimeが機能しなかったりして自前で実装した
右側のPlayerStateTransitionはStateMachineBehaviour継承したクラスで
・Inputの入力受付時間
・ステートの自動終了時間
・ステートのキャンセル時間
・ステートのキャンセル先と優先度登録
とかできるようになってて、遷移先の切り替えが楽になった
やったね
Unity+VRの開発用DebugConsoleを作った
こんにちは
GearVR向けアプリのビルド後にDebug.Logが確認したかったり、頂点数やFPSを見たかったりしたので作りました
FPSみたいだけならOculusSDKのプラグイン入れた方がいいかも
UnityPackageはここ
使い方
BuildSettingsにDebugシーンを追加
好きなシーンのオブジェクトにAddDebugSystems.csをアタッチ
追記
Jsonをusingでimportしてますが使ってないので記述を消して大丈夫です
見れる機能
ビルドしたUnityのバージョン
OS名
グラフィックス設定
システムメモリサイズ
ビデオメモリサイズ
スクリーンサイズ(width,height)
頂点数(若干不正確な可能性高め)
Console(debug.logとか見れる)
今後追加したいもの
DebugWindowのActive切り替え
ドローコール(できれば)
Menuのアクティブ切り替え
Recenter機能
がべこれ関係(Profilerから取得)
終わり