반응형

 

 

유니티에는 단축키를 쉽게 확인하고 단축키를 지정할수 있는 기능이 있다.

게임엔진 답게 다른 프로그램보다 확인하기 쉽게 되어있다.

 

너무 간단한 기능이기에 이런게 있구나 하고  어떤 단축키들이 할당되어있는지 보고 넘어가도 좋다.

 

 

한번 보도록 하자.

 

 

우선 Shortcuts을 키는 법은 Edit -> Shortcuts.. 에서 확인할수 있다.

누르면 창이 하나 켜진다.

 

 

 

아래와 같은 창이 켜지는 것을 확인할수있다.

키에 마우스를 올리면 어떠한 단축키가 할당되어있는지 확인할수있다.

색마다 다른데

유니티에는 단축키를 쉽게 확인하고 단축키를 지정할수 있는 기능이 있다.

 

게임엔진 답게 다른 프로그램보다 확인하기 쉽게 되어있다.

 

한번 보도록 하자.

 

 

 

 

 

우선 쇼우올컷 을 키는 법은 Edit -> Shortcuts..

아래와 같은 창이 켜지는 것을 확인할수있다.

 

 

초록색 네모칸은 현재 할당되어 있는 키를 확인할수있는데.

마우스를 올리면 어떤 기능이 할당되어있는지 알수있다.

설명이 버전마다 살짝식 차이가 있는데.

 

우선 유니티 공식 문서에선 아래와 같이 설명하고있다.

 

 

 

 

하지만  직접 캡쳐한 버전에선

위에 설명으로 

보라색 키 역시 mixed key 로 색이 다르게 추가되어있다.

 

 

 

마우스를 올리고 기다리면 할당되어있는 단축키를 보여준다

 

 

우클릭시

지우거나 기본설정으로 초기화 할수있으며

 

특수키 를 키보드로 누르거나 마우스로 누르면 

연계되어있는 숏컷만 확인도 가능하다.

 

 

 

 

 

 

 

 

 

 

또한 단축키 세팅을 새로만들거나 저장, 불러오기 가 가능하다.  

 

 

 

 

 

 

 

 

 

 

마지막으로 아래와 같이  숏컷의 종류들을 전부 확인가능하다.

할당안되어있는 것들은 눌러서 단축키를 넣어줄수있다.

아래와같이  맨오른쪽의 숏컷 부분을 누른뒤 원하는 키를 눌렀다 때면 생성할수있고.

사용할수있다.

 

 

여기서도 우클릭하면 초기화 제거 를 할수있다.

 

 

 

 

 

'엔진 > 유니티' 카테고리의 다른 글

유니티 데칼 (decal)  (0) 2024.04.16
Unity Spline 기능 추가!  (1) 2023.06.01
Unity Simulator  (0) 2023.01.20
Unity ObjectPool Api  (0) 2022.11.02
unity Redis  (0) 2022.07.13
반응형

 

원하는 도장, 스프레이 기능, 또는 자연스럽게 꾸미는 기능이 필요할경우

 

HDRP 유니티의 기능중 decal 기능을 사용할수있다

 

 

 

 

아래의 이미지 처럼  두개의 오브젝트에도 자연스럽게 위에 그릴수있다.

 

unity3d.com 에서 설명하는 이미지

 

 

현재 사용한엔진은 2022.2.20f 버전의 데칼이다.

 

Component 에서 HDRP Decal Projector 을 추가해준다.

 

 

이전 기능에서는 projecter 으로 일반에서도 쓸수있던 기능이지만 HDRP 로 변경되었다.

 

 

우선  새로운 Material 을 생성해준다

 

 

shader을 decal로 선택하여준다

 

 

위처럼 이미지를 넣어준 머터리얼을  아까 추가해준 Decal Projector 의 material 에 넣어주면  끝이다.

 

 

 

아래와 같이 데칼의 경우 네모상자와 방향이 표시된다 방향에 맞게 비치할경우 이미지가 그려진다.

 

 

 

 

 

 

 

간단한 사용법을 알아봤으니 이제 내부 변수들을 확인해 보자

 

 

위의 3가지 이미지는 이미지로 보이는것처럼

DECAL을 조절하는  방식을 변경할수 있다.

 

Scale Move  : Scale Invariant , inherit from Hierachy  

 

Scale Invariant   :  아래의 Size , Depth Pivot 들만 사용하여 decal을 지정

 

 inherit from Hierachy    :  아래의 size Depth Pivot 들과 오브젝트의 Transform 의값도 포함하여 계산

 

Draw Distance : 카메라가 데칼을 렌더링하는 최대 거리

 

Tiling : uv 축을 따른 머터리얼의 Tiling 값

 

offset : uv 축을 따른 머터리얼의 offset 

 

fade factor :  데칼의 투명도 조절 

 

Affects Transparent : 투명 포면위에 그릴수 있다.  Affect Transparenc가 활성화 되어있으면 

텍스처를 아틀라스에 패킹한다고 한다.

 

 

 

decal은 버전마다 조금씩 변수가 다르기에  아래의 주소에서 버전을 바꿔보면서 자신의 버전에 맞는 가이드를 읽어보는게 좋아보인다.

 

https://docs.unity3d.com/kr/Packages/com.unity.render-pipelines.high-definition@10.5/manual/Decal-Projector.html

 

데칼 프로젝터 | High Definition RP | 10.5.0

데칼 프로젝터 고해상도 렌더 파이프라인(HDRP)에는 특정 머티리얼(데칼)을 씬에 투사할 수 있도록 해주는 Decal Projector 컴포넌트가 있습니다. 데칼은 데칼 셰이더나 데칼 마스터 스택을 사용하는

docs.unity3d.com

 

'엔진 > 유니티' 카테고리의 다른 글

unity shortcuts  (0) 2024.09.03
Unity Spline 기능 추가!  (1) 2023.06.01
Unity Simulator  (0) 2023.01.20
Unity ObjectPool Api  (0) 2022.11.02
unity Redis  (0) 2022.07.13
반응형

Unity 2022버전 부터는 에디터 기능Spline이 새롭게 추가되었다.

