총구 화염 효과는 파티클 효과나 성능을 고려해 가벼운 메시를 사용할 수 있다. 

하이라키뷰의 Player하위에 있는 FirePos를 선택하고 우클릭후 팝업 메뉴에서 Create>3D Object>Quad를 선택한다. 이름을 MuzzleFlash로 수정한다. 발사되는 총알의 충돌을 막기위해 Mesh Collider 컴포넌트는 삭제한다.

총구 화염은 실시간 그림자가 필요없으므로 Mesh Renderer의 Cast Shdows를 Off로 설정라고 조명과 관련된 Receive Shadows를 Uncheck한다. 내경우는 Disable되어 있어 끌수가 없었다. 이상함..

다운받았던 Resources>Texture>Wepons폴더의 MuzzleFlash.png파일을 끌어다 05.Images 폴더로 드래그해 임포트한다.

이 이미지는 4개의 화염이미지가 들어 있지만 4등분해서 랜덤하게 하나만 사용한다.

MuzzleFlash.png를 끌어다 MuzzleFlash에 적용한고 Shader를 Mobile/Particles/Additive로 하면 검은부분이 투명하게 바낀다.

Shader 왼쪽 삼각형을 눌러 메뉴를 펴서 Particle Texture Tiling을 0.5, 0.5로 하면 4장으로 자르게 된다.

밑의 offet을 변경해 4장중 한장을 고를 수 있다.

주인공 캐릭터 하위의 MuzzleFlash에 포한된 MeshRenderer 컴포넌트를 추출하는 로직을 FireCtrl스크립트에 추가한다. MuzzleFlash의 Offset값을 변경하려면 머터리얼 정보를 담고 있는 MeshRenderer컴포넌트에 접근해야 한다. FireCtrl에 이미 있는 firePos변수를 이용해서 접근한후 비활성화 한다.  총을 발사할때문 보이게 할것이다.

muzzleFlash = firePos.GetComponentInChildren<MeshRenderer>();

muzzleFlash.enabled = false;

실행해보면 MuzzleFlash의 MeshRenderer컴포넌트가 비활성활되어 있다.

Play옆 포즈를 누르고 씬뷰탭을 선택후 ALT+좌클릭후 마우스를 움직여 씬뷰를 회전시키면 총구의 화염이 없는 것도 확인할수 있다

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
[RequireComponent(typeof (AudioSource))]  //삭제되는것을 방지하는 어트리뷰트
public class FireCtrl : MonoBehaviour
{
    public GameObject bullet;  //총알프리팹
    public Transform firePos;  // 총알 발사 좌표
    public AudioClip fireStx;  //총소리에 사용할 음원
    private new AudioSource audio;  //오디오 소스 컴포넌트를 저장할 변수
    private MeshRenderer muzzleFlash;  //머즐이펙트 참조
    // Update is called once per frame
    private void Start() {
        audio = GetComponent<AudioSource>();  //오디오소스를 얻어온다
        muzzleFlash = firePos.GetComponentInChildren<MeshRenderer>();  //자식 컴포넌트를 얻어온다
        muzzleFlash.enabled = false;  //안보이게한다
    }
    void Update()
    {  //마우스 왼쪽 버튼을 클릭했을때  Fire 함수 호출
        if(Input.GetMouseButtonDown(0)) {
            Fire();  //발사처리
        }
    }
    void Fire() {
        Instantiate(bullet,firePos.position, firePos.rotation); //Bullet프리팹을 동적으로 발생
        audio.PlayOneShot(fireStx, 1.0f);  //총소리발생
    }
}

코루틴함수

유니티의 모든 스크립트는 메시지루트가 동작한다. 다양한 이벤트함수가 정해진 순서대로 실행되는 순환구조이다. 일반 함수를 호출하면 해당 함수 안의 로직이 다 수행해야만 실행이 끝난다. 

함수안에서 로직이 10초 걸린다고 하면10초동안 메시지루프의 다른 로직을 기다리게 하는데 이걸 Blocking이라고 한다. 

이를 개선하려면 함수를 병렬로 호출해야한다. 이걸 Multi thread라고 한다. 

유니티는 코루틴이라는 병렬처리기능을 제공한다. 

만일 Fade()라는 함수는 for문을 통해 알파값을 감소시켜 투명처리하는 함수인데 순식간에 처리하므로 효과를 확인할수 없어 갑자기 꺼지게 될것이다.

void Fade() {
    for(float f = 1f; f>=0; f-= 0.1f) {
       Color c = GetComponent<Renderer>().material.color;
       c.a = f;  //알파값을 천천히 감소시킨다
       GetComponent<Renderer>().material.color = c;
    }
}

코루틴의 아이디어는 yield return null; 키워드를 만나면 제어 권한을 유니티시스템의 메시지루프로 양보하는 방식이다.

코루틴 함수는 열거자 IEnumerator 타입으로 선언해야 하고 함수내에 하나이상의 yeild 키워드를 사용해야 한다.

Ienumerate void Fade() {
    for(float f = 1f; f>=0; f-= 0.1f) {
       Color c = GetComponent<Renderer>().material.color;
       c.a = f;  //알파값을 천천히 감소시킨다
       GetComponent<Renderer>().material.color = c;
       yield return null;  //메시지루프로 제어권을 넘긴다.
    }
}

yield return null;키워드는 함수내에 여러개 삽입될 수도 있다.

코루틴 함수는 호출시 StartCoroutine()함수를 이용하여 호출한다. 전달인자는 함수의 원형(포인터)를 권장한다. "함수명"으로 호출하는건 가비지컬렉션을 발생시키 개별적으로 정지시킬수 없기 때문이다.

StartCoroutine(Fade());

yield return null대신 yield return WaitForSecond(0.3f)같이 하면 자기 자신을 0.3초동안 멈추게 할 수 있다. 대신 로직을 잘짜 무한 루프에 안 빠지게 해야한다. 다음은 적이 죽지 않았다면 0.3초간 기다려주는 로직이다. 만일 yield return new WaitForSeconds(0.3f)가 없다면 정말 무한루프에 빠질것이다.

bool isDie;
IEnumerator CheckState() {
    while(!isDie)  {  //죽지않았다면
        yield return new waitForSecond(0.3f); //3초 대기하기
    }
}

MuzzleFlash의 블링크 효과

총알알 발사할때 MuzzleFlash가 깜빡거리는 Blink효과를 구현해보자.  다음과 같이 하면 순식간에 일어나 효과가 없다

void ShowMuzzleFlash() {  //일반함수
    muzzleFlash.enabled = true;  //MuzzleFlash활성화
    muzzleFlash.enable = false; //MuzzleFlash비활성화
}

Blink효과는 점멸을 천천히 반복해야 하므로 코루틴을 사용해야한다.

Ienumerator void ShowMuzzleFlash() { //코루틴
    muzzleFlash.enabled = true; //MuzzleFlash활성화
    yield return new WaitForSecond(0.2f);
    muzzleFlash.enable = false;  //MuzzleFlash비활성화
}

MuzzleFlash의 텍스처 오프셋 변경

MuzzleFlash에 연결된 텍스처의 오프셋을 불규칙하게 변경해보자 또한 각도및 스케일도 조절해보자.

텍스처 오프셋값은 SetTextureOffset함수의 mainTextureOffset속성으로 설정할 수 있다.

처음 tiling걊을 (0.5,0.5)로 했기때문에 오프셋값은 다음 4개중 하나이다. (0,0), (0,0.5), (0.5,0), (0.5,0.5)

Randome.Range(0,2)가 리턴하는 숫자는 0, 1이므로 이값에 0.5f를 곱하여 이용하면 된다.

