728x90
MainScene
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace Test2
{
public class Test_PlayerAttackSceneMain : MonoBehaviour
{
[SerializeField]
private Button btnAttack;
[SerializeField]
private HeroController heroController;
[SerializeField]
private MonsterController monsterController;
[SerializeField]
private GameObject hitFxPrefab;
void Start()
{
Debug.LogFormat("btnAttack: {0}", btnAttack); //Button 컴포넌트의 인스턴스
//이벤트 등록
this.monsterController.onHit = () =>
{
Debug.Log("이펙트 생성");
Vector3 offset = new Vector3(0, 0.5f, 0); //이펙트 위치 지정
Vector3 tpos = this.monsterController.transform.position + offset;
Debug.LogFormat("생성위치: {0}", tpos);
//프리팹 인스턴스(복사본) 생성
GameObject fxGo = Instantiate(this.hitFxPrefab);
//위치설정
fxGo.transform.position = tpos;
//파티클 실행
fxGo.GetComponent<ParticleSystem>().Play();
};
this.btnAttack.onClick.AddListener(() =>
{
//사거리 체크
//두 점(A,B)과의 거리, 두 오브젝트의 radius의 합
//B-A : C(방향벡터), magnitude (벡터의 길이)
//MonsterController 컴포넌트가 붙어있는 게임오브젝의 Transform컴포넌트의 Position속성 (Vector3)
Vector3 b = monsterController.transform.position;
Vector3 a = heroController.transform.position;
Vector3 c = b - a; //정규화되지 않은 방향벡터 (방향과 크기), 크기 : 길이
//--------------> (방향 ->, 크기 ------------ )
float distance = c.magnitude; //거리(크기)
Debug.LogFormat("distance : {0}", distance);
Debug.DrawLine(a, b, Color.red, 5f); //영웅과 몬스터의 길이를 출력
//단위벡터 (길이가 1인 벡터)
//Vector3 normal = c.normalized; //방향
//시작위치, 방향, 얼마동안 보여줄건가(초), 색상, 타입 (채움)
//DrawArrow.ForDebug(a, normal, 5f, Color.red, ArrowType.Solid);
//DrawArrow.ForDebug(a, c, 5f, Color.red, ArrowType.Solid);
//Vector3. Distance
//두 컴포넌트의 radius (반지름)의 합
float radius = this.heroController.Radius + this.monsterController.Radius;
Debug.LogFormat("radius: {0}", radius);
Debug.LogFormat("<color=yellow>distance: {0},radius: {1}</color>", distance, radius);
Debug.LogFormat("IsWithRange: <color=lime>{0}</color>", this.IsWithinRange(distance, radius));
if (this.IsWithinRange(distance, radius))
{
//HeroController에게 공격을 명령
this.heroController.Attack(this.monsterController);
}
});
}
//사거리 체크
private bool IsWithinRange(float distance, float radius)
{
//distance > radius //false
return radius >= distance; //true
}
// Update is called once per frame
void Update()
{
}
}
}
HeroController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test2
{
public class HeroController : MonoBehaviour
{
public enum eState
{
Idle, Attack
}
[SerializeField]
private float radius = 1f;
private Animator anim;
//private eState state = eState.Idle;
private eState state; //초기화 0(Idle)
private float impactTime = 0.399f;
public MonsterController target;
private Coroutine attackRoutine;
public float Radius
{
get
{
return this.radius;
}
}
void Start()
{
//내가(HeroController) 컴포넌트가 붙어있는 게임오브젝트에 붙어있는 Animator컴포넌스 가져옴
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
public void Attack(MonsterController target)
{
this.target = target;
//공격 애니메이션을 1회 실행
//애니메이터 컴포넌트가 필요
this.PlayAnimation(eState.Attack);
}
//enum을 변수로 받아 애니메이션 실행
private void PlayAnimation(eState state)
{
//this.state : prev, state: current
//중복막기
if(this.state != state)
{
Debug.LogFormat("{0} -> {1}", this.state, state);
this.state = state;
this.anim.SetInteger("State", (int)state); //정수 -> enum
switch (state)
{
case eState.Attack:
//이미 코루틴이 실행중이라면 중지
if(this.attackRoutine != null)
{
this.StopCoroutine(this.attackRoutine);
}
//코루틴 함수는 StartCoroutine으로 실행해야 함
this.attackRoutine = this.StartCoroutine(this.WaitForCompleteAttackAnimation());
break;
}
}
else
{
Debug.LogFormat("{0}는 현재와 동일한 상태입니다.", state);
}
}
//코루틴 함수
//IEumerator 반환타입을 갖는 1개 이상의 yield return을 포함하는 함수
//Update와 동일하게 동작 가능
private IEnumerator WaitForCompleteAttackAnimation()
{
yield return null; //다음의 시작(1프레임 건너뜀, next frame)
Debug.Log("공격 애니메이션이 끝날때까지 기다림");
//layerIndex : 0
AnimatorStateInfo animStateInfo = this.anim.GetCurrentAnimatorStateInfo(0);
bool isAttackState = animStateInfo.IsName("Attack01");
Debug.LogFormat("isAttackState: {0}", isAttackState);
if (isAttackState)
{
Debug.LogFormat("animStateInfo.length: {0}", animStateInfo.length);
}
else
{
Debug.LogFormat("Attack State가 아닙니다.");
}
//0.11초 이후에 임펙트 효과 넣기
yield return new WaitForSeconds(impactTime); //Impact
Debug.Log("<color=red>Impact!!!</color>");
//대상에게 피해를 입힘
this.target.HitDamage();
//0.833초를 대기
//yield return new WaitForSeconds(0.833f);
yield return new WaitForSeconds(animStateInfo.length - impactTime); //0.48초만큼 기다림
//Idle 애니메이션을 함
//this.anim.SetInteger("State",0);
this.PlayAnimation(eState.Idle);
}
//기즈모 생성
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
}
}
}
MonsterController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Test2
{
public class MonsterController : MonoBehaviour
{
[SerializeField]
private float radius = 1f;
private Animator anim;
//대리자
public Action onHit;
public float Radius
{
get
{ return this.radius; }
}
void Start()
{
this.anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
//공격받는 메서드
public void HitDamage()
{
Debug.Log("피해 애니메이션을 실행합니다.");
//대리자 호출
this.onHit();
this.anim.SetInteger("State",2);
}
//기즈모 생성
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
}
}
}
ParticleController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ParticleDestroyer : MonoBehaviour
{
private ParticleSystem ps;
//private float elapsedTime = 0;
// Start is called before the first frame update
void Start()
{
this.ps = this.GetComponent<ParticleSystem>();
//코루틴 실행
this.StartCoroutine(this.CoWaitForPlayAfterDestory());
}
//IEnumerator반환하는 함수, 1개 이상의 yield return을 포함하는 함수
private IEnumerator CoWaitForPlayAfterDestory()
{
//this.ps.main.duration 기다렸다가 (프레임 경과)
yield return new WaitForSeconds(this.ps.main.duration);
//파괴
Destroy(this.gameObject);
}
//void Update()
//{
// this.elapsedTime += Time.deltaTime;
// if(this.elapsedTime >= this.ps.main.duration)
// {
// Destroy(this.gameObject);
// }
//} ==> 이렇게 칠 것을 CoRutine을 이용하여 처리
}
Gizmos
using UnityEngine;
public class GizmosExtensions
{
private GizmosExtensions() { }
/// <summary>
/// Draws a wire arc.
/// </summary>
/// <param name="position"></param>
/// <param name="dir">The direction from which the anglesRange is taken into account</param>
/// <param name="anglesRange">The angle range, in degrees.</param>
/// <param name="radius"></param>
/// <param name="maxSteps">How many steps to use to draw the arc.</param>
public static void DrawWireArc(Vector3 position, Vector3 dir, float anglesRange, float radius, float maxSteps = 20)
{
var srcAngles = GetAnglesFromDir(position, dir);
var initialPos = position;
var posA = initialPos;
var stepAngles = anglesRange / maxSteps;
var angle = srcAngles - anglesRange / 2;
for (var i = 0; i <= maxSteps; i++)
{
var rad = Mathf.Deg2Rad * angle;
var posB = initialPos;
posB += new Vector3(radius * Mathf.Cos(rad), 0, radius * Mathf.Sin(rad));
Gizmos.DrawLine(posA, posB);
angle += stepAngles;
posA = posB;
}
Gizmos.DrawLine(posA, initialPos);
}
static float GetAnglesFromDir(Vector3 position, Vector3 dir)
{
var forwardLimitPos = position + dir;
var srcAngles = Mathf.Rad2Deg * Mathf.Atan2(forwardLimitPos.z - position.z, forwardLimitPos.x - position.x);
return srcAngles;
}
}
DrawArrow
using UnityEngine;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
#endif
// adapted from http://wiki.unity3d.com/index.php/DrawArrow
public enum ArrowType
{
Default,
Thin,
Double,
Triple,
Solid,
Fat,
ThreeD,
}
public static class DrawArrow
{
public static void ForGizmo(Vector3 pos, Vector3 direction, Color? color = null, bool doubled = false, float arrowHeadLength = 0.2f, float arrowHeadAngle = 20.0f)
{
Gizmos.color = color ?? Color.white;
//arrow shaft
Gizmos.DrawRay(pos, direction);
if (direction != Vector3.zero)
{
//arrow head
Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * new Vector3(0, 0, 1);
Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * new Vector3(0, 0, 1);
Gizmos.DrawRay(pos + direction, right * arrowHeadLength);
Gizmos.DrawRay(pos + direction, left * arrowHeadLength);
}
}
public static void ForDebug(Vector3 pos, Vector3 direction, float duration = 0.5f, Color? color = null, ArrowType type = ArrowType.Default, float arrowHeadLength = 0.2f, float arrowHeadAngle = 30.0f, bool sceneCamFollows = false)
{
Color actualColor = color ?? Color.white;
duration = duration / Time.timeScale;
float width = 0.01f;
Vector3 directlyRight = Vector3.zero;
Vector3 directlyLeft = Vector3.zero;
Vector3 directlyBack = Vector3.zero;
Vector3 headRight = Vector3.zero;
Vector3 headLeft = Vector3.zero;
if (direction != Vector3.zero)
{
directlyRight = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + 90, 0) * new Vector3(0, 0, 1);
directlyLeft = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - 90, 0) * new Vector3(0, 0, 1);
directlyBack = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180, 0) * new Vector3(0, 0, 1);
headRight = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * new Vector3(0, 0, 1);
headLeft = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * new Vector3(0, 0, 1);
}
//draw arrow head
Debug.DrawRay(pos + direction, headRight * arrowHeadLength, actualColor, duration);
Debug.DrawRay(pos + direction, headLeft * arrowHeadLength, actualColor, duration);
switch (type)
{
case ArrowType.Default:
Debug.DrawRay(pos, direction, actualColor, duration); //draw center line
break;
case ArrowType.Double:
Debug.DrawRay(pos + directlyRight * width, direction * (1 - width), actualColor, duration); //draw line slightly to right
Debug.DrawRay(pos + directlyLeft * width, direction * (1 - width), actualColor, duration); //draw line slightly to left
//draw second arrow head
Debug.DrawRay(pos + directlyBack * width + direction, headRight * arrowHeadLength, actualColor, duration);
Debug.DrawRay(pos + directlyBack * width + direction, headLeft * arrowHeadLength, actualColor, duration);
break;
case ArrowType.Triple:
Debug.DrawRay(pos, direction, actualColor, duration); //draw center line
Debug.DrawRay(pos + directlyRight * width, direction * (1 - width), actualColor, duration); //draw line slightly to right
Debug.DrawRay(pos + directlyLeft * width, direction * (1 - width), actualColor, duration); //draw line slightly to left
break;
case ArrowType.Fat:
break;
case ArrowType.Solid:
int increments = 20;
for (int i = 0; i < increments; i++)
{
float displacement = Mathf.Lerp(-width, +width, i / (float)increments);
//draw arrow body
Debug.DrawRay(pos + directlyRight * displacement, direction, actualColor, duration); //draw line slightly to right
Debug.DrawRay(pos + directlyLeft * displacement, direction, actualColor, duration); //draw line slightly to left
//draw arrow head
Debug.DrawRay((pos + direction) + directlyRight * displacement, headRight * arrowHeadLength, actualColor, duration);
Debug.DrawRay((pos + direction) + directlyRight * displacement, headLeft * arrowHeadLength, actualColor, duration);
}
break;
case ArrowType.Thin:
Debug.DrawRay(pos, direction, actualColor, duration); //draw center line
break;
case ArrowType.ThreeD:
break;
}
/*#if UNITY_EDITOR
//snap the Scene view camera to a spot where it is looking directly at this arrow.
if (sceneCamFollows)
SceneViewCameraFollower.activateAt(pos + direction, duration, "_arrow");
#endif*/
}
public static void randomStar(Vector3 center, Color color)
{
//special: refuse to draw at 0,0.
if (center == Vector3.zero) return;
for (int i = 0; i < 2; i++)
DrawArrow.ForGizmo(center, UnityEngine.Random.onUnitSphere * 1, color, false, 0.1f, 30.0f);
}
public static void comparePositions(Transform t1, Transform t2)
{
//direct from one to the other:
ForDebug(t1.position, t2.position - t1.position);
//direction
//Vector3 moveDirection = (t2.position-t1.position).normalized;
}
}
'KDT > 유니티 기초' 카테고리의 다른 글
23/08/10 내용 복습 (0) | 2023.08.10 |
---|---|
23/08/10 Test3 캐릭터 이동, 몬스터 제거 및 아이템 생성, 포탈 생성 (0) | 2023.08.10 |
23/08/09 SimpleRPG 몬스터 공격 및 데미지 받기 (0) | 2023.08.09 |
23/08/08 복습 - 내용정리 (0) | 2023.08.08 |
23/08/08 캐릭터 이동 및 몬스터 공격하기 (0) | 2023.08.08 |