반응형

안녕하세요.

Player Settings에서 Target API Level을 API level 29로 설정을 한 후 GoolglePlayServices에서 오류가 발생되었습니다.

 

다음 에러입니다.

Stopped polling job due to exception: System.NullReferenceException: Object reference not set to an instance of an object
  at GooglePlayServices.UnityCompat.VersionFromAndroidSDKVersionsEnum (System.String enumName, System.String fallbackPrefKey, System.Int32 fallbackValue) [0x00000] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/UnityCompat.cs:58 
  at GooglePlayServices.UnityCompat.GetAndroidTargetSDKVersion () [0x00015] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/UnityCompat.cs:116 
  at GooglePlayServices.PlayServicesResolver.CanEnableJetifierOrPromptUser (System.String titlePrefix) [0x000ae] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:2314 
  at GooglePlayServices.PlayServicesResolver.ResolveUnsafe (System.Action`1[T] resolutionComplete, System.Boolean forceResolution, System.Boolean isAutoResolveJob, System.Boolean closeWindowOnCompletion) [0x00014] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1635 
  at GooglePlayServices.PlayServicesResolver+<ScheduleResolve>c__AnonStorey1E.<>m__3F () [0x00000] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1604 
  at GooglePlayServices.PlayServicesResolver.ExecuteNextResolveJob () [0x00069] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1461 
  at GooglePlayServices.PlayServicesResolver.ScheduleResolve (System.Boolean forceResolution, System.Boolean closeWindowOnCompletion, System.Action`1[T] resolutionCompleteWithResult, System.Boolean isAutoResolveJob) [0x000a7] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1617 
  at GooglePlayServices.PlayServicesResolver.AutoResolve (System.Action resolutionComplete) [0x00017] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1134 
  at GooglePlayServices.PlayServicesResolver.<ScheduleAutoResolve>m__47 () [0x00016] in /Users/smiles/dev/src/unity-jar-resolver/source/PlayServicesResolver/src/PlayServicesResolver.cs:1113 
  at Google.RunOnMainThread.ExecutePollingJobs () [0x0004a] in /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:300 
UnityEngine.Debug:LogError(Object)
Google.RunOnMainThread:ExecutePollingJobs() (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:303)
Google.RunOnMainThread:<ExecuteAll>m__A() (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:414)
Google.RunOnMainThread:RunAction(Action) (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:234)
Google.RunOnMainThread:ExecuteAll() (at /Users/smiles/dev/src/unity-jar-resolver/source/VersionHandlerImpl/src/RunOnMainThread.cs:406)
UnityEditor.EditorApplication:Internal_CallUpdateFunctions() (at C:/buildslave/unity/build/Editor/Mono/EditorApplication.cs:303)

검색을 해보니, Play Services Resolver를 업데이트 해야 해결된다고 합니다.

 

이리저리해보다가 안되서... API level 28로 낮춘 후 재시작하고, 다시 타겟 API 레벨을 상위로 올렸습니다.

 

근본적인 문제해결하면 다시 올리겠습니다.

반응형
반응형

안녕하세요

포맷 후 앱을 빌드하다가 Target Android SDK installed 에러가 발생했습니다.

내용은 Android SDK does not include your Target SDK of 29. Please use the Android SDK Manager to install your target SDK version. Restart Unity after SDK installation for the changes to take effect. 였습니다.

번역하면 "Android SDK에는 Target SDK 29가 포함되어 있지 않습니다. Android SDK Manager를 사용하여 대상 SDK 버전을 설치하십시오. 변경 사항을 적용하려면 SDK 설치 후 Unity를 다시 시작하세요" 입니다.

target 버전의 SDK가 설치가 안되었다는 뜻인데, 설치하려면 안드로이드 스튜디오로 들어가서 File - Settings로 들어갑니다.

좌측에 SDK를 선택해주고 해당 안드로이드 SDK를 설치합니다.

 

설치가 완료되면 unity를 재시작한 후 빌드를 합니다.

 

반응형
반응형

안녕하세요.

개발을 하다 보면 터치 혹은 마우스 클릭으로 오브젝트를 선택해야 하는 경우가 있습니다.

1. 3D 오브젝트 선택하기 

새로 프로젝트를 만들고 3D 오브젝트를 생성해줍니다.

저는 Cube, Capsule, Sphere, Cyinder를 생성한 후 적당한 위치로 이동시켜봅니다.

그리고 빈 오브젝트를 하나 생성해서 스크립트를 다음과 같이 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class SelectObjectManager : MonoBehaviour
{
    Vector3 m_vecMouseDownPos;
 
    void Update()
    {
#if UNITY_EDITOR
        // 마우스 클릭 시
        if (Input.GetMouseButtonDown(0))
#else
        // 터치 시
        if (Input.touchCount > 0)
#endif
        {
 
#if UNITY_EDITOR
            m_vecMouseDownPos = Input.mousePosition;
#else
            m_vecMouseDownPos = Input.GetTouch(0).position;
            if(Input.GetTouch(0).phase != TouchPhase.Began)
                return;
#endif
            // 카메라에서 스크린에 마우스 클릭 위치를 통과하는 광선을 반환합니다.
            Ray ray = Camera.main.ScreenPointToRay(m_vecMouseDownPos);
            RaycastHit hit;
 
            // 광선으로 충돌된 collider를 hit에 넣습니다.
            if(Physics.Raycast(ray, out hit))
            {
                // 어떤 오브젝트인지 로그를 찍습니다.
                Debug.Log(hit.collider.name);
 
                // 오브젝트 별로 코드를 작성할 수 있습니다.
                if (hit.collider.name == "Cube")
                    Debug.Log("Cube Hit");
                else if (hit.collider.name == "Capsule")
                    Debug.Log("Capsule Hit");
                else if (hit.collider.name == "Sphere")
                    Debug.Log("Sphere Hit");
                else if (hit.collider.name == "Cylinder")
                    Debug.Log("Cylinder Hit");
            }
 
        }
    }
}
 
