Panel을 UI로 만든후 시점이 맞았을때

패널을 보이게 하고 그렇지 않을 경우 보이지 않게 한다.

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.LowLevel;

public class Car : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IGvrPointerHoverHandler
{
    private Coroutine coroutine;
    public GameObject menuUI;
    public void OnGvrPointerHover(PointerEventData eventData)
    {
        //Debug.Log("Hover");
    }


    public void OnPointerEnter(PointerEventData eventData)
    {
        coroutine = StartCoroutine(CoClick());
        Debug.Log("Enter");
        menuUI.SetActive(true);

    }


    private IEnumerator CoClick()
    {
        float delta = 0f;
        while (true)
        {
            delta += Time.deltaTime;
            if(delta >= 3)
            {
                Debug.LogFormat("Clicked , {0}", delta);
                delta = 0f;
            }
            yield return null;
        }
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        Debug.Log("Exit");
        menuUI.SetActive(false);
        StopCoroutine(coroutine);
    }
}

 

 

플레이어의 위치에 따라서 패널의 방향이 변경되는데

이는 캔버스안에 넣어주어야 한다.

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

public class Billboard : MonoBehaviour
{
    

    // Update is called once per frame
    void Update()
    {
        this.transform.LookAt(Camera.main.transform.position);
    }
}

 

 

 

 

IPointerEnterHandler, IPointerExitHandler는 유니티엔진에 있는 메소드이지만,

IGvrPointerHoverHandler는 직접 만들어준 메소드이다.

 


 

커스텀 래티클 만들기

 

이번엔 기존에 사용했던 빨간색 래티클을 없애고 새로운 래티클을 만들어 주려 한다.

 

Main Camera의 GvrRecticlePointer와 GvrPointerPhysicsRaycast를 비활성화  한다.

 

Main Camera자식으로 Canvas를 생성하고  다음과  같이  속성을  변경  한다

 

 

그리고 적절한 이미지를 붙여준 후 Fill효과를 넣어줄 것이므로

복사해서 앞과 뒤를 만든다.

Back은 알파 값을 조금 줄여주고

Front는 filled, Radial 360, Top으로 변경하였다.

 

우선 래티클이 변경되었으니 인지를 하게 만드는 것이 우선인데

차의 레이어는 7 메뉴의 레이어는 6으로 만들어서

인지할수 있도록 하였다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.LowLevel;

public class Car : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IGvrPointerHoverHandler
{
    private static Car instance;
    private Coroutine coroutine;
    public GameObject menuUI;