이글은 2022.1.20f1 버전으로 spline 1.01 버전을 사용하였다.

 

이전 버전에선 직접 만들거나 에셋으로 사용하던 기능이 추가된것이다.

 

어떻게 추가되었는지 확인해 보자

 

자세한 내용과 코드 라이브러리를 확인할수 있는 주소다.

https://docs.unity3d.com/Packages/com.unity.splines@1.0/api/UnityEngine.Splines.SplineUtility.html

 

Class SplineUtility | Splines | 1.0.1

Class SplineUtility A collection of methods for extracting information about Spline types. Inheritance SplineUtility Assembly : solution.dll Syntax public static class SplineUtility : object Fields DrawResolutionDefault The default resolution used when unr

docs.unity3d.com

 

 

목차

1. 다운로드 위치

2. Spline 

2. Spline Instantiate

3. Spline Animate

4. Splline Extude

5. Spline Examples

 

6. 2.2.1 버전 업데이트

 

 

 

 

package manager ->package : unity Regisry ->splines 를 임포트 해준다.

추가를 해주면 아래처럼 Gameobject->3Dobject->Spline {Draw Spline Tool.., Square, Circle } 이 추가된다

순서대로

 

Draw Spline Tool : Spline 기본 오브젝트 생성

Square : 네모가 그려져있는 spline 오브젝트 생성

Circle : 원형이 그려져 있는 spline 오브젝트 생성

 

Square 생성시 만들어주는 Spline

 

Spline을 만들어준뒤 오브젝트를 눌러주면  Scene 좌측상단에 새로운 아이콘이 생겼다.

아이콘을 누른뒤 움직여주면  아래 사진처럼 변경이 가능하다

 

맨아레 아이콘을 눌러주면 Line 위에 새로운 점을 추가가능하다.

 

아래 화면이 InsPector 창의 Spline 이다.

 

 

 

먼저 Edit Mode Type 은 3가지로

{Catmull Rom , Bezier , Linear}

 

 

먼저 Catmull Rom  은 곡률을 수학적으로 계산해서 만들어주는 계산법이다.

점 3개를 가지고 0->2 과 1번의점을 평행하게 그어준뒤  허밋 곡선을 그어준다.

 

이미지 출처& 자세한 설명:

https://lee-seokhyun.gitbook.io/game-programming/client/easy-mathematics/gdc2012/catmull-rom-splines 

 

캣멀-롬 스플라인(Catmull-Rom Splines) - Game Programming

캣멀-롬 스플라인은 3차 허밋 스플라인에서 시작(U)과 끝(V) 지점의 속도 벡터를 결정하기 위한 특정한 값을 가진 스플라인 입니다. 새로운 스플라인 이라기 보다는 3차 허밋 스플라인을 구현하기

lee-seokhyun.gitbook.io

 

 

 

 

다음은 많이 사용하는 Bezier 형식이다

점 1,2를 지정후 가상의 1-1점과 2-1 점 총 4개의 점을 가지고 계산하는 방법으로

선위를 이동하는 점 과 이어주어 선을 그리는 방식이다.

 

마지막으로 Linear은 가장 기본적으로 점과 점을이어 선을 만드는 방식이다.

 

Knots는 점들의 정보를 저장한 리스트다.

 

Closed는 아래의 이미지처럼 시작점과 끝점을 이어주는가 아닌가에 대한 데이터다.

 

 

또한 spline의 위치는 x,y,z 모두 변경이 가능하다

 

 

 

 

 

 

오브젝트의 Add Component에서도 Splines라는 항목을 확인할수 있는데

그내부는 기본적으로 4가지가있다

 


먼저 Instantiate

아래 이미지 처럼 라인 위에 오브젝트들을 정렬생성 시킬수있다.

container에 원하는 Spline을 넣어준뒤

items to Instantiate에  { 오브젝트 , 나올 퍼센트} 를 입력해주고 맨아래의 Randomize를 누르고 Regenerate를 눌러주면

랜덤하게 배치해주는걸 볼수있다.

Instantiated Object Setup 설정을 변경해주면

배치될 오브젝트의 방향과 중점등을 세팅해 줄수있다.

Instantiation은 생성될 갯수로

Instance Count :  Dist 값이 늘어날수록 오브젝트 배치량이 늘고 간격이 좁아진다. 값은 Random과 Exact로 설정가능하다.

Spline Distance : 0.1~ 시작해 시작지점 오브젝트 부터 간격의 길이를 지정하여 배치하는 방법이다.

Linear Distance : 이 역시 간격의 길이를 지정하지만 계산을 배치할때 Linear 형식으로 배치하여 곡률이 없다.

 

 

 


이번엔 Spline Animate다

움직이길 원하는 오브젝트에 추가하여 사용한다.

 

Animated Object Setup 은 이전 Instantiate에 나온것과 같이 오브젝트의 방향 중점 등을 지정한다

 

Movement 는 기본적인 세팅을 할수있다.

 

Play on Awake : awake 실행 타이밍에 Play

 

Method : 움직이는 속도의 지정방식을 정할수 있다{ speed, time}

             time: 시간값 으로 숫자가 커질수록 느려진다.

             speed: 속도값 으로 숫자가 작아질수록 느려진다.

 

Easing :구간의 속도를 지정할수있다{None ,Ease in only , Ease Out Only , Ease In-Out}

              순서대로 {일정한속도, 들어갈때 느려짐, 나올때 느려짐, 들어갈때 나올때 느려짐}

 

Loop Mode: 반복 모드를 정할수 있다{,,, PingPong}

           Once :  한번만

          LoopContinous : 계속반복

          Ease in Then Continous : Easing 셋팅을 처음만 적용한뒤 반복 

          PingPong : 시작점->끝점->시작점으로 왕복을 반복한다.

 

세팅을 한후 Preview 에서 에니메이션을 확인할수 있다.

 


 

 

Splline Extude

 

Spline에 맞게 메쉬를 생성한다.

spline 오브젝트에 컴퍼넌트를 추가시 파일에 씬 이름과오브젝트 이름으로 메쉬파일을 만들어준다.

 