cs

실행하면 오브젝트를 클릭할 때마다 로그가 찍히는 것을 확인할 수 있습니다.

 

2. 2D 오브젝트 선택하기

같은 방식으로 2D 오브젝트를 Square, Circle, Capsule을 생성해줍니다.

2D 오브젝트는 생성할 때 기본적으로 Collider가 없기 때문에 오브젝트에 맞게 Collider를 넣어줘야 합니다.

Square에는 Box Collider 2D를 넣습니다.
Circle에는 Circle Collider 2D를 넣어줍니다.
Capsule에는 Capsule Collider 2D를 넣어줍니다.

그리고 스크립트를 넣을 빈 오브젝트도 생성한 후 다음 스크립트를 넣어줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class SelectObjectManager : MonoBehaviour
{
    Vector3 m_vecMouseDownPos;
 
    void Update()
    {
#if UNITY_EDITOR
        // 마우스 클릭 시
        if (Input.GetMouseButtonDown(0))
#else
        // 터치 시
        if (Input.touchCount > 0)
#endif
        {
 
#if UNITY_EDITOR
            m_vecMouseDownPos = Input.mousePosition;
#else
            m_vecMouseDownPos = Input.GetTouch(0).position;
            if(Input.GetTouch(0).phase != TouchPhase.Began)
                return;
#endif
            
 
            // 마우스 클릭 위치를 카메라 스크린 월드포인트로 변경합니다.
            Vector2 pos = Camera.main.ScreenToWorldPoint(m_vecMouseDownPos);
 
            // Raycast함수를 통해 부딪치는 collider를 hit에 리턴받습니다.
            RaycastHit2D hit = Physics2D.Raycast(pos, Vector2.zero);
 
            if (hit.collider != null)
            {
                // 어떤 오브젝트인지 로그를 찍습니다.
                Debug.Log(hit.collider.name);
 
                // 오브젝트 별로 코드를 작성할 수 있습니다.
                if (hit.collider.name == "Square")
                    Debug.Log("Square Hit");
                else if (hit.collider.name == "Circle")
                    Debug.Log("Circle Hit");
                else if (hit.collider.name == "Capsule")
                    Debug.Log("Capsule Hit");
            }
 
        }
    }
}
 
cs

클릭할 때마다 로그가 찍히는 것을 확인할 수 있습니다.

 

3. 2D오브젝트가 선택이 제대로 안될 때

카메라 설정에 Projection이 "Perspective"로 되어있으면 제대로 선택이 안됩니다.

꼭 2D 일 때는 "Orthographic"로 설정해야 합니다.

Perspective : 원근감이 적용됩니다. (주로 3D)
Orthographic : 직각 투영으로 원근감이 없습니다.(주로 2D)

반응형
반응형

안녕하세요.

Unity와 Firebase를 연동한 후 Firebase기능 중 하나인 데이터베이스를 연동해보도록 하겠습니다.

 

1. Firebase셋팅

Firebase Colsole에 접속합니다.

https://console.firebase.google.com/?hl=ko 

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

 

프로젝트를 추가합니다.

프로젝트 이름을 입력한 후 계속 버튼을 클릭해줍니다.

 

애널리틱스 사용여부를 확인한 후 계속 버튼을 클릭합니다.

애널리틱스 계정 선택을 하라고 나옵니다.

따로 계정이 있다면 설정해주고, 없다면 Default Account for Firebase를 선택한 후 프로젝트 만들기를 클릭합니다.

잠시 기다린 후 준비되었다는 화면이 나오면 계속 버튼을 클릭합니다.

 

프로젝트 창으로 이동되는데, 여기서 Unity마크를 클릭합니다.

 

앱을 등록합니다.

IOS, Android를 각각 등록합니다.

 

유니티 ProjectSettings에 패키지네임을 적으면 됩니다.

 

IOS번들ID와 Android 패키지이름을 넣으면 앱등록 버튼이 활성화됩니다. 

클릭해줍니다.

google-services.json, GoogleService-Info.plist 구성 파일 다운로드를 해서 Unity프로젝트의 Assets폴더에 넣어줘야합니다.

넣어준 후 다음 버튼을 클릭합니다.

Firebase SDK 추가를 합니다.

Firebase Unity SDK(Zip)파을 다운로드 받은 후 압축을 풀어줍니다.

압축을 풀어주면 추후에 변경될지도 모르겠지만, 지금 제가 받은 파일에 dotnet3, dotnet4폴더로 구성되어있는데