    private void Start()
    {
        //menuUI.SetActive(false);
    }

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else
        {
            Debug.LogWarning("Duplicate instance of Car found!");
            Destroy(gameObject); // 중복된 인스턴스 제거
        }
    }

    public static Car GetInstance()
    {
        return instance;
    }



    public void OnGvrPointerHover(PointerEventData eventData)
    {
        //Debug.Log("Hover");
    }


    public void OnPointerEnter(PointerEventData eventData)
    {
        coroutine = StartCoroutine(CoClick());
        Debug.Log("Enter");
        menuUI.SetActive(true);
        Debug.Log("이벤트 대상: " + eventData.pointerEnter.name);
    }


    private IEnumerator CoClick()
    {
        float delta = 0f;
        while (true)
        {
            delta += Time.deltaTime;
            if(delta >= 3)
            {
                Debug.LogFormat("Clicked , {0}", delta);
                delta = 0f;
            }
            yield return null;
        }
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        Debug.Log("Exit");
        menuUI.SetActive(false);
        StopCoroutine(coroutine);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class EyeCast : MonoBehaviour
{
    private Transform trans;
    private Ray ray;
    private RaycastHit hit;
    public float dist = 10f;
    public Image gauge;
    bool isOpenedUIMenu = false;
    private Car carInstance; // 전역 변수로 선언

    void Start()
    {
        this.trans = this.GetComponent<Transform>();
        carInstance = Car.GetInstance(); // 전역 변수에 할당
        carInstance.menuUI.SetActive(false);
    }

    void Update()
    {
        ray = new Ray(this.trans.position, this.trans.forward);
        Debug.DrawRay(ray.origin, ray.direction * this.dist, Color.green);

        var mask = 1 << 6 | 1 << 7; // 레이어 마스크 설정
        if (Physics.Raycast(ray, out hit, dist, mask))
        {
            this.GazeButton();
        }
        else
        {
            ReleaseButton();
            // 여기에서 메뉴 닫는 동작을 추가할 수 있습니다.
            // 예: carInstance.menuUI.SetActive(false);
        }
    }

    private void GazeButton()
    {
        if (this.hit.collider.gameObject.layer == 7 && carInstance != null)
        {
            carInstance.menuUI.SetActive(true);
        }
    }

    private void ReleaseButton()
    {
        if (this.hit.collider == null || this.hit.collider.gameObject == null)
        {
            carInstance.menuUI.SetActive(false);
        }
    }
}

 

보기와 같이 코드에서 차뿐만이 아닌 버튼에도 레이어를 설정해두었기 때문에

버튼쪽에 래티클을 갖다 두어도 창이 사라지지 않는다.

 

레이어를 인식해서 게이지를 채우고

나갔을 때 초기화

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class EyeCast : MonoBehaviour
{
    private Transform trans;
    private Ray ray;
    private RaycastHit hit;
    public float dist = 10f;
    public Image gauge;
    bool isOpenedUIMenu = false;
    private Car carInstance; // 전역 변수로 선언
    private float delta;

    void Start()
    {
        this.trans = this.GetComponent<Transform>();
        carInstance = Car.GetInstance(); // 전역 변수에 할당
        carInstance.menuUI.SetActive(false);
    }

    void Update()
    {
        ray = new Ray(this.trans.position, this.trans.forward);
        Debug.DrawRay(ray.origin, ray.direction * this.dist, Color.green);

        var mask = 1 << 6 | 1 << 7; // 레이어 마스크 설정
        if (Physics.Raycast(ray, out hit, dist, mask))
        { 
            //gauge.fillAmount = 0;
            StartCoroutine(GazeButton());
        }
        else
        {
            delta = 0;
            gauge.fillAmount = 0;

            StartCoroutine(ReleaseButton());
           

            // 여기에서 메뉴 닫는 동작을 추가할 수 있습니다.
            // 예: carInstance.menuUI.SetActive(false);
        }
    }
    IEnumerator GazeButton()
    {
        
        if (this.hit.collider.gameObject.layer == 7 && carInstance != null)
        {
            carInstance.menuUI.SetActive(true);

            this.delta += Time.deltaTime;
            gauge.fillAmount = delta / 3;
        }
        else
        {

        }
        yield return null;
    }

    IEnumerator ReleaseButton()
    {
        if (this.hit.collider == null || this.hit.collider.gameObject == null)
        {

            carInstance.menuUI.SetActive(false);


        }
        yield return null;
    }
}

 

 

게이지를 채워서 예를 누르면 예가 찍히고

아니요를 누르면 창을 종료 시켰다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class EyeCast : MonoBehaviour
{
    private Transform trans;
    private Ray ray;
    private RaycastHit hit;
    public float dist = 10f;
    public Image gauge;
    private Car carInstance; // 전역 변수로 선언
    private float delta;
    public Button clickYes;
    public Button clickNo;
    private bool isYesClicked = false;
    private Coroutine coroutine;

    void Start()
    {
        this.trans = this.GetComponent<Transform>();
        carInstance = Car.GetInstance(); // 전역 변수에 할당
        carInstance.menuUI.SetActive(false);
    }

    void Update()
    {
        

        ray = new Ray(this.trans.position, this.trans.forward);
        Debug.DrawRay(ray.origin, ray.direction * this.dist, Color.green);

        var mask = 1 << 7; // 레이어 마스크 설정
        if (Physics.Raycast(ray, out hit, dist, mask))
        {
            //gauge.fillAmount = 0;
            
              if(coroutine != null)
            {
                StopCoroutine(coroutine);

            }

            StartCoroutine(GazeButton());

        }
       

        else if (Physics.Raycast(ray, out hit, dist, 1 << 6))
        {
            //gauge.fillAmount = 0;
            //StartCoroutine(GazeButton());
       
         
              
                StartCoroutine(GazeButton());
                StartCoroutine(ClickButton());

          
           
        }

        else
        {
            if (isYesClicked == true)
            {
                isYesClicked = false;
            }
            delta = 0;
            gauge.fillAmount = 0;

            StartCoroutine(ReleaseButton());


            // 여기에서 메뉴 닫는 동작을 추가할 수 있습니다.
            // 예: carInstance.menuUI.SetActive(false);
        }
    }
    IEnumerator GazeButton()
    {

        if (this.hit.collider.gameObject.layer == 7 || this.hit.collider.gameObject.layer == 6 && carInstance != null)
        {
            carInstance.menuUI.SetActive(true);

            this.delta += Time.deltaTime;
            gauge.fillAmount = delta / 2;
        }
        else
        {
            delta = 0;
            gauge.fillAmount = 0;
        }
        yield return null;
    }

    IEnumerator ClickButton()
    {
        if (this.hit.collider.gameObject.layer == 6)
        {
            this.delta += Time.deltaTime;
            if (gauge.fillAmount >= 1)
            {
                if (hit.collider.gameObject.name == "ButtonYes" && isYesClicked == false)
                {
                    isYesClicked = true;
                    Debug.Log("예를 입력하였습니다");
                }
                if (hit.collider.gameObject.name == "ButtonNo")
                {
                    carInstance.menuUI.SetActive(false);
                }
            }
        }
        yield return null;
    }


    IEnumerator ReleaseButton()
    {
        if (this.hit.collider == null || this.hit.collider.gameObject == null)
        {
            carInstance.menuUI.SetActive(false);
        }
        yield return null;
    }
}

 

 

 

마지막으로 레이어 이동시 게이지를 초기화 시키도록 구현하기 위해 수정을 하였다.

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class EyeCast : MonoBehaviour
{
    private Transform trans;
    private RaycastHit hit;
    public float dist = 10f;
    public Image gauge;
    public Car car;
    public Button clickYes;
    public Button clickNo;

    private int lastLayer = 0;
    private string lastButton = "";

    float carCount = 0;
    float yesButtonCount = 0;
    float noButtonCount = 0;


    void Start()
    {
        this.trans = this.GetComponent<Transform>();
        car.menuUI.SetActive(false); // 처음엔 menu가 닫힌채로 시작

        StartCoroutine(ReleaseButton());
        StartCoroutine(GazeButton());
        StartCoroutine(ClickButton());
    }


    IEnumerator GazeButton()
    {
        while (true)
        {
            Ray ray = new Ray(this.trans.position, this.trans.forward);
            if (Physics.Raycast(ray, out hit, dist, 1 << 7)) // Layer 7 = Car
            {
                if (lastLayer != 7 && carCount < 2)
                {
                    carCount = 0;
                    gauge.fillAmount = 0;
                }
                else if (lastLayer != 7 && carCount >= 2)
                {
                    carCount = 2;
                    gauge.fillAmount = 1;
                }
                else if (lastLayer !=7 && carCount >= 2 && !car.menuUI.gameObject.activeSelf) // No 버튼으로 menu가 닫혔을때, 다시 초기화
                {
                    carCount = 0;
                    gauge.fillAmount = 0;
                }
                lastLayer = 7;
                lastButton = "";

                //car.menuUI.SetActive(true);  -> Car를 응시 했을 때, 바로 메뉴 오픈

                if (carCount < 2)
                {
                    carCount += Time.deltaTime;
                    gauge.fillAmount = carCount / 2;

                    if (gauge.fillAmount >= 1)
                    {
                        car.menuUI.SetActive(true); // -> Car를 응시 했을 때, 2초 후 메뉴 오픈
                    }
                }
            }
            yield return null;
        }
    }



    IEnumerator ClickButton()  // ButtonYes와 ButtonNo 콜라이더 사이에 공백이 있으면 ResetCountAndGauge 메서드(메뉴 닫힘 및 초기화)가 실행 될 수 있으니 유의
    {
        while (true)
        {
            Ray ray = new Ray(this.trans.position, this.trans.forward);
            if (Physics.Raycast(ray, out hit, dist, 1 << 6)) //Layer 6 = Button
            {
                if (hit.collider.gameObject.name == "ButtonYes")
                {
                    lastLayer = 6;

                    if (lastButton != "ButtonYes" && yesButtonCount < 2)
                    {
                        lastButton = "ButtonYes";
                        yesButtonCount = 0;
                        gauge.fillAmount = 0;
                    }
                    else if (lastButton != "ButtonYes" && yesButtonCount >= 2)
                    {
                        lastButton = "ButtonYes";
                        yesButtonCount = 2;
                        gauge.fillAmount = 1;
                    }
                    if (yesButtonCount < 2)
                    {
                        yesButtonCount += Time.deltaTime;
                        gauge.fillAmount = yesButtonCount / 2;

                        if (gauge.fillAmount >= 1)
                        {
                            Debug.Log("예를 입력하였습니다");
                            car.uiText.text = "차량 정보 확인"; // UI Text 변경
                        }
                    }
                }
                else if (hit.collider.gameObject.name == "ButtonNo")
                {
                    lastLayer = 6;

                    if (lastButton != "ButtonNo")
                    {
                        lastButton = "ButtonNo";
                        noButtonCount = 0;
                        gauge.fillAmount = 0;
                    }
                    if (noButtonCount < 2)
                    {
                        noButtonCount += Time.deltaTime;
                        gauge.fillAmount = noButtonCount / 2;

                        if (gauge.fillAmount >= 1)
                        {
                            car.menuUI.SetActive(false);

                            // Count 및 Text 초기화
                            car.uiText.text = "차량의 정보를 보시겠습니까?"; 
                            carCount = 0;
                            yesButtonCount = 0;
                            noButtonCount = 0;
                            Debug.Log("아니오를 입력하였습니다. 메뉴를 종료합니다.");
                        }
                    }
                }
            }
            yield return null;
        }
    }


    IEnumerator ReleaseButton()
    {
        while (true)
        {
            Ray ray = new Ray(this.trans.position, this.trans.forward);
            if (!Physics.Raycast(ray, out hit, dist))
            {
                //car.menuUI.SetActive(false); -> Car, 버튼 어느것도 응시하지 않으면 menu 닫음
                gauge.fillAmount = 1;
                lastLayer = 0;
                lastButton = "";
            }
            yield return null;
        }
    }





}

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.UI;
using TMPro;

public class Car : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IGvrPointerHoverHandler
{

    private Coroutine coroutine;
    public GameObject menuUI;
    public Text uiText; // menuUI Text

    private void Start()
    {
        //menuUI.SetActive(false);
    }



    public void OnGvrPointerHover(PointerEventData eventData)
    {
        //Debug.Log("Hover");
    }


    public void OnPointerEnter(PointerEventData eventData)
    {
        //coroutine = StartCoroutine(CoClick());
        //Debug.Log("Enter");
        ////menuUI.SetActive(true);
        //Debug.Log("이벤트 대상: " + eventData.pointerEnter.name);
    }


    private IEnumerator CoClick()
    {
        float delta = 0f;
        while (true)
        {
            delta += Time.deltaTime;
            if(delta >= 3)
            {
                Debug.LogFormat("Clicked , {0}", delta);
                delta = 0f;
            }
            yield return null;
        }
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        //Debug.Log("Exit");
        //menuUI.SetActive(false);
        //StopCoroutine(coroutine);
    }
}

rhttps://www.youtube.com/watch?v=1BtSgFkrkY8

 

 

360도 회전가능하게 만들어진 영상을 다운로드

www. 다음에 앞에 ss를 붙이면 다운로드 사이트로 갈 수 있다.

 

 

https://gist.github.com/unity3dcollege/d059b376f7461d908107e97534ed9e04

 

InvertedSphere.cs

GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

이 사이트의 스크립트를 복사 한후 스크립트를 만들어준다.

 

 

 

InvertedSphere 스크립트는  Editor폴더에  넣어주어야 한다.

 

그 후 메뉴에서 GameObject/Create Other/Inverted Sphere 를 선택해 구체를 생성한다.

 

구체에 Video Player컴포넌트를  부착 하고 Source에 영상을 넣자

GvrEditorEmulator와  비슷한
Editor에서만 동작하는 마우스를 움직여 카메라를 조작하는 스크립트 작성

 

그 후 메인카메라의 좌표를 0, 0 , 0으로 맞춰주어야 한다.

 

새로운 메터리얼을 만들고 Shader를  Unlit/Texture로  변경한다

 

Sphere안에 카메라를 넣어주고 해당 메타리얼을 넣어준다.

 

 

1. 앞서 만들었던 HMDEmulator를  Main Camera에  컴포넌트로 추가

 

2. Main Camera에  Tracked Pose Driver컴포넌트를  부착

 

 

 

 

만들어진 프로그램은 간이식 장치(안드로이드)로 apk로 추출후 테스해볼 수 있다.

 

 

 

'산대특 > VRAR' 카테고리의 다른 글

Oculus Settings and Grab  (0) 2024.04.17
Reticle  (0) 2024.04.16
캐릭터 이동지점 변경시 VR시점 변경  (0) 2024.04.12
VR Setting 문제  (0) 2024.04.12
VR Setting 문제  (0) 2024.04.12

 

시점을 변경하고 자동차에 콜라이더를 넣어서

점의 레이캐스트가 닿을 시 인지할 수 있도록 하였다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.LowLevel;

public class Car : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IGvrPointerHoverHandler
{
    private Coroutine coroutine;

    public void OnGvrPointerHover(PointerEventData eventData)
    {
        //Debug.Log("Hover");
    }


    public void OnPointerEnter(PointerEventData eventData)
    {
        coroutine = StartCoroutine(CoClick());
        Debug.Log("Enter");
    }


    private IEnumerator CoClick()
    {
        float delta = 0f;
        while (true)
        {
            delta += Time.deltaTime;
            if(delta >= 3)
            {
                Debug.LogFormat("Clicked , {0}", delta);
                delta = 0f;
            }
            yield return null;
        }
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        Debug.Log("Exit");
        StopCoroutine(coroutine);
    }
}

 

 

플레이어가 지정한 지정한 위치에 도달하면 방향을 전환하여

다음 목적지를 향해 이동하고 그에 맞춰 VR의 시선이 달라진다.

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

public class Player : MonoBehaviour
{
    public Transform[] wayPoints;
    private int nextIdx = 0;
    private float speed = 2f;
    void Start()
    {
        
    }

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

    public void MoveWayPoint()
    {
        Vector3 dir = wayPoints[nextIdx].position - this.transform.position;
        // 회전 각도
        Quaternion rot = Quaternion.LookRotation(dir);

        this.transform.Translate(Vector3.forward * speed * Time.deltaTime);

        this.transform.rotation = Quaternion.Slerp(this.transform.rotation, rot, Time.deltaTime * speed);

    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("WayPoint"))
        {
            nextIdx++;
            if(nextIdx == 4)
            {
                nextIdx = 0;
            }
        }
    }



}

 

