ぐーるらいふ

底辺。

第三回 unity1week 「積む」に挑戦 前編 (企画編)

先週また@naichilabさんのunityroomにて、unity1weekが開催されました。
unityの勉強は継続してやっていて、このブログも出来るだけ続けていきたいなと思っているので
今回もチャレンジしていく事にしました。

積みゲーけしけし | 無料ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

企画について

積むって。

もーこれが難しい。だって最初にパッと浮かんだのアレですよ、アレ!
f:id:ghoul_life:20170627020126p:plain
もうずーっと上位にいるネズミとかクマとかファンシーで可愛いアレのイメージが強すぎる。

とりあえずその考えを頭から振り払って、
他のことを考えよう。
荷物を積む、オブジェクトを積み上げて塔を作る、
など上にベクトルを向けるものがイメージとしてすぐに浮かぶが、
これも一杯出るだろうなぁ、と一旦振り払う。

積むんだよな、ゲームだよな、とシンプルに考えだした時
「積む+ゲーム=積みゲーをゲームにしたらどうだろう」
と思い立つ。

詳細をちょっとだけ詰める

積みゲーがただあるだけではダメだ。
それをどうにかしてゲームに落とし込まないと。
積みゲーを消化するって言うよな…。
シンプルに消化していくゲームはどうだろう。

  • 積みゲーから一本ゲームを選ぶ
  • そのゲームにパラメータが割り振ってある
  • ゲームにはクリアまでの所要時間がある
  • プレイヤーは所要時間を消費しそのパラメータ分成長する
  • 称号が手に入る(アクションゲームばかりクリアしていくとアクションマスターなど)
  • 一定期間過ぎた時に結果を振り返ることが出来る(一ヶ月など)

というゲームはどうだろうか。

だめだー

簡単にモックにしてやってみるが、全然駄目。

  • ゲーム拘束時間が長くて、辛い。
  • 長い割に別に大した結果が出るわけでもない。
  • やれる事に比べて周りを固める要素が多く、分かりにくい。

普通の人ならちょっと触ったらもうブラウザ閉じてるわーこれは。
もうこの時点で金曜日の深夜。だけど考え直そう。

無理矢理な方向転換

もっとシンプルにしよう。所要時間も称号も捨てよう。
パラメータももっとシンプルでいい。
パズルゲーム風に要素を調整して…。

・お題が出る
・それを選ぶ
・正解なら+1 不正解なら0

としたらグッと触り心地が良くなった。
(面白いかどうかは一旦置いておいて)
後はこれでなんとか完成まで持っていこう。

開発編につづく
ghoul-life.hatenablog.com

【Unity】uGUIでimageに穴を開けたい!(くり抜く)

ルパン三世的な…?

チュートリアルなどでゲーム画面の説明をしたい。
よくある画面を暗くして見てほしい箇所にライトを当てるような演出をしたい。

f:id:ghoul_life:20170626200151p:plain

こんなんただ塗って穴開けてるだけやん。
それだけなのに、パッと実装が分からない。
Maskじゃない、なんというかMaskの逆?
uGUIだけで出来る?どうやるんだ?

  • すでにゲームは作ってあるので、そこはなるべく触りたくない
  • uGUIベースのゲームなのでuGUIでやりたい。
  • 実装はなるべくシンプルで簡単に

どうも既存機能だけでは厳しそうな感触。
なんらかの工夫が必要か。

くりぬく?

nn-hokuson.hatenablog.com
なるほど、ColorMask 0!
これでも行けそう?だけど
裏のQueueもいじらないと駄目か…。うーむ。
あ、そうか別Layerにして、サブカメラにすればいけそうかな?

ワイプ、トランジション

裏に影響なく画面全体を被せるのはこれが近いのかな?
tsubakit1.hateblo.jp
これを応用すればやりたいことが出来そう?

おお!これか!?これじゃん!
nn-hokuson.hatenablog.com
これを応用してみよう。

実装してみる

もうほとんどそのままだけどパラメータを外から設定出来るように。

