모바일에서 게임 플레이 중에 홈버튼으로 나가게 된다면 애니메이션이나 프레임은 어떻게 동작하는 것이 궁금하여 큐브가 회전하는 간단한 애니메이션을 만들어 테스트해봤다.

유니티 에디터에서 모바일에서 홈버튼이 눌린 상태를 만들기 위해서는 아래와 같은 세팅이 필요하다.

Run In Background 체크를 해제한다. 그러면 유니티 에디터 창이 비활성화 상태를 만들면 게임은 멈추게 된다. 

그럼 이제 몇 가지 테스트를 해보자

1. 애니메이터 Update Mode : Normal / WaitForSecondsRealtime

    void Start()
    {
        Debug.Log("Test 시작");
        StartCoroutine(CorTest());
    }

    public IEnumerator CorTest()
    {
        yield return (CorWaitForRealSeconds());
    }
    private IEnumerator CorWaitForRealSeconds()
    {
        yield return new WaitForSecondsRealtime(5);
        Debug.Log("Test2 WaitForSecondsRealtime 5seconds");
    }
    //애니메이션 이벤트 콜.
    public void AnimEnd()
    {
        Debug.LogError("AnimEnd");
    }

 

에디터가 시작하면 CorTest를 시작하면서 RealSeconds로 5초를 기다린 후 로그를 출력하고, AnimEnd는 애니메이션에서 6초에 이벤트 키를 넣었다.

정상적으로 아무 동작을 하지 않으면 차례대로 5초 뒤에 "Test 2 WaitForSeconds 5 seconds"을 출력하고 그다음에 1초 뒤에 곧이어 "AnimEnd"을 출력하게 될 것이다.

예상 : "Test 2 WaitForSeconds 5 seconds" -> 1초 뒤  "AnimEnd"

에디터가 활성화되어있지 않을 때는 애니메이션이 멈추는 것을 볼 수 있다. 5초쯤에 유니티를 클릭하면 바로 "Test 2 WaitForSecondsRealtime 5 seconds"을 출력하게 된다. 그리고 "AnimEnd"은 1초가 아닌 약 5초 뒤에 출력하게 되는 것을 볼 수 있다.

결과 : "Test 2 WaitForSeconds 5 seconds" -> 약 5초 뒤  "AnimEnd"

테스트 결론 : 비활성화되었을 때도 WaitForSecondsRealtime은 계속해서 흐르지만 애니메이션은 활성화 되었을때 다시 카운팅을 하는 것이다. 

 

2. 애니메이터 Update Mode : Unscaled Time / WaitForSeconds

    void Start()
    {
        Debug.Log("Test 시작");
        StartCoroutine(CorTest());
    }

    public IEnumerator CorTest()
    {
        yield return StartCoroutine(CorWaitForSeconds());
        //Debug.LogError("CorTest");
    }
    private IEnumerator CorWaitForSeconds()
    {
        yield return new WaitForSeconds(5);
        Debug.Log("Test2 WaitForSeconds 5seconds");
    }
    //애니메이션 이벤트 콜.
    public void AnimEnd()
    {
        Debug.LogError("AnimEnd");
    }

애니메이션 이벤트 콜은 6초이기 때문에 WaitForSeconds 5 seconds 후 1초 뒤에 AnimEnd가 불려야 하지만 

애니메이터는 Unscale Time이기 때문에 비활성화 상태에도 시간은 흐른다. 그렇기 때문에 "AnimEnd" 후 "WaitForSeconds 5 seconds"가 출력된다. 

결론으로 짝을 매겨보자면.

Unscale Time과 WaitForSecondsRealtime과 짝꿍/  Normal과 WaitForSeconds이 짝이 될수 있겠다.

애니메이션이 종료 시점에 맞추어 코 루틴으로 제어한다면 애니메이터 업데이트 모드를 확인하고 그에 맞는 대기 코 루틴을 설정할 필요가 있다.

반응형

딱히 카테고리를 찾기어려워서 개발하다가 생각난 부분이기에 이쪽에다가 쓴다. ExtensionMethod라는 스태틱 클래스를 만드는게 여러모로 편리하다고 생각했다.  일단 사용정의는 데이터를 확장시켜사용하는? 밑에 코드사진을 보면 이해가 될 것 같다.

ExtensionMethod은 어떻게 활용?

활용하기에 가장 먼저 떠오르는 것은 Table데이터들이다.

ExtensionMethod.class

저장된 테이블의 데이터를 키값으로 호출하기 위한 메서드이다.

클릭하는 히어로의 데이터를 받기위해 만들었다.

 

호출방법

PropertySelect.class

호출하려는 히어로의 넘버를 통해 원하는 데이터를 불러온 후 그데이터를 알맞게 사용한다.

UI_PropertySelect.class

 

반응형

3D물체를 움직이면 캐릭터에 가까운 지형은 활성화 멀리있는 지형은 비활성화 하도록 풀링을 해보았다.

땅을 생성하면 자동적으로 랜덤으로 땅위 바위와 나무들이 랜덤으로 위치한다.