'산대특 > VRAR' 카테고리의 다른 글

Oculus Settings and Grab  (0) 2024.04.17
Reticle  (0) 2024.04.16
VR로 360도 동영상 다운로드 후 적용하기 + 오큘러스 적용  (0) 2024.04.16
VR Setting 문제  (0) 2024.04.12
VR Setting 문제  (0) 2024.04.12

VR 셋팅시 오류가 발생

 

 

 

Project Settings - Player - Other Settings

 

 

Publishing Settings

 

그 후 스크립트를 수정한다

 

 

 

//-----------------------------------------------------------------------
// <copyright file="CardboardStartup.cs" company="Google LLC">
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
//-----------------------------------------------------------------------

using Google.XR.Cardboard;
using UnityEngine;

/// <summary>
/// Initializes Cardboard XR Plugin.
/// </summary>
public class CardboardStartup : MonoBehaviour
{
    /// <summary>
    /// Start is called before the first frame update.
    /// </summary>
    public void Start()
    {
        // Configures the app to not shut down the screen and sets the brightness to maximum.
        // Brightness control is expected to work only in iOS, see:
        // https://docs.unity3d.com/ScriptReference/Screen-brightness.html.
        Screen.sleepTimeout = SleepTimeout.NeverSleep;
        Screen.brightness = 1.0f;

        // Checks if the device parameters are stored and scans them if not.
        if (!Api.HasDeviceParams())
        {
            Api.ScanDeviceParams();
        }
    }