버전에 따라 다른 패키지를 임포트합니다.(Unity 5.x버전은 dotnet3 패키지, Unity 2017.x이상에서는 dotnet4 패키지)

애널리틱스를 위에서 사용하기로 했으므로 FirebaseAnalytics.unitypackage를 임포트한 후 Database를 사용하기 위해 FirebaseDatabase.unitypackage도 임포트합니다. 기타 필요한 패키지를 임포트합니다.

 Assets(애셋) - Import Package(패키지 가져오기) - Custom Package(커스텀 패키지)로 추가 가능합니다.

그 후 Firebase Colsole로 돌아와서 다음을 클릭합니다.

이제 설정이 끝났습니다.

콘솔로 이동을 클릭합니다.

 

2. Firebase에서 Database추가

이제 Database를 추가해줍니다.

Realtime Database를 클릭합니다.

 

데이터 베이스 만들기를 클릭합니다.

다음으로 위치설정이있는데, 대한민국은 없기 때문에 미국으로 설정합니다.

테스트를 위해 테스트 모드에서 시작으로 설정합니다.

이제 데이터 베이스를 추가할 수 있도록 셋팅되었습니다.

 

3. 유니티(Unity)에 적용

간단하게 유니티에서 데이터 저장과 로드를 적용해보도록 하겠습니다.

빈오브젝트를 생성하고 스크립트를 넣습니다.

CFirebase.cs 코드는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Firebase;
using Firebase.Database;
using Firebase.Extensions;
 
public class CFirebase : MonoBehaviour
{
    DatabaseReference m_Reference;
    
    void Start()
    {
        m_Reference = FirebaseDatabase.DefaultInstance.RootReference;
 
        //WriteUserData("0", "aaaa");
        //WriteUserData("1", "bbbb");
        //WriteUserData("2", "cccc");
        //WriteUserData("3", "dddd");
 
        ReadUserData();
 
 
    }
 
    void ReadUserData()
    {
        FirebaseDatabase.DefaultInstance.GetReference("users")
            .GetValueAsync().ContinueWithOnMainThread(task =>
        {
            if (task.IsFaulted)
            {
                // Handle the error...
            }
            else if (task.IsCompleted)
            {
                DataSnapshot snapshot = task.Result;
                // Do something with snapshot...
            for ( int i = 0; i < snapshot.ChildrenCount; i++)
                Debug.Log(snapshot.Child(i.ToString()).Child("username").Value);
              
            }
        });
    }
 
    void WriteUserData(string userId, string username)
    {
        m_Reference.Child("users").Child(userId).Child("username").SetValueAsync(username);
    }
 
}
 
cs

 

WriteUserData함수를 통한 데이터를 저장하면, Database는 다음과 같이 저장됩니다. 

ReadUserData함수를 통해 데이터를 로드하면 디버그로그로 다음과 같이 출력되는 것을 확인할 수 있습니다.

반응형
반응형

안녕하세요.

유니티에서 빌드해서 apk를 생성 후 블루스택에서 확인하려고 했지만 실행되지 않는 문제가 발생하여, 공유하려고 합니다.

Unity 2020.3.19f1에서 발생한 문제였습니다.

휴대폰에 넣었을 때는 문제가 발생하지 않는데 블루스택에 설치하면 까만 화면만 나오고 더 이상 진행되지 않았습니다.

휴대폰에 넣어서 확인하면 되긴 하지만, 아무래도 블루스택에서 다양한 해상도나 환경을 만들 수 있기 때문에 해결하고 싶었습니다.

제가 가지고 있는 이전버전(2019.2.9f1)으로 할 때는 발생하지 않은 문제였습니다.

그래서 시험삼아 2019.2.9f1로 프로젝트를 새로 생성한 후 2020.3.19f1로 업그레이드해서 빌드를 해보았습니다.

그랬더니 정상적으로 블루스택에서 실행이 되었습니다.

먼가 설정문제인 것 같아서 두 프로젝트의 Project Setting을 확인했습니다.

처음부터 2020.3.19f1로 생성한 프로젝트에만 Optimized Frame Pacing이 체크되어있었습니다.

그래서 체크 해제를 한 후 다시 빌드하니 정상적으로 블루스택에서 실행되었습니다.

2019.2 버전부터 지원하는 기능이었는데, 보통 꺼져있는 것이 디폴트 값이었는데, 2020.3.19f1에서는 켜지는 것이 디폴드 값으로 변한 것 같습니다.

https://unity.com/kr/releases/2019-2/platforms-and-editor#optimized-frame-pacing-android

 

플랫폼과 에디터 | Unity

플랫폼과 일반 에디터 워크플로에 대한 Unity 2019.2의 새로운 기능에 대해 알아보세요. AR 파운데이션에 대한 업데이트와 모바일 개발자들을 위한 추가 툴이 새롭게 제공됩니다.

unity.com

 

반응형
반응형

안녕하세요.

오늘은 하이라이키(Hierarchy)에서 순위 변경하는 방법에 대해 알아보도록 하겠습니다.

UI 등 같은 위치에 겹치게 되면 하이라이키(Hierarchy)의 나중에 있는 게 더 위로 나옵니다.