Shader "Custom/HoleViewShader"
{
	Properties{
		_BackColor("background color", Color) = (0, 0, 0, 0) // 背景色
		_HoleX("Hole Position X", float) = 0 // 穴の位置X
		_HoleY("Hole Position Y", float) = 0 // 穴の位置Y
		_Radius("hole radius", float) = 0 // 穴の大きさ
		_ScreenW("Screen Width" , float) = 960.0 // 画面の幅
		_ScreenH("Screen Height" , float) = 640.0 // 画面の高さ
		}

	SubShader{
			Tags{ "Queue" = "Transparent" } // alphaに対応するのに必要

			Blend SrcAlpha OneMinusSrcAlpha // alphaに対応するために必要
			Pass{
				CGPROGRAM

				#include "UnityCG.cginc"
				#pragma vertex vert_img
				#pragma fragment frag

				// Propertiesの値をShaderに渡す
				float _HoleX;
				float _HoleY;
				fixed4 _BackColor;
				float _Radius;
				float _ScreenW;
				float _ScreenH;

				fixed4 frag(v2f_img i) : COLOR{

					i.uv.x *= _ScreenW / _ScreenH; // アスペクト比を計算してあげる

					if (distance(i.uv, fixed2(_HoleX, _HoleY)) < _Radius){
						discard; // 指定位置より一定距離以内だったら処理を飛ばすだけ
					}
					return _BackColor;
				}
				ENDCG
			}
		}
}

値を渡すスクリプト側はこんな感じ。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HoleView : MonoBehaviour {

    void Start()
    {
        // 外部から設定する
        SetHole(new Vector2(480, 320), 0.2f);
    }

    public void SetHole(Vector2 pos, float radius)
    {

        // 画面との比率を出す
        var pinPos = new Vector2(pos.x / Screen.width, pos.y / Screen.height);

        // アスペクト比の問題なのか、位置的にはこのあたりで調整すると思った位置になるので計算してあげる
        // x range 0.45 - 1.05 この値が画面端から画面端でいい感じの所
        // y range 0.3 - 0.7

        // 比率と範囲値を計算して値を出す
        pinPos.x *= (1.05f - 0.45f);
        pinPos.y *= (0.7f - 0.3f);

        // 最下値を足して範囲に入れる
        pinPos.x += 0.45f;
        pinPos.y += 0.3f;

        // shaderに値を渡す
        var img = GetComponent<Image>();
        img.material.SetFloat("_HoleX", pinPos.x);
        img.material.SetFloat("_HoleY", pinPos.y);
        img.material.SetFloat("_Radius", radius);
        img.material.SetFloat("_ScreenW", Screen.width);
        img.material.SetFloat("_ScreenH", Screen.height);
    }
}

githubにもさくっと。
github.com



Inspectorはこれだけ!
Image一個あればOK!

f:id:ghoul_life:20170626190258p:plain

これで超簡単!後からちょい載せで使えるヤーツの完成です。
uGUI同士ならCanvasのSortOrderとかで順番をいい感じにしてあげてください。

注意事項として

  • ホールの形

え、星型にくり抜きたい?shaderで書くんだ!ってのは嘘で、
複雑な形にくり抜きたいならLayer&サブカメラ&ColorMask0でやったほうがいいかも。

こればっかりはどうしようも無い?
汎用的に外部パラメータ化してスクリプトから渡すように。
後は実際にゲーム画面を見ながらスクリプト側で調整してあげて下さい。

【Unity】Inputをいい感じにしたい

UnityでInputを取りたいなぁ。なんて思ったら
void Update()
などで
Input.GetMouseButton(0)
とか書くだろう。

そしてif分で押したらこのイベントをして…
なんていう処理を書くだろう

そしてそれが複数必要になることだってあるだろう。
そして仕様上それら全てを一時的に無効にしたいタイミングが来たりしたら
とっても大変だろう。(pause中とかね)

なので、Input周りはWrapperを使うようにしている。

自分はこんな感じで。

SingletonMonoBehaviorはこちら。
ghoul-life.hatenablog.com



シンプルだけど重宝している…。
simple is best.

どっからでもアクセス出来て、on/offも一括だし。
一括on/offは

Input.simulateMouseWithTouches = false

これでももしかしていける?使ったこと無いけど。

とりあえずこれはmouseだけど、touchとかも入れていけば
mobileにも対応できそう?
なんかそのままでもmobileでとりあえずは動いちゃうとか
聞いたこと有る。

一部だけ有効にしたい、とか
マルチタッチに対応したい、とか
DownとUpの差を見てフリック判定する、とか(時間も要るか)

要望は尽きない。メンテナンスしていきたい所。
なんかパッと書けちゃいそうだけどねーこのレベルだと。
でも自分用にメモっとこう。

【Unity】SingletonMonoBehaviourでUnityObjectにアクセス