    /// <summary>
    /// Update is called once per frame.
    /// </summary>
    public void Update()
    {
        if (Api.IsGearButtonPressed)
        {
            Api.ScanDeviceParams();
        }

        if (Api.IsCloseButtonPressed)
        {
            Application.Quit();
        }

        if (Api.IsTriggerHeldPressed)
        {
            Api.Recenter();
        }

        if (Api.HasNewDeviceParams())
        {
            Api.ReloadDeviceParams();
        }

#if !UNITY_EDITOR
        Api.UpdateScreenParams();
#endif
    }
}

CardboardStartup.cs

 

apply plugin: 'com.android.library'
**APPLY_PLUGINS**

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.0.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.gms:play-services-vision:15.0.2'
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'com.google.protobuf:protobuf-javalite:3.8.0'
    


**DEPS**}

android {
    ndkPath "**NDKPATH**"

    compileSdkVersion **APIVERSION**
    buildToolsVersion '**BUILDTOOLS**'

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }

    defaultConfig {
        minSdkVersion **MINSDKVERSION**
        targetSdkVersion **TARGETSDKVERSION**
        ndk {
            abiFilters **ABIFILTERS**
        }
        versionCode **VERSIONCODE**
        versionName '**VERSIONNAME**'
        consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
    }

    lintOptions {
        abortOnError false
    }

    aaptOptions {
        noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
    }**PACKAGING_OPTIONS**
}
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**