Vector2 offset = New Vector2(Randome.Range(0,2), Randome.Range(0,2))*0.5f;
muzzleFlash.material.mainTextureOffset = offset;
//muzzleFlash.material.setTextureOffset("_MainTxt",offset);  //이렇게도 가능하다

MuzzleFlash는 다른 게임오브젝트(FirePos)아래에 차일드화된 게임오브젝트로서, 좌표, 회전, 각도, 스케일을 수정하려면 반드시 localPosition, localRotation, localScale속성을 사용해야 한다.

MuzzleFlash를 회전시키기 위한 localRotation속성은 Quaternion 타입이므로 오일러각을 변화시키는 Quaternion.Euler(x,y,x)함수를 사용한다. 0~360도의 난수를 발생시켜 회전시켜본다. 유니티 원시모델 Quad로 만들어진 MuzzleFlash는 x축으로 -90도 회전된 모델로 z축을 기준으로 회전시켜야 하므로

float angle = Random.Range(0,360);
muzzleFlash.transfor.localRotation = Quaternion.Euler(0,0,angle);

다음과 같이 단위벡터를 사용할수도 있다.  z축은 Vector3.forward를 사용해야한다.

float angle = Random.Range(0,360);
muzzleFlash.transfor.localRotation = Quaternion.Euler(Vector3.forward*angle);

localScale을 이용해 사이즈를 조절한다. Vector3.one은 Vector3(1,1,1)을 나타내는 상수이다.

 

float scale = Random.Range(1.0f,2.0f);
muzzleFlash.transfor.localScale = Vector3.one * scale;

다음과 같이 FireCtrl을 변경하고 실행해보면 MuzzleFlash의 텍스처 크기 회전이 불규칙하게 변하는 것을 확인할 수 있다.

각도 때문에 게임뷰에서 확인이 어렵다면 게임뷰와 씬뷰를 동시에 보면서 할수 있다. 씬뷰는 게임중에도 위치와  회전을 할 수 있다.

왼쪽:씬뷰 어른쪽:게임뷰

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
[RequireComponent(typeof (AudioSource))]  //삭제되는것을 방지하는 어트리뷰트
public class FireCtrl : MonoBehaviour
{
    public GameObject bullet;  //총알프리팹
    public Transform firePos;  // 총알 발사 좌표
    public AudioClip fireStx;  //총소리에 사용할 음원
    private new AudioSource audio;  //오디오 소스 컴포넌트를 저장할 변수
    private MeshRenderer muzzleFlash;  //머즐이펙트 참조
    // Update is called once per frame
    private void Start() {
        audio = GetComponent<AudioSource>();  //오디오소스를 얻어온다
        muzzleFlash = firePos.GetComponentInChildren<MeshRenderer>();  //자식 컴포넌트를 얻어온다
        muzzleFlash.enabled = false;  //안보이게한다
    }
    void Update()
    {  //마우스 왼쪽 버튼을 클릭했을때  Fire 함수 호출
        if(Input.GetMouseButtonDown(0)) {
            Fire();  //발사처리
        }
    }
    void Fire() {
        Instantiate(bullet,firePos.position, firePos.rotation); //Bullet프리팹을 동적으로 발생
        audio.PlayOneShot(fireStx, 1.0f);  //총소리발생\
        StartCoroutine(ShowMuzzleFlash()); //총구화염효과 코루틴함수 호출
     
    }
    IEnumerator ShowMuzzleFlash() {  //코루틴
        Vector2 offset = new Vector2(Random.Range(0, 2), Random.Range(0, 2)) * 0.5f;
        muzzleFlash.material.mainTextureOffset = offset;  //4장중 한장을 선택
        float angle = Random.Range(0, 360);
        muzzleFlash.transform.localRotation = Quaternion.Euler(0,0, angle);  //로컬회전, 쿼터니언으로 변경할것
        float scale = Random.Range(1.0f, 2.0f);
        muzzleFlash.transform.localScale = Vector3.one * scale;  //로컬스케일변경
        muzzleFlash.enabled=true; //muzzleFlash 활성화
        yield return new WaitForSeconds(0.2f);  // new를 붙여줘야함. 권한을 0.2초 넘겨줌
        muzzleFlash.enabled=false;  //muzzleFlash 비활성화
    }
}

코루틴의 응용 -  임계치

게임을 실행하면 Player의 방향이 불규칙하다. 이건 마우스의 좌우 이동값이 불규칙하게 넘어오기 때문이다. Start함수를 코루틴으로 변경시켜 해결해보자. Player스크립트를 다음과 같이 수정한다. 교재는 PlayerCtrl이다.

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;

public class Player : MonoBehaviour {
    // Start is called before the first frame update
    Transform tr;
    private float moveSpeed=10f;
    private float turnSpeed=0f;
    private Animation anim;

    IEnumerator  Start() {  //start()함수는 코루틴으로 실행할 수 있다.
        tr = GetComponent<Transform>();
        anim = GetComponent<Animation>();  //추가된 코드
        anim.Play("Idel");
        yield return new WaitForSeconds(0.3f);
        turnSpeed = 500f;
    }

    // Update is called once per frame
    void Update() {
        float h = Input.GetAxis("Horizontal");  //AD 입력 좌우
        float v = Input.GetAxis("Vertical");  //WS 입력 전후
        if (Mathf.Abs(h) > float.Epsilon || Mathf.Abs(v) > float.Epsilon) {  //움직임이 없다면 불필요한 동작을 안한다.
            Vector3 dir = Vector3.right * h + Vector3.forward * v;
            tr.Translate(dir.normalized * moveSpeed * Time.deltaTime);
            PlayerAnim(h, v);
        }
        float r = Input.GetAxis("Mouse X");  //마우스 x축 입력 
        tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * r);
    }
    void PlayerAnim(float h, float v) {
        Debug.Log("Move");
        if (v >= 0.1f) {
            anim.CrossFade("RunF",0.25f);
        } else if(v <= -0.1f) {
            anim.CrossFade("RunB", 0.25f);
        } else if(h >= 0.1f) {
            anim.CrossFade("RunR", 0.25f);
        } else if (h <= -0.1f) {
            anim.CrossFade("RunL", 0.25f);
        } else {
            anim.CrossFade("Idle", 0.25f);
        }
    }
}

게임에 음악을 추가하려면 AudioSource필요하다.

MainCamera에는 AudioListener가 기본적으로 추가되어있고 설정할 것은 없는데 카메라가 여러대일경우 하나만 남겨놓고 지워야 한다.

Resouces/Sounds폴더에서 WeaponSFX 패키지를 임포트하고 프로젝트뷰의 06.Sounds 폴더로 드래그&드롭해 위치를 옮긴다. 이패키지는 Rifle과 Shotgun 두 가지의 총소리와 폭발음이 포함돼 있다. Rifle폴더에 있는 p_m4_1사운드파일을 사용한다. 임포트한 오디오 클립은 Force To Mono옵션으 체크해서 가볍게 하고 사이즈도 줄일수 있다.

 

오디오 임포트 옵션 - Load Type

Decompress On Load : 로드시 압축을 해제하므로 사이즈가 큰 파일은 오버헤드를 발생시킨다. 작은 사이즈의 오디오에 적합하고 압축후에는 CPU자원을 덜 소비한다.

Compressed in Memory : 압축된 상태로 메모리에 상주한다. 큰 사이즈의 오디오에 적합하다.

Streaming : HDD에서 부터 스트리밍 하듯이 재생한다. 메모리가 필요없다.

 

오디오 임포트 옵션 - Compression Format

PCM : 비압축

ADPCM : 압축율 3.5배로 노이즈가 포함돼어 있는 음원에 적합

