今までは同じメッシュのオブジェクトに別のコンポーネントやタグなどが付いていた場合に、それをプレハブ化しておいて、置き換えるようにしていましたが、同じオブジェクトにコンポーネント等を追加、削除するようにしてみました。
もとのテレビはメッシュとマテリアル、Box Colliderが付いたシンプルなものです。
これにスクリプトを付けると、Startメソッドでオーディオソースなどのコンポーネントが付けられて、テレビを付けるメソッドで再生されるようにしました。
using UnityEngine;
using UnityEngine.Video;
public class TV1 : MonoBehaviour
{
AudioSource audioSource;
MeshRenderer meshRenderer;
Texture defaultTexture;
VideoPlayer videoPlayer;
TV1Assets tv1Assets;
Light pointLight;
bool isOn;
public bool GetIsOn()
{
return isOn;
}
// Start is called before the first frame update
void Start()
{
tv1Assets = Instantiate(ItemManager.GetInstance().GetItem("TV1Assets").GetPrefab()).GetComponent<TV1Assets>();
meshRenderer = gameObject.GetComponent<MeshRenderer>();
// VideoPlayerを追加
videoPlayer = gameObject.AddComponent<VideoPlayer>();
videoPlayer.playOnAwake = false;
videoPlayer.isLooping = true;
videoPlayer.renderMode = VideoRenderMode.RenderTexture;
videoPlayer.audioOutputMode = VideoAudioOutputMode.None;
videoPlayer.clip = tv1Assets.GetVideoClip();
videoPlayer.Prepare();
// オーディオソースを追加
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.volume = 0.5f;
audioSource.spatialBlend = 0.9f;
audioSource.playOnAwake = false;
audioSource.loop = false;
audioSource.clip = tv1Assets.GetAudioClip();
// ポイントライトを作る
GameObject g = new GameObject();
g.transform.position = transform.position - transform.forward * 0.8f;
pointLight = g.AddComponent<Light>();
pointLight.type = LightType.Point;
pointLight.intensity = 15f;
pointLight.range = 40f;
pointLight.enabled = false;
pointLight.shadows = LightShadows.Soft;
}
public void TVON()
{
isOn = true;
// ライトをオン
pointLight.enabled = true;
// 音を再生
audioSource.Play();
// 画面を光らせる
Material mat = meshRenderer.materials[1];
mat.SetColor("_EmissiveColor", new Color(0.1f, 0.1f, 0.1f));
mat.SetFloat("_EmissiveIntensity", 0.1f);
defaultTexture = mat.GetTexture("_BaseColorMap");
// 画面に動画を再生
RenderTexture rt = new RenderTexture(256, 256, 24, RenderTextureFormat.ARGB32);
videoPlayer.targetTexture = rt;
mat.SetTexture("_BaseColorMap", rt);
videoPlayer.Play();
}
public void TVOFF()
{
isOn = false;
// 画面の色を戻す
Material mat = meshRenderer.materials[1];
mat.SetColor("_EmissiveColor", Color.black);
mat.SetFloat("_EmissiveIntensity", 0f);
mat.SetTexture("_BaseColorMap", defaultTexture);
audioSource.Stop();
// 追加したライトやコンポーネントを削除
Destroy(audioSource);
Destroy(videoPlayer);
Destroy(this);
Destroy(tv1Assets.gameObject);
Destroy(pointLight.gameObject);
}
}
オーディオクリップやビデオクリップは、それを持っておくクラスを作って、プレハブ化して置きました。
using UnityEngine;
using UnityEngine.Video;
public class TV1Assets : MonoBehaviour
{
[SerializeField] VideoClip videoClip;
public VideoClip GetVideoClip()
{
return videoClip;
}
[SerializeField] AudioClip audioClip;
public AudioClip GetAudioClip()
{
return audioClip;
}
}
テレビを消すメソッドを呼ぶと、このスクリプトを含むコンポーネントやライトが削除されて、元の状態に戻ります。
テレビはアタッチしておいたり、タグや名前で検索できます。
// アタッチする
[SerializeField] GameObject tv1;
// ---
// タグや名前から探す
foreach (var g in GameObject.FindGameObjectsWithTag("Props"))
{
if (g.name == "TV1")
{
tv1 = g;
break;
}
}
// ---
if (Input.GetKeyDown(KeyCode.Alpha1))
{
tv1.AddComponent<TV1>();
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
TV1 t = tv1.GetComponent<TV1>();
if (t.GetIsOn())
{
tv1.GetComponent<TV1>().TVOFF();
}
else {
tv1.GetComponent<TV1>().TVON();
}
}
変更を加えたいものが複数あるときは、同じメソッドの引数にオブジェクトを渡して、名前やインデックスなどで場合分けしたりすると便利です。