mainTemplate

 

org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
unityStreamingAssets=**STREAMING_ASSETS**
**ADDITIONAL_PROPERTIES**
android.enableJetifier=true
android.useAndroidX=true

gradleTemplate

 

<?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">
    <application android:requestLegacyExternalStorage="true">
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:theme="@style/UnityThemeSelector">
            <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>
</manifest>
​

AndroidManifest

 

 

그 후 수정이 다 되었으면

씬을 올리고 (단, 씬이 많으면 빌드되야 할 부분이 맨 위로 올라가야 함)플랫폼 확인하고 build를 한 후저장 위치를 정하면 apk가 만들어진다.

 

'산대특 > VRAR' 카테고리의 다른 글

Oculus Settings and Grab  (0) 2024.04.17
Reticle  (0) 2024.04.16
VR로 360도 동영상 다운로드 후 적용하기 + 오큘러스 적용  (0) 2024.04.16
캐릭터 이동지점 변경시 VR시점 변경  (0) 2024.04.12
VR Setting 문제  (0) 2024.04.12

VR 셋팅시 오류가 발생

 

 

 

Project Settings - Player - Other Settings

 

 

Publishing Settings

 

그 후 스크립트를 수정한다

 

 

 

//-----------------------------------------------------------------------
// <copyright file="CardboardStartup.cs" company="Google LLC">
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
//-----------------------------------------------------------------------

