インターフェースを使って、同じメソッドを呼んだときの処理を変えてみました。
まずインターフェースに変化させるのと元に戻すメソッドを作りました。
using UnityEngine;
public interface IUnstable
{
void Change(RaycastHit hit, Transform player);
void Reverse(RaycastHit hit, Transform player);
}
そして、複数のクラスを作って、それぞれでこのインターフェースを継承します。MonoBehaviourとコンマ区切りで書くだけです。実装を書かないとエラーになりました。
拡大する、移動する、透明になるの3種類のクラスを作りました。
using UnityEngine;
public class Expandable : MonoBehaviour,IUnstable
{
public void Change(RaycastHit hit, Transform player)
{
if (hit.distance < 3f) return;
Vector3 scale = transform.localScale;
scale *= 1.02f;
transform.localScale = scale;
}
public void Reverse(RaycastHit hit, Transform player)
{
Vector3 scale = transform.localScale;
scale *= 0.98f;
transform.localScale = scale;
}
}
using UnityEngine;
public class Dynamic : MonoBehaviour, IUnstable
{
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
public void Change(RaycastHit hit, Transform player)
{
rb.AddForceAtPosition((hit.point - player.position) * 0.05f, hit.point, ForceMode.Impulse);
}
public void Reverse(RaycastHit hit, Transform player)
{
rb.AddForceAtPosition((player.position - hit.point) * 0.05f, hit.point, ForceMode.Impulse);
}
}
using UnityEngine;
public class Transparent : MonoBehaviour, IUnstable
{
MeshRenderer meshRenderer;
void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
}
public void Change(RaycastHit hit, Transform player)
{
Color color = meshRenderer.material.GetColor("_BaseColor");
color.a -= 0.02f;
if (color.a <= 0) color.a = 0f;
meshRenderer.material.SetColor("_BaseColor", color);
}
public void Reverse(RaycastHit hit, Transform player)
{
Color color = meshRenderer.material.GetColor("_BaseColor");
color.a += 0.02f;
if (color.a >= 1) color.a = 1f;
meshRenderer.material.SetColor("_BaseColor", color);
}
}
引数に無駄が多くなりました。
プレイヤーのカメラのスクリプトでは、前にレイを飛ばしてCubeに当たったときにマウスの左右クリックで上のメソッドを呼びます。スクリプトを取得する時にインターフェース名を使えます。
using UnityEngine;
using UnityEngine.UI;
public class PlayerCamera : MonoBehaviour
{
[SerializeField] Text text;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
text.text = "";
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, Mathf.Infinity, ~(1 << 9)))
{
if (hit.collider.tag == "Cube")
{
text.text = "Hit";
if (Input.GetMouseButton(0))
{
var cubeScript = hit.collider.GetComponent<IUnstable>();
if (cubeScript != null)
{
cubeScript.Change(hit, transform);
}
}
else if (Input.GetMouseButton(1))
{
var cubeScript = hit.collider.GetComponent<IUnstable>();
if (cubeScript != null)
{
cubeScript.Reverse(hit, transform);
}
}
}
}
}
}
これで同じメソッドを呼ぶだけで簡単に処理を変えられました。