Voris / MP3 : 70%정도의 압축률

 

총소리 구현

 p_mp_1.wav을 선택해 인스펙터에서 다음과 같이 설정한다. 총소리는 발사할 때마다 총소리를 발생시키므로 Decompress On Load로 Compression Format은 ADPCM정도로 한다.

Bullet프리팹을 선택해 AudioSoruce컴포넌트를 추가한다. 속성은

Audio Clip : p_mp_1.wav , 발생시킬 음원 파일

Play On Awake : 체크, 해당 컴포넌트가 활성화될 때 자동 재생 여부

Min Distance : 5 , 볼륨 100% 값으로 음원이 들리는 영역범위

Max Distance : 10 , 음원이 들리는 최대범위

하이라키의 Bullet을 수정했기 때문에 Override>Apply All버튼을 클릭해 원본 Bullet프리팹에 저장한다. 다른 방법은 Audio Source 컴포넌트에서 우클릭후 팝업된 메뉴에서 Added Component>Apply to Prefab "Bullet"을 선택한는 것이다.

 

이렇게 Bullet Prefab에서 구현한 총소리는 충돌하자 마자 삭제되므로 사운드가 끊어지는 현상이 발생한다. 따라서 스크립트로 처리해 보겠다. Bullet Prefab에서 AudioSource 컴포넌트를 제거한다.

하이라키뷰의 Player를 선택하고 AudioSource컴포넌트를 추가한다. 수정할 필요는 없다. 다음과 같이 스크립트를 추가하고 스크립트에 오디오클립을 연결해준다.

FireCtrl 스크립 코드

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
[RequireComponent(typeof (AudioSource))]  //삭제되는것을 방지하는 어트리뷰트
public class FireCtrl : MonoBehaviour
{
    public GameObject bullet;  //총알프리팹
    public Transform firePos;  // 총알 발사 좌표
    public AudioClip fireStx;  //총소리에 사용할 음원
    private new AudioSource audio;  //오디오 소스 컴포넌트를 저장할 변수
    // Update is called once per frame
    private void Start() {
        audio = GetComponent<AudioSource>();
    }
    void Update()
    {  //마우스 왼쪽 버튼을 클릭했을때  Fire 함수 호출
        if(Input.GetMouseButtonDown(0)) {
            fire();
        }
    }
    void fire() {
        Instantiate(bullet,firePos.position, firePos.rotation); //Bullet프리팹을 동적으로 발생
        audio.PlayOneShot(fireStx, 1.0f);  //총소리발생
    }
}

 

여러개의 드럼통의 같은 텍스처로 적용되여 있다. 시작과 동시에 다양하게 바꿔보자. 텍스처의 적용은 Mesh Rendere 컴포넌트에 연결된  Material에서 지정한다. 여기에 사용한 Barrel모델의 Mesh Renderer컴포넌트는 Barrel 하위에 있는 Barrel에 적용되어 있다. 부모 오브젝트는 빈 오브젝트이다.

하위의 Mesh Renderer를 연결할 변수를 선언하고 연결후 사용할 수도 있지만 BarrelCtrl스크립트에서 동적으로연결해 보자. 추가된 코드는 다음과 같다. 

public Texture[] textures;  //무작위로 적용할 텍스쳐배열

private new MeshRenderer renderer;  //하위 MeshRenderer를 저장할 변수, new를 사용하는데 Component.renderer로 정의된 멤버 변수로서 new키워드를 사용해야 한다는데 잘 이해가 안 간다.

renderer= GetComponentInChildren<MeshRenderer>(); //자식컴포넌트 추출

int idx = Random.Range(0, textures.Length);//난수발생
renderer.material.mainTexture= textures[idx]; //텍스처지정

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BarrelCtrl : MonoBehaviour {

    public GameObject expEffect;  //폭발효과를 연결할 참조
    public Texture[] textures;  //무작위로 적용할 텍스쳐배열
    private new MeshRenderer renderer;  //하위 MeshRenderer를 저장할 변수
    private Transform tr;//컴포넌트를 저장할 변수
    private Rigidbody rb;
    private int hitCount = 0;  //총알맞은 회수를 누적시킬 변수
    void Start() {
        tr = GetComponent<Transform>();
        rb = GetComponent<Rigidbody>();

        renderer= GetComponentInChildren<MeshRenderer>(); //자식 컴포넌트 추출
        int idx = Random.Range(0, textures.Length);//난수발생
        renderer.material.mainTexture= textures[idx]; //텍스처지정
    }

    private void OnCollisionEnter(Collision col) {
        if (col.collider.CompareTag("BULLET")) {
            if (++hitCount == 3) {
                ExpBarrel();
            }
        }
    }
    void ExpBarrel() {  //드럼통을 폭발시킨다
        // 파티클효과을 참조
        GameObject exp = Instantiate(expEffect, tr.position, Quaternion.identity);
        Destroy(exp, 5.0f);  //3초후 파티클 효과 제거
        rb.mass = 1.0f; //mass를 20에서 1로 가볍게 한다.
        rb.AddForce(Vector3.up * 1500.0f); //위쪽으로 날라가게 힘을 준다
        Destroy(gameObject, 3.0f); //3초후 드럼통 제거
    }
}

Barrel Prefab 원본에 Models/Barrel폴도안의 Barrel_D, Barrel_D1, Barrel_D2를 끌어다 Barrel Ctrl Script의 Textures에 끌어다 놓는다.

 

실행해보면 3가지 텍스쳐가 적용되어 있는걸 볼수 있다.

폭발력 적용하기 - AddExplosionForce

드럼통이 폭발할때 주변의 드럼통한테만 폭발력이 전달되어 데미지를 주는 로직을 구현한다. 

폭발시 주변의 물체가 어던것인지 알아야 한다. 드럼통의 Collider를 통해 충돌된 물체를 알수 있지만 충돌시 주변의 물체를 추출하는 방식으로 구현해보자 도한 드럼통만 데미지를 적용한다.

스크립트를 변경하기전 Layer를 추가한다. 유니티는 게임객체를 각각의 레이어에 배치해 로직을 필요한 레어어에만 적용할 수 있다.

다음과 같이 BARREL 레이어를 추가하고 적용시킨다. 이름은 TAG와 마찬가지로 대문자로 사용한다.

폭발하는 드럼통 주위를 살필때는 Physics.OverlapsSphere함수를 사용한다. 이 함수는 검사 반경와 특정 레이어를 지정할 수 있다.

BarrelCtrl 스크립트를 다음과 같이 변경한다. 코드를 살펴보면

public float radius = 10.0f;  // 검사할 주변 반경을 설정하였고

아래 두줄을 주석처리하고

 //rb.mass = 1.0f; //mass를 20에서 1로 가볍게 한다.
 //rb.AddForce(Vector3.up * 1500.0f); //위쪽으로 날라가게 힘을 준다
IndirectDamage(tr.position);  //파괴력을 전달하는 코드를 추가했다.

IndirectDamage()는 폭발위치를 전달하면 다음과 같이 처리한다.

 Collider[] cols = Physics.OverlapSphere(pos, radius, 1 << 3);  //주변객체를 검색해서 리턴
        foreach (var col in cols) {  //차례대로 반복
            rb = col.GetComponent<Rigidbody>();
            rb.mass = 1.0f;  //무게를 가볍게하고
            rb.constraints = RigidbodyConstraints.None;  // 움직임과 회전의 제한을 푼다
            rb.AddExplosionForce(1500.0f, pos, radius, 1200.0f);  //반경안에서 폭발력을 생성
        }

