Unity2019.2.2f1
Windows10
□
【UnityC#講座】3D人型モデルを三人称視点で動かす操作を改良
【UnityC#講座】ユニティちゃんに殴り合いをさせる【NavMeshAgent】
またこれらの記事の続きです。
今回はユニティちゃんアセットに入っているボイスを使ってみます。
攻撃とダメージを受ける時に声が出るようにしました。
完成したのがこの動画です。
ユニティちゃんのボイス使ってみました。
攻撃とダメージ時に言います。
しかしUnityRecorder録画中に音声出ないは何でだろう?#unity pic.twitter.com/Xo9OEbyH2c— イシゲー@UnityとBlender (@ishidahanta) November 22, 2019
■SEオブジェクトとSEスクリプトを作る
まず空のオブジェクトを出しSEと名付けます。
SEはSound Effectの略でボイスを扱うにはふさわしくないかもしれませんが、ボイスとSEのUnity上での扱いは変わらないので良しとしましょう。
次にSEスクリプトを作ります。
C#ファイルの名前をこちらもSEにしてください。
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
//オブジェクトにAudioSourceコンポーネントを追加 | |
[RequireComponent(typeof(AudioSource))] | |
public class SE : MonoBehaviour | |
{ | |
//音声ファイルを入れる | |
public AudioClip[] sound; | |
//AudioSourceコンポーネントを入れる変数 | |
AudioSource audioSource; | |
void Start() | |
{ | |
//AudioSourceコンポーネントを取得 | |
audioSource = GetComponent<AudioSource>(); | |
} | |
public void AttackSound() | |
{ | |
//音声を鳴らす | |
audioSource.PlayOneShot(sound[0]); | |
} | |
public void DamageSound() | |
{ | |
audioSource.PlayOneShot(sound[1]); | |
} | |
} |
AudioSourceコンポーネントを追加・取得し、PlayOneShot()で鳴らします。
攻撃時にはAttackSound()メソッドを、ダメージ時にはDamageSound()メソッドを他のスクリプトから呼び出します。
Player、Opponentスクリプトに直接書いても良いのですが、手間を減らすためにこうしました。
続いて、SEスクリプトをSEオブジェクトにアタッチしたらInspectorから設定をします。
Soundに2と入れてインター押すと空欄が2つでき、そこに使う音声を入れます。
Element 0にuniv0001を、Element 1にuniv0012を入れてください。
ボイスの在り処はこちらです。
Project > Assets > unity-chan! > unity-chan!Model > Audio > Voice
■Player、Opponentスクリプトに追加する
次はPlayer、OpponentスクリプトにSEを呼び出す記述を追加します。
変数を宣言し、Start()でオブジェクトとスクリプトを取得、そして後は攻撃、ダメージ時に一度だけ呼び出される部分からSEスクリプトのメソッドを呼び出してやるだけで完成です。
Action.AttackとAction.Damageの時に呼ぶ条件にすると音声が連続して出てしまうので注意してください。
Player.cs
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[RequireComponent(typeof(CapsuleCollider))] | |
[RequireComponent(typeof(Rigidbody))] | |
public class Player : MonoBehaviour | |
{ | |
[SerializeField] float speed = 4f; | |
private Animator animator; | |
Transform cam; | |
Rigidbody rb; | |
CapsuleCollider caps; | |
enum Action | |
{ | |
Move, | |
Attack, | |
Damage | |
} | |
[SerializeField] Action action = Action.Move; | |
[SerializeField]GameObject attackObj; | |
//SEオブジェクトを入れる | |
GameObject seObj; | |
//SEスクリプトを入れる | |
SE seScr; | |
void Start() | |
{ | |
animator = GetComponent<Animator>(); | |
rb = GetComponent<Rigidbody>(); | |
rb.constraints = RigidbodyConstraints.FreezeRotation; | |
cam = Camera.main.transform; | |
caps = GetComponent<CapsuleCollider>(); | |
caps.center = new Vector3(0, 0.76f, 0); | |
caps.radius = 0.23f; | |
caps.height = 1.6f; | |
attackObj.SetActive(false); | |
//SEオブジェクトを取得 | |
seObj = GameObject.Find("SE"); | |
//SEスクリプトを取得 | |
seScr = seObj.GetComponent<SE>(); | |
} | |
void Update() | |
{ | |
if (action == Action.Move) | |
{ | |
float x = Input.GetAxisRaw("Horizontal") * Time.deltaTime * speed; | |
float z = Input.GetAxisRaw("Vertical") * Time.deltaTime * speed; | |
animator.SetFloat("X", x * 50); | |
animator.SetFloat("Y", z * 50); | |
if (z > 0) | |
{ | |
transform.rotation = Quaternion.Euler(new Vector3(transform.rotation.x, | |
cam.eulerAngles.y, transform.rotation.z)); | |
} | |
else if (z < 0) | |
{ | |
z = z / 1.5f; | |
} | |
transform.position += transform.forward * z + transform.right * x; | |
if (Input.GetMouseButtonDown(0)) | |
{ | |
action = Action.Attack; | |
//SEスクリプトのAttackSound()を呼ぶ | |
seScr.AttackSound(); | |
} | |
} | |
else if (action == Action.Attack) | |
{ | |
animator.SetBool("Attack", true); | |
attackObj.SetActive(true); | |
} | |
else if (action == Action.Damage) | |
{ | |
animator.SetBool("Damage", true); | |
} | |
} | |
private void OnTriggerEnter(Collider other) | |
{ | |
if (other.gameObject.tag == "EnemyAttack") | |
{ | |
if (action == Action.Damage) | |
{ | |
return; | |
} | |
else | |
{ | |
action = Action.Damage; | |
//SEスクリプトのDamageSound()を呼ぶ | |
seScr.DamageSound(); | |
} | |
} | |
} | |
public void AttackEnd() | |
{ | |
Invoke("AttackEndAnim", 0.5f); | |
} | |
void AttackEndAnim() | |
{ | |
action = Action.Move; | |
animator.SetBool("Attack", false); | |
attackObj.SetActive(false); | |
} | |
void DamageEnd() | |
{ | |
action = Action.Move; | |
animator.SetBool("Damage", false); | |
} | |
} |
スポンサーリンク
Opponent.cs
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.AI; | |
[RequireComponent(typeof(CapsuleCollider))] | |
[RequireComponent(typeof(Rigidbody))] | |
[RequireComponent(typeof(NavMeshAgent))] | |
public class Opponent : MonoBehaviour | |
{ | |
private NavMeshAgent agent; | |
private Vector3 startPoint; | |
Rigidbody rb; | |
CapsuleCollider caps; | |
private Animator animator; | |
GameObject player; | |
[SerializeField] float time; | |
[SerializeField] float chaseTime = 5.0f; | |
[SerializeField] float attackTime = 0.5f; | |
[SerializeField] float chaseSpeed = 3.5f; | |
[SerializeField] float returnSpeed = 1.0f; | |
enum Action | |
{ | |
Wait, | |
Attack, | |
Chase, | |
Damage, | |
Return | |
} | |
[SerializeField] Action action = Action.Wait; | |
public GameObject attackJudgment; | |
//SEオブジェクトを入れる | |
GameObject seObj; | |
//SEスクリプトを入れる | |
SE seScr; | |
void Start() | |
{ | |
animator = GetComponent<Animator>(); | |
rb = GetComponent<Rigidbody>(); | |
rb.constraints = RigidbodyConstraints.FreezeRotation; | |
caps = GetComponent<CapsuleCollider>(); | |
caps.center = new Vector3(0, 0.8f, 0); | |
caps.radius = 0.23f; | |
caps.height = 1.6f; | |
agent = GetComponent<NavMeshAgent>(); | |
agent.autoBraking = false; | |
startPoint = transform.position; | |
player = GameObject.FindGameObjectWithTag("Player"); | |
attackJudgment.SetActive(false); | |
//SEオブジェクトを取得 | |
seObj = GameObject.Find("SE"); | |
//SEスクリプトを取得 | |
seScr = seObj.GetComponent<SE>(); | |
} | |
void Update() | |
{ | |
if (action == Action.Wait) | |
{ | |
agent.isStopped = true; | |
animator.SetFloat("Y", agent.velocity.sqrMagnitude); | |
} | |
else if (action == Action.Chase) | |
{ | |
agent.isStopped = false; | |
agent.destination = player.transform.position; | |
agent.speed = chaseSpeed; | |
animator.SetFloat("Y", agent.velocity.sqrMagnitude); | |
time += Time.deltaTime; | |
if (time > chaseTime) | |
{ | |
action = Action.Return; | |
time = 0; | |
} | |
} | |
else if (action == Action.Attack) | |
{ | |
animator.SetBool("Attack", true); | |
agent.speed = 0; | |
attackJudgment.SetActive(true); | |
} | |
else if (action == Action.Damage) | |
{ | |
animator.SetBool("Damage", true); | |
agent.speed = 0; | |
} | |
else if (action == Action.Return) | |
{ | |
animator.SetFloat("Y", agent.velocity.sqrMagnitude); | |
agent.speed = returnSpeed; | |
agent.destination = startPoint; | |
if (!agent.pathPending && agent.remainingDistance < 0.1f) | |
{ | |
action = Action.Wait; | |
} | |
} | |
} | |
private void OnTriggerEnter(Collider other) | |
{ | |
if (other.gameObject.tag == "PlayerAttack") | |
{ | |
if (action == Action.Damage) | |
{ | |
return; | |
} | |
else | |
{ | |
action = Action.Damage; | |
//SEスクリプトのDamageSound()を呼ぶ | |
seScr.DamageSound(); | |
} | |
} | |
} | |
private void OnCollisionEnter(UnityEngine.Collision collision) | |
{ | |
if (collision.gameObject.tag == "Player" && action == Action.Chase) | |
{ | |
action = Action.Attack; | |
//SEスクリプトのAttackSound()を呼ぶ | |
seScr.AttackSound(); | |
} | |
} | |
void DamageEnd() | |
{ | |
animator.SetBool("Damage", false); | |
action = Action.Chase; | |
} | |
void AttackEnd() | |
{ | |
Invoke("AttackEndAnim", attackTime); | |
} | |
void AttackEndAnim() | |
{ | |
animator.SetBool("Attack", false); | |
attackJudgment.SetActive(false); | |
action = Action.Chase; | |
} | |
} |
これでボイスが出るようになったはずですがちゃんと出たでしょうか?
今回はこれで終わりです。
■関連記事
【UnityC#講座】ユニティちゃんをスカイリム風に操作する
この作品はユニティちゃんライセンス条項の元に提供されています
スポンサーリンク