ゲーム全体を管理するGameManagerであったり、Inputであったりと

  • 一意で管理したい
  • 好きな所からサクッとアクセスしたい

なんて場合に重宝する。

これだけだけど、メモっておこう

【Unity】UnityのAnimationがわかんないよ

ずっと避けていた。
自作スクリプトでやっちゃったり、iTweenで代用していた。
プログラマーとしてはそれでいいと思っていた。
細かい制御、イベント発行だって自由自在だし、困ったことも無かったし。
何よりよく分からないし。
何度か挑戦はしてみたが、いつも思った動きが作れないので諦めてしまっていた。

が、このままではずっと出来ない。
もう一度挑戦してみよう。

作りたいもの

作りたいものはこれだ。
出来とるやん、って突っ込まない。

f:id:ghoul_life:20170526150208g:plain

一枚の画像がリズムを取るように上下scaleが伸縮するだけ。
もちろんposition , rotation , scaleをいじっても
それに追従して動いてくれるものじゃないと使い物にならない。
相対で動いてくれるものが絶対だ。

自分がやった手順をまとめておく

触ってこなかったので、調べながら見よう見まねでやってみたのをまとめておく。

配置~初期設定
  1. 適当なpngを画面にD&Dでinspectorに配置する
  2. Window > AnimationでAnimationタブを開く
  3. 1で配置したGameObjectを選択している状態でCreateを押下して、適当な.Animファイルを作る
  4. Add PropertyでTransform > Scaleを選択。

ここまではいいだろう。思ったまま操作すればいい。簡単だ。
問題はこっからだ。

パラメータ

まずは全体の長さを確認。何もせずそのまま実行する
ちょっとアニメーションの長さが長いので 0:40に短くしたい。
右側にある最後のキーフレームをグイッと0:40の所まで持っていけばOKだ。

さて、では実際にリズムを取るアニメーションを作る

0:25 , 0:30 , 0:35の箇所3つにAdd keyしてkeyframeを作る
赤い線を持っていって、右クリックしてAdd Keyだ。
カーソルの位置ではなく赤い線の箇所に作られちゃうぞ!
そして、0:30にまた赤い線を合わせて、transformのscale.yを0.5にする。
これで良さそうだ。

実行してみる。

f:id:ghoul_life:20170526150546g:plain

おお、それなりに合ってる。もうちょっと感覚を狭くしたら良さそうだ。
調査段階なのでこれでとりあえずいいだろう。

実験

ちゃんと実用に耐えられるかテストしてみよう。

移動してみる

先程のAnimatorを付けたものを移動させてみる
こんなん。

  if (Input.GetKey(KeyCode.LeftArrow))
  {
      var p = this.transform.position;
      p.x += MOVE_VALUE * Time.deltaTime;
      this.transform.position = p;
  }
  else if(Input.GetKey(KeyCode.RightArrow))
  {
      var p = this.transform.position;
      p.x -= MOVE_VALUE * Time.deltaTime;
      this.transform.position = p;
  }

f:id:ghoul_life:20170526151032g:plain

おお、問題なく動くぞ!(当たり前)

回転させてみる

無茶な傾きではどうか

f:id:ghoul_life:20170526151147g:plain

これも問題なし!
Unity最高だな

拡大させてみる

問題はここだ。
scale値を2,2,2にしたオブジェクトをAnimationさせたらどうなるのか。

f:id:ghoul_life:20170526152146g:plain

はい、死にました。

scale2なら
2 -> 1.5 -> 2
と動いてほしい。

相対的に設定するには…?

なんかあるはずだ。Unityは馬鹿じゃない。
何かしら方法があるはずだ…!

tsubakit1.hateblo.jp

あったあああ!
これだ!神がいた!こうすればいけるはずだ!

早速設定して実行!

f:id:ghoul_life:20170526152944g:plain


……
………

なんだこれは

BlendingをAditiveに設定すると、初期値からの移動量でアニメーションを行う

つまり、初期値からy:-0.5縮んでくれればいいのだ。
が、結果

0 -> -0.5 -> 0

になってしまった。
何故だ。初期値はtranformの2じゃないのか、一体初期値とはどこにあるんだ。

ガクッ。

結果

他で紹介されているのと同じように親オブジェクトの下でAnimation動かせばいいんだ。
そして、親オブジェクトのtransformをいじれば何ら問題ない。

【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にしっかり分けたのが良かったかもしれない。
ちょっとゲームの遷移についてググって調べてみたり本を読んでみよう。

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

やっときたいこと

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