BarrelCtrl.cs의 전체소스

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BarrelCtrl : MonoBehaviour {

    public GameObject expEffect;  //폭발효과를 연결할 참조
    public Texture[] textures;  //무작위로 적용할 텍스쳐배열
    public float radius = 10.0f;   // 검사할 주변 반경을 설정하였고
    private new MeshRenderer renderer;  //하위 MeshRenderer를 저장할 변수
    private Transform tr;//컴포넌트를 저장할 변수
    private Rigidbody rb;
    private int hitCount = 0;  //총알맞은 회수를 누적시킬 변수
    void Start() {
        tr = GetComponent<Transform>();
        rb = GetComponent<Rigidbody>();

        renderer= GetComponentInChildren<MeshRenderer>(); //자식컴포넌트 추출
        int idx = Random.Range(0, textures.Length);//난수발생
        renderer.material.mainTexture= textures[idx]; //텍스처지정
    }

    private void OnCollisionEnter(Collision col) {
        if (col.collider.CompareTag("BULLET")) {
            if (++hitCount == 3) {
                ExpBarrel();
            }
        }
    }
    void ExpBarrel() {  //드럼통을 폭발시킨다
        // 파티클효과을 참조
        GameObject exp = Instantiate(expEffect, tr.position, Quaternion.identity);
        Destroy(exp, 5.0f);  //3초후 파티클 효과 제거
        //rb.mass = 1.0f; //mass를 20에서 1로 가볍게 한다.
        //rb.AddForce(Vector3.up * 1500.0f); //위쪽으로 날라가게 힘을 준다
        IndirectDamage(tr.position);  //파괴력을 전달
        Destroy(gameObject, 3.0f); //3초후 드럼통 제거
    }
    void IndirectDamage(Vector3 pos) {
        // 주변의 드럼통 추출
        Collider[] cols = Physics.OverlapSphere(pos, radius, 1 << 3);  //주변객체를 검색해서 리턴
        foreach (var col in cols) {  //차례대로 반복
            rb = col.GetComponent<Rigidbody>();
            rb.mass = 1.0f;  //무게를 가볍게하고
            rb.constraints = RigidbodyConstraints.None;  // 움직임과 회전의 제한을 푼다
            rb.AddExplosionForce(1500.0f, pos, radius, 1200.0f);  //반경안에서 폭발력을 생성
        }
    }
}

 OverlapSphereNonAlloc

Physics.OverlapSphere함수는 실행시 Sphere범위에 검출될 개수가 명확지 않을때만 사용해야한다. 동적으로 메모리를 만들기 때문에 메모리 Garbage가 발생하기 때문이다. 따라서 Sphere범위에 검출될 개수가 명확할 때는 Garbage가 발생하지 않는 Physics.OverlapSphereNoneAlloc함수를 사용하기를 권장한다. 이 함수는 결괏값을 저장할 정적 배열을 미리 선언하여 실행정에 배열의 크기를 변경할 수 없다. 우리는 배럴을 20개 배치했기 때문에 최대 검출치가 20개 이므로 이 함수를 사용할수 있는 것이다.

IndirectDamage()함수를 다음과 같이 변경하자

    Collider[] cols = new Collider[10];
    void IndirectDamage(Vector3 pos) {
        // 주변의 드럼통 추출
        //Collider[] cols = Physics.OverlapSphere(pos, radius, 1 << 3);  //주변객체를 검색해서 리턴
        Physics.OverlapSphereNonAlloc(pos, radius, cols, 1 << 3);
        foreach (var col in cols) {  //차례대로 반복
            rb = col.GetComponent<Rigidbody>();
            rb.mass = 1.0f;  //무게를 가볍게하고
            rb.constraints = RigidbodyConstraints.None;  // 움직임과 회전의 제한을 푼다
            rb.AddExplosionForce(1500.0f, pos, radius, 1200.0f);  //반경안에서 폭발력을 생성
        }
    }

 

 

Models/Barrel 폴더를 보면 Barrel이 2개 있다. 화살표가 달려있는 확장자 FBX인 원본 3D로 작업한다.

선택해보면 프로젝트뷰 아래 확장자가 표시된다.

Barrel을 하이라키로 끌어다 놓고 Transform을 Reset하면 캐릭터에 비해 큰 Barrel이 보인다. 캐럭터 크기에 맞게 스케일을 조정해보자

Scale Factor

외부에서 임포트한 3D모델은 반드시 Transform의 Scale속성을 수정하지 말고 FBX Import setting의 Scale Factor속성을 수정한다. 프로젝트 뷰의 Barrel 3D모델을 선택하면 인스펙터 뷰의 3D모델의 여러정보(FBX Import Settigns)가 표시된다. 첫번째(Model)맵을 선택하고 Scale Factor를 0.4로 설정하면 현재 Barrel모델의 크기를 40% 크기로 조정할 수 있다. 스케일을 변경하고 하단에 있는  [Apply] 버튼을 클릭해 저장한다. (나의 경우 화면에 Apply 팝업창이 떳다)

이제 캐릭터와 배럴의 크기가 비슷해졌고, 배럴의 하이라키속 transform.Scale의 속성은 (1,1,1) 그대로이다.

하이라키뷰의 Barrel에 충돌처리를 위해 Capsule Collider와 Rigidbody컴포넌트를 추가한다. 잘보면 영역을 나타내는 구역이 작다.

Capsule Collider의 속성은 다음과 같이 수정해서 맞춘다. 

Rigidbody 컴포넌트는 질량 mass는 20으로 하고 Constraints는 위치와 회전에 제한을 거는 속성으로 Freeze Rotation x와 z축을 체크한다. x축 z축으로 회전을 금지한다. 넘어지지 않게한다.

게임 Play 후 총알을 발사해 보면 배럴이 살짝 뒤로 움직인다.

이제 Barrel에 충돌한 총알을 제거하고 스파크 효과를 만든다. Wall에 추가한 RemoveBullet스크립트를 재활용한다. Barrel에 RemoveBullet 스크립트를 추가하고 SparksEffect를 연결한다.

이제 실행해보면 배럴에 스파크 효과가 발생하고 Bullet이 없어진다.

배럴에 총알이 3번 충돌하면 배럴이 폭발하게 해보겠다. BarrelCtrl이라는 스크립트를 생성하고 다음과 같이 작성하고 하이라키 뷰의 Barrel에 추가한다.

BarrelCtrl의 ExpEffect속성에 폭발 효과를 내는 파티클을 연결한다. 03. Prefabs/ EffectExamples/ FireExplosionEffects/ Prefabs 폴더에 있는 SmallExplosionEffect를 연결한다. .새로 연결하면 Bullet의 Tag가 변경되는 이상한 증상이 있어 다시 만들어주고 연결해줬다.  폴더내 없는 분들은 Unity Particle Pack에서

 

 import 한후 새로만들어진 폴더에서 기존의 Prefabs폴더로 옮긴다.

SmallExplosionEffect는 프리팹을 선택하고 차일드를 포함하여 모든 Looping 속성을 모두 언체크한다.

실행해보면 잘된다.

 

하이라키뷰의 간략화

Barrel을 03.Prefabs폴더로 이동시켜 프리팹으로 변환하다.

이 프리팹을 이용해 20개정도 배럴을 배치하려고 하는데 그러면 하이라키뷰가 지저분해진다.

따라서 _Stage라는 EmptyObject를 만드고 하위에 복제하면 간단히 정리된다.

하이라키뷰에 빈게임오브젝트를 하나 만들고 이름을  _STAGE로 저장한다. _를 붙이는 이유는 하이라키뷰의 맨위로 보내기 위해서다.