Geometry는 메쉬를 설정해줄수 있다.

           Radius : 굵기

           Profile Edfes : 메쉬의 원둘래 각의 개수를 

           Segaments Per Unit :메쉬의 한단위의 길이를 만드는 루프수

 

Advanced

    Range 는 시작 길이와 끝나는 지점을 지정할수있다.

    Auto - Regen Geometry :  true 일경우 spline이 변경되었을경우 자동 메쉬재생성 (런타임때 수정되지않으면 비활성화)

                Rebuild Frequency : 초당 최대 재생성 횟수

 

 


 

 

 

Spline Examples 

 

 Spline의 라이브러리 코드 기능들을 이용하여 만든 추가 예시 프로젝트들 이다.

이 예시 프로젝트는

Splines를 다운받은 화면 에서 확인할수있다 

아래 Samples를 import하면 확인할수 있다.

 

 

자동 도로 생성

 

 

Point Spline Data

 

추가 포인터 데이터

예시 프로젝트에선 탱크 오브젝트에 Look At 을 추가하여 움직일때 포인트를 바라보게 하였다.

 

 

 

Spline GetNearestPoint 

 

주변 Spline 찾기

 

 

또한 제공되는 예제에는 Spline 과 쉐이더를 같이 이용하는 모습도 보여준다.

spline 데이터를 GPU에 전달하는 방법

 

 

 


 

Unity 2022.3 버전이 나오면서

Splines 역시  2.2.1 버전으로 업데이트 하였다.

 

위치 변경과 기본 프리셋이 추가되었다.

3D Object 내부에 있던 Spline 이 밖으로 나왔고 프리셋이 몇가지 늘어났다.

 

 

또한 spline 설정법과 아쉬웠던 에디터에서의 조작이 편하게 바뀌었다.

 

보기 쉬워진 ui와  쉬워진 조작

spline의 UI가 바뀌어 Line 방향이 추가되었다.

또한 일전에는 Spline 컴퍼넌트에 들어있던 시스템들이 point마다 설정가능하게 변경되었다.

 

아래 이미지 처럼 하나의 spline Object에  이어지지 않은 여러개의 자유로운 spline을 만들수있다.

 

새롭게 생긴 Element inspector 창에서

기본적이 값도 변경이 가능하지만 Spline의 Knot 끼리의 상태를 설정가능하다.  

이렇게 다른 두개의 Knot 끼리 붙였다 뗄 수도 있고

중간에 위치하는 Knot을 둘로 나눠버릴수도있다.

 

 

 

 

Spline Examples 에서도 변경된 부분이 많았다.

 

라인 그리면 라인대로 spline을 그려주는 examples 이 추가되었고

 

이전 예제에서 Unity Editor 라이브러리를 이용하여 기능을 만들어서 자동차의 속도와 위치를 설정하는 부분이 생겼다. 

또한 새롭게 생긴 예제에서는 이번 업데이트로 인해  자유롭게 만들수 있는 Spline을 사용하는 방법도 보여준다.

 

'엔진 > 유니티' 카테고리의 다른 글

unity shortcuts  (0) 2024.09.03
유니티 데칼 (decal)  (0) 2024.04.16
Unity Simulator  (0) 2023.01.20
Unity ObjectPool Api  (0) 2022.11.02
unity Redis  (0) 2022.07.13
반응형

유니티 2021 버전부터는 Unity Simulator라는 것을 제공한다.

Game 창의 좌상단의 화살표를 클릭하면 Game화면과 Simulator화면을 선택할 수 있다.

Simulator로 변경하면

 

위 사진처럼 변경되는 모습을 볼 수 있다.

 

 

상단 목록

창의 상단에는 위 같은 목록들을 확인할 수 있는데

좌측부터 순서대로

1. 화면 실행 뷰 선택[Game, Simulator]

2. 원하는 기종 선택

3. 화면 확대, 축소

4. (3) 번의 확대, 축소 한 화면을 원상복귀

5.Rotate [좌, 우] 화면 돌리기

6.Safe Area 

 

와 같은 6가지 항목들이 존재한다.

이중에 6번 항목을 키는 경우

 

위 사진처럼 노란 테두리가 생기는데

이 역시 새롭게 추가된 기능으로 노치 디자인에 ui가 가려 버리는 사태를 막기 위해 있는 기능이다.

 

위 사진처럼 ui를 잡으라고 라인을 배치해 준다.

 

코드에서도 Safe Area가 생겨서 라인 내부로 ui들을 안나가게 할 수 있다.

https://docs.unity3d.com/ScriptReference/Screen-safeArea.html

 

Unity - Scripting API: Screen.safeArea

On some displays, certain areas of the screen might not be visible to the user. This might be because the display's shape is non-rectangular or in the case of TV displays, it can be caused by overscan. Avoid placing user interface elements in areas outside

docs.unity3d.com

 

또한 좌측에 application Settings라는 항목이 있어서 세팅을 추가로 해줄 수 있는데

 

시스템 언어 설정 

장치에의 네트워크 도달 옵션

이 기기의 인터넷 연결가능 옵션 설정

 

 

연결 불가능 

이동통신사 데이터 네트워크 연결

근거리 통신망 연결

 

On Low Memory

먼저 Low Memory는 foreground 말 그대로 앞에서 작동할 때

장치의 메모리부족일 때 앱이 종료되는 것을 방지하기 위해 중요하지 않은 자산(텍스쳐, 오디오)을 해제할 수 있다.

이러한 기능을 테스트하기 위한 버튼이다.

 

 

하지만 역시 안드로이드 시뮬레이터는 진짜 안드로이드로 돌리는게 아니기 때문에 여러가지 제한사항이 존재한다.

1. 기기의 성능 특성(기기의 프로세서 속도,메모리)

2. 기기의 렌더링 능력

3. 에디터에서 작동하지 않는 네이티브 플러그인

4. UNITY_IOS와 같은 시물레이션된 기기에 대한 플랫폼 #define 지시문

5. 자이로스코프 회전 센서

4.멀티터치 (한손가락 터치만 가능)

 

 

https://docs.unity3d.com/kr/2021.1/Manual/device-simulator.html

 

기기 시뮬레이터 - Unity 매뉴얼

