ぐーるらいふ

底辺。

【Unity】フェードイン・アウトを簡単に実現

前回のunity1weekチャレンジで作りたかったけど断念した
この機能を今のうちに用意したいな、なんか無いかなと思ったら
神おったーおったー!
kan-kikuchi.hatenablog.com
参考にさせてもらいます!

参考にして実装

そのまま使いたい所だが、それでは勉強にならない。
参考にしつつ自分なりにカスタマイズして身にしていきたい。

  • 好き勝手なタイミングでFadeInOutさせたい。
  • FadeInした後、待機時間を得てからOutしたい
  • スッキリと1クラスにまとめる

というわけで実装コード。
詳しく解説は書かないけどシンプルなコードなので読めばわかると思う。


呼び出しはこんな感じで

    public Fade fade;

    public void Fire()
    {
        fade.FadeInStarted += FadeInStart;

        fade.FadeInFinished += () => { Debug.Log("Fade in finished"); };
        fade.FadeOutStarted += () => { Debug.Log("Fade out started"); };

        // 2つのメソッドを呼ぶことも可能
        fade.FadeOutFinished += FadeOutFinished1;
        fade.FadeOutFinished += FadeOutFinished2;
        fade.FadeStart();
    }

    private void FadeInStart()
    {
        Debug.Log("Fade in started");
    }

    private void FadeOutFinished1()
    {
        Debug.Log("Fade out finished 1");
    }
    private void FadeOutFinished2()
    {
        Debug.Log("Fade out finished 2");
    }

動作画面は割愛するけど、イベントはしっかり発行されているのを確認。

f:id:ghoul_life:20170530124437p:plain

これは次に使いたいって事でメモ。

【Unity】無謀にもunity1week(二回目)に挑戦【転がる】

ghoul-life.hatenablog.com

第一回に引き続き、
先週の第二回unity1weekにチャレンジしてきた。

ころころフレンズ | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

なんだかんだでやっぱり血反吐を吐いたので、振り返って
次につなげたいと思う。

何作ろうか?

参加の目的としては「Unityの学習」にあり、
このチャレンジを通して一連の流れ(ゲームの遷移)について学びたいと思った。
ゲームの遷移とはゲーム内で行われる状態の遷移だ。
今回は

タイトル -> (ADV -> ゲーム待機 -> ゲーム) x n -> ゲームクリア

というシンプルな流れなんだけど、
ADVモードとゲームモードを行き来するのがよくある形なのかなと
思ってそこを勉強したかった。

後は

  • 平日は時間がない、土日でやりきれるボリューム
  • ADVがあるのでストーリーがある。
  • 遅刻はしない。制限時間を守る。

このぐらいものがいいなぁ、と漠然と考えていた。

ゲームは何にするか?

正直全然思いつかなかった。
twitterで周りの人の発想を見て感嘆の吐息を漏らすばかり。
とはいえ諦めたら何にもならん。誰でも思いつくような

「高いところから低いところへ球を転がす」

恥ずかしいけど、簡単なゲームでいい、完成まで作ってUnity力を少しでも上げるのだ。
と自分に言い聞かせた。

後はなるべく自力でやる。絵も自力だ。
これもやんなきゃ身につかないだろうな…と。

画面構成

ノートの端っこにでも画面を書いておく。

Sceneはもちろん1枚。
UIの切り替えで画面遷移を実現させる。
ADVモード用のUIとGame用のUIと画面中央にドーンとロゴを出すUIと
とUIを3つのグループに分けておくことを考えた。

この時はフレンズなんて頭の片隅にもありませんでした。

血反吐ポイントその1

ここが血反吐ポイントその1。
必要なものを洗い出しておいて作業量を見極める。

  • 雪山フィールド
  • ADVアイコン画
  • ロゴ
  • 立ちキャラ
  • プログラム

この内最もヤバそうなのは雪山フィールドだ。

雪山フィールドエディタ

terrainやらAsset Storeやらも頭をよぎったけど、
そこまで高機能じゃなくていいので自分で作ってみる。
これは平日の夜にちまちまやってた。


頂点を軽く動かすとそれに沿ったベゼルカーブが描かれて、そのベゼルカーブに沿った
Meshを構成してそれに沿ったオブジェクトを作ってあげればOKだ。
頂点を好きなだけ追加することが出来るが、位置は一つ一つマウスで動かしてあげる必要がある。

