CSVからのobject設定と三次元空間内移動 〜Unity
無限の情報空間を逍遙する
広大な開架式図書館、のようなDatabaseを目指している。
Databaseというのは、基本、全体像が見えない。
検索したら、ほしい情報はくれるが、
何がどこにどれぐらい保管されているかは、見えない。
閉架式図書館、国立国会図書館みたいなもの。Wikipediaもそう。
どんな情報がどれぐらいあるのか、全体像は見えない。
そもそも、ふつうの大百科事典、を作るはずだったWikipedia。
今それを全部印刷して、製本したら、どれぐらいの巻数になるのだろう。
Databaseは現実世界の物理的限界を突破できる。
その代償として、全体像、を失った。
それを、バーチャル空間で取り戻したい。
無限に広い図書館。
すべてのDataの時間的、空間的位置関係を一望できる。
その中を歩き回れる。
気に入ったものを手に取って見ることができる。
自分で検索しようとは思いも寄らなかった、未知の情報にも出会う。
この辺の情報が足らないな、ということも見える。
だったらそこにあるべき情報を探してこよう、と思うことができる。
そんな図書館を作る。
三度目の正直で気づいたこと
これまで22年正月、23年正月の二回、Unityを学んで、空間作りに挑戦した。
今回で三回目。
Unityはそもそもゲームを作るプラットフォームだ。
シンプルなtutorialでも、この先複雑になっていく、を前提にしている。
だから、「言われたとおり」やっていると、よぶんな機能がふえていく。
最初は仕方がない。どれが必要で、どれが余分か、わからないから。
そもそもコードも読んでなくて、貼っただけ、写経しただけ。
でもそろそろそこは脱しないといけない。
私はUnityの、ほんとうに限られた機能しか必要としていない。
自分がやりたいことは何か?
そのためにこのコード、この機能、このPackageはほんとうに必要か?
だから今回は、かなり引き算の実装になった。
必要なこと1 一人称視点で三次元空間を無重力に動き回る
まずは広大な図書館を自由に移動する能力が必要。
この図書館は水平に広いだけでなく、垂直にも広い。
なんせ、一番下はBIGBANG、最上階は「今」だから。
階段は上らない、飛びましょう、これが私の子どもの時からの夢(笑)
一人称視点で空間を見る方法
Unityの世界を見ているのはCamera。
なので、カメラを内蔵した私、をつくる。
つまり、私になる3D object、例えばCapsuleの下に、Cameraを入れてしまう。
それだけ。
無重力で動き回る方法
実体として動くのだから物理演算は使う。つまり Rigidbody をつける。
でも重力は感じない。なので Use Gravityのチェックを外す。
そして動きの速さや入力Keyを指定するScriptを書いてattachする。
以前、自分でつくった空間をまともに移動できなかった経験から
今回は「とんぼ返り型Rotation」つまりz軸を基準にした動きはつけなかった。
もう一つ、いったん動き始めると制御が効かない
つまり慣性の法則に従って等速運動しつづける、を防止するために
Keyを離したら止まる、ブレーキをつけた。
それでも以前より、ずっと簡単になっている。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour
{
private Rigidbody rb;
private float moveSpeed = 10f;
private float rotationSpeed = 1f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
//player移動の処理
//前に進む
if (Input.GetKey(KeyCode.E)) {
rb.AddForce(transform.forward * moveSpeed);
}
//後ろに進む
if (Input.GetKey(KeyCode.T)) {
rb.AddForce(-transform.forward * moveSpeed);
}
//右に進む
if (Input.GetKey(KeyCode.G)) {
rb.AddForce(transform.right * moveSpeed);
}
//左に進む
if (Input.GetKey(KeyCode.D)) {
rb.AddForce(-transform.right * moveSpeed);
}
//上に進む
if (Input.GetKey(KeyCode.R)) {
rb.AddForce(transform.up * moveSpeed);
}
//下に進む
if (Input.GetKey(KeyCode.F)) {
rb.AddForce(-transform.up * moveSpeed);
}
//上を向く
if (Input.GetKey(KeyCode.U)) {
transform.Rotate(-rotationSpeed, 0, 0);
}
//下を向く
if (Input.GetKey(KeyCode.J)) {
transform.Rotate(rotationSpeed, 0, 0);
}
//右を向く
if (Input.GetKey(KeyCode.K)) {
transform.Rotate(0, rotationSpeed, 0);
}
//左を向く
if (Input.GetKey(KeyCode.H)) {
transform.Rotate(0, -rotationSpeed, 0);
}
}
private void Update()
{
if (Input.GetKeyUp(KeyCode.E) ||
Input.GetKeyUp(KeyCode.R) ||
Input.GetKeyUp(KeyCode.T) ||
Input.GetKeyUp(KeyCode.D) ||
Input.GetKeyUp(KeyCode.F) ||
Input.GetKeyUp(KeyCode.G))
{
rb.velocity = Vector3.zero;
}
}
}
必要なこと2 データに応じて情報を配置する
図書館に並べる本、それをDatabaseに応じて生成する。
最終的にはデータベースの検索結果をリアルタイムで表示したいが、
今回はそこまで狙わない。CSVを読み込んで、表示するだけ。
本棚は要らない。無重力だから、本は指定した場所に浮いていてくれる。
動きも要らない。クリックしたら内容が表示される。
たった一つの「元になる」pointer
そのDataの位置に配置されるpointerをProBuilderで作った。
方法は別の記事に書いた。
これに「マウスが載ったら内容を表示する」Text、pop-upをつけた。
pop-upの付いたpointerをAssetsに引っぱることで、プレハブの種になる。
pop-upにScriptをattach
CSVから読み込んだDataをセットする、マウスを検知したら表示する。
実はDataからはname以外のデータも読んでいるが、
今のところnameだけを表示する設定にしている。
これはデザイン上の今後の課題。
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class PopUp : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public TextMesh text;
private string displayText = "";
// SetDataメソッドをpublicで追加
public void SetData(string data)
{
displayText = data;
}
public void OnPointerEnter(PointerEventData eventData)
{
text.text = $"{name} ";
print($" {name} ");
}
public void OnPointerExit(PointerEventData eventData)
{
text.text = $" ";
print($" ");
}
}
もう一つ、どちら側からDataに近づいても、表示がこちら向きに出るためのScript。
これをpop-upにattach。
using UnityEngine;
using System.Collections;
public class EnFace : MonoBehaviour
{
void Start()
{
transform.localScale = new Vector3(-1, 1, 1);
}
void Update()
{
transform.LookAt(Camera.main.transform);
}
}
CSVを読み込む
空のobjectを作って読み込みのScriptをattachする。
pointerをプレハブの種に指定する。
Assets/Resourcesに置いたCSVを読むのはこちら。
この方法は非推奨、と書いてある記事もあるが、
このままずっと行くわけではないので、とりあえず構わない。
using UnityEngine;
using System.Collections.Generic;
using System.IO;
public class CSVImporter : MonoBehaviour
{
public GameObject pointerPrefab; // プレハブを指定
public string fileName = "WithMap-csv"; // CSVファイル名
void Start()
{
// CSVファイルを読み込み、行ごとに分割する
TextAsset csvData = Resources.Load<TextAsset>(fileName);
string[] lines = csvData.text.Split('\n');
for (int i = 1; i < lines.Length; i++)
{
string[] parts = lines[i].Split(',');
if(parts.Length < 7) continue; // フィールドが足りない行は無視
string date = parts[0];
string name = parts[1];
string country = parts[2];
string city = parts[3];
float x = float.Parse(parts[4]);
float y = float.Parse(parts[5]);
float z = float.Parse(parts[6]);
// オブジェクトを生成し、位置とテキストを設定
GameObject cityObject = Instantiate(pointerPrefab, new Vector3(x, y, z), Quaternion.identity);
cityObject.name = name;
PopUp popUpComponent = cityObject.GetComponent<PopUp>();
if(popUpComponent != null)
{
popUpComponent.SetData($"{date}, {name}, {country}, {city}");
}
}
}
}
諸々つなぎ合わせる
Hierarchy→UI→EventSystemをつくる。
マウスの検知などをするらしい。
InputModuleの部分の設定が、記事の時期によって違う。
私の状況では、「作っただけ」でちゃんと役立っている。
大言壮語しておいて残念なところ
空間は広大だが、資料が少ない
なんせ、CSVには50項目しか入っていない。
どこまでも空の本棚だけがある図書館みたいなものだ。
まず見つけるのが大変。
広大さを宇宙空間で表したせいで・・・
背景にある星屑とDataのpointerの区別が付かない。
チラチラ瞬いているのがData、動かないのは背景画像、みたいな。
よっぽど近づくまで、なんだかわからない。
表示が粗い
これが一番の難点。もっとすっきり文字が読めるようにしないと。
先は長い。でも、それが楽しい
ともかくいったん動画を撮ってみよう。
日々の歩みを支えてくれるのは
Discussion