이제 Barrel 프리팹을 _STAGE로 옮긴후 Ctrl-D를 눌러 20개 복사하고 위치를 바궈도 되지만 스크립트를 이용해 자동으로 배치해 보겠다.

StageCtrl 스크립트를 하나 만들어 _Stage에 적용시킨다.

x,z좌표를 랜덤으로 발생해서 Barrel을 배치한면서 Parent를 _Stage 의 transform으로 한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StageCtrl : MonoBehaviour
{
    public GameObject barrel;
    void Start()
    {
        for(int i = 0; i < 20; i++) {
            float x = (float) Random.Range(-24f, 24f);
            float z = (float) Random.Range(-24f, 24f);
            Instantiate(barrel,new Vector3(x,5f,z), Quaternion.identity).transform.SetParent(transform);
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

왼쪽이 실행전 오른쪽이 실행후이다.동적으로 생성된다.

사실 배럴의 좌표는 Random이므로 겹칠수도 있다. 따라서 49x49개의 좌표를 리스트로 만들어 놓고 랜던으로 하나씩 뽑으면서 배치하고 배치한건 리스트에서 지우주면 겹치치않게 만들수 있다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StageCtrl : MonoBehaviour
{
    public GameObject barrel;
    void Start()
    {
        List<Vector3> posList = new List<Vector3>();
        for (int ix= -24; ix < 24; ix++) {
            for (int iz = -24; iz < 24; iz++) {
                posList.Add(new Vector3(ix, 0f, iz));
            }
        }
        for(int i = 0; i < 20; i++) {
            int randomIndex = Random.Range(0,posList.Count-1);
            Instantiate(barrel, posList[randomIndex], Quaternion.identity).transform.SetParent(transform);
            posList.RemoveAt(randomIndex);
        }
    }
}

 

 

 

다운로드후 모든걸 import한다 총탄충돌효과 말고도 나중에 배럴을 폭파할 효과도 필요하기 때문이다

 import후 다음같은 폴더내에 sparksEffect.prefab을 Prefabs폴더로 옮겨주고 하이라키나, 씬뷰에 끌어다 주면 불꽃튀는 효과가 보인다.

스파크효과는 총알이 벽에 충돌했을때 발생한 스파크 효과는 RemoveBullet 스크립트에서 구현한다. RemoveBullet스크립트를 다음과 같이 수정한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RemoveBullet : MonoBehaviour
{
    public GameObject sparkEffect;
    private void OnCollisionEnter(Collision coll) {
        if(coll.collider.tag == "Bullet") {
            Instantiate(sparkEffect, coll.transform.position, Quaternion.identity);
            Destroy(coll.gameObject);
        }
    }
}

Wall Prefab인스펙터창의 RemoveBullet스크립트컴포넌트의 sparkEffect참조를 끌어다 연결한다. 실행하기전 하이리키의 Bullet와 sparkle은 지운다.

실행해보면 충돌각도에 관계없이 스파클의 각도가 고정되어 있다. 이유는 sparksEffect를 만들때 Instantiate( , , Quaternion.identity)로 sparksEffect의 원래각도로 만들어서 그렇다. 

따라서 충돌한 지점에서 법선 벡터를 구해 해당 방향으로 스파크가 튀게 변경해보자, 법선 벡터는 두 물체가 충돌한 평면 또는구면의 점접에서 수직 방향으로 바라보는 벡터를 말한다.

RemoveBullet 스크립트를 다음과 같이 수정해 Bullet과 Wall의 정확한 충돌 지점과 해당 접점에서의 법선 벡터를 구해 스파크 파티클을 회전시켜보자

Instantiate()의 세번째 인자는 각도를 서정하며 Quatenion타입이다. Vector3()를 넣면 안된다.

다음 스크립트를 보면 충돌지점 정보는 Collision.GetContact, GetContacts함수를 통해 알수 있다.

ContactPoint cp = coll.GetContact(0);

충돌지점으로 리턴되는 ContactPoint의 프라퍼티는 다음과 같다.

normal Normal of the contact point.
otherCollider The other collider in contact at the point.
point The point of contact.
separation The distance between the colliders at the contact point.
thisCollider The first collider in contact at the point.

Quaternion rot = Quaternion.LookRotation(-cp.normal);   //충돌한 총알의 법선 벡터를 쿼터니언 타입으로 변환

Quaternion.LookRotation()의 정의를 보면 Vector라 cp.normal (노말벡터)를 넣는다.

        public static Quaternion LookRotation(Vector3 forward) {
            return LookRotation(forward, Vector3.up);
        }

cp.normal (노말벡터)는 충돌체의 진행방향이라고 생각하는게 편할듯하다. 이펙트는 총알의 반대방향으로 되야하니 -를 곱하고 쿼터니언으로 바꿔 rot에 넣는다. 이 rot를 이용해 이펙트를 초기화 한다.

사실 총알의 진입방향의 반대라는게 생각하면 이상하다. 벽에 부딪치면 반사되서 반대방향으로 가는 효과는 아닌거다. 이건 나중에 생각하자.

실행해보면 총알의 입사각의 반대로 스파크 효과가 난다. 그러나 없어지지 않는다.

SparksEffect 프리팹을 씬뷰에 끌어다 놓고 하이라키에서 눌러 보면 다음과 같이 3개의 효과가 들어 있다.

위에서 부터 순서대로 눌러 인스펙터뷰에서  Duration은 2 Loop는 꺼준다.

맨마지막꺼는 루프만 꺼주었다.

이렇게 하면 효과는 2초후 꺼지지만 하이라키뷰에서 오브젝트이름은 사라지지 않는다. 따라서 스크립트에서

Instantiate()이후 Destroy(spark,0.5f)로 0.5초후에 파괴되라고 예약을 걸었다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RemoveBullet : MonoBehaviour {
    public GameObject sparkEffect;
    private void OnCollisionEnter(Collision coll) {
        if (coll.collider.CompareTag("Bullet")) {
            //첫번째 충돌 지점의 정보추출
            ContactPoint cp = coll.GetContact(0);
            //충돌한 총알의 법선 벡터를 쿼터니언 타입으로 변환
            Quaternion rot = Quaternion.LookRotation(-cp.normal);
            // 스파크 파티클을 동적으로 생성, 총알의 법선벡터의 반대방향으로 
            GameObject spark = Instantiate(sparkEffect, cp.point, rot);
            //충돌한 오브젝트제거
            Destroy(spark,0.5f);
            Destroy(coll.gameObject);
        }
    }
}

RPG류 게임에서 주인공이 휘두르는 검에 표현되는 궤적이나 총알을 발사했을때 총알이 날아가는 궤적을 만들어 보겠다. 

유니티는 이런 효과를 할수 있는 Trail Rendere를 제공한다.

 

Trail Renderer

 

 

Bullet Prefab을 끌어다 씬에 놓는다.

하이러키 뷰에서 Bullet을 선택하고 메뉴에서 Component>Effects>Trail Renderer를 선택해 Trail Renderer를 추가한다. Bullet의 Z축을 잡고 앞으로 드래그하면 동적으로 생성된 메시를 볼수 있다. 이때 씬뷰의 렌더링모드를 Wireframe으로 변경하면 동적으로 만들어진 메시의 형태를 볼 수 있다.

동적으로 생성된 메시는 위와 같이 노란색이 아니라 분홍색이다. 아직 머터리얼이 없어서 그렇다.

Resources/Textures 폴더에 Trail.png를 04.Images폴더에 끌어다 놓는다.\

Images/Material 폴더에 머터리얼을 새로 만들고 BulletTrail으로 이름을 바꾼다.

Shader를 Mobile/Particles/Additive로 변경하면 Particle Texture속성이 나타난다. 여기에 trail.png를 끌어다 연결한다.

완성된 Material을 Bullet에 추가된 Trail Rendere컴포넌트의 Material속성중 Element0에 끌어다 놓는다. 이러면 분홍색에 텍스처가 입려진다.

Trail Rendere컴포넌트의 디테일이다. Width는 곡선의 작은 동그라미를 마우스로 잡고 위치를 바꿀수 있다. 시작두께와 끝나는 지점의 두께를 조정할 수 있다. 더블클릭하면 새로운 노드가 생긴다.

 

타임은 Trail의 지속시간 Min Vertex Distance는 Trail의 진동시간이다. 길면 파도가 길어진다.

칼라를 누르면 다음과 같은 창이 뜨는데 왼쪽끝과 오른쪽 끝 아래 잉크를 눌러 색을 바꾸고 위잉크를 누르면  불투명도를 바꿀수 있다. 앞쪽을 노란색으로 하고 뒤쪽의 불투명도를 180으로 하겠다.

프리팹의 변경내용 조회및 저장

Bullet의 Prefab이 아닌 씬위의 인스턴스를 변경했기 때문에 변화를 Prefab에 저장할 필요가 있다.

하이라키의 Bullet을 선택하고  인스펙터의 Overrides를 클릭하면 변경된 부분이 나타나면 Apply All하면 Prefab에 적용된다. Revert All하면 인스턴스는 다시 Prefab상태로 돌아간다.

변경전 변경된 내용을 클릭하면 다음과 같이 변경된 부분을 비교하면서 확인할 수 있다.

프로젝트뷰의 Bullet Prefab을 눌러 인스펙트뷰에서 Scale을 (0.3,0.3,0.3), 

총알을 빠르게 하기위해서 Rigidbody컴포의 Mass(무게)를 0.1로 해봤는데 파티클이펙트가 안되는 경우가 많아 다시 1로 되돌렸다. 

그냥 총알에 AddForce()를 크게 해주는게 좋을듯 하다.

총기가 밑에 CreateEmpty를 만든후 이름을 FirePos로 변경한고 자식으로 한다.

여기에 MyGizmo라는 Script를 하나 넣어준다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyGizmo : MonoBehaviour
{
    public Color _color = Color.yellow;
    public float _radius = 0.1f;
    private void OnDrawGizmos() {
        Gizmos.color = _color;
        Gizmos.DrawSphere(transform.position, _radius);
    }
}

총끝에 노란공이 보인다. 너무크다

인스펙터뷰에의 My Gizmo Script변수 Radius를 0.02 Color를 클릭해 A를50으로 바꾼다. 

다음같이 예쁘게 바뀐다. 이 기즈모는 씬뷰에서만 보이고 프리뷰에서는 안보인다.

그런데 노란공은 총구와 위치가 잘 않맞는다.

FirePos의 위치를 총구쪽으로 이동시켜준다. 그런데 총이 비스듬하게 되어 있어 되는듯하지만 맞추기 어렵다.

 

GamePlay를 누른후 포즈를 누른다.

그럼 다음같이 총구를 맞추기 쉬운 자세로 드래그및 로테이션을 할수 있다.. 이상태에서 기즈모를 하이리체서 선택해 끌어다 맞춘다. 잘되었으면 그냥 나오면 힘들게 맞춘게 틀어진다. 따라서 현재의 파라메터를 기록해야한다.

Transfor 오른쪽 삼점을 누르면 Copy>Component 할수 있다 플레이를 멈춘후  Paste해 준다. 잘 달라붙는다

 

이렇게 기즈모 스크립트를 작성하지 않아도 유니티에서 좌상 육각형을 눌러보면 아이콘을 고를 수 있다. 대신 이건 사이즈나 투명도를 조정할 수는 없다.

그리고 하이라키뷰의 Player를 선택하고 육각형 Icon을 눌러 위쪽으 가로로긴 원 Lable을 선택하면 게임오브젝트의 이름이 씬뷰에만 표시된다.

 

FireCtrl

BulletCtrl도 원래대로한다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletCtrl : MonoBehaviour
{
    public float damage = 20.0f;
    public float force = 1500.0f;
    private Rigidbody rb;
    void Start() {
        rb = GetComponent<Rigidbody>();
        rb.AddForce(transform.forward * force);
    }
}

이전에 만든 AddForceCtrl.cs 을 제거하고 프로젝트뷰에서 아예 지워버리고 마우스좌클릭을 하면 총알을 발사하기 위해 FireCtrl.cs 스크립트을 다시 작성해서 Player에 적용할 것이다. 총알은 게임중 동적으로 생성할것이므로 하이라키의 Bullet은 지운다. 지워도 아까 프리팹으로 만들어 놨기때문에 괜찮다. 

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class FireCtrl : MonoBehaviour
{
    public GameObject bullet;
    public Transform firePos;

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0)) {
            fire();
        }
    }
    void fire() {
        Instantiate(bullet,firePos.position, firePos.rotation);
    }
}