これをうねうねさせて作ったのが雪山フィールドだ。
デコレーションで木を乗せているが、これはMagical Voxelでささっと作って後乗せ。

これでフィールドは出来た。

フレンズ

金曜日のニコニコ一挙見てたらカッとなってしまった。
そしてやってしまった。後悔はしていない。

後は作っていくだけ

必要なUIを置いたり、オブジェクトを置いたりして
画面を組み立てていく。
その都度必要になるスクリプトを書いていく。

今回全体で作ったクラス関連図はこんな感じ。

f:id:ghoul_life:20170529170256p:plain

ゲームって割り込みで制御したくなるものが多いんで
分けるとアクセス周りがガバッちゃうんですよねぇ。
1つにまとめちゃうと鬼クラスの出来上がりだし。

見直して今後に使いまわせるようなものにしたい。
UIやSnowBallとかは特化しているので流用しにくいかもしれないけど。

血反吐ポイントその2

素材だ。画像素材。
ここが一番時間かかった。慣れの問題もあるけど。
もうとにかく描く。下手でも描く。
下手の横好きだけど楽しかった。もっと描きたい。

ロゴはジェネレーターをお借りしました。
https://aratama.github.io/kemonogen/

日曜日

エロマンガ先生~ヤバい○○まで見てTVを消して集中する。
朝日が眩しくなり、大分日が昇ったなとTVを改めて付けたら
さまぁ~ずの神ギモンってTVがやってた。

一通り出来て、結合して動かして
最後にお礼一枚絵を描いてビルドして提出。

そして夕飯素材を買いに行き、餃子を包む。

感想と次回

プレイして下さった方、本当にありがとう。
自分は普段Unity使ってませんので、難しかったですがあっという間でとても楽しかった。
そして次はもっと良いものを作ろうと沸々と湧いてくるものがあります。

目的としていたゲーム遷移だけど、

敵に攻撃した時、敵が全て倒れていたら、次の状態へ進む

という遷移も割りと噛み砕けて書けたんじゃないかと思う。
UpdateとEventとStateにしっかり分けたのが良かったかもしれない。
ちょっとゲームの遷移についてググって調べてみたり本を読んでみよう。

次も頑張ります。次のお題は何だろうなぁ。

やっときたいこと

黒画面がフェードイン・フェードアウトをさっと出来るスクリプト用意しておきたい。
コールバック付与出来るやつで。ステージ切り替わりとかに使ってもっとゲームっぽくしたいところだ。

【Unity】メッシュカッターについて その4

は?(威圧)

なんだよ、前回で終わりじゃねーのかよ。
と悪態をつきたい所だが、まだ終わりじゃない。

前回までは流れを理解するためのkindar_codeに過ぎない。
しっかり実践寄りに調整し直してみよう。
ゴールはcubeを切るところまでだ。

f:id:ghoul_life:20170523131439g:plain


いきなりだけど、まるっとproject化してgithubに公開しておいた。
ゲームにも応用が出来そうなRigidbody入りだ。
github.com

あんまり変わらない?

概ねの流れはここまでで把握できている。
後は複数のものに対応出来るように変えた。

meshのポリゴン数が増えるので、ちゃんと三角形ずつ計算
するようにしたり