using Google.XR.Cardboard;
using UnityEngine;

/// <summary>
/// Initializes Cardboard XR Plugin.
/// </summary>
public class CardboardStartup : MonoBehaviour
{
    /// <summary>
    /// Start is called before the first frame update.
    /// </summary>
    public void Start()
    {
        // Configures the app to not shut down the screen and sets the brightness to maximum.
        // Brightness control is expected to work only in iOS, see:
        // https://docs.unity3d.com/ScriptReference/Screen-brightness.html.
        Screen.sleepTimeout = SleepTimeout.NeverSleep;
        Screen.brightness = 1.0f;

        // Checks if the device parameters are stored and scans them if not.
        if (!Api.HasDeviceParams())
        {
            Api.ScanDeviceParams();
        }
    }

    /// <summary>
    /// Update is called once per frame.
    /// </summary>
    public void Update()
    {
        if (Api.IsGearButtonPressed)
        {
            Api.ScanDeviceParams();
        }

        if (Api.IsCloseButtonPressed)
        {
            Application.Quit();
        }

        if (Api.IsTriggerHeldPressed)
        {
            Api.Recenter();
        }

        if (Api.HasNewDeviceParams())
        {
            Api.ReloadDeviceParams();
        }

#if !UNITY_EDITOR
        Api.UpdateScreenParams();
#endif
    }
}

CardboardStartup.cs

 

apply plugin: 'com.android.library'
**APPLY_PLUGINS**

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.0.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.gms:play-services-vision:15.0.2'
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'com.google.protobuf:protobuf-javalite:3.8.0'
    


**DEPS**}

android {
    ndkPath "**NDKPATH**"

    compileSdkVersion **APIVERSION**
    buildToolsVersion '**BUILDTOOLS**'

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }

    defaultConfig {
        minSdkVersion **MINSDKVERSION**
        targetSdkVersion **TARGETSDKVERSION**
        ndk {
            abiFilters **ABIFILTERS**
        }
        versionCode **VERSIONCODE**
        versionName '**VERSIONNAME**'
        consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
    }

    lintOptions {
        abortOnError false
    }

    aaptOptions {
        noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
    }**PACKAGING_OPTIONS**
}
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**

mainTemplate

 

org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
unityStreamingAssets=**STREAMING_ASSETS**
**ADDITIONAL_PROPERTIES**
android.enableJetifier=true
android.useAndroidX=true

gradleTemplate

 

<?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">
    <application android:requestLegacyExternalStorage="true">
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:theme="@style/UnityThemeSelector">
            <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>
</manifest>
​

AndroidManifest

 

 

그 후 수정이 다 되었으면

씬을 올리고 (단, 씬이 많으면 빌드되야 할 부분이 맨 위로 올라가야 함)플랫폼 확인하고 build를 한 후저장 위치를 정하면 apk가 만들어진다.

 

'산대특 > VRAR' 카테고리의 다른 글

Oculus Settings and Grab  (0) 2024.04.17
Reticle  (0) 2024.04.16
VR로 360도 동영상 다운로드 후 적용하기 + 오큘러스 적용  (0) 2024.04.16
캐릭터 이동지점 변경시 VR시점 변경  (0) 2024.04.12
VR Setting 문제  (0) 2024.04.12

'산대특' 카테고리의 다른 글

Download Python  (0) 2024.05.08
Learn Firebase  (0) 2024.05.02
팬텀로즈스칼렛 모작 최종  (0) 2024.04.08
2D Airplane - 원근감있는 무한 배경 만들  (0) 2024.03.17
2D Airplane - 5  (1) 2024.03.14

'산대특' 카테고리의 다른 글