이 문서 섹션은 Unity의 기기 시뮬레이터에 대한 정보를 포함합니다.

docs.unity3d.com

'엔진 > 유니티' 카테고리의 다른 글

유니티 데칼 (decal)  (0) 2024.04.16
Unity Spline 기능 추가!  (1) 2023.06.01
Unity ObjectPool Api  (0) 2022.11.02
unity Redis  (0) 2022.07.13
unity _Prefab Variants  (0) 2022.03.17
반응형

unity ObjectPool API 
(Version:2021)

이 글을 읽기 전에 자신이 쓰는 유니티 버전을 확인해보라

유니티가 지원하는 objectpool은 2021년 이후 버전부터 추가되었다.

 

1.ObjectPool 이란?

2.Unity ObjectPool

3. 글쓴이가 응용한 방식


 

1.ObjectPool

우리가 사용 하려는 오브젝트 풀은 간단하게 설명하면

오브젝트를 담아두고 재활용하기 위한 디자인 패턴이다.

 

어째서 재활용을 해야할까? 라는 생각을 할 수 있다.

이 물음에 답하자면

 

 생성과 파괴보다 재사용이 빠르고 가볍다.

 

생각해보라 우리가 오브젝트를 "생성" 한다는것은 그냥 그 자리에 나오는 것이 아닌

생성-> class에 맞는 데이터 크기만큼 메모리 할당-> 재생성시 재 대입해줘야 하는 데이터 값

그리고 파괴할 때 가비지 메모리 제거 등 많은 작업이 필요하다.

 

이러한 작업이 적을 경우에는 크게 상관이 없을 수 있지만 많은 데이터를 생성과 제거를 반복한다 생각하면 끔찍하다.

 

이러한 작업을 적게 할 방법이 ObjectPool이라는 방식이다.

 

ObjectPool은 오브젝트를 (생성-> 사용-> 제거)반복 에서  생성-> 사용-> (보관->재사용)반복 ->제거 식으로 사용하여

메모리를 아끼는 방식이다.


 

2.Unity ObjectPool

 

 

 

 

 

 

 

 

 

 

 

Pool 관련 클래스는 몇 가지가 있지만. 대부분 비슷한 사용법을 가진다.

그중에서 ObjectPool <T0>을 사용할 것이다.

namespace UnityEngine.Pool
{
    //
    // 요약:
    //     A stack based Pool.IObjectPool_1.
    public class ObjectPool<T> : IDisposable, IObjectPool<T> where T : class
    {
        public ObjectPool(Func<T> createFunc, Action<T> actionOnGet = null, Action<T> actionOnRelease = null, Action<T> actionOnDestroy = null, bool collectionCheck = true, int defaultCapacity = 10, int maxSize = 10000);

        public int CountAll { get; }
        public int CountActive { get; }
        public int CountInactive { get; }

        public void Clear();
        public void Dispose();
        public T Get();
        public PooledObject<T> Get(out T v);
        public void Release(T element);
    }
}

 

이게 내부 구성과 ObjectPool의 매개변수다.

ObjectPool(생성할 때 함수, 사용할 때 함수, 사용 끝났을 때 함수, 제거 함수, 충돌 체크, 기본적으로 생성해둘 양, 최대 양)

으로 생각하면 쉽다


 

총과 총알로 설명하겠다.

먼저 총알 prefab에 IobjectPool <GameObject> pool {get;set;}을 생 성해준 뒤 Update에 날아가는 코드를 작성해준다.

using UnityEngine.Pool;

public class Bullet : MonoBehaviour
{
    public IObjectPool<GameObject> Pool { get; set; }
    
    public virtual void ReleaseObject() => Pool.Release(this.gameObject);
    public virtual void OnTakeFromPool(GameObject obj) { }
    public virtual void OnReturnedToPool(GameObject obj) => obj.SetActive(false);
    public virtual void OnDestroyPoolObject(GameObject obj) => Destroy(obj);


}


public class Bullet_1 : BulletBase
{
    public float speed = 7;
    private void Update()
    {
        if (transform.position.y >= 10)
        {
            ReleaseObject();
        }
        transform.Translate(speed * Time.deltaTime * Vector3.up);
    }

    public override void OnTakeFromPool(GameObject obj)
    {
        obj.SetActive(true);
    }
}

 

그 후 BulletSpawner.cs를 만들어주어  ObjectPool <Gameobject>  Pool를 만들어준 뒤

ObjectPool내부에 생성할 Bullet의 함수들을 넣어둔다.

그리고 bullet 생성 함수에서 bullet 내부의 IObjcetPool pool에 spawn의  Pool을 넣어준다.

( bullet 내부에서 spawn의  Pool을  사용해야 하기 때문에) 

 

그리고 특정 상황마다 BulletSpawner 에서  Pool.Get();을 해준다.

 Pool.Get()은  Pool 내부 함수로 자동으로 현재 재사용 가능한 오브젝트가 있는지 없는지를 판단하여

생성해준다.

public class BulletSpawner : MonoBehaviour
{
 
    public BulletBase poolablePrefab;
    public IObjectPool<GameObject> Pool { get; private set; }
    

    public void Init()
    {
        
              Pool = new ObjectPool<GameObject>(
              delegate {
        // 오브젝트 생성함수
        // 오브젝트 생성
        GameObject obj = Instantiate(poolablePrefab.gameObject);
        //생성한 오브젝트의 IObjectPool Pool 에 Spawner의 ObjectPool을 넣어준다.
        obj.GetComponent<BulletBase>().Pool = Pool;
            return obj;
        },
        // Bullet에 구현된 사용할 함수들 입력
        poolablePrefab.OnTakeFromPool, poolablePrefab.OnReturnedToPool,
        poolablePrefab.OnDestroyPoolObject,
        true, poolablePrefab.defaultCapacity, 50));

    }
    
    public void Shoot()
    {
       var a= poolablePrefab.Pool.Get();
        a.transform.position = this.gameObject.transform.position;
    }
    private void Start()
    {
        Init();
        InvokeRepeating("Shoot", 0f,5f);

    }
}

 

 

 

 

 