실행시키기전 글로벌변수를 인스펙트에서 끌어다 놔야한다.  프리팹의 Bullet과 하이라키 총밑에 있는 FirePos를 끌어다 연결해준다.

전 실행해보니 벽에 맞은 총알이 안없어지고 튕겨서 wall prefab에 removeBullet Script를 다시 적용해 줬다.

 

이번 장을 정리해보면 Player가 좌클릭을 감지하면 Fire()로 Bullet객체를 하나 만들어 준다.

만들어진 Bullet은 start()이벤트에서 AddForce()로 스스로 앞으로 날라간다.

 

좌클릭을 많이하면 하이라키뷰에 Bullet인스턴스가 많이 보일것다. 벽에 부딪치면 없어질것이고

총알이 Wall에 충돌했을 때 Wall의 관점에서 생각해 보면 Collider 컴포넌트를 가진 어떤 게임오브젝트가 날아와서 충돌이 일어났는지 알 필요가 있다. 물론 충돌한 오브젝트의 이름으로 판단할 수도 있지만 인스턴트의 경우 번호가 붙으므로 프리팹에 Tag를 지정하고  Tag명식별하는 법이 있다. 

Tag는 기본적으로는 Untagged이지만 디폴트로 생성된 이름을 선택할 수도 있고 Tag 콤보박스를 클릭한다음 Add Tag로 만들수 있다.  대소문자를 식별한다.

 

Tags의 +를 누르면 이름을 추가할 수 있다.

Inspector의 루트로 빠져나오면 Tab에 Bullet이 추가되어 있고 선택하면 Untagged에서 Bullet로 변경된다.

총알이 벽에 충돌할때 발생되는 이벤트함수가 호출되는지 확인해보자 Wall prefab에 스크립트를 추가한후 RemoveBullet라고 이름바꾼다. 이러면 하이라키의 4개의 wall에 다 적용된다.

코드를 보면 총알이 벽에 부딪치면 다음같은 이벤트가 발생되고 Collision 객체가 전달된다.

이 Collision은 충돌 객체및 Tag이름, 충돌위치, 충돌속도가 들어 있다

 

코드는 이중 tag를 식별해 충돌된 Bullet 오브젝트를 제거한다.
    private void OnCollisionEnter(Collision coll) {
        if(coll.collider.tag == "Bullet") {
            Destroy(coll.gameObject);
        }
    }

 

collision.CompareTag()

 if(coll.collider.tag == "Bullet")  와 같이 게임오브젝트의 문자속성을 가져오는 코드는 실행시 문자열의 복사본을 생성한다. 따라서 가지비컬렉션이 발생하지 않는 coll.collider.comapreTag("bullet")를 추천한다.

 

Bullet의 Prefab 전환