물론 순서를 바꾸면, 순위를 바꿀 수 있습니다.

하지만, 실행 중에 변경하려면 스크립트를 이용해야 합니다.

스크립트에서 다음 함수를 사용할 수 있습니다.

Transform.SetAsLastSibling
해당 오브젝트의 순위를 마지막으로 변경(가장 나중에 출력되므로 겹쳐졋을 경우 앞으로 나옵니다.)

Transform.SetAsFirstSibling
해당 오브젝트의 순위를 처음으로 변경(가장 처음 출력되므로 겹쳐졋을 경우 가려집니다.)

Transform.SetSiblingIndex(int nIndex)
nIndex를 매개변수를 넣어서 순위를 지정합니다.(0이 처음입니다.)

Transform.GetSiblingIndex()
해당 오브젝트의 순위를 얻어옵니다.

 

예제

일단 이미지 오브젝트를 생성하고, blue, red로 지정하겠습니다.

그리고 스크립트가 들어갈 오브젝트를 하나 만듭니다.(ScriptObject)

스크립트에 다음과 같이 입력하면 현재 오브젝트의 순위값을 알 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameManger : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject goRed = GameObject.Find("Canvas/red");
        GameObject goBlue = GameObject.Find("Canvas/blue");
 
        Debug.Log("goRed : " + goRed.transform.GetSiblingIndex());
        Debug.Log("goBlue : " + goBlue.transform.GetSiblingIndex());
    }
}
 
cs

출력값은 다음과 같습니다.

빨간 사각형이 나중에 나오기 때문에 1로 표기 되었습니다.

순위를 변경할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class GameManger : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject goRed = GameObject.Find("Canvas/red");
        GameObject goBlue = GameObject.Find("Canvas/blue");
 
        Debug.Log("before goRed : " + goRed.transform.GetSiblingIndex());
        Debug.Log("before goBlue : " + goBlue.transform.GetSiblingIndex());
 
        goRed.transform.SetSiblingIndex(0);
        Debug.Log("after goRed : " + goRed.transform.GetSiblingIndex());
        Debug.Log("after goBlue : " + goBlue.transform.GetSiblingIndex());
    }
}
cs

출력값

16번째 줄 "goRed.transform.SetSiblingIndex(0);" 대신에 "goRed.transform.SetAsFirstSibling();", "goBlue.transform.SetAsLastSibling();"를 넣으면 같은 결과를 얻을 수 있습니다. 

 

반응형
반응형

안녕하세요.

오늘은 하나의 이미지를 자르는 방법에 대해 알아보도록 하겠습니다.

기본적인 ui image에서는 자르는게 안 되는 것 같습니다.(못 찾았습니다.)

Raw Image를 사용하면 자를 수 있습니다.

Hierarchy에서 UI - Raw Image로 오브젝트를 추가합니다.

Inspector에서 Raw Image 항목의 UV Rect 값을 변경하여 자를 수 있습니다.

X, Y에는 0~1 값이 들어가며, X, Y 자르는 시작 점을 지정할 수 있습니다.

W, H에는 0~1값이 들어가며, 너비와 높이를 지정할 수 있습니다.

좌표계는 다음과 같이 됩니다.

만약에 4등분으로 오른쪽 위를 반으로 자르고 싶다면 다음과 같이 설정하면 됩니다.

 

같은 방식으로 4등분에 X, Y값은 다음과 같이 설정할 수 있습니다.

1.  X : 0, Y : 0.5 (왼쪽 위)

2. X : 0.5, Y : 0.5 (오른쪽 위)

3. X : 0, Y : 0 (왼쪽 아래)

4 X : 0.5 Y 0 (오른쪽 아래)

 

반응형
반응형

안녕하세요.

유니티에서 개발을 하다보면, 투명도를 설정하려면 어떻게 해야할까요?

Inspector에 color에서 설정할 수 있습니다.

color설정창을 열어서 알파값을 변경하면 됩니다.

수치를 낮추면, 더 투명하게 할 수 있습니다.

 

코드로 추가할 수도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;   // Image class를 사용하기 위해 추가합니다.
 
 
public class CGameManager : MonoBehaviour
{
    void Start()
    {
        GameObject goImage = GameObject.Find("Canvas/Image");
        Color color = goImage.GetComponent<Image>().color;
        color.a = 0.5f;
        goImage.GetComponent<Image>().color = color;
    }
}
cs

0.5f는 255를 기준으로 255 * 0.5 = 127.5 소수점 반올림해서 128을 의미합니다.

반응형
반응형

안녕하세요

유니티 안드로이드 플랫폼에서 화면 회전을 설정하는 법에 대해 알아보도록 하겠습니다.

설정을 위해서는 플랫폼을 Android로 변경해야 합니다.

Build Settings(Ctrl+Shift+B)에서 Platform을 Android로 설정하고 Switch Platform으로 설정합니다.

 

Android로 바뀌었으면 Player Settings버튼을 클릭합니다.

 

Project Settings창이 뜨는데, Player에 Resolution and Presentation을 선택합니다.

 

여기서 Default Orientation설정을 이용하여 화면을 회전하거나 고정할 수 있습니다.

 

설정은 5가지로 할 수 있습니다.