아래는 유니티에서 제공한 예제다

더보기
using UnityEngine.Pool;

// This component returns the particle system to the pool when the OnParticleSystemStopped event is received.
[RequireComponent(typeof(ParticleSystem))]
public class ReturnToPool : MonoBehaviour
{
    public ParticleSystem system;
    public IObjectPool<ParticleSystem> pool;

    void Start()
    {
        system = GetComponent<ParticleSystem>();
        var main = system.main;
        main.stopAction = ParticleSystemStopAction.Callback;
    }

    void OnParticleSystemStopped()
    {
        // Return to the pool
        pool.Release(system);
    }
}

// This example spans a random number of ParticleSystems using a pool so that old systems can be reused.
public class PoolExample : MonoBehaviour
{
    public enum PoolType
    {
        Stack,
        LinkedList
    }

    public PoolType poolType;

    // Collection checks will throw errors if we try to release an item that is already in the pool.
    public bool collectionChecks = true;
    public int maxPoolSize = 10;

    IObjectPool<ParticleSystem> m_Pool;

    public IObjectPool<ParticleSystem> Pool
    {
        get
        {
            if (m_Pool == null)
            {
                if (poolType == PoolType.Stack)
                    m_Pool = new ObjectPool<ParticleSystem>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject, collectionChecks, 10, maxPoolSize);
                else
                    m_Pool = new LinkedPool<ParticleSystem>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject, collectionChecks, maxPoolSize);
            }
            return m_Pool;
        }
    }

    ParticleSystem CreatePooledItem()
    {
        var go = new GameObject("Pooled Particle System");
        var ps = go.AddComponent<ParticleSystem>();
        ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);

        var main = ps.main;
        main.duration = 1;
        main.startLifetime = 1;
        main.loop = false;

        // This is used to return ParticleSystems to the pool when they have stopped.
        var returnToPool = go.AddComponent<ReturnToPool>();
        returnToPool.pool = Pool;

        return ps;
    }

    // Called when an item is returned to the pool using Release
    void OnReturnedToPool(ParticleSystem system)
    {
        system.gameObject.SetActive(false);
    }

    // Called when an item is taken from the pool using Get
    void OnTakeFromPool(ParticleSystem system)
    {
        system.gameObject.SetActive(true);
    }

    // If the pool capacity is reached then any items returned will be destroyed.
    // We can control what the destroy behavior does, here we destroy the GameObject.
    void OnDestroyPoolObject(ParticleSystem system)
    {
        Destroy(system.gameObject);
    }

    void OnGUI()
    {
        GUILayout.Label("Pool size: " + Pool.CountInactive);
        if (GUILayout.Button("Create Particles"))
        {
            var amount = Random.Range(1, 10);
            for (int i = 0; i < amount; ++i)
            {
                var ps = Pool.Get();
                ps.transform.position = Random.insideUnitSphere * 10;
                ps.Play();
            }
        }
    }

 

 

3.

내가 구현한 방식이다.

 

 

Spawn에도 IObjectPool로 PoolManager에 BulletPool을 받아서 사용한다.
Manager 에서 새로운 오브젝트가 아닐경우 서로 공유해서 사용하게 한다.

 

글쓴이는 싱글톤으로 PoolManager을 만들어서 같은 총알은 서로 공유하여 사용하게 만들어보았다.

이런식으로 만들경우 Spawn컴퍼넌트를 오브젝트에 붙여주고 원하는 BulletPrefab을 넣어주면 완성이다.

 

참고자료 : https://docs.unity3d.com/ScriptReference/Pool.ObjectPool_1.html 

 

Unity - Scripting API: ObjectPool<T0>

Object Pooling is a way to optimize your projects and lower the burden that is placed on the CPU when having to rapidly create and destroy new objects. It is a good practice and design pattern to keep in mind to help relieve the processing power of the CPU

docs.unity3d.com

외 여러 영상들과 블로그

'엔진 > 유니티' 카테고리의 다른 글

Unity Spline 기능 추가!  (1) 2023.06.01
Unity Simulator  (0) 2023.01.20
unity Redis  (0) 2022.07.13
unity _Prefab Variants  (0) 2022.03.17
Unity Inspector 창 정리  (2) 2022.02.24
반응형

Unity 에서 Redis 서버를 사용해보자

 

Unity 버전 2019.4.15f1

 

NuGet의 StackExchange.Redis를 사용했다.

 


 설치&세팅

 

visual studio의 NuGet에서 Plugin을 다운받고 사용하면 사용이 안된다.

사용이 안되는 이유는 두가지로 

 

1. 유니티 내부에 있어야한다.

2. 유니티에서 호완하는 버전이 아니다

 

 

 

 

1. 누겟 페키지를 다운받았으면 다운받은 파일에 들어가서 

 

 

 

 

 

dll 파일과 xml 파일을 

 

unity Assets 파일에 Plugin 파일을 만들어서 넣어준다

 

 

 

 

 

 

 

 

 

 

 

2. 유니티 2019버전에서는 Redis 2버전대가 호환이 안된다

그럼으로 1.5버전을 다운받아서 넣어주면 된다.

 

 


사용법

 

 

그뒤로 unity 내부에서 사용하는 방법은 매우간단하다.

    private ConnectionMultiplexer redisConnection;
    private IDatabase DB;
    private ISubscriber sub;

3가지를 선언해 준다.

 

 첫줄은 StackExchange.Redis의 메인 객체다

 두번째 줄은 DB 데이터 를 주고받을 객체다.

 마지막줄 sub역시 데이터를 전달하기위해 있는객체다.

 

백문이 불여일견 코드로 보겠다.

Init Code

 public bool Init(string host, int port)
    {

        this.redisConnection = ConnectionMultiplexer.Connect(host + ":" + port);
        if (redisConnection.IsConnected)
        {
            this.DB = this.redisConnection.GetDatabase();
            sub = redisConnection.GetSubscriber();
            return true;
        }

        return false;
    }

    public bool Init(string host, int port, Events LoopEvents)
    {

        T = new Thread(new ThreadStart(LoopEvents));
        
        try
        {
            ConfigurationOptions option = new ConfigurationOptions
            {
                ConnectTimeout = 1000,
                AbortOnConnectFail = false,
                EndPoints = { $"{host}:{port}" },
            };
            redisConnection = ConnectionMultiplexer.Connect(option);
        }
        catch (Exception e)
        {
            Debug.Log(e);
        }

        if (redisConnection.IsConnected)
        {
            this.DB = this.redisConnection.GetDatabase();
            sub = redisConnection.GetSubscriber();
            T.Start();

            return true;
        }

        return false;
    }

 

