読者です 読者をやめる 読者になる 読者になる

デジゲー博お疲れさまでした&SleepWalkerデモ版配布

 

どうも、かせです。

 

本日、デジゲー博にSleepWalkerのデモ版を出展させていただきました。

f:id:yutakaseda3216:20161113205901p:plain

会場から閉会まで絶え間なくプレイしていただき、デジゲー博の熱量の高さを思い知りました。

 

また、夏から開発しはじめ、初めて人前でプレイをしていただけたので、様々なフィードバックを得ることができました。

この場を借りて

デジゲー博準備会様

各出展者様

来場者様

に深く感謝の意を述べさせていただきたく思います。

 

また、ゲームライターコミュニティ様にて記事を書いていただきました。

【デジゲー博2016】SleepWalker – ゲームライターコミュニティ

ありがとうございました。

 

SleepWalkerについて

夏から開発をしている「オープンワールド3DアクションRPG」です。

世界の体験をコンセプトとして、開発をしています。

また、プレイ感覚としてリアルな感覚を追求するのではなく

より爽快、かつなめらかなアクションを目指しています。

 

今回のデモは、アクション部分のコンセプトモデルでした。

 

f:id:yutakaseda3216:20161113210515p:plain

 

f:id:yutakaseda3216:20161113210625p:plain

 

このデモ版の配布をさせていただきます。

 

Dropbox - sleepwalker.zip

 

操作方法

 

「移動」左スティック

「視点移動」右スティック

「会話」Bボタン

「ジャンプ」Aボタン

「飛行」ジャンプ中にAボタンを再度押す、押しっぱなしで持続

「弱攻撃」地上・空中でXボタン

「強攻撃」地上・空中でYボタン

「打ち上げ」地上でRトリガーをおしながらXボタン

「追撃」地上・空中でRトリガーをおしながらYボタン

「回避」Rトリガーボタン

 

打ち上げ、追撃はすべての行動をキャンセルすることができます。

かっこいいコンボができると気持ちいいです。

 

動作環境

 

そこそこのグラフィックスカードがあれば、ラップトップでも30FPSで動作すると思います。

また、ゲームパッドはXInput対応のもののみのサポートになります。

Xbox360コントローラ、XboxOneコントローラの動作は確認済みです。

ご意見などございましたら、気軽にTwitterの方でお声がけください。

twitter.com

 

今後について

冬コミに当選しました。

1日目・西"ひ"-13a

でSleepWalkerの

オープンワールドになってる(する)

ボス戦とか実装した(する)

体験版を頒布予定です。

 

少しでも魅力を感じていただけましたら、ぜひご来場くだされば幸いです。

よろしくお願い致します。

 

最後に

ゲームを面白くするために努力してまいりますので、ぜひSleepWalkerの完成をお楽しみに!

UniRxを紐解く「Take(1)とFirst()の違い」

UniRxとは

大変便利なReactiveExtensionsのUnity版ライブラリ。

neue cc

neuecc (@neuecc) | Twitter

こちらで製作者の神様が進捗などを公開されています。

 

最近、業務でも業務外でもこちらを触ることが多く、色々な地雷を踏み倒してきました。

備忘録の意味も兼ねて今回は

  • 「Take(1)とFirst()」の違い

をまとめようと思います。

入門者向きではないです、ご了承ください。

あとかなり長いです。

 

ソースコードなどはこちらの

qiita.com

を参考にさせていただいています。

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. クラスの役割を明確に分けられておらず、なんでもできる神クラスになっている
  2. 役割は明確だが、メソッドなどが抽象化できていないので同じ処理を複数回書いている
  3. 役割も明確で抽象化もできているが、仕様が多い

 

1の場合はまずクラスの役割を定めましょう。partialで分けるとさらに可読性が低くなります。

2の場合はまず同じメソッドを呼び出していないか、同じ計算を書いていないかを探して最適化しましょう。DRY原則を守れの一言に尽きます。

3の場合。お待たせしました、partialの出番です。

 

そもそもpartialってなんぞ

partial (型) (C# リファレンス)

これ(投げやり)

 

クラスの定義を、複数ファイルにまたいで行うことができます。

例として、ある特定のクラス内で使用するStateの中身をpartialで追加していきます。

 

gist3c692f67badadfc5e98a8f8abd8480a1

 

こんな感じです。

これだけだと分かりづらいかもしれませんが、このStateを継承したState1やState2というクラスはこのソースに帰属しているということがわかるので、メンテナンス性や拡張性も向上します。

 

 最後

使用方法を間違えると、スパゲッティになりがちなので要注意です。

適切な場所で使いましょう。

 

おわり

デジゲー博とコミケに申し込んだ話

 

タイトルの通り申し込みました

オープンワールド(に頑張ればなってる)3DのARPGを開発してます

 

サークル名は申し込み時に適当に決めたので今後変わるかもしれません

今は「PhantomIsland」です、マボロシ島です、レアな木の実はなってません(わかる人いるのかな)

 

デジゲー博

f:id:yutakaseda3216:20160830095148p:plain

こんなサークルカットで出てると思います

多分展示だけです

 

コミケ

f:id:yutakaseda3216:20160830095339p:plain

 

受かればこれが出てると思います

完成版を頒布予定です

 

ゲームの中身

本気で作ってるのでお楽しみに

 

終わり

 

うちのプランナー兼デザイナーの渾身の作品

f:id:yutakaseda3216:20160830095951p:plain

 

宜しくお願いします。

 

UnityのStateMachineBehaviourについてのメモ

 

 こっちを読んでください

 

yutakaseda3216.hatenablog.com

 

 

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 追記

qiita.com

 

こんなものがあった。

併用してアニメーション遷移の汎用コンポーネント作りたい

 

2017/4月の追記

制御コンポーネントを作成して適用してみた(年明け前くらい)

いい感じだけど、NormalizedTimeが機能しなかったりして自前で実装した

 

f:id:yutakaseda3216:20170404113601p:plain

 

右側のPlayerStateTransitionはStateMachineBehaviour継承したクラスで

・Inputの入力受付時間

・ステートの自動終了時間

・ステートのキャンセル時間

・ステートのキャンセル先と優先度登録

 

とかできるようになってて、遷移先の切り替えが楽になった

やったね

Unity+VRの開発用DebugConsoleを作った

 

こんにちは

 

GearVR向けアプリのビルド後にDebug.Logが確認したかったり、頂点数やFPSを見たかったりしたので作りました

FPSみたいだけならOculusSDKのプラグイン入れた方がいいかも

 

UnityPackageはここ

www.dropbox.com

 

使い方

BuildSettingsにDebugシーンを追加

好きなシーンのオブジェクトにAddDebugSystems.csをアタッチ

追記
Jsonをusingでimportしてますが使ってないので記述を消して大丈夫です

 

見れる機能

ビルドしたUnityのバージョン

OS名

グラフィックス設定

システムメモリサイズ

ビデオメモリサイズ

スクリーンサイズ(width,height)

頂点数(若干不正確な可能性高め)

FPS

Console(debug.logとか見れる)

 

今後追加したいもの

DebugWindowのActive切り替え

ドローコール(できれば)

Menuのアクティブ切り替え

Recenter機能

がべこれ関係(Profilerから取得)

 

 

終わり