//tips
//一人称視点に足を追加する
MeMyselfEyeの子要素に頭と体を設ける。頭の部分にカメラ、体の部分に足を組み込む。
一人称になるようにカメラの座標も調整し直し、足の画像をプロジェクトにインポートする。
インポート画像を新規作成したマテリアルのalbedoの画像として選択することで、足画像のマテリアルが作成される。オブジェクトに画像を上書きできる点やUIをわざわざ使用しなくても作成できる点がいいところ。
Planeもquadオブジェクトも平面のオブジェクトとして使用されるが、
Planeは、XZ平面に広がるオブジェクトで、それぞれUnity世界で10単位の長さを持つ。床として使用するのに最適なオブジェクト。
Quadは、XY平面を向いており、大きさはUnity世界で1単位となっている。
双方とも、Mesh Colliderがアタッチされており、裏側からカメラを映されても描画されない。
歩いている方向に爪先を向けたいのでMeMyselfEyeにスクリプトを付加する。
体はy軸のみで回転させたいので頭の角度に合わせて、足も設定するようにしている。そのためMeMyselfEyeに一緒にアタッチされているHeadLookWalkのスクリプトを参照し、動作を許可するisWalkingと連動して、頭だけではなく、体の動きも一緒にさせるようにしている。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BodyWalk : MonoBehaviour
{
private HeadLookWalk lookWalk;
private Transform head;
private Transform body;
void Start()
{
lookWalk = GetComponent<HeadLookWalk>();
head = Camera.main.transform;
body = transform.Find("MeBody");
}
void Update()
{
if (lookWalk.isWalking)
{
body.transform.rotation = Quaternion.Euler(new Vector3(0.0f, head.transform.eulerAngles.y, 0.0f));
}
}
}
歩いている際に足音も出すことができ、Audio Sourceコンポーネントをアタッチし、足音のclipを選択、play on awakeのチェックを外し、loopにチェックを入れる。
スクリプトはBodyWalkを編集する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BodyWalk : MonoBehaviour
{
private HeadLookWalk lookWalk;
private AudioSource footsteps;
private Transform head;
private Transform body;
void Start()
{
lookWalk = GetComponent<HeadLookWalk>();
footsteps = GetComponent<AudioSource>();
head = Camera.main.transform;
body = transform.Find("MeBody");
}
void Update()
{
if (lookWalk.isWalking)
{
body.transform.rotation = Quaternion.Euler(new Vector3(0.0f, head.transform.eulerAngles.y, 0.0f));
if (!footsteps.isPlaying)
{
footsteps.Play();
}
}
else
{
footsteps.Stop();
}
}
}
//物理法則でボールを操る
Staticのチェックを外し、球にrigidbodyを加えて操作する。
physics materialを作成し、bounciness を1に設定。materialをオブジェクトにアタッチする。
これで弾むボールは作成できるが、ボールの弾む高さを一定に保ちたい場合は、マテリアルのインスペクターパネルのBounce CombineをMximumに変えることで維持することができる。
Bouncinessで弾みの減少具合を決めることができるので、少しづつ弾む高さを減りたい場合は1から少しづつ下げると良い。
Bouncyballをprefab化して、大量生成をスクリプトで行うようにする。0.5秒のインターバルで新しいボールが生成される仕組みにした。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallsFromHeaven : MonoBehaviour
{
public GameObject ball;
public float startHeight = 10f;
public float fireInterval = 0.5f;
private float nextBallTime = 0.0f;
void Update()
{
if(Time.time > nextBallTime)
{
nextBallTime = Time.time + fireInterval;
Vector3 position = new Vector3( Random.Range(-4.0f,4.0f),startHeight, Random.Range(-4.0f,4.0f));
Instantiate(ball, position, Quaternion.identity);
}
}
}
同時に対象外となったボールを削除するスクリプトを作成する。BouncyBall prefabに対象外ボールの削除スクリプトをアタッチする。
オブジェクトのy座標が地面を下回るときにオブジェクトを削除する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroySelf : MonoBehaviour
{
void Update()
{
if(transform.position.y < -5f)
{
Destroy(gameObject);
}
}
}
//ボールをヘディングする
今度は落ちてくる球をヘディングする。球は一つにし、cameraオブジェクトにbox colliderをアタッチして、接触判定をつける。
新しいボールをbox上に生成し、Quaternationで回転はなくす。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallGame : MonoBehaviour
{
public GameObject ball;
public float startHeight = 10f;
public float fireInterval = 5f;
private float nextBallTime = 0.0f;
private GameObject activeBall;
private Transform head;
private AudioSource audio;
void Start()
{
head = Camera.main.transform;
audio = GetComponent<AudioSource>();
}
void Update()
{
if(Time.time > nextBallTime)
{
nextBallTime = Time.time + fireInterval;
audio.Play();
Vector3 position = new Vector3(head.position.x, startHeight, head.position.z + 0.2f);
activeBall = Instantiate(ball, position, Quaternion.identity) as GameObject;
}
}
}
MeMyselfオブジェクトにもキーボード操作可能にするスクリプトも添付した。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyObject : MonoBehaviour
{
void Update()
{
// 左に移動
if (Input.GetKey(KeyCode.LeftArrow))
{
this.transform.Translate(-0.1f, 0.0f, 0.0f);
}
// 右に移動
if (Input.GetKey(KeyCode.RightArrow))
{
this.transform.Translate(0.1f, 0.0f, 0.0f);
}
// 前に移動
if (Input.GetKey(KeyCode.UpArrow))
{
this.transform.Translate(0.0f, 0.0f, 0.1f);
}
// 後ろに移動
if (Input.GetKey(KeyCode.DownArrow))
{
this.transform.Translate(0.0f, 0.0f, -0.1f);
}
}
}
//メッシュコライダーについて
メッシュは一枚の多角形の面であるポリゴンが複数集まることで構成されるもので、それに基づいたメッシュコライダーは、オブジェクトの形に沿った細かい判定が行えるコライダーとなり、厳密な当たり判定が可能となる。
サーフェスとメッシュの違いは、面が1つであるかどうかで、サーフェスの場合、面が1つで1つの形を作るのに対し、メッシュはポリゴンが集まって1つの形を作っている。
ただし、描画に必要な負荷が大きいので、そこまで厳密な当たり判定が必要でない場合は出来合いのcolliderを組み合わせたものを使う場合が多いよう。
https://squmarigames.com/2018/11/24/unity-begginner-collider-type/#toc5
https://docs.unity3d.com/ja/2018.4/Manual/class-MeshCollider.html
https://matcha-choco010.net/2018/08/25/unity-mesh-from-script/
このメッシュを画像として表示するためには、メッシュの上に画像を貼っていく必要があり、その画像テクスチャの貼り付けかたはUV、座標(u,v)という指標で表される。
UV展開と言われるそれは、3Dのメッシュを2Dの画像として押し潰した展開図と言える。
uv座標とは、テクスチャ上の点の位置を表すための座標で、これにより、画像のどの点が3Dメッシュのどの部分に該当するのかという割り当てを行なっている。
四角形展開図の一つの点が、組み立てられた四角形のどこに来るかを確認しているものと考えればわかりやすい。