위 코드의

        this.redisConnection = ConnectionMultiplexer.Connect(host + ":" + port);  줄에서 알수있듯

       "ip주소:포트넘버: 로 이루어져 있다. 

 

로컬로 테스트 할때는 아래 코드처럼 "localhost" 를 넣어서 사용하면된다.

this.redisConnection = ConnectionMultiplexer.Connect("localhost")

 

 그냥 주소로 connect를 시도 해도 좋지만

 

   ConfigurationOptions option = new ConfigurationOptions
            {
                ConnectTimeout = 1000,
                AbortOnConnectFail = false,
                EndPoints = { $"{host}:{port}" },
            };
            redisConnection = ConnectionMultiplexer.Connect(option);

이 부분처럼 ConfigurationOptions 를 사용하여 전달해도 좋다.

 그러면 구성 옵션을 세팅을 한번에 해줄수도 있다.

   

 

      this.redisConnection = ConnectionMultiplexer.Connect(host + ":" + port);

           ㄴ주소로 연결


        if (redisConnection.IsConnected) //연결 완료되었는가
        { 

       //연결 완료후 데이터들을 받는다.

            this.DB = this.redisConnection.GetDatabase();

            sub = redisConnection.GetSubscriber();

        }

 

 

 

 

이제 정상적으로 넘어간다면 다 끝났다. 

데이터를 주고받는 방법은 간단하다.

 

 

 

 

 

 

 

 

 

 

 

아까 선언해주었던 DB 객체의 내부에 전부 들어있다. 

아래 코드처럼 자신의 프로젝트에서 사용하기 편하게 만들어주면 끝이다.

 

   public string GetString(string key)
    {
        return this.DB.StringGet(key);
    }
    public bool SetString(string key, string val)
    {
        return this.DB.StringSet(key, val);
    }
    public RedisValue GetHASH(string key, string val)
    {
        return this.DB.HashGet(key, val);
    }
    public bool GetHASH_Bool(string key, string val)
    {
        var data = this.DB.HashGet(key, val);
        if (data.ToString()[0] == 't' || data.ToString()[0] == 'T')
        {
            return true;
        }
        return false;
    }
    public int GetHASH_Int(string key, string val)
    {
        var data = this.DB.HashGet(key, val);
        int Idata = 0;
        if (data.HasValue == true)
        {
            int DataSize = data.ToString().Length - 1;
            int sizenum = (int)Math.Pow(10, DataSize);
            foreach (var d in data.ToString())
            {
                if ('0' <= d && d <= '9')
                {
                    Idata += ((d - 48) * sizenum);
                    sizenum /= 10;
                }
                else
                {
                    return -int.MaxValue;
                }
            }
        }
        return Idata;
    }
    public double GetHASH_Double(string key, string val)
    {
        var data = this.DB.HashGet(key, val);
        if (data.HasValue == true)
        {
            double Idata = Double.Parse(data);
            return Idata;
        }
        return -Double.MaxValue;
    }
    public void SetHASH(string key, HashEntry[] val)
    {
        this.DB.HashSet(key, val);
    }
    public void DestroyHash(string key, RedisValue field)
    {
        this.DB.HashDelete(key, field);
    }

또한 Redis 서버에 메시지를 따로보내는 방법이 있는데 

그게 아까 보여주었던 sub 로 가능하다

    public void Meseage(string Channel, string Meseage)
    {
        sub.Publish(Channel, Meseage);
    }

특정 채널에 메시지를 보낼수있다.

또한 채널의 메시지를 구독하여 올라올때마다 확인받을수 있다.

 

    public void Setsubscrib(string _channel, CallBack_Funtc _CallBack_Funtc)
    {
        if (redisConnection.IsConnected)
        {
            sub.Subscribe(_channel, (channel, message) =>
            {
                try
                {
                    _CallBack_Funtc?.Invoke(channel+" "+message);
                    Debug.Log(message);
                }
                catch
                {

                }
            });
        }
    }

 

 

 

 

 

 