총을을 발사해보면 벽과 충돌하면 Destroy()되면서 하이라키뷰에서 사라지기 때문에 한발이상 쏠수가 없다 이걸 해결해야한다.

Bullet을 끌어다 Prefab 폴더에 넣는다.

 

❤️Collision 설명 - Collider가 아닙니다. 충돌이 발생하면 리턴되는 인자입니다.

모든 충돌체의 기본 클래스입니다.

참조: BoxCollider , SphereCollider , CapsuleCollider , MeshCollider , PhysicMaterial , Rigidbody .

Collider가 있는 개체를 게임 플레이 중에 이동해야 하는 경우 개체에 Rigidbody 구성 요소도 연결해야 합니다. 개체가 다른 개체와 물리적 상호 작용을 하지 않도록 하려면 Rigidbody를 운동학적으로 설정할 수 있습니다 .

속성

attachedArticulationBody 콜라이더가 부착된 관절 본체입니다.
attachedRigidbody 콜라이더가 부착된 리지드바디 .
bounds 콜라이더의 세계 공간 경계 볼륨(읽기 전용).
contactOffset 이 콜라이더의 접촉 오프셋 값입니다.
enabled 활성화된 Collider는 다른 Collider와 충돌하지만 비활성화된 Collider는 충돌하지 않습니다.
hasModifiableContacts 이 Collider의 연락처를 수정할 수 있는지 여부를 지정합니다.
isTrigger 이 콜라이더가 트리거로 구성되었는지 지정합니다.
material 충돌체에서 사용되는 재료입니다.
sharedMaterial 이 충돌체의 공유 물리 물질입니다.

공개 방법

ClosestPoint 주어진 위치에 가장 가까운 충돌체의 지점을 반환합니다.
ClosestPointOnBounds 부착된 콜라이더의 경계 상자에 가장 가까운 지점입니다.
레이캐스트 이 충돌체를 제외한 모든 충돌체를 무시하는 광선을 던집니다.

메시지

OnCollisionEnter OnCollisionEnter는 이 collider/ rigidbody가 다른 rigidbody /collider 에 닿기 시작 했을 때 호출됩니다 .
OnCollisionExit OnCollisionExit는 이 collider/ rigidbody가 다른 rigidbody /collider와 접촉하는 것을 멈췄을 때 호출됩니다.
OnCollisionStay OnCollisionStay는 다른 Collider 또는 Rigidbody 에 닿는 모든 Collider 또는 Rigidbody 에 대해 프레임당 한 번씩 호출됩니다 .
OnTriggerEnter GameObject가 다른 GameObject와 충돌 하면 Unity는 OnTriggerEnter를 호출합니다 .
OnTriggerExit OnTriggerExit는 다른 Collider가 트리거 터치를 중지했을 때 호출됩니다.
OnTriggerStay OnTriggerStay는 트리거에 닿는 모든 Collider 다른 프레임에 대해 거의 모든 프레임이라고 합니다. 이 함수는 물리 타이머에 있으므로 모든 프레임에서 반드시 실행되는 것은 아닙니다.

상속된 구성원

속성

gameObject 이 구성 요소가 연결된 게임 개체입니다. 구성 요소는 항상 게임 개체에 연결됩니다.
tag 이 게임 오브젝트의 태그입니다.
transform GameObject 에 첨부된 Transform입니다 .
hideFlags 개체를 숨겨야 합니까, 장면과 함께 저장해야 합니까, 아니면 사용자가 수정할 수 있어야 합니까?
이름 개체의 이름입니다.

공개 방법

BroadcastMessage 이 게임 개체 또는 그 자식의 모든 MonoBehaviour 에서 methodName 이라는 메서드를 호출합니다 .
CompareTag 정의된 태그에 대해 GameObject의 태그를 확인합니다 .
GetComponent GameObject 에서 유형 T의 구성 요소에 대한 참조를 가져옵니다 .
GetComponentInChildren GameObject 의 자식과 동일한 GameObject 에서 유형 T의 구성 요소에 대한 참조를 가져옵니다 .
GetComponentInParent GameObject 의 부모와 동일한 GameObject 에 있는 T 유형의 구성 요소에 대한 참조를 가져옵니다 .
GetComponents GameObject 에서 유형 T의 모든 구성 요소에 대한 참조를 가져옵니다 .
GetComponentsInChildren GameObject 의 자식과 동일한 GameObject 에 있는 T 유형의 모든 구성 요소에 대한 참조를 가져옵니다 .
GetComponentsInParent GameObject 의 부모와 동일한 GameObject 에 있는 T 유형의 모든 구성 요소에 대한 참조를 가져옵니다 .
SendMessage 이 게임 개체의 모든 MonoBehaviour 에서 methodName 이라는 메서드를 호출합니다 .
SendMessageUpwards 이 게임 개체의 모든 MonoBehaviour 와 동작 의 모든 조상에 대해 methodName 이라는 메서드를 호출합니다 .
TryGetComponent 존재하는 경우 지정된 유형의 구성 요소를 가져옵니다.
GetInstanceID 개체의 인스턴스 ID를 가져옵니다.
ToString 객체의 이름을 반환합니다.

정적 메서드

Destroy GameObject , 구성 요소 또는 자산을 제거합니다 .
DestroyImmediate 개체 obj를 즉시 파괴합니다. 대신 Destroy를 사용하는 것이 좋습니다.
DontDestroyOnLoad 새 장면을 로드할 때 대상 개체를 파괴하지 마십시오.
FindAnyObjectByType 유형 의 활성 로드된 개체를 검색합니다 .
FindFirstObjectByType type 의 첫 번째 활성 로드된 개체를 검색합니다 .
FindObjectOfType 유형 의 첫 번째 활성 로드된 개체를 반환합니다 .
FindObjectsByType type 의 모든 로드된 객체 목록을 검색합니다 .
FindObjectsOfType type 의 모든 로드된 개체 목록을 가져옵니다 .
Instantiate 개체 원본을 복제하고 복제본을 반환합니다.

연산자

bool 개체가 존재합니까?
operator != 두 개체가 다른 개체를 참조하는지 비교합니다.
operator == 두 개체 참조를 비교하여 동일한 개체를 참조하는지 확인합니다.

충돌체

UnityEngine 의 클래스 / 상속 : 구성요소 / 구현 위치: UnityEngine.PhysicsModule

 

설명

모든 충돌체의 기본 클래스입니다.

참조: BoxCollider , SphereCollider , CapsuleCollider , MeshCollider , PhysicMaterial , Rigidbody .

Collider가 있는 개체를 게임 플레이 중에 이동해야 하는 경우 개체에 Rigidbody 구성 요소도 연결해야 합니다. 개체가 다른 개체와 물리적 상호 작용을 하지 않도록 하려면 Rigidbody를 운동학적으로 설정할 수 있습니다 .

 

 

충돌시 OnCollision()계열 이벤트함수가 발생한다. 

모든 Collider 컴포넌트에는 IsTrigger 속성이 있다. 이속성이 Eable되어 있으면 OnTrigger()이벤트함수가 발생하며, 충돌감지는 되지만 물리충돌은 이뤄지지않는다

 

메시지 (이벤트함수)