Portratit, Portrait Upside Down, Landscape Right, Landscape Left는 게임 시작 시 해당 방향으로 화면이 고정됩니다.

Auto Rotation은 휴대폰의 방향에 따라 화면을 회전합니다.

Portrait - 디바이스 홈버튼이 아래에 있는 세로 모드로 고정

PortraitUpsideDown - 디바이스 홈 버튼이 위에 있는 세로 모드로 고정

LandscapeLeft - 디바이스 홈 버튼이 오른쪽에 있는 가로모드로 고정

LandscapeRight - 디바이스 홈버튼이 왼쪽에 있는 가로모드로 고정

AutoRotation - 휴대폰 방향에 따라 화면이 변경됩니다.

AutoRotation을 선택하면 세부 옵션들이 생기는데, 휴대폰의 해당 방향에 따라 화면이 자동으로 회전될 것인지 설정하는 것입니다.

체크를 해제하면 휴대폰의 방향을 변경해도 화면이 회전되지 않습니다.

예를 들면 Protratit Upside Down을 체크를 해제하면 홈버튼을 위로 향하게 휴대폰 방향을 변경해도 화면을 그대로 유지됩니다.

 

참고로 코드로 직접 셋팅도 가능합니다.

Screen.orientation = ScreenOrientation.Portrait; //세로 방향을 나타냅니다.
Screen.orientation = ScreenOrientation.PortraitUpsideDown; //장치의 윗부분이 아래를 향하는, 세로 방향을 나타냅니다.
Screen.orientation = ScreenOrientation.LandscapeLeft; //가로 방향을 나타내며, 세로 방향으로부터 반 시계방향으로 회전한 상태를 나타냅니다.
Screen.orientation = ScreenOrientation.LandscapeRight; //가로 방향을 나타내며, 세로 방향으로부터 시계방향으로 회전한 상태를 나타냅니다.
Screen.orientation = ScreenOrientation.AutoRotation; //활성화된 방향으로 자동 회전 하도록 설정합니다.

 

"ScreenOrientation.AutoRotation"설정한 후 세부설정은 다음과 같이합니다.

Screen.autorotateToPortrait = false;
Screen.autorotateToPortraitUpsideDown = false;
Screen.autorotateToLandscapeLeft = true;
Screen.autorotateToLandscapeRight = true;

 

추가로 Scene별로 다르게 설정을 하려면 Scene별로 스크립트를 생성하여 GameObject에 생성해준 후 Start 함수에 위 코드를 넣어주면 될 것 같습니다.

Scene1, Scene2가 있다면 

Scene1에는 다음과 같이 넣습니다.

public class SceneManager1 : MonoBehaviour
{
    void Start()
    {
        Screen.orientation = ScreenOrientation.Landscape;
    }
}

그리고 Scene2에는 다음과 같이 코드를 작성합니다.

public class SceneManager2 : MonoBehaviour
{
    void Start()
    {
        Screen.orientation = ScreenOrientation.Portrait;
    }
}

 

조금 더 자세한 예제는 다음 글에서 확인해주세요.

https://scvtwo.tistory.com/220

 

[Unity] 씬(Scene) 별로 화면 고정하기

씬마다 다른 화면 고정을 적용하려면 다음과 같이 합니다. 직접 프로젝트를 만들면서 알아보도록 하겠습니다. 1. 어떤 씬인지 확인을 위해서 텍스트 오브젝트, 그리고 씬 이동을 위해서 버튼 오

scvtwo.tistory.com

 

반응형
반응형

안녕하세요.

오늘은 모바일 게임에서 멀티터치로 카메라 줌인 / 줌아웃을 구현해보도록 하겠습니다.

줌인/줌아웃이 되는지 확인할 수 있도록 아무 객체나 생성합니다.

저는 큐브를 하나 생성하도록 하겠습니다.

그리고 빈프로젝트를 생성해서 스크립트를 추가하겠습니다.

생성한 스크립트에 다음과 같은 코드를 추가하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TouchManager : MonoBehaviour
{
 
    float m_fSpeed = 0.1f;       // 변경 속도를 설정합니다 
    float m_fFieldOfView = 60f;     // 카메라의 FieldOfView의 기본값을 60으로 정합니다.
 
    void Update()
    {
        CheckTouch();
    }
 
    void CheckTouch()
    {
        if (Input.touchCount == 2)
        {
            Vector2 vecPreTouchPos0 = Input.touches[0].position - Input.touches[0].deltaPosition;
            Vector2 vecPreTouchPos1 = Input.touches[1].position - Input.touches[1].deltaPosition;
 
            // 이전 두 터치의 차이 
            float fPreDis = (vecPreTouchPos0 - vecPreTouchPos1).magnitude;
            // 현재 두 터치의 차
            float fToucDis = (Input.touches[0].position - Input.touches[1].position).magnitude;
 
 
            // 이전 두 터치의 거리와 지금 두 터치의 거리의 차이
            float fDis = fPreDis - fToucDis;
 
            // 이전 두 터치의 거리와 지금 두 터치의 거리의 차이를 FleldOfView를 차감합니다.
            m_fFieldOfView += (fDis * m_fSpeed);
 
            // 최대는 100, 최소는 20으로 더이상 증가 혹은 감소가 되지 않도록 합니다.
            m_fFieldOfView = Mathf.Clamp(m_fFieldOfView, 20.0f, 100.0f);
 
            Camera.main.fieldOfView = m_fFieldOfView;
 
        }
    }
}
 
