Unity z軸に関係なくダメージを最前面に出したい
ダメージをz軸に関係なく最前面に出したいとおもって
SortingLayerを弄っていたのですが、うまく行かず。。
結局カメラを追加する形になりました。
やりたいこと
これをこうしたい。
z軸に関わらず前面に表示されるレイヤーを作成する
FrontObjという名前で作成しました
カメラを作成する
FrontObjCameraという名前で作成します
注意点
Clear FlagsをDepth Onlyにしないといけません。
もともとあったはずのMainCameraをDepth0
新しく追加したFrontObjCameraをDepth1にします
いらないコンポーネントは外しておきましょう
カメラのマスクレイヤーを設定する
Main Camera
FrontObjCamera
カメラを増やして2つとも全部描画させるともちろんポリゴン数も頂点数も2倍になります。
マスク設定がかぶらないようにします。
これで期待通りの描画になりました。
もともSortingLayerがz軸を無視して描画順序を変更してくれるとばかり思っていたのですが、
うまくいきませんでした。
シェーダーをかける人はシェーダーでなんとでもできるかもしれません。
他の方法やご意見マサカリとう歓迎しております!!
Unity ScriptableObjectはバトルデータに向いていると思う
久しぶりのブログです。
アプリ作成は進んでいるのですが、いかんせんブログのネタになる作業をしていない&見せられないよ!
という事であまりブログが書けてません。。むしろブログ書きたいのに。。。
今日の話はScriptableObjectが結構使えそうだったのでその話です。
ScriptableObjectについてはこちらの記事が丁寧に書かれていますのでこちらを参考にしてください。
それでは問題です。
ステージ毎に敵の出現ポイントやタイミングを変更したいのですが、どうしたらいいでしょうか?
よくある事です、
○秒後に○の敵が出現その後○秒後にボスが出現といった
いわゆるバトルデータ(シナリオデータ)をどうやって実現しましょうか?というお話です。
幾つかすぐに出てくる答えとしては、
・csvやjsonでデータを作成してなんやかんやパースすればええやん
・シナリオDBでも作って適当に出せるようにしたらええやん
・最低データのみ保持してランダムで出現させればええやん
全部正解だと思います。 作ろうとしているものの用途に合わせて上記で選ぶのも良いでしょう。 ですが、Unityの場合はScriptableObjectがこれに適合している気がします。
なぜなら、Inspector上で値を変更しながらバトルデータを作成できるから!
です
という事で早速作成します。
まずは構造を決めます。
[Scripts/QuestBattleData]として保存します
using UnityEngine; using System.Collections; using System.Collections.Generic; [System.Serializable] public class QuestBattleData : ScriptableObject { //適当なパラメータ public int param1; public Rect param2; //敵が出現する場所とID public List<EnemyDetail> entryEnemy; } [System.Serializable] public class EnemyDetail{ public int enemy_id; public Vector3 enemy_pos; }
構造を型にアセットを作成できるようにします。
[Editor/CreateBattleData]として保存します
using UnityEngine; using UnityEditor; using System.Collections; public class CreateBattleData : MonoBehaviour { [MenuItem("Assets/Create/CreateBattleData")] public static void CreateAsset() { QuestBattleData item = ScriptableObject.CreateInstance<QuestBattleData>(); //アセットを保存するパス string path = AssetDatabase.GenerateUniqueAssetPath("Assets/Resources/QuestBattleData/" + typeof(QuestBattleData) + ".asset"); AssetDatabase.CreateAsset(item, path); AssetDatabase.SaveAssets(); EditorUtility.FocusProjectWindow(); Selection.activeObject = item; } }
これでAssets/Resources/QuestBattleData/フォルダを作成して、
Project > Createメニューを開くと一番下に出てきます。
これで作成されたアセットはこんなInspectorになってます。
あとはQuestBattleDataとしてスクリプトにアタッチすればOK
public QuestBattleData battleData;
スクリプトからQuestBattleDataを参照する事が可能です。
また、Resouces/に入れておけば動的にアタッチする事も出きますし、
.assetなのでこのままAssetBundle化してLoadしてもよいでしょう。
そして何より、
Inspector上で動的にゲームバランスを整えながらバトルデータを作成できます!
これにより、CSVやJsonのようにパーサーを用意しなくても良いですし、
DBデータでマスタデータを更新して検証DBに反映してとかやらなくても良いし、
値を追加変更する場合も影響範囲がわかりやすいという状態です(スバラっ!)
という事で今回はScriptableObjectのお話でした、
他に良い方法があるよ!とかこんな使い方があるよ!?とか
ご意見マサカリ歓迎しております。
Unity PloyWorldを使ってステージを作成してみる
さて、なんかゲームの大枠ができつつあるのですが、
仮ばっかりでチープさが抜けません!
なのでちょっと一個くらいステージ背景を作ろうとおもいます。
最初Unity付属のTerrainをそのまま使用したところFPSがひどいことになったので、
Terrainをローポリ化してくれる+オブジェクトやらなSkyboxやらも全部丸っとつけて
$50だもってけドロボー的な素晴らしいアセット購入しました。
これの素晴らしいところは他のハイポリモデルも
この世界観にあった感じでローポリ化してくれるらしいのですが、
自分が作ってるVoxleは元々ローポリなので世界観にバッチリです!!
兎にも角にも自分的は$50分働いてもらわないといけないので早速何か作ってみます。
SkyBox変えよう
まずは形から入る私ですが、とりあえずSkyBoxを変えることになりました。
PloyWorldは素晴らしいことに10種類以上のSkyBoxが入っています!(スバラ!!
今回は「Sky_factedにします」
Terrainで適当に地形を作る
これはもうStandard Assets様に頼って適当作りますが、
この時点で頂点数をふやしてもあまり意味がないのでこんな設定にしておきます。
初期値は結構な数字になていますのでスマホ向けに考えているのならここを抑えましょう。
こんな感じになった
まぁよくある山です、これはこのままで使うと
ポリゴン16k、、これはちょっと多いですね、
それに頂点数も10kですか、もっと抑えたいです。
これでも結構使いますね、だいぶ下げたんですけどね。
PolyWorld登場
この状態からWindow > Quantum Theory > PolyWorld Terrainを押すとこんあ画面が出てくるので
作成したTerrainを選択してGenerateボタンを押します。
今回はHalfを選択してみます
するとエラーが出ます(笑)
Terrainって名前はダメだからなんか違う名前にしてよ鬼のおにーちゃんいぇーい、ピースピース
と言われました。
しょうがないので名前も適当にTerrainMountainにして山っぽさを出します。
もう一回ジェネレートすると。
こんなかんじになるのでしたのチェックボックスのUse Associated Meshを押します。
その後Use Custom Shadearsボタンをおして、 Bake Vertex Colorsボタンを押します。
最後に、Hide Terrainにチェックをつけると。。?
いい感じになりました。
ただし
ポリゴン数は設定通り半分になりましたが、頂点数はふえました(笑)
カクついた分頂点数がふえた?Terrainが元々やってくれてたBatchingに負けた?
どちらにせよこの山の時にhalfじゃ期待以上の軽量化を狙えなさそうです。
なので1/4にしてみました。
うん確かに1/4であれましたが、果たしてこの背景にどこまでユーザーはクオリティを求めるでしょうか?(笑
今回は背景をローポリでスマホに耐える形でというのが前提だったので、
1/4を採用しようとおもいます。
今後このPoly Worldをつかっていろいろやってみたいとおもいます。
ご意見マサカリ等募集しておりますm()m
Unity キャラクターの見え方をなんとかしてみる
元はこんな感じ。 まだステージができていないのでなんともチープですが、この段階でもきっとできることがあるはずです。
・影が欲しい
・ちょっとアンチエイリアスががパッキリしすぎてる
影が欲しい
通常であればLightから影を作るのでしょうが、
これだとアクティブなオブジェクトが増えてくると負荷になりそうなので、
今回はただの丸影をつけたいとおもいます。
StandardAssetからEffetsをインポートして、
キャラクターのプレハブにBlobShadowProjectorをアタッチします。
あとはBlobShadowProjectorをキャラクターの頭上に移動すれば丸影ができるのですが、
このままだとキャラクター本体にも影が落ちてしまうので、
Inspectorの
Ignore Layerを使って回避しましょう。
これで丸影ができました
アンチエイリアスがパッキリしすぎている
元々そういうモデルやんみたいな根も葉もないことを言われるとそれまでですが、
もう少し境界をぼやっとさせたいわけです。
これにはカメラにAntialiasingをアタッチして値を調整しましょう。
こうすると
わかるかなー?微妙ですが、雰囲気はバッチリです。
現状できるのはこのくらいでしょうか?
微々たるところがゲームのクオリティに繋がると信じています(笑)
Unity UniRxをつかってピンチやスワイプの処理を書いてみる その2
前回はこんな記事を書いたところ、
Bufferつかった方がらくですよー!とお告げをいただきましたので、つかってみました。
Bufferとは引数分コレクションが溜まったらSubscribeするという便利機能らしいので
前回の機能をかきなおしてみました。
スワイプ
public void MapSwipe() { #if UNITY_EDITOR var drug = Observable.EveryUpdate ().Select (pos => Input.mousePosition); var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)).First(); #elif UNITY_IOS || UNITY_ANDROID var drug = Observable.EveryUpdate ().Select (pos => Input.GetTouch(0).position); var stop = Observable.EveryUpdate ().Where(_ => Input.touchCount != 1).First(); #endif IDisposable onDrug = drug.Buffer (3) .TakeUntil(stop) .Subscribe (colPos => { float delPosx = colPos.Last().x - colPos.First().x; float delPosz = colPos.Last().y - colPos.First().y; float Speed = 0 -(5 * (MainCamera.fieldOfView / 60)); MainCamera.gameObject.GetComponent<Rigidbody>().velocity = new Vector3(delPosx, 0, delPosz) * Speed; }); }
ピンチ
public void MapPinch() { #if UNITY_EDITOR var pinch = Observable.EveryUpdate ().Select (pos_dist => Input.mousePosition.x); var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)).First(); #elif UNITY_IOS || UNITY_ANDROID var pinch = Observable.EveryUpdate () .Select (pos_dist => Vector2.Distance(Input.GetTouch (0).position, Input.GetTouch (1).position)); var stop = Observable.EveryUpdate ().Where (_ => Input.touchCount != 2).First(); #endif IDisposable onPinch = pinch.Buffer(3) .TakeUntil(stop) .Subscribe(distanceParam => { float diff = distanceParam.Last() - distanceParam.First(); #if UNITY_EDITOR MainCamera.fieldOfView -= diff; #elif UNITY_IOS || UNITY_ANDROID MainCamera.fieldOfView -= diff / 10; #endif }); }
ふむふむ、前のソースより可読性が上がっていい感じです。
挙動も問題ないのでこっちで行ってみようと思います!
Unity UniRxをつかって似非ピンチ処理を作ってみる
ピンチインアウトって本来2点座標の中間地点を拡大縮小する機能な気がするんですけど、
今回似非なのでカメラの中心点を拡大する形になります。
またエディター上ではマルチタッチが再現できないので、
スペースキー + スワイプで代用します。
前回のソースに追記するので流れがわからない人はこちら
これに、ピンチ処理を作ってみます。
using UnityEngine; using System.Collections; using System; using UniRx; public class CameraMove : MonoBehaviour { //メインカメラ public Camera MainCamera; // Update void Update () { #if UNITY_EDITOR // マウスが押された場合 if (Input.GetMouseButtonUp(0)) { }else if(Input.GetKey(KeyCode.Space) && Input.GetMouseButton(0)){ //エディターではマルチタッチが再現できないので適当にスペースキー+スワイプでピンチを再現します。 MapPinch(); } else if (Input.GetMouseButton(0)) { MapSwipe(); } #elif UNITY_IOS || UNITY_ANDROID if (Input.touchCount == 0) { } else if (Input.touchCount == 1) { MapSwipe(); } else if (Input.touchCount >= 2) { MapPinch(); } #endif } //スワイプの処理は省略 ~Skip //ピンチの処理 public void MapPinch() { #if UNITY_EDITOR //エディターではマウスポジションで判定する(検証用) var pinch = Observable.EveryUpdate ().Select (pos_dist => Input.mousePosition.x); var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)); #elif UNITY_IOS || UNITY_ANDROID //2点の距離を取得 var pinch = Observable.EveryUpdate () .Select (pos_dist => Vector2.Distance(Input.GetTouch (0).position, Input.GetTouch (1).position)); //タッチカウントが2では無くなったら購読停止 var stop = Observable.EveryUpdate ().Where (_ => Input.touchCount != 2); #endif //次フレームのポジションを取得して2点座標の差分を取得 IDisposable onPinch = pinch.Zip(pinch.Skip(1), (dist1, dist2) => new { diff = dist2 - dist1}) .TakeUntil(stop) .Subscribe(distanceParam => { // カメラのfieldOfViewを変更することでピンチを再現する MainCamera.fieldOfView -= distanceParam.diff / 30; //0以下になると反転してしまうので限界値を設ける if(MainCamera.fieldOfView < 4){ MainCamera.fieldOfView = 4; } if(MainCamera.fieldOfView > 70){ MainCamera.fieldOfView = 70; } }); } }
若干動きがあやしいです、
本来はスワイプ > ピンチの状態管理はもっと適切に行う必要があります。
ご意見マサカリ歓迎しています!
Unity UniRxをつかってスワイプでカメラ移動をしてみた
UniRxをAssetsストアから落としてきます。
アセット検索すれば出てきます。
パネルを用意する
今回わかりやすいように色をかえてみましたが
特に意味はありません。
カメラの位置を決定する
斜め45℃下を向くカメラを置き、パネル全体が写るように調整します。
カメラにRigidBodyを追加する。
適当なオブジェクトに下記スクリプトをアタッチする
名前は適当にCameraMove.csにしました。
MainCameraにカメラをタッチします。
using UnityEngine; using System.Collections; using System; using UniRx; public class CameraMove : MonoBehaviour { //メインカメラ public Camera MainCamera; // FixedUpdate void FixedUpdate () { // マウスが押された場合 if (Input.GetMouseButtonUp(0)) { } else if (Input.GetMouseButton(0)) { MapSwipe(); } } //スワイプの処理 public void MapSwipe() { //mousePositionの取得 var drug = Observable.EveryUpdate ().Select (pos => Input.mousePosition); //クリックが話されたら購読停止 var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)); //マウスポジションの4フレーム後のポジションを比較してカメラのRigidbodyに力を加える。 IDisposable onDrug = drug.Zip (drug.Skip (4), (pos1, pos2) => new {x = pos2.x - pos1.x, z = pos2.y - pos1.y}) //クリックが話されたら購読停止 .TakeUntil(stop) .Subscribe (deltaPosition => { MainCamera.gameObject.GetComponent<Rigidbody>().velocity = new Vector3(deltaPosition.x, 0, deltaPosition.z) * -5; } ); } }
いい感じにうごきました、がブログ用に抜粋して書いたのでちょっといびつですね。
実際はupdate内で状態管理したりすると思います。
稼働領域の限界値はSubscribe内に書くと慣性の力で限界値よりも動いてしまう場合があるので
それはupdate内で監視しておいた方がいいかもしれません。
また、購読完了はTakeUntilでやりましたが、実際に使う場合は
停止は停止でSubscribe呼び出してその中でステート変更などを行うのが良いでしょう。
次は似非ピンチイン、ピンチアウトでも作成しようかと思います。
--- 追記
上記スクリプトはエディター専用で実機の場合は別途対応が必要になります。
面倒くさがらずにあるなら書けやと言われそうなので下記に記載しておきます。
参考までにどうぞmm
using UnityEngine; using System.Collections; using System; using UniRx; public class CameraMove : MonoBehaviour { //メインカメラ public Camera MainCamera; // FixedUpdate void FixedUpdate () { #if UNITY_EDITOR // マウスが押された場合 if (Input.GetMouseButtonUp(0)) { } else if (Input.GetMouseButton(0)) { MapSwipe(); } #elif UNITY_IOS || UNITY_ANDROID if (Input.touchCount == 0) { } else if (Input.touchCount == 1) { MapSwipe(); } #endif } //スワイプの処理 public void MapSwipe() { #if UNITY_EDITOR //mousePositionの取得 var drug = Observable.EveryUpdate ().Select (pos => Input.mousePosition); //クリックが話されたら購読停止 var stop = Observable.EveryUpdate ().Where(_ => Input.GetMouseButtonUp(0)); #elif UNITY_IOS || UNITY_ANDROID //positionの取得 var drug = Observable.EveryUpdate ().Select (pos => Input.GetTouch(0).position); //タッチカウントが変更され場合に購読停止 var stop = Observable.EveryUpdate ().Where(_ => Input.touchCount != 1); #endif //マウスポジションの4フレーム後のポジションを比較してカメラのRigidbodyに力を加える。 IDisposable onDrug = drug.Zip (drug.Skip (4), (pos1, pos2) => new {x = pos2.x - pos1.x, z = pos2.y - pos1.y}) //クリックが話されたら購読停止 .TakeUntil(stop) .Subscribe (deltaPosition => { MainCamera.gameObject.GetComponent<Rigidbody>().velocity = new Vector3(deltaPosition.x, 0, deltaPosition.z) * -5; } ); } }
ご意見マサカリ等歓迎しております!