클릭 하면 gif 재생

처음에는 지형이 가지고 있는 스크립트에서 캐릭터와의 거리를 체크해주려고 했는데 오브젝트가 꺼져있을때 체크가 불가능하기 때문에 지형이 생성될 때 위치를 관리하고 있다가 그 거리를 캐릭터와 비교 하도록 했다.

m_lipool : 풀링에 들어온 오브젝트

m_liActive : 활성화 된 오브젝트

유니티 실행하면 초기에 땅을 생성하는 함수이다. 생성과 동시에 리스트에 지형오브젝트의 위치를 추가해준다. 

캐릭터와 멀리있는 지형에 있는 오브젝트를 비 활성화 해주기 위한 함수이다. 

m_liTemp는 멀리있는 지형을 비 활성화 해주기 위한 리스트이다. PlanSet스크립트를 통해 멀리있으면 m_liTemp에 담아 두고 꺼주도록 한다. m_liActive에는 삭제해주고 다시 m_liPool에 넣어둔다. 

무한이 로딩되는 맵에 사용하도록 하면 좋을 듯하다.

반응형

이쪽 카테고리는 학습하면서 삽질 + 복습용으로 사용해야겠다.

문법중에 제네릭인데 구조적으로 자주 사용하는게 좋은데 안쓰다보니 계속 안쓰게된다.... 다시 복습겸 기본 예제 코드를 만들어서 복습했다.

public class Test<T>
{
	public T field;
	
	public Test(T t)
	{
		field = t;
	}
}

제네릭 Test.class를 만들고 클래스 인스턴스를 생성할때 생성자를 통해 변수 field에 할당 하도록 했다.  

public class m_test : MonoBehaviour
{
	public Test<int> m_int;
	public GameObject obj_test;
	public Test<GameObject> m_gobj;

	void Start()
    {
		m_int = new Test<int>(10);
		Debug.Log(m_int.field);


		m_gobj = new Test<GameObject>(obj_test);
		Debug.Log(m_gobj.field.gameObject.name);
	}
}

예로 <int>, <GameObject>두 가지로 클래스를 생성했다. Test<int>는 10을 넣고 Test<GameObject>는 TestObj라는 이름 인 GameObject를 인스펙터창에서 넣고    Test<GameObject> 클래스 생성할 때 생성자에 넣었다.

유니티 디버그 콘솔창