cs

 

 

유니티에서 테스트가 안되기 때문에(테스트하는 방법을 아신다면 댓글 남겨주시면 감사하겠습니다.) 애뮬레이터로 테스트했습니다.

저는 미뮤를 이용하여 테스트했습니다.

가상 키로 터치하는 위치를 정하고 마우스 터치를 하면서 줌인/줌아웃을 확인했습니다.

실행하면 줌인/줌아웃이 제대로 실행되는 것을 확인할 수 있습니다.

 

 

반응형
반응형

안녕하세요.

오늘은 오브젝트를 따라다니는 HP UI를 만들어 보도록 하겠습니다.

 

 

오브젝트 생성 및 위치 설정

1. 메인 카메라 위치 설정

2. Cube 오브젝트(움직일 오브젝트) 생성 및 위치는 0, 0, 0으로 설정하고 Material을 추가하여 큐브색을 변경합니다.

3. Slider 오브젝트(HP바) 생성 및 설정

1) Handle Silde Area는 비활성화

2) 배경 및 채울색 설정

 

 

스크립트 추가

Cube에 스크립트를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class Mover : MonoBehaviour
{
    private GameObject m_goHpBar;
    private float m_fSpeed = 5.0f;
    void Start()
    {
        m_goHpBar = GameObject.Find("Canvas/Slider");
    }
 
    void Update()
    {
        // 테스트를 위한 키보드 이동 시작
        float fHorizontal = Input.GetAxis("Horizontal");
        float fVertical = Input.GetAxis("Vertical");
 
        transform.Translate(Vector3.right * Time.deltaTime * m_fSpeed * fHorizontal, Space.World);
        transform.Translate(Vector3.up * Time.deltaTime * m_fSpeed * fVertical, Space.World);
        // 테스트를 위한 키보드 이동 끝
 
 
        // 오브젝트에 따른 HP Bar 위치 이동
        m_goHpBar.transform.position = Camera.main.WorldToScreenPoint(transform.position + new Vector3(00.8f, 0));
    }
}
 
cs

 

 

 

반응형
반응형

안녕하세요

오늘은 유니티에서 진동을 울리는 방법에 대해 알아보도록 하겠습니다.

퍼즐게임에서 퍼즐을 잘못찾았거나 여러가지 경고를 띄울 때 주로 진동을 울리는 경우가 많이 있습니다.

이럴때 사용하는 진동을 유니티에서도 호출할 수 있습니다.

 

진동 울리는 함수

Handheld.Vibrate();

진동이 울려야 할 위치에 위의 함수를 호출하면 진동이 1초간 울립니다.

 

진동 세부설정

Handheld.Vibrate() 함수를 이용하면, 울리는 시간을 설정할 수 없고 1초간 진동이 울리는 것만 가능합니다.

1초말고 진동울리는 시간과 울리는 패턴 설정할 수 있습니다.

안드로이드 자바 클래스를 사용합니다.

사용하려면 진동권한이 필요합니다.

진동권한 추가를 위해서 매니페스트 수정이 필요합니다.

C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk

이 폴더에서 AndroidManifest.xml파일을 해당 프로젝트 폴더의 Asset\Plugins\Android\에 넣습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
    xmlns:tools="http://schemas.android.com/tools"
    android:installLocation="preferExternal">
    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:anyDensity="true"/>
 
    <application
        android:theme="@style/UnityThemeSelector"
        android:icon="@mipmap/app_icon"
        android:label="@string/app_name">
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
    <uses-permission android:name="android.permission.VIBRATE" />
</manifest>
 
 
cs

VIBRATE권한을 맨 밑에 </application>와 </manifest>사이에 넣으면 됩니다.

1
2
<uses-permission android:name="android.permission.VIBRATE" />
 
 
cs

 

다음 클래스를 추가한 후 사용하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System.Collections;
using UnityEngine;
 
public static class Vibration
{
#if UNITY_ANDROID && !UNITY_EDITOR
    public static AndroidJavaClass AndroidPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    public static AndroidJavaObject AndroidcurrentActivity = AndroidPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    public static AndroidJavaObject AndroidVibrator = AndroidcurrentActivity.Call<AndroidJavaObject>("getSystemService""vibrator");
#endif
    public static void Vibrate()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidVibrator.Call("vibrate");
#else
        Handheld.Vibrate();
#endif
    }
 
    public static void Vibrate(long milliseconds)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidVibrator.Call("vibrate", milliseconds);
#else
        Handheld.Vibrate();
#endif
    }
    public static void Vibrate(long[] pattern, int repeat)
    {
 
 
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidVibrator.Call("vibrate", pattern, repeat);
#else
        Handheld.Vibrate();
#endif
    }
 
    public static void Cancel()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
            AndroidVibrator.Call("cancel");
#endif
    }
 
}
 
cs

 

실제 사용 예제

위 스크립트를 Assets폴더에 추가를 합니다.

빈오브젝트를 생성해서 버튼 이벤트에 사용할 스크립트를 추가합니다.