OnCollisionEnter OnCollisionEnter는 이 collider/ rigidbody가 다른 rigidbody /collider 에 닿기 시작 했을 때 호출됩니다 .
OnCollisionExit OnCollisionExit는 이 collider/ rigidbody가 다른 rigidbody /collider와 접촉하는 것을 멈췄을 때 호출됩니다.
OnCollisionStay OnCollisionStay는 다른 Collider 또는 Rigidbody 에 닿는 모든 Collider 또는 Rigidbody 에 대해 프레임당 한 번씩 호출됩니다 .
OnTriggerEnter GameObject가 다른 GameObject와 충돌 하면 Unity는 OnTriggerEnter를 호출합니다 .
OnTriggerExit OnTriggerExit는 다른 Collider가 트리거 터치를 중지했을 때 호출됩니다.
OnTriggerStay OnTriggerStay는 트리거에 닿는 모든 Collider 다른 프레임에 대해 거의 모든 프레임이라고 합니다. 이 함수는 물리 타이머에 있으므로 모든 프레임에서 반드시 실행되는 것은 아닙니다.

속성

attachedArticulationBody 콜라이더가 부착된 관절 본체입니다.
attachedRigidbody 콜라이더가 부착된 리지드바디 .
bounds 콜라이더의 세계 공간 경계 볼륨(읽기 전용).
contactOffset 이 콜라이더의 접촉 오프셋 값입니다.
enabled 활성화된 Collider는 다른 Collider와 충돌하지만 비활성화된 Collider는 충돌하지 않습니다.
hasModifiableContacts 이 Collider의 연락처를 수정할 수 있는지 여부를 지정합니다.
isTrigger 이 콜라이더가 트리거로 구성되었는지 지정합니다.
material 충돌체에서 사용되는 재료입니다.
sharedMaterial 이 충돌체의 공유 물리 물질입니다.

Public Methods

ClosestPoint 주어진 위치에 가장 가까운 충돌체의 지점을 반환합니다.
ClosestPointOnBounds 부착된 콜라이더의 경계 상자에 가장 가까운 지점입니다.
Raycast 이 충돌체를 제외한 모든 충돌체를 무시하는 광선을 던집니다.

상속된 구성원 속성

gameObject 이 구성 요소가 연결된 게임 개체입니다. 구성 요소는 항상 게임 개체에 연결됩니다.
tag 이 게임 오브젝트의 태그입니다.
transform GameObject 에 첨부된 Transform입니다 .
hideFlags 개체를 숨겨야 합니까, 장면과 함께 저장해야 합니까, 아니면 사용자가 수정할 수 있어야 합니까?
이름 개체의 이름입니다.

Public Methods

BroadcastMessage 이 게임 개체 또는 그 자식의 모든 MonoBehaviour 에서 methodName 이라는 메서드를 호출합니다 .
CompareTag 정의된 태그에 대해 GameObject의 태그를 확인합니다 .
GetComponent GameObject 에서 유형 T의 구성 요소에 대한 참조를 가져옵니다 .
GetComponentInChildren GameObject 의 자식과 동일한 GameObject 에서 유형 T의 구성 요소에 대한 참조를 가져옵니다 .
GetComponentInParent GameObject 의 부모와 동일한 GameObject 에 있는 T 유형의 구성 요소에 대한 참조를 가져옵니다 .
GetComponents GameObject 에서 유형 T의 모든 구성 요소에 대한 참조를 가져옵니다 .
GetComponentsInChildren GameObject 의 자식과 동일한 GameObject 에 있는 T 유형의 모든 구성 요소에 대한 참조를 가져옵니다 .
GetComponentsInParent GameObject 의 부모와 동일한 GameObject 에 있는 T 유형의 모든 구성 요소에 대한 참조를 가져옵니다 .
SendMessage 이 게임 개체의 모든 MonoBehaviour 에서 methodName 이라는 메서드를 호출합니다 .
SendMessageUpwards 이 게임 개체의 모든 MonoBehaviour 와 동작 의 모든 조상에 대해 methodName 이라는 메서드를 호출합니다 .
TryGetComponent 존재하는 경우 지정된 유형의 구성 요소를 가져옵니다.
GetInstanceID 개체의 인스턴스 ID를 가져옵니다.
ToString 객체의 이름을 반환합니다.

정적 메서드

Destroy GameObject , 구성 요소 또는 자산을 제거합니다 .
DestroyImmediate 개체 obj를 즉시 파괴합니다. 대신 Destroy를 사용하는 것이 좋습니다.
DontDestroyOnLoad 새 장면을 로드할 때 대상 개체를 파괴하지 마십시오.
FindAnyObjectByType 유형 의 활성 로드된 개체를 검색합니다 .
FindFirstObjectByType type 의 첫 번째 활성 로드된 개체를 검색합니다 .
FindObjectOfType 유형 의 첫 번째 활성 로드된 개체를 반환합니다 .
FindObjectsByType type 의 모든 로드된 객체 목록을 검색합니다 .
FindObjectsOfType type 의 모든 로드된 개체 목록을 가져옵니다 .
Instantiate 개체 원본을 복제하고 복제본을 반환합니다.

연산자

bool 개체가 존재합니까?
operator != 두 개체가 다른 개체를 참조하는지 비교합니다.
operator == 두 개체 참조를 비교하여 동일한 개체를 참조하는지 확인합니다.

 

게임에서 충돌 감지는 매우 중요한 요소 중 하나다. 유니티는 충돌 감지를 위해 다양한 Collider 컴포넌트를 제공한다. Collider 컴포넌트는 충돌을 감지하는 일종의 센서라고 생각하면 이해하기 쉽고, 다음과 같이 여러 형태로 제공하다.

모양과 기능에 따라 Box, Sphere Capsule, Mesh, Wheel, Terrain 등이 있다

 

충돌 감지 조건

충돌을 일으키는 양쪽 게임오브젝트에는 모두 Collider 컴포넌트가 추가돼 있어야 한다.

두 게임오브젝트 중 움직이는 쪽에는 반드시 Rigidbody 컴포넌트가 있어야 한다.

사방의 벽인 Wall에는 기본적으로 Collider가 들어 있으나 Bullet에는 Rigidbody만 있고  Collider는 안들어 있다 . AddComponent로 Box Collider를 추가해준다.

박스가 총알에 비해 크므로 좀 줄여준다.

플레이 해보면 총알이 벽에 튕기는 걸 볼수 있다.

 

Collision action matrix

두 객체가 충돌하면 충돌하는 객체의 강체 구성에 따라 다양한 스크립트 이벤트가 발생할 수 있습니다. 아래 차트는 개체에 연결된 구성 요소를 기반으로 호출되는 이벤트 함수에 대한 세부 정보를 제공합니다. 일부 조합은 두 오브젝트 중 하나만 충돌의 영향을 받지만 일반적인 규칙은 Rigidbody 구성 요소가 첨부되지 않은 오브젝트에는 물리가 적용되지 않는다는 것입니다.

충돌 감지가 발생하고 충돌 시 메시지가 전송됩니다. 리지드바디는 트리거가 아닌 콜라이더와 반응한다.

  Static Collider Rigidbody Collider Kinematic Rigidbody Collider Static Trigger Collider Rigidbody Trigger Collider Kinematic Rigidbody Trigger Collider
Static Collider   Y        
Rigidbody Collider Y Y Y      
Kinematic Rigidbody Collider   Y        
Static Trigger Collider            
Rigidbody Trigger Collider            
Kinematic Rigidbody Trigger Collider            

트리거 메시지는 충돌 시 전송됩니다. 트리거는 트리거끼리 반응하는것 같다.

  Static Collider Rigidbody Collider Kinematic Rigidbody Collider Static Trigger Collider Rigidbody Trigger Collider Kinematic Rigidbody Trigger Collider
Static Collider         Y Y
Rigidbody Collider       Y Y Y
Kinematic Rigidbody Collider       Y Y Y
Static Trigger Collider   Y Y   Y Y
Rigidbody Trigger Collider Y Y Y Y Y Y
Kinematic Rigidbody Trigger Collider Y Y Y Y Y Y

+ Recent posts