for (var i = 0; i < meshTriangles.Length; i += 3)
{

var idx0 = meshTriangles[i];
var idx1 = meshTriangles[i + 1];
var idx2 = meshTriangles[i + 2];

渡されたmeshからちゃんと頂点位置を計算するようにしたり

// 頂点位置をscaleやpositionに合わせてしっかり計算しないとおかしくなる
// あれ、もうmatrixで計算したほうがいい?
var v1 = Vector3.Scale(meshVertices[idx0], meshScale) + meshPos;
var v2 = Vector3.Scale(meshVertices[idx1], meshScale) + meshPos;
var v3 = Vector3.Scale(meshVertices[idx2], meshScale) + meshPos;

verts.Add(v1);
verts.Add(v2);
verts.Add(v3);

// そのポリゴンの法線を計算しておく
var normal = Vector3.Cross(meshVertices[idx2] - meshVertices[idx0], meshVertices[idx1] - meshVertices[idx0]);

後はゲームっぽさを出して複数のinputに対応出来るようにしたり
rigidbodyつけたり
と調整しただけ。

この後

ここまでの流れが把握できていれば、もうなんでも出来る。
SkinedMeshに対応してあげればunityちゃんだって切れるし、
切り口が気になるなら、そこを塞ぐmeshを作るプログラムを組むのもいい。
(交点を全部保持しておいて、そこを繋ぐようなmesh作るだけでいい?)
submeshがあるオブジェクトも同じように計算していくだけだ。
また、uvやMaterialsが入っていないのでそれを追加してもいい。

やってみて

MeshCutterなんて検索すればいくらでもあるし、
それを使えば機能は満たす事が出来るだろう。
だけど、理解しているか否かでは雲泥の差がある。
「ライブラリが対応していないので出来ません。」
が通用する世界では無いのだろうと思っている。

Unityはやっぱり楽しい。
仕事で使ってみたいですね。

【Unity】メッシュカッターについて その3

MeshとPlaneは作った

ghoul-life.hatenablog.com
ghoul-life.hatenablog.com
前回、前々回で必要なものは用意出来た。
ではこの2つを使ってMeshを実際に切ってみよう。

planeの交点の計算

とはいえ、いきなり切るわけにはいかない。
まずはPlaneと三角形の交点を計算しなければならない。
計算してみよう。




Cross Point Check source file
(このソースファイルは後述のCutter.csの一部分を切り出したもの。
プロジェクトには入れなくてもOK)


一点の頂点から別の二つの頂点に対してRayを作る。

f:id:ghoul_life:20170519000955p:plain

そのRayがPlaneに当たるまでを計算してその距離を測れば
交点を計算出来る。

f:id:ghoul_life:20170519001103p:plain

実行した結果はこんな感じだ。
わかりやすく頂点にSphereを表示するようにしている。
引いた線と三角形の辺の交点が求められているのがわかる。

f:id:ghoul_life:20170518170725g:plain

後は切るだけ

ここまで来たらもう切るだけだ。
カットするということは2つのオブジェクトに分ける
という意味に捉えることが出来る。

片側のグループの頂点数は3、
もう片方のグループの頂点数は4になるように当てはめて、
個別にMeshを作ってあげれば完成だ。




Mesh Cutter source file


気になるのは

cross = Vector3.Cross(pos[triIdx2] - pos[triIdx0], pos[triIdx1] - pos[triIdx0]);
inner = Vector3.Dot(cross, Camera.main.transform.forward);

ここだろうか。
これは、頂点インデックスを計算したときに裏側を向いているかどうかをチェックしていて、
裏側を向いてしまっていたら反転させてあげているだけだ。

http://www.sousakuba.com/Programming/gs_polygon_inside_outside.html

頂点インデックスを元にしたベクトルABとBCの外積が0より大きければ表、小さければ裏になる。
ここではカメラの方を向いているかで調べてしまっているが、本来ならnormalの方向でチェックするのがいい。

実行した結果はこんな感じだ。カットできた。

f:id:ghoul_life:20170518174330g:plain

切って生成したオブジェクトにRigidbodyを付ける、などすれば
ゲームに実用出来るだろう。

ここまでで基本的な流れは抑えられる。簡単でしょう?
が、そう思ったやつから死んでいく…。

【Unity】メッシュカッターについて その2

これを切断するわけだが

 

ghoul-life.hatenablog.com

 

前回でメッシュの作り方は書いた。
メッシュカッターはズバッとこれを切断する。
ポリゴン数が増えても各ポリゴンで繰り返すだけだ。

 
どっちに頂点があるかチェックする

3つの頂点があり、これを2つのグループに分けた場合、以下になる

  • 全部1グループに属し、2グループは0になる
  • 全部2グループに属し、1グループは0になる
  • 1つが1グループに属し、2グループが2つ
  • 2つが1グループに属し、1グループが1つ

f:id:ghoul_life:20170518002102p:plain

 

外を切る!という考えがあることに注意。

 

この内

  • 全部1グループに属し、2グループは0になる
  • 全部2グループに属し、1グループは0になる

この2つは切る必要がないため、後回しにする。

 

グループ分けの方法


正直なんでもいい。自作でもいいし。
有り物で行くならUnityではPlaneを使うのがシンプルだ。

docs.unity3d.com

 

3DオブジェクトにあるPlaneでは無く、
たった一つのpointとたった1つのnormalを持つ平面を表す構造体だ。

 

この

Plane.GetSide(Vector3)


これを使う。

内部的には
その頂点が法線方向にあればtrue。
無ければfalseなだけだ。

これを使えば一定の位置からどっちのグループにあるか計算出来る。
まずは、Planeを作るスクリプトを組んでみよう
ここではLineRendererで引いた線に沿ってplaneを作る。

 

Create Plane source file

 

こんな感じにシンプルに。

OnDrawGizmosSelected()でPlaneの法線が見えるようにしている。
一歩踏み込んでマウスで自由に線を引けるようにして、
その都度Planeを作ってもいい。

 

f:id:ghoul_life:20170518003002p:plain

 

「もうこれで頂点分けてメッシュ作るだけでええやん」
と思ったかと思います。そのとおりです。

次はいよいよ本当にカットします。

【Unity】メッシュカッターについて その1

きっと恐らくまず間違いなく途中で力尽きるので分けて書く。
メッシュカッターはUnityなら簡単らしいが、よーわからんのでまとめてみる。
参考にしたかったが無いので、自力でやる。
 
間違ってたり表現が怪しいかもしれないが、ご愛嬌。
 
ゾンビの道も一歩からだ。
一歩ずつ進んでみよう。

 

最小構成で作ってくる 

3Dのモデルの最小構成は1ポリゴンメッシュだ。
まずはこれをプログラムで作ってみよう。
 
 
これで三角形を作ることが出来る。
本当ならnormalやらuvやら作る必要があるが、今は置いておく。
 
適当にGameObjectをEmptyで作って、
上記のスクリプトをアタッチして実行すればこんな感じ。
 

f:id:ghoul_life:20170517002317p:plain

 
三角形が表示出来ました。
もちろん、頂点数を変え、triangleを増やせば、
色々なポリゴンメッシュが作れるはずだ。
 
もう疲れましたね。今日は寝よう。
明日も仕事だ。

【Unity】ScreenToWorldPointが上手く取れない?

ScreenToWorldPointを使う

Unityを使用していて、クリックした位置にオブジェクトを移動させたりすることはよくある。
クリックした位置を取得するのは容易だ。流石Unity。

https://docs.unity3d.com/jp/540/ScriptReference/Input-mousePosition.html

これだけでいい。
しかし、これはあくまでScreen上のpointであって、Scene上のpositionに変換してあげなければ 思っていたような動きをしてくれない。

調べると

https://docs.unity3d.com/ja/540/ScriptReference/Camera.ScreenToWorldPoint.html

を使えばOK。
という記事が大量に見つかる。

「OK!やったるで!」

と素直な君はそのまま書くだろう。

が、
「上手く取れない…なんでだ、Unityやっぱクソだな。」
と絶望を感じるだろう。

逆に
「上手く取れた!やっぱUnity神だな。そして俺天才だな。」
と大いに自惚れるだろう。

UnityのCamera

Cameraの投影設定には2つのモードがある。
Perspective
Orthographic
誤解を恐れずに簡潔に言えば、立体投影と平面投影の違いだ。

f:id:ghoul_life:20170516001446p:plain

なんでや

この
Perspective
に設定されている時はz値の設定が無いと
正しく ScreenToWorldPoint で値を変換することが出来ない。 Input.mousePositon はそのままだとxyだけで事足りるのでz値が無いのだ。
このz値を設定してあげれば正しく変換することが出来る。

ScreenToWorldPoint check source file

このソースを実行して画面の真ん中辺りをクリックすると

f:id:ghoul_life:20170515192743p:plain

こんな値が取れる。
ちなみにtmpPos側は画面のどこをクリックしても同じこの値が返ってくる。

また、z値によって変換されて返ってくる値が変わってくるのに注意だ。
「そりゃそうだろ」って話なんだが、
Perspectiveで描画するがゲーム自体は2Dのように動かす、 なんて時には直面するかもしれない。

では
Orthographic
の時はどうだろう?

これはz値が必要ないので、直でもOKだ。
ちゃんと値が変換されて返ってくる。

また、逆にz値に何を入れてもxy値は変わらずに返ってくる。
これも「そりゃそうだろ」って話なんだが、
ハッキリわかっておくと安心出来る。