ButtonEvent 스크립트를 다음과 같이 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ButtonEvent : MonoBehaviour
{
    public void OnClick1()
    {
        Vibration.Vibrate((long)5000);
    }
 
    public void OnClick2()
    {
        long[] pattern = new long[4];
        pattern[0= 1000;
        pattern[1= 200;
        pattern[2= 1000;
        pattern[3= 200;
 
 
        Vibration.Vibrate(pattern, 1);
    }
 
    public void OnClick3()
    {
        long[] pattern = new long[4];
        pattern[0= 1000;
        pattern[1= 5000;
        pattern[2= 2000;
        pattern[3= 1000;
 
 
        Vibration.Vibrate(pattern, -1);
    }
 
    public void OnClick4()
    {
        Vibration.Cancel();
    }
}
 
 
cs

 

1. OnClick1() 함수는 5초동안 진동을 울립니다.

2. OnClick2() 함수는 1초쉬고 0.2초 울리고, 1초 쉬고, 0.2초 울린 후 1초에 한번씩 1초 진동을 반복합니다.

3. OnClick3() 함수는 1초쉬고 5초 울리고, 2초 쉬고, 1초 울린 후 반복되지 않습니다.

4. OnClick4() 함수는 진동 울리는 도중에 진동을 취소합니다.

그 후 버튼을 다음과 같이 4개 추가해서 추가합니다.

버튼에 OnClick1~onClick4를 다음과 같이 넣습니다.

Button에 OnClick1을 넣습니다.

Button (1)에 OnClick2을 넣습니다.

Button (2)에 OnClick3을 넣습니다.

Button (3)에 OnClick4을 넣습니다.

버튼을 누를 때마다 해당되는 이벤트가 실행되는 것을 확인할 수 있습니다.

그리고 검색하다가 Android 8.0(API 레벨 26)이상에서는 다르게 작업을 해야한다고 작업을 해야한다고 찾았는데, 갤럭시 S8(안드로이드 9.0)에서 테스트 했을 때 진동이 안울렸습니다.

혹시나 특정 최신 휴대폰에서 진동이 울리지 않는다면, 다음 웹페이지를 참조하시는 것도 좋을 것 같습니다.

https://gist.github.com/munkbusiness/9e0a7d41bb9c0eb229fd8f2313941564

 

Vibration for Unity3d with Android native Call that supports both the new vibrationEffectClass and the old simple vibrate, with

Vibration for Unity3d with Android native Call that supports both the new vibrationEffectClass and the old simple vibrate, with fallback to Handlheld.Vibrate(). - Vibration.cs

gist.github.com

안드로이드의 vibrate함수 사용은 다음 웹페이지에서 확인할 수 있습니다.

https://developer.android.com/reference/android/os/Vibrator#vibrate(long[],%20int)

 

Vibrator  |  Android 개발자  |  Android Developers

Vibrator public abstract class Vibrator extends Object java.lang.Object    ↳ android.os.Vibrator Class that operates the vibrator on the device. If your process exits, any vibration you started will stop. Summary Public methods abstract void cancel() Turn

developer.android.com

틀린 부분이나 제가 잘못 올린부분은 댓글을 남겨주시면 수정하도록 하겠습니다.

 

반응형
반응형

안녕하세요

많은 모바일 게임에서는 캐릭터를 컨트롤하기 위해 조이스틱을 사용합니다.

조이스틱 사용 게임 화면 (브롤스타즈)

유니티에서 조이스틱을 구현해보도록 하겠습니다.

일단 바닥과 이동시킬 오브젝트인 큐브를 생성하도록 하겠습니다.

그리고 이동을 명확하게 보기 위해 카메라의 위치를 변경합니다.

image UI를 생성합니다.

Image Object를 왼쪽 구석으로 이동합니다.

그 후 SourceImage를 Knob으로 변경하겠습니다.

그리고 Color도 변경합니다.

Image 오브젝트의 하위 오브젝트 하나 더 생성합니다.

오브젝트 이름이 같아서 헬갈릴 수 있기 때문에 오브젝트 이름을 상위 image오브젝트를 Joystickback, 하위 image오브젝트를 Joystick으로 이름을 변경하겠습니다.

JoyStick Object를 클릭하여 Width와 Height, Source Image를 변경합니다.

Cube의 정면 위치를 표시하기 위해, Cube의 하위에 Cube 오브젝트를 하나 더 추가합니다.

추가한 큐브의 크기와 위치를 변경하여, 정면에 위치시킵니다.

그다음 Canvas에 스크립트를 추가합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class JoyStick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
    RectTransform m_rectBack;
    RectTransform m_rectJoystick;
 
    Transform m_trCube;
    float m_fRadius;
    float m_fSpeed = 5.0f;
    float m_fSqr = 0f;
 
    Vector3 m_vecMove;
 
    Vector2 m_vecNormal;
 
    bool m_bTouch = false;
 
 
    void Start()
    {
        m_rectBack = transform.Find("Joystickback").GetComponent<RectTransform>();
        m_rectJoystick = transform.Find("Joystickback/Joystick").GetComponent<RectTransform>();
 
        m_trCube = GameObject.Find("Cube").transform;
 
        // JoystickBackground의 반지름입니다.
        m_fRadius = m_rectBack.rect.width * 0.5f;
    }
 
    void Update()
    {
        if (m_bTouch)
        {
            m_trCube.position += m_vecMove;
        }
            
    }
 
    void OnTouch(Vector2 vecTouch)
    {
        Vector2 vec = new Vector2(vecTouch.x - m_rectBack.position.x, vecTouch.y - m_rectBack.position.y);
 
        
        // vec값을 m_fRadius 이상이 되지 않도록 합니다.
        vec = Vector2.ClampMagnitude(vec, m_fRadius);
        m_rectJoystick.localPosition = vec;
 
        // 조이스틱 배경과 조이스틱과의 거리 비율로 이동합니다.
        float fSqr = (m_rectBack.position - m_rectJoystick.position).sqrMagnitude / (m_fRadius * m_fRadius);
 
        // 터치위치 정규화
        Vector2 vecNormal = vec.normalized;
 
        m_vecMove = new Vector3(vecNormal.x * m_fSpeed * Time.deltaTime * fSqr, 0f, vecNormal.y * m_fSpeed * Time.deltaTime * fSqr);
        m_trCube.eulerAngles = new Vector3(0f, Mathf.Atan2(vecNormal.x, vecNormal.y) * Mathf.Rad2Deg, 0f);
    }
 
    public void OnDrag(PointerEventData eventData)
    {
        OnTouch(eventData.position);
        m_bTouch = true;
    }
 
    public void OnPointerDown(PointerEventData eventData)
    {
        OnTouch(eventData.position);
        m_bTouch = true;
    }
 
    public void OnPointerUp(PointerEventData eventData)
    {
        // 원래 위치로 되돌립니다.
        m_rectJoystick.localPosition = Vector2.zero;
        m_bTouch = false;
    }
}
 
 
cs

 

 

 

반응형
반응형

안녕하세요.

해상도 변경에 따라서 UI위치를 변경하는 방법에 대해 알아보도록 하겠습니다.

Canvas의 셋팅을 2560x1440기준으로 Match을 1로 셋팅하여 세로 해상도에 영향을 받지 않도록 하겠습니다.

일단 다음과 같이 버튼 UI를 배치했을 경우가 있습니다.

16:9 해상도에 맞춰서 UI를 배치했습니다.

근데 만약 해상도를 18:9로 변경되었을 경우에는 여백이 많이 생기게됩니다.

이런 경우 해상도 비율에 맞춰서 UI를 이동시킬 수 있습니다.

버튼 오브젝트에 스크립트를 추가합니다.

버튼 오브젝트를 모두 선택한 후 Add Componect로 스크립트를 추가합니다.

그 후 스크립트에 다음 코드를 작성합니다.

16:9 기준으로 코드를 작성했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class csUIPositon : MonoBehaviour
{
    void Start()
    {
        float fScaleWidth = ((float)Screen.width / (float)Screen.height) / ((float)16 / (float)9);
        Vector3 vecButtonPos = GetComponent<RectTransform>().localPosition;
        vecButtonPos.x = vecButtonPos.x * fScaleWidth;
        GetComponent<RectTransform>().localPosition = new Vector3 (vecButtonPos.x, vecButtonPos.y, vecButtonPos.z);
    }
}
 
cs

 

이렇게 작성후 해상도를 변경한 후 실행을 해보면 버튼 UI가 해상도에 맞춰서 이동하는것을 확인할 수 있습니다.

16:9 실행화면
18:9 실행화면
800x480실행화면
2160x1080 실행화면

반응형
반응형

안녕하세요

오브젝트를 따라가는 카메라를 만드는 코드를 공유하려고 합니다.

바닥(Plane)과 따라갈 오브젝트(Cube)를 생성합니다.

오브젝트(Cube)에 이동관련 스크립트를 추가합니다.

키보드로 이동이 가능하도록 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Mover : MonoBehaviour
{
 
    float m_fSpeed = 5.0f;
 
    void Update()
    {
        float fHorizontal = Input.GetAxis("Horizontal");
        float fVertical = Input.GetAxis("Vertical");
 
        transform.Translate(Vector3.right * Time.deltaTime * m_fSpeed * fHorizontal, Space.World);
      transform.Translate(Vector3.forward * Time.deltaTime * m_fSpeed * fVertical, Space.World);
    }
}
 
 
cs

다음은 메인 카메라(Main Camera)에 오브젝트를 따라가는 스크립트를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class CFollowCamera : MonoBehaviour
{
    public Transform target;        // 따라다닐 타겟 오브젝트의 Transform
 
    private Transform tr;                // 카메라 자신의 Transform
 
    void Start()
    {
        tr = GetComponent<Transform>();
    }
 
    void LateUpdate()
    {
        tr.position = new Vector3(target.position.x - 0.52f, tr.position.y, target.position.z - 6.56f);
 
        tr.LookAt(target);
    }
}
 
cs

그리고 Target에 오브젝트(Cube)를 넣어줍니다.

실행을 해보면 오브젝트(Cube)를 따라서 카메라가 이동하게 됩니다.

 

위에서 바라보는게 더 자연스러울 것 같아서 카메라 위치를 변경해보겠습니다.

감사합니다.

반응형

+ Recent posts