위에서 만들었던 클래스 사용

  private string Key;
    public string RedisIP_Num;
    public int PortNum;
    public bool GetDataLoop;
    public int ThreadDelay;

    private void Start()
    {
     // 따로 XMl로 받아오는 데이터들
        Key = Datas.data.DataKey;
        RedisIP_Num = Datas.data.RedisIP_Num;
        PortNum = Datas.data.PortNum;
        GetDataLoop = Datas.data.GetDataLoop;
        ThreadDelay = Datas.data.ThreadDelay;

        redis = new Redis();
        if (redis.Init(RedisIP_Num, PortNum, delegate
         {
             while (GetDataLoop)
             {
                 GEtD(); // redis.GetHASH_Bool(Key, "KeyData") 데이터들을 받아오는 함수
                 Thread.Sleep(ThreadDelay);

             }
         }))
        {
            Debug.Log("connect");
        }
        else
        {
            Debug.Log("Non_connect");
        }

 GEtD()함수 내부 코드는 이렇게 데이터를 받는다.

 

또한 Init 의 델리게이트에 데이터를 받아오는 함수와 스레드.Sleep(변수)

를 이용하여 연결이 완료되었을때 데이터를 주기적으로 받아오게 만들었다.

 

 

 

전체코드

더보기

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using StackExchange.Redis;
using System.Threading;
using System;
using System.Threading.Tasks;

namespace TStory
{
    static public class Global
    {
        public static bool Dnet_Connection;
        public static bool Dnet_readwrite;
        public static bool Dnet_error;
        public static double server_cache_alive;
        public static int client_connection_count;

    }
}

public class RDS : MonoBehaviour
{
    private Redis redis;
    public RedisValue redisValue;

    private string Key;
    public string RedisIP_Num;
    public int PortNum;
    public bool GetDataLoop;
    public int ThreadDelay;

    private void Start()
    {
        Key = Datas.data.DataKey;
        RedisIP_Num = Datas.data.RedisIP_Num;
        PortNum = Datas.data.PortNum;
        GetDataLoop = Datas.data.GetDataLoop;
        ThreadDelay = Datas.data.ThreadDelay;

        redis = new Redis();
        if (redis.Init(RedisIP_Num, PortNum, delegate
        {
            while (GetDataLoop)
            {
                GEtD();
                Thread.Sleep(ThreadDelay);

            }
        }))
        {
            Debug.Log("connect");
        }
        else
        {
            Debug.Log("Non_connect");
        }


    }

    private void OnApplicationQuit()
    {
        GetDataLoop = false;
        //redis.T.Join();
    }

    public void GEtD()
    {
        TStory.Global.Dnet_Connection = (redis.GetHASH_Bool(Key, "TStory-connection"));
        TStory.Global.Dnet_readwrite = (redis.GetHASH_Bool(Key, "TStory-readwrite"));
        TStory.Global.Dnet_error = (redis.GetHASH_Bool(Key, "device-net-error"));
        TStory.Global.server_cache_alive = (redis.GetHASH_Double(Key, "server-cache-alive"));
        TStory.Global.client_connection_count = (redis.GetHASH_Int(Key, "client-connection-count"));

    }

}

public class Redis
{
    private ConnectionMultiplexer redisConnection;
    private IDatabase DB;
    private ISubscriber sub;
    public delegate void Events();
    public Thread T;
    public bool Init(string host, int port)
    {

        this.redisConnection = ConnectionMultiplexer.Connect(host + ":" + port);
        if (redisConnection.IsConnected)
        {
            this.DB = this.redisConnection.GetDatabase();
            sub = redisConnection.GetSubscriber();
            return true;
        }

        return false;
    }

    public bool Init(string host, int port, Events LoopEvents)
    {


        T = new Thread(new ThreadStart(LoopEvents));
        try
        {
            ConfigurationOptions option = new ConfigurationOptions
            {
                ConnectTimeout = 1000,
                AbortOnConnectFail = false,
                EndPoints = { $"{host}:{port}" },
            };
            redisConnection = ConnectionMultiplexer.Connect(option);
        }
        catch (Exception e)
        {
            Debug.Log(e);
        }

        if (redisConnection.IsConnected)
        {
            this.DB = this.redisConnection.GetDatabase();
            sub = redisConnection.GetSubscriber();
            T.Start();

            return true;
        }

        return false;
    }
    public string GetString(string key)
    {
        return this.DB.StringGet(key);
    }
    public bool SetString(string key, string val)
    {
        return this.DB.StringSet(key, val);
    }
    public RedisValue GetHASH(string key, string val)
    {
        return this.DB.HashGet(key, val);
    }
    public bool GetHASH_Bool(string key, string val)
    {
        var data = this.DB.HashGet(key, val);
        if (data.ToString()[0] == 't' || data.ToString()[0] == 'T')
        {
            return true;
        }
        return false;
    }
    public int GetHASH_Int(string key, string val)
    {
        var data = this.DB.HashGet(key, val);
        int Idata = 0;
        if (data.HasValue == true)
        {
            int DataSize = data.ToString().Length - 1;
            int sizenum = (int)Math.Pow(10, DataSize);
            foreach (var d in data.ToString())
            {
                if ('0' <= d && d <= '9')
                {
                    Idata += ((d - 48) * sizenum);
                    sizenum /= 10;
                }
                else
                {
                    return -int.MaxValue;
                }
            }
        }
        return Idata;
    }
    public double GetHASH_Double(string key, string val)
    {
        var data = this.DB.HashGet(key, val);
        if (data.HasValue == true)
        {
            double Idata = Double.Parse(data);
            return Idata;
        }
        return -Double.MaxValue;
    }
    public void SetHASH(string key, HashEntry[] val)
    {
        this.DB.HashSet(key, val);
    }
    public void DestroyHash(string key, RedisValue field)
    {
        this.DB.HashDelete(key, field);
    }
    public void Meseage(string Channel, string Meseage)
    {
        sub.Publish(Channel, Meseage);
    }

}

 

'엔진 > 유니티' 카테고리의 다른 글

Unity Spline 기능 추가!  (1) 2023.06.01
Unity Simulator  (0) 2023.01.20
Unity ObjectPool Api  (0) 2022.11.02
unity _Prefab Variants  (0) 2022.03.17
Unity Inspector 창 정리  (2) 2022.02.24
반응형

 

 

 

2018버전부터 Prefab Variants 라는것을 지원한다.

Prefab Variants 는 프리펩의 자식 계념이라 생각하면 쉽다.

 

왼쪽이 Variants  ,오른쪽이 Original

 

아래 그림처럼 기존 프리팹을 바꿔서 Original 프리팹을 재생성 하게되었을때 

 

 

 

 

 

 

 

 

두개로 나뉘어버린 프리팹에 같은걸 추가하고 싶을땐

둘다 다시작업을 해주는 경우가 생긴다

이런경우 Variants 프리팹을 사용하면

 

 

아래 사진처럼 부모 프리팹을 수정하면 자식 프리팹도 수정이 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

왼쪽이 기존 프리팹 예시이고 오른쪽이 variants 예시다.

프리팹을 새로 만든후, 붉은 네모를 원본에 넣었을때 아래 예시처럼 작동한다.

 

 

 

 

 

 

 

 

 

 

 

 

모두 붉은 박스를 넣어주려고 할때

왼쪽이미지 처럼 복사 하여 생성한 프리팹은 붉은 박스를 전부 넣어주는 시간이 들어간다.

하지만 프리팹을 부모로 두고 variants로 작업할경우 쉽게 변형 시키고 추가 할수 있다.

 

 

 

 

 

 

variant 생성방법은

 

아래 사진처럼     Original 프리팹 우클릭->Create->Prefab Variant 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

또는  Hierarchy 창에서 오리지널 프리팹을 Project 창으로 드래그시 

 어떤식으로 저장할지 Create Prefab 창이 뜬다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

참고한 링크 :https://www.youtube.com/watch?v=pv30sE_Vsis

'엔진 > 유니티' 카테고리의 다른 글

Unity Spline 기능 추가!  (1) 2023.06.01
Unity Simulator  (0) 2023.01.20
Unity ObjectPool Api  (0) 2022.11.02
unity Redis  (0) 2022.07.13
Unity Inspector 창 정리  (2) 2022.02.24
반응형

 

 

 

목차

1.인스펙터창 목록

2.인스펙터창 구성

3.인스펙터창 어트리뷰트 코드

 

 

 

 

인스펙터 창 우클릭 시

Debug-Normal 모드 : 창 모드 변경

Expand All Components : 세부 정보 펴기

Collapse All Components: 세부 정보 접기

Lock : 현재 component로 계속 보이게 지정

Maximize :  전체 화면

UIElements Debugger & UIToolkit Debugger : 유니티 화면 구성이 나오는 창

 

컴포넌트 우클릭 시

Reset : 초기화 (초기 세팅 값으로 돌아감)

Move Down-UP : 컴포넌트끼리의 위치 조정

Copy Component : 내부 값들 복사

Paste Component As  New : 새로 복사

Paste Component Valuse : 값 복사 

Find References In Scene : 씬에서 찾기

Properties... : 새창으로 보기

Edit Script : 스크립트 창으로 이동

 

 

디버그 모드 사용

사정자 정의 에디터가 표시되고 private 변수가 표시된다.

(Public처럼 수정은 불가능)

 

 

 

 

 

 

 

 

 

 

디버그 모드는 인스펙터 창 마다 설정 가능 하기에

하나만 켜 두고 볼 수 있다.

 

 

 

 

 

그리고 만약 Run 타임때 값을 저장하고싶으면 

컴퍼넌트 우클릭후 copy 
run 타임정지후 Paste 를 사용하여 데이터를 옮길수 있다.

 

 


 

 

 

상단구성

inspector 상단 구성

 

게임 Scene에서 보이는 아이콘 선택

아래 사진처럼 색 모양 또는 직접 아이콘 이미지를 설정할 수 있다

 

 

 

 

Scene에서 이렇게 보인다

 

 

 

 

 

 

Static

 

 

오브젝트 Static 설정

 ㄴ 최적화를 위해서 플레이 도중 오브젝트가 움직일 수 있는지 여부

   오브젝트의 연산을 미리 수행하고 런타임 시 적용하여 런타임 연산을 줄인다.

 

세팅에 따라 활성 비활성화되는 설정이 있다.

&nbsp;위 사진의 왼쪽은 static 설정이 켜진상태 / 오른쪽은 static 설정이 꺼진상태 이다.

사전 연산 설정을 따로 지정할 수도 있다.

이 부분의 자세한 설명은 매뉴얼을 참고하자

https://docs.unity3d.com/kr/2019.3/Manual/StaticObjects.html

 

 

 

 

 

 

Tag

Tag 설정

Tag 설정은 오브젝트를 식별할 때 도움을 준다.

addTag로 태그를 추가할 수 있다.

 

 

 

Layer

Layer&nbsp; 설정

1. 렌더링 설정 (렌더링 순서 또는 카메라에서 렌더링 제외도 가능하다)

 카메라 Culling Mask 레이서 설정으로 렌더링 제외 가능

 

 

 

 

2. 충돌 설정 (레이어끼리 선택적으로 충돌 안 하게 가능하다.)

 Edit->Project Settings -> physics

 

Layer 마다 충돌 설정 가능

 

 

 

 

3. 레이 캐스팅 충돌

  레이 캐스팅 충돌을 할 때 필요 없는 Collider을 걸러낼 수 있다

   https://docs.unity3d.com/ScriptReference/Physics.Raycast.html

 

 

 

 

Add Tag&Layer

 

Tag 추가

 

Sorting Layer (렌더링 순서) 추가

 

Layers 추가

 

 

 

 

 

 이사진처럼 SpriteRenderer에 Sorting Layer가 있다.

 

 

 

 

 

 

 

활성화/비활성화

 

비활성화 시 실행되지 않는다.

오브젝트 비활성화/활성화

비활성화 시 오브젝트 내부 컴포넌트들이 없는 것으로 인식된다.

 

 

Lock 다른 오브젝트를 눌러도 lock 누를때 설정된 오브젝트로 고정시켜준다.

 


코드 설정

 

Reset

데이터 리셋

컴퍼넌트 우클릭시 나오는 창의 상단에 Reset 버튼이 존재한다. 누르면 초기세팅으로 돌아가지만

원하는 리셋 설정을 해줄수있다.

 

 

 

 

 

 

AnimationCurve

 

데이터를 직접 보며 지정하여 사용할수있다.

 

특정위치마다 key를 넣거나 선의 곡률을 지정한뒤 에니메이션 이나  시간에따른 작업 같은 여러상황에 사용할수있다

 

 

 

 

 

 

 

 

[SerializeField]

priavte 함수를 inspector 창에서 값을 변경할수 있다.

위의 TextArea의 최대줄수와 최소줄수 역시 설정가능

 

 

 

[Space]

사용자가 보기쉽게 중간중간 공간을 띄워줄수있다.

 

 

 

 

[Header]

 

헤더 이름으로 중간에 이름만 넣을수있다.

 

 

[Range]

숫자의최소 최대값을 설정할수있다. 

 

 

[TooltipAttribute]

마우스를 올렸을때 설명을 설정할수있다.

 

 

[HideInInspector]

public 함수를 인스펙터에서 숨길수 있다.

 

[HelpURL]

inspector의 ? 부분의 URL을 설정할수 있다.

 

 

 


 

'엔진 > 유니티' 카테고리의 다른 글

Unity Spline 기능 추가!  (1) 2023.06.01
Unity Simulator  (0) 2023.01.20
Unity ObjectPool Api  (0) 2022.11.02
unity Redis  (0) 2022.07.13
unity _Prefab Variants  (0) 2022.03.17

+ Recent posts