여러개의 드럼통의 같은 텍스처로 적용되여 있다. 시작과 동시에 다양하게 바꿔보자. 텍스처의 적용은 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);  //반경안에서 폭발력을 생성
        }
    }

 

 

+ Recent posts