Learn Firebase  (0) 2024.05.02
2D Vertical Shooting Game 모작 최종  (0) 2024.04.08
2D Airplane - 원근감있는 무한 배경 만들  (0) 2024.03.17
2D Airplane - 5  (1) 2024.03.14
2D Airplane - 4  (0) 2024.03.12

https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676

 

DOTween (HOTween v2) | 애니메이션 도구 | Unity Asset Store

Use the DOTween (HOTween v2) tool from Demigiant on your next project. Find this & more animation tools on the Unity Asset Store.

assetstore.unity.com

 

애니메이션 컨트롤러와 애니메이션을 만들지 않고 이 패키지를 설치하면 코드로 애니메이션을 구현할 수 있습니다.

 

https://dotween.demigiant.com/

 

DOTween (HOTween v2)

DOTween is a fast, efficient, fully type-safe object-oriented animation engine for Unity, optimized for C# users, free and open-source, with tons of advanced features It is also the evolution of HOTween, my previous Unity tween engine. Compared to it, DOTw

dotween.demigiant.com

 

설치 방법

 

 

설치를 하고 유니티로 들어가면 이런 창이 뜰텐데

x를 클릭해도 계속 창이 나오니 이 순서대로 해주시면 됩니다.

 

 

 

사용방법


우선 테스트를 하기 위해 셋팅은 이런 식으로 했습니다.

 

 

 

 코드 설명

 

 

using 에 DG.Tweening

 

 

 

 

여기서 주의깊게 봐야할 곳은 DOLocalMoveY입니다.

여기에 endValue, duration을 인자로 받는데

이것은 targetPosition.y 가 200으로 맞춰져 있고

y좌표로 10초동안 이동됩니다.

그리고 디버그가 출력된 후 삭제됩니다.

 

 

 

그 다음으로 봐야할 곳은 DOScale 입니다.

앞에 인자는 기존 사이즈를 1이라 보고 몇배로 크게 할것인가

그리고 뒤에 인자는 몇초동안 그 사이즈를 만들 것인가 입니다.

 

'한 줄로 풀어 해석하면 기존사이즈를 5초동안 2배로 만든다' 입니다.

 

그러면 아래는 5초동안 0.1의 사이즈로 축소됩니다.

 

 

위의 코드는 10초 이동 후 삭제

아래 코드는 5초간 커지고 5초간 작아지고

그러면 이동중에 커졌다 작아지며

사라지는 시간은 10초 후 크기 변화도 5+5=10 초니깐

사이즈가 0.1이 되자마자 사라질 것입니다.

 

 

 

알파(희미해지고 선명해지는)값을 조절해주는 코드입니다.

우선 TextMeshProUGUI 컴포넌트를 불러와야 합니다.

x를 y로 바꾸어보았는데 별 차이가 없는 것을 보아

흔히 변수를 선언할 때 int x = 1; int y = 1;

상관없듯이 그런 것 같지만 확실한 것은 아닙니다.

뒤에 0f, 7f는 첫번째는 알파값을 조절 뒤에 값은 똑같이 몇동안이므로

(알파 값이 0이면 보이지 않습니다, 반대로 1이면 있는 그대로 색을 띄웁니다.)

 

이러면 이 코드는 '7초동안 알파를 0으로 만든다' 입니다.

 

 

 

완성물

 

 

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

    public class test : MonoBehaviour
    {
        private TMP_Text damageText;
        void Start()
        {
            damageText = GetComponent<TMP_Text>();

            Debug.Log(this.transform.localPosition);

            Vector3 targetPosition = this.transform.localPosition;

            targetPosition.y += 200;

            this.transform.DOLocalMoveY(targetPosition.y, 10).OnComplete(() =>
            {
                Debug.Log("MoveY Complete!");
                Destroy(this.gameObject);
            });

            this.transform.DOScale(2, 5f).OnComplete(() =>
            {
                Debug.Log("DoScale Complete 1 -> 2");
                this.transform.DOScale(0.1f, 5f).OnComplete(() =>
                {
                    Debug.Log("DoScale Complete 2 -> 0.1");
                });

            });

            var tmpUGUI = this.damageText.GetComponent<TextMeshProUGUI>();

            DOTween.ToAlpha(() => tmpUGUI.color, x => tmpUGUI.color = x, 0f, 7f);
        }

    }

 

10초간 위로 이동하면서

5초간 커지고, 5초간 작아지고

7초동안 알파값이 0이 되므로

보이지 않더라도 실제로 10초 - 7초 = 3초 후에

이 오브젝트는 Destroy됩니다.

'라이브러리' 카테고리의 다른 글

[GitHub] Sprites-Outline  (0) 2024.05.20

