Unityのゲーム開発で、こんなコマンドルーレットを作ろうとしたのですが、ネットサーフィンしてもそれっぽいやつが見つかりませんでした。
結局自作したので、個人的な備忘録として、また同じ悩みを持った誰かの一助になるものとして、作り方をネット空間に残しておこうと思います。
結局自作したので、個人的な備忘録として、また同じ悩みを持った誰かの一助になるものとして、作り方をネット空間に残しておこうと思います。
なお、"Unity2D"とタグつけてますし、特に3Dにする理由もなかったので私は2Dで作成しましたが、コマンドルーレット自体は3Dだろうが2Dだろうが使えるUIなので安心してください。
目次
実行環境について
Unityバージョン:2019.4.18f1
Visual Studio Community 2019バージョン:16.9.1
UIの配置
①Hierarchy(ヒエラルキー)の"+"からUI→Canvasと進みCanvasを設置
シーン画面で編集しやすいように、Canvasを全て画面に収まるように調整だとか、Render Mode弄ってカメラの範囲にCanvasがおさまるように調整だとか、その辺お好みで。
②Canvasの下に、空オブジェクト一つ作成
空オブジェクト(以下、空オブ)のInspector(インスペクター)いって、Rect Transformのコンポーネントでサイズ調整とかは各自。(私は下の画像の通りにしましたが、たぶん皆さんと画面比全然違うので参考にならないんじゃないでしょうか…)
③空オブに"Vertical Layout Group(垂直レイアウトグループ)"のコンポーネントを追加
空オブのインスペクター一番下の"Add Component"から、"Vertical Layout Group"を検索、追加。
"Vertical Layout Group"は垂直に均等にオブジェクトを並べてくれるコンポーネント。皆さんが作りたいルーレットのコマンド数が、私と同じ7個とは限らないわけですが、これさえあればその下に何個オブジェクトつけても均等に配置してくれるので、その辺の問題を解決してくれて便利。
写真のように設定して、次は一つ一つのコマンドに当たるUIを作っていきます。
④空オブの下に、Image、さらにその下にTextのUI作成
このTextにコマンドを記入する感じですね。Imageは特に何もしなくていいですが、TextのRect Transformは下画像みたいに弄って、親オブジェクトとサイズ一致させておいてください。
…さきほど、「Imageは特に何もしなくていい」と書いた直後に恐縮ですが、ここで一工夫、Imageのソース画像に適当なフリー素材を入れると見映えがよくなったり。
私のはこんな感じ。
下記のサイトから借りてきました!クレジット代わりにリンクを貼っておきます。
⑤Imageを好きなだけ複製
見映えもよくなったコマンドが完成したら、あとは増産するだけ。
Imageにカーソル合わせてマウス右クリック、Duplicate(複製)を、お求めの数だけしてください。
③でも説明しましたが、どれだけ増産しても勝手にサイズ調整されるはず。
これでUIの準備は完了です。
スクリプト作成
ProjectのAssetsで右クリック、create(作成する)からC#scriptへ、というおなじみの流れはもう省略しますが、いよいよスクリプトです。
難しいスクリプトではありませんが、基本的にはこんな感じでしょうか。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; //UI弄るときに必須
public class RoulettEasy : MonoBehaviour
{
[SerializeField] Image[] commandlist;
private float countTime;
private int lastTime;
private float speed = 10;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
countTime += Time.deltaTime * speed;
if (countTime > commandlist.Length)
{
countTime = 0f;
}
if (lastTime != (int)countTime)
{
foreach (var command in commandlist)
{
command.color = new Color(1, 1, 1);
}
lastTime = (int)countTime;
commandlist[(int)countTime].color = new Color(1, 0, 0);
}
if (Input.GetKeyDown(KeyCode.Space))
{
speed = 0;
}
}
}
ちょこちょこ説明いれてますが、だいたいこんな感じですね。
あとはこのスクリプトを空オブにアタッチして、インスペクターから[SerializeField]の事項を登録するだけですね。
私の場合、コマンドが7個の設定だったので、こんな感じ。
実際に動かしたら、ちゃんとルーレット動くと思います。
Spaceキー押したら止まるはずなので、それも確認してください。
ちょっと記事長くなってるので、一回切ります…。
あとは応用編が続くのですが、もしよかったらお付き合いください…。
(公開直後確認更新:なぜ「追記に挿入」してるのに一回切れないんだ…)
【応用その①】他スクリプトにアクセスしやすく改造
さて、では続きです。
一応の完成を見たコマンドルーレット。この子は特性上、ルーレットで得た情報が次の行動につながるというようなシチュエーションで使うことが多いのではないでしょうか。
すなわち、他のスクリプトへ情報を送るのが前提での使用が予想されます。ということで、お節介やもしれませんが少しだけ、他スクリプトへアクセスしやすいように付け足しておきます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RoulettEasy : MonoBehaviour
{
[SerializeField] Image[] commandlist;
private float countTime;
private int lastTime;
private float speed = 10;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
countTime += Time.deltaTime * speed;
if (countTime > commandlist.Length)
{
countTime = 0f;
}
if (lastTime != (int)countTime)
{
foreach (var command in commandlist)
{
command.color = new Color(1, 1, 1);
}
lastTime = (int)countTime;
commandlist[(int)countTime].color = new Color(1, 0, 0);
}
if (Input.GetKeyDown(KeyCode.Space))
{
speed = 0;
//ここで(int)countTimeを他スクリプトに送信
}
}
public void StartEasyRoulett()
{
speed = 10;
countTime = 0;
}
}
この場合、他スクリプトからコマンドルーレットを開始させる時は、そのスクリプトにこのRoulettEasyスクリプトをアクセスしたうえで([SerializeField]が楽じゃないかな…)、StartEasyRoulett()を呼び出せばいいし。
他スクリプトに結果を流す場合は、このスクリプトに目的のスクリプトをアクセスしたうえで(int)countTimeを送るプログラムを書けばいいと。
まぁこんな感じですね~。
【応用その②】はらはらドキドキ(?)コマンドルーレット
そもそも、これを説明するのが凄く難しい…。
ということで、こちらをご覧ください!
…私が青春の時間を捧げた思い出深いゲームですが…。
こういう感じで、押したらすぐ止まるのではなく、少々間があって(しかもその間がランダム)止まる、みたいなルーレットを作ってみたいと思います。
…これ、誰かの参考になるんでしょうかね…?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RoulettControll : MonoBehaviour
{
[SerializeField] Image[] commandlist;
private float countTime;
private int lastTime;
private float fireTime;
private float speed = 10;
bool isStop = false;
private float lottery;
bool justOnce = true;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//タイマーA
countTime += Time.deltaTime * speed;
if (countTime > commandlist.Length)
{
countTime = 0f;
}
//タイマーB
fireTime += Time.deltaTime;
if (lastTime != (int)countTime)
{
fireTime = 0f;
foreach (var command in commandlist)
{
command.color = new Color(1, 1, 1);
}
lastTime = (int)countTime;
commandlist[(int)countTime].color = new Color(1, 0, 0);
}
if (Input.GetKeyDown(KeyCode.Space))
{
isStop = true;
lottery = Random.Range(990, 997) * 0.001f;
}
if (isStop)
{
speed *= lottery;
}
if (fireTime >= 2.5 && justOnce)
{
fireTime = 0;
justOnce = false;
//(int)countTimeを他スクリプトに送信
}
}
public void startRoulett()
{
isStop = false;
speed = 10;
justOnce = true;
countTime = 0;
fireTime = 0;
}
}
いわゆるタイマーを二つも使うという荒技で困難を為しました…。
私はこちらが真なるコマンドルーレットだと信じているので、スクリプトの名前も変えてますが、土台となるところは同じです。
最後に
ここまで読んでくださり、感謝の至りです…。
最後なんて完全に趣味に走ってましたが、皆さんのお役に立っていたなら幸いです( ´∀` )
0 件のコメント:
コメントを投稿