where T : 제약조건  (인터페이스

where T : <인터페이스 이름> 형식 인수가 지정된 인터페이스이거나 지정된 인터페이스를 구현해야 합니다. 여러 인터페이스 제약 조건을 지정할 수 있습니다. 제한하는 인터페이스는 제네릭이 될 수도 있습니다.
public interface IMonster
{
	void print();
}
public class MessagePrinter : IMonster
{
	string Message;

	public MessagePrinter(string message)
	{

		this.Message = message;
	}

	public void print()
	{
		Debug.Log(this.Message);
	}
}

public class Test<T>  where T : IMonster
{
	public T[] Array { get; set; }

	public Test(int size)
	{
		Array = new T[3];
	}

}

 

public class m_test : MonoBehaviour 
{

	Test<IMonster> test = new Test<IMonster>(3);
	void Start()
    {
		test.Array[0] = new MessagePrinter("하나");
		test.Array[1] = new MessagePrinter("둘");
		test.Array[2] = new MessagePrinter("셋");


		for (int i = 0; i < 3; i++)
			test.Array[i].print();
	}
}

반응형

문제점 : 빨간색 / 해결방법 : 파란색 / 느낀 점 : 녹색 

 

위 box, 밑 bomb 

폭탄이 터지면 4방향(좌,위,우,하)를 레이캐스트로 확인해주려고 한다.

오브젝트 종류 : box,wall,player,enemy

4방향의 wall있으면 wall이있는 방향에는 폭탄이 터지는 애니메이션 발동X

box는 box를 애니메이션 발동과 box를파괴를 하고싶었다.

이런식으로 레이가 4방향으로 돌면서 콜라이더를 검출하도록 했다.

우선 충돌처리를 하기 위해 boxcollider2D와 rigidbody2D컴포넌트를 추가했다.

이상하게 계속 검출이 안됐다. 이유는 rigidbody2D의 Simulated체크를 안했었다.

유니티도큐 : 리지드바디 2D 및 연결된 모든 콜라이더 2D와 조인트 2D가 런타임에 물리 시뮬레이션과 상호작용하도록 하려면 Simulated 를 활성화합니다(체크박스를 선택합니다). 비활성화되면(체크박스가 선택 해제되면) 이들 컴포넌트가 시뮬레이션과 상호작용하지 않습니다. 

느낀 점 : 충돌처리를 할때는 생각해야 할 부분들이 있다 . Coliider,Rigidbody, 스크립트 상의 OnTrigger,On ColiiderOnCollisi

onEnter등 차이점과 활성화와 비활성화 했을때 각각 다른점들을 다시 한번에 체크해봐야겠다.

반응형

 

형식이 같은 두 개체를 비교할때 자주 사용하는  Comparsion 델리게이트이다.

public class m_test : MonoBehaviour 
{
	public delegate int Comparsion<in T>(T x, T y);
	static int SortWithPrice(Product a, Product b)
	{
		return a.price.CompareTo(b.price);
	}
	class Product
	{
		public string Name { get; set; }
		public int price { get; set; }
	}
	void Start()
	{
		List<Product> products = new List<Product>()
		{
			new Product() { Name = "감자", price = 500 },
			new Product() { Name = "사과", price = 700 },
			new Product() { Name = "고구마", price = 400 },
			new Product() { Name = "배추", price = 600 },
			new Product() { Name = "상추", price = 300 }
		};

		products.Sort(SortWithPrice);
		foreach(var val in products)
		{
			Debug.Log(string.Format("품목:{0}, 가격:{1}",val.Name, val.price));
		}
	}

}

public delegate int Comparison<in T>(T x, T y);

T : 비교할 개체의 형식,

x : 비교할 첫 번째 개체

y : 비교할 두 번째 개체

public class m_test : MonoBehaviour 
{
	//public delegate int Comparsion<in T>(T x, T y);
	//static int SortWithPrice(Product a, Product b)
	//{
	//	return a.price.CompareTo(b.price);
	//}
	class Product
	{
		public string Name { get; set; }
		public int price { get; set; }
	}
	void Start()
	{
		List<Product> products = new List<Product>()
		{
			new Product() { Name = "감자", price = 500 },
			new Product() { Name = "사과", price = 700 },
			new Product() { Name = "고구마", price = 400 },
			new Product() { Name = "배추", price = 600 },
			new Product() { Name = "상추", price = 300 }
		};

		products.Sort(delegate (Product a, Product b)
		{
			return a.price.CompareTo(b.price);
		});
		//products.Sort(SortWithPrice);
		foreach(var val in products)
		{
			Debug.Log(string.Format("품목:{0}, 가격:{1}",val.Name, val.price));
		}
	}

}

=> SortWithPrice 메서드를 선언하지 않고도 가능하다.

		products.Sort((a, b) => 
		{
			return a.price.CompareTo(b.price);
		});

=> 람다 사용

 

콜백메서드 구현하기

		class Monster
		{
			public string Name { get; set; }
			public double Pow { get; set; }

			public Monster(string name, double pow)
			{
				Name = name;
				Pow = pow;
			}

			public override string ToString()
			{
				return this.Name+" : " +this.Pow;
			}
		}

Monster.class 몬스터이름과 파워수치를 받는 클래스

		class Monsters
		{
			private List<Monster> listOfMonster = new List<Monster>();
			public delegate void PrintProcess(Monster list);

			public void Add(Monster monster)
			{
				listOfMonster.Add(monster);
			}

			public void Print()
			{
				Print((monseter) =>
				{
					Console.WriteLine(monseter);
				});
			}
			public void Print(PrintProcess porocess)
			{
				//콜백메서드를 사용
				foreach(var item in listOfMonster)
				{
					porocess(item); //콜백 메서드에 매개변수를 전달해 호출
				}
			}

		}

Mosters.class 

Add메서드를 통해 Monster클래스를 가지고있는 객체들을 리스트로 넣어주고,

델리게이트를 통해 몬스터 리스트들의 정보를 출력해준다.

monsters.Print(); : monster.class ToString을 통해서 출력

monsters.Print((monster) =>
{
      Console.WriteLine();
      Console.WriteLine("이름: " + monster.Name);
      Console.WriteLine("파워: " + monster.Pow);
});

: 델리게이트를 통해 출력형식을 지정한 출력

풀 코드

...더보기

 

using System;
using System.Collections.Generic;

namespace ConsoleApp23
{
    class Program
    {
        class Monster
        {
            public string Name { get; set; }
            public double Pow { get; set; }

            public Monster(string name, double pow)
            {
                Name = name;
                Pow = pow;
            }

            public override string ToString()
            {
                return this.Name + " : " + this.Pow;
            }
        }

        class Monsters
        {
            private List<Monster> listOfMonster = new List<Monster>();
            public delegate void PrintProcess(Monster list);

            public void Add(Monster monster)
            {
                listOfMonster.Add(monster);
            }

            public void Print()
            {
                Print((monseter) =>
                {
                    Console.WriteLine(monseter);
                });
            }
            public void Print(PrintProcess porocess)
            {
                foreach (var item in listOfMonster)
                {
                    porocess(item);
                }
            }

        }
        static void Main(string[] args)
        {
            Monsters monsters = new Monsters();
            monsters.Add(new Monster("고블린", 100));
            monsters.Add(new Monster("슬라임", 10));

            monsters.Print();
            monsters.Print((monster) =>
            {
                Console.WriteLine();
                Console.WriteLine("이름: " + monster.Name);
                Console.WriteLine("파워: " + monster.Pow);
            });


        }
    }
}
   

 

반응형

+ Recent posts