Simple camera shake effect for Unity3d, written in C#. Attach to your camera GameObject. To shake the camera, set shakeDuration to the number of seconds it should shake for. It will start shaking if it is enabled.

 

카메라의 Transform을 Public으로 설정하여

인스펙터에서 메인카메라를 할당한다면

메인카메라로 보는 오브젝트들의 흔들림을 조정할 수 있습니다.

Shake Duration : 지속 시간

Shake Amount : 흔들림 강도

Decrease Factor : 흘러가는 시간을 조정(Shake Duration 수치 조정)

팀 프로젝트를 하며 적용을 한 장면입니다.

 

using UnityEngine;
using System.Collections;

public class CameraShake : MonoBehaviour
{
	// Transform of the camera to shake. Grabs the gameObject's transform
	// if null.
	public Transform camTransform;
	
	// How long the object should shake for.
	public float shakeDuration = 0f;
	
	// Amplitude of the shake. A larger value shakes the camera harder.
	public float shakeAmount = 0.7f;
	public float decreaseFactor = 1.0f;
	
	Vector3 originalPos;
	
	void Awake()
	{
		if (camTransform == null)
		{
			camTransform = GetComponent(typeof(Transform)) as Transform;
		}
	}
	
	void OnEnable()
	{
		originalPos = camTransform.localPosition;
	}

	void Update()
	{
		if (shakeDuration > 0)
		{
			camTransform.localPosition = originalPos + Random.insideUnitSphere * shakeAmount;
			
			shakeDuration -= Time.deltaTime * decreaseFactor;
		}
		else
		{
			shakeDuration = 0f;
			camTransform.localPosition = originalPos;
		}
	}
}

 

 

https://gist.github.com/ftvs/5822103

 

Simple camera shake effect for Unity3d, written in C#. Attach to your camera GameObject. To shake the camera, set shakeDuration

Simple camera shake effect for Unity3d, written in C#. Attach to your camera GameObject. To shake the camera, set shakeDuration to the number of seconds it should shake for. It will start shaking i...

gist.github.com

 

 

'Study > ' 카테고리의 다른 글

[Tip] Object.FindObjectOfType  (0) 2024.06.11
[Tip] RenderSettings  (0) 2024.06.05
[팁] Slider.onValueChanged  (0) 2024.06.05
[Tip] 3D 프로젝트에서 SpriteAtals 패킹하는 법  (0) 2024.05.23
[Tip] 패키지에서 프리팹찾기  (0) 2024.04.18

구조

이때 주의할것은 뭐가 위에 올라와야 하는지 구조를 잡는 것이다.

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class UISkillButton : MonoBehaviour
{
    [SerializeField] private Button btn;
    [SerializeField] private int maxCooltime = 10;
    [SerializeField] private TMP_Text cooltimeText;
    [SerializeField] private Image slier;
    private float cooltime;
    private bool isCoolTime;

    void Start()
    {
        btn.onClick.AddListener(() => {
            if (IsAvaliable())
            {
                this.UseSkill();
            }
            else
            {
                Debug.Log("아직은 사용할수 없습니다.");
            }
        });

        this.Init();
    }

    private void Init()
    {
        Debug.Log("스킬버튼을 초기화 합니다.");
        this.cooltime = this.maxCooltime;
        this.slier.fillAmount = 0;
        this.cooltimeText.text = this.cooltimeText.ToString();
        this.cooltimeText.gameObject.SetActive(false);
        this.isCoolTime = false;
    }

    private void UseSkill()
    {
        Debug.Log("스킬을 사용했습니다.");
        this.cooltimeText.gameObject.SetActive(true);
        this.cooltimeText.text = this.cooltime.ToString();
        this.slier.fillAmount = 1;
        this.StartCoroutine(this.CoWaitForCoolTime());
    }

    private IEnumerator CoWaitForCoolTime()
    {
        this.isCoolTime = true;

        while (true)
        {
            this.cooltime -= Time.deltaTime;
            this.cooltimeText.text = Mathf.RoundToInt(this.cooltime).ToString();
            this.slier.fillAmount = this.cooltime / this.maxCooltime;
            if (this.cooltime <= 0)
            {
                break;
            }
            yield return null;
        }

        this.isCoolTime = false;

        Debug.Log("스킬을 사용할수 있습니다.");

        this.Init();
    }

    private bool IsAvaliable()
    {
        return !isCoolTime;
    }
}

 

 

'낙서장 > UIUX' 카테고리의 다른 글

Slider  (0) 2024.03.18
Switch Button  (0) 2024.03.18
Button and Inputfield  (0) 2024.03.18

+ Recent posts