//tips
//overrideの使い方
派生クラスが基底クラスのメソッドを上書きすることを言い、一部の派生クラスでは異なる処理をさせたいという場合に、このオーバーライドをすることによって、任意の処理に変更することができる。
基底クラスではvirtualキーワードを使って、派生クラスへの書き換え可能という意思表示をする。
派生クラスでは、基底クラスでvirtualキーワードがついているメソッドに対して、overrideキーワードを使って書き換えることが可能。
基底クラスのGetDataメソッドを書き換える例を以下にあげる。
namespace CS27
{
class A1
{
private int _privateValue;
protected int ProtectedValue;
public A1(int value)
{
_privateValue = value;
}
//基底クラス:virtualキーワード
//「書き換えていいですよ」のサイン
public virtual int GetData()
{
return 1;
}
}
}
namespace CS27
{
class A2 : A1
{
public A2(int value) : base(value)
{
base.ProtectedValue = 3;
}
//派生クラスで基底クラスのメソッドを書き換える
//派生クラス:overrideキーワード
//「書き換えますよ」という意味
public override int GetData()
{
return 2;
}
}
}
//Awake()とStart()の違い
StartよりもAwakeの内容の方が先に呼び出される。
オブジェクトがすべて配置される→すべてのAwake()が呼び出される→Start()が呼び出されるという順番になる。
GameObject.FindやGetComponentなどでオブジェクト・コンポーネントを参照することはAwake()内で可能だが、どのスクリプト(オブジェクト)のAwake()が先に呼び出されるかというAwake()どうしの順序はランダムなようなので、他のスクリプトの変数の値を参照したりするのはAwake()ではしない方がいい。
Awakeでは自身に関する初期化処理(パラメータなど)を行う際用いられる。オブジェクトの生成後呼ばれるのでこのタイミングで初期化。
//raycasttargetのオフ作業
UnityのUIボタンが突然反応しなくなった場合、押したいボタンの上にRaycastTargetが有効なオブジェクトが被っているというものがある。
Raycastとは、ある地点から透明な線を特定の方向に引いて、そのRay上のどこかでコライダがあるか検知をするもので、ボタンなどのオブジェクトに接触を行なった場合の当たり判定の実装として使われる。
Physics.Raycast(Vector3 origin(rayの開始地点), Vector3 direction(rayの向き),RaycastHit hitInfo(当たったオブジェクトの情報を格納), float distance(rayの発射距離), int layerMask(レイヤマスクの設定));として表され、origin(rayの開始地点)とdirection(rayの向き)のみ必須情報だが、他の情報は入力しなくても良い。
Hitしたオブジェクトの座標を獲得するためには下記のスクリプトで可能。
ちなみに、下記スクリプト実際やる際にはMainCameraタグがきちんと付加されているかチェックする。
「Camera.main」と書くことでMainCameraタグがついたゲームオブジェクトを検索してCameraコンポーネントを取得することになる。
GameObject.FindWithTag(“MainCamera”).GetComponent<Camera>();
と同じ意味を持つ。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray,out hit,10.0f))
{
Debug.Log(hit.collider.gameObject.transform.position);
}
}
}
//ドラッグの検知について
ドラッグを検知する機能がMonoBehaviorにはないようなのでIBeginDragHandler, IDragHandler, IEndDragHandlerなどのインターフェースを継承して検知を行う。
ドラックが開始したとき呼ばれるpublic void OnBeginDrag(PointerEventData eventData)、ドラック中に呼ばれるpublic void OnDrag(PointerEventData eventData)、ドラックが終了したとき呼ばれるpublic void OnEndDrag(PointerEventData eventData)で下記の検証をする。
using UnityEngine;
using UnityEngine.EventSystems;
public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
// ドラックが開始したとき呼ばれる.
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log(1);
}
// ドラック中に呼ばれる.
public void OnDrag(PointerEventData eventData)
{
Debug.Log(2);
}
// ドラックが終了したとき呼ばれる.
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log(3);
}
}
ちなみにeventsystemのインスペクターdragthresholdでどのくらいの移動でドラッグかという設定が行える。
//Mathf.Atan2の使用
ある点から見てもう一つの点は、何度の位置にあるのかを取得する際にMathf.Atan2を使う。
Atanとは、tan(タンジェント)の逆関数Atan(アークタンジェント)のことを示し、tanX=Yの場合X=AtanYが成り立つ。この際にXは度数であり、Yは値であることからAtanを使うことで度数を求めることができることがわかる。
tan(タンジェント)をもう少し噛み砕くと、ACを底辺とする直角三角形 ABCの頂点A部分のタンジェントは
tanA=BC/AC
であり、中学生の頃は、tanAの値と度数の早見表があればAの度数を知ることができた。この早見表の部分が計算機能に追加されていると考えればわかりやすい。
このBC/ACの数値部分がYとしてAtanに処理されることになる。つまり、tanの値を渡すと角度を返してくれるのがMathf.Atanである。
ただ、Mathf.Atan2に渡すと角度がラジアンで返ってくるので、Mathf.Rad2Degで度に変換する。
度数法では、円周を 360 等分したときの角の大きさを 1° と規定、つまり、円 1 周の角の大きさは 360° 。
一方、弧度法ラジアンでは、円の半径と同じ長さの孤を切り取るときの角の大きさを 1 rad と規定。円 1 周の角の大きさは、半径を , 円周率を π とおくと、2/=2 (rad)
細かい違いは下記参照。
今回はy座標は変えずに、xとzの関係でみたいので下記のスクリプトで位置ごとの角度にして出してみた。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GetAngle1 : MonoBehaviour
{
[SerializeField]
GameObject _start;
[SerializeField]
GameObject _target;
void Update()
{
float angle = GetAngle(_start.transform.position, _target.transform.position);
Debug.Log(angle);
}
float GetAngle(Vector3 start, Vector3 target)
{
Vector3 dt = target - start;
float rad = Mathf.Atan2(dt.z, dt.x);
float degree = rad * Mathf.Rad2Deg;
return degree;
}
}
二体のオブジェクトの座標から距離がわかり、その距離の軸ごとの数値から相対的な角度が割り出せることがわかる。
スティックのコードの分析は障害で出てきたので現在確認中。
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CameraStick : Graphic, IEndDragHandler, IDragHandler, IPointerDownHandler, IPointerUpHandler
{
public Transform padObjectTransform;//位置・回転を保持
private float padMovableRadius = 100;//padの可動範囲
private static Vector2 axis = Vector2.zero;//Vector2(0, 0) と同じ意味
public static float GetAxisHorizontal()
{
Debug.Log(9);
return axis.x;//操作対象にaxis.xを返す
}
public static float GetAxisVertical()
{
Debug.Log(10);
return axis.y;//操作対象にaxis.yを返す
}
protected override void Awake()
{
base.Awake();
Debug.Log(1);
Image padImage = padObjectTransform.GetComponent<Image>();//imageコンポーネントを参照
padImage.raycastTarget = false;//imageコンポーネントのraycasttargetをオフ
raycastTarget = true;//アタッチオブジェクトのraycasttargetはオン
Debug.Log(2);
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log(3);
OnDrag(eventData);//ドラッグ開始された時OnDrag発動
}
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log(7);
OnEndDrag(eventData);//ドラッグ終了時OnEndDrag発動
}
public void OnDrag(PointerEventData eventData)
{
Debug.Log(4);
//CanvasがScreen Space - Overlayの場合のみ//
Vector2 tapPosition = transform.InverseTransformPoint(eventData.position);
//ワールド空間からローカル空間へ position を変換
//タップ位置の半径が指定半径より長かったら修正//
if (Vector3.Distance(Vector3.zero, tapPosition) > padMovableRadius)
{
tapPosition = GetRadiusLimitedPosition(tapPosition, padMovableRadius);
//最大可動域以上ドラッグされたらradiusに対して値を最大可動域のところで止める
Debug.Log(5);
}
SetPadObjectPosition(tapPosition);
}
//指定半径に収めた座標を返す//
private Vector2 GetRadiusLimitedPosition(Vector2 tapPosition, float radius)
{
float radian = Mathf.Atan2(tapPosition.y, tapPosition.x);
// y/x になる角度をラジアンで返す float Atan2 (float y, float x);
Vector2 limitedPosition = Vector2.zero;
limitedPosition.x = radius * Mathf.Cos(radian);
limitedPosition.y = radius * Mathf.Sin(radian);
//limitedPositionを元に最大スティック可動域360度分を表している
return limitedPosition;
}
//JoyStickのPad位置を設定//
public void SetPadObjectPosition(Vector3 position)
{
Debug.Log(6);
padObjectTransform.localPosition = position;//スクリプトのアタッチオブジェクトの座標をpositionとする
axis = new Vector2(
padObjectTransform.localPosition.x / padMovableRadius,
padObjectTransform.localPosition.y / padMovableRadius
);//pad座標変化を操作対象に反映
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log(8);
SetPadObjectPosition(Vector3.zero);//ドラッグ終了時初期地点にpadが戻る
}
}