본문 바로가기
유니티 최고/유니티 구현

유니티(Unity) 터치, 마우스 클릭시 이펙트 생성하기

by Lee_story_.. 2024. 4. 4.
728x90

 

 

많은 게임의 경우 클릭이나 마우스 이동 등에 많은 이펙트가 달려 있습니다.

(소소한 이펙트라 체감이 안될지도...?) 

 

이런 이펙트가 없으면 약간 밋밋해 보일수 있기에 이번에 한번 이펙트를 구현해보고자 글을 작성합니다!

 

 

가장 먼저 참고한 유튜브 영상입니다!

 

 

 

 

오늘 결과물은 아래처럼!

 

 

 

그럼 시작해 보겠습니다. 

 

 

영상을 참고하여 작성하고 확인해보니 코드는 2D 환경에서 적합한 코드였습니다..... (저는 3D...)

그래서 약간의 개선사항과 최종 코드에 대해서 적어볼 예정입니다! 

(2D게임이 아니라면 아래로~)

 

 

 

 

 

첫번째! 이펙트를 지정 좌표 생성하는 방법! 


 

 

일단 영상을 참고 하였기에 코드부터 뜯어보겠습니다!

 

코드구성들은 다음과같은 순서로 이루어져있었습니다. 

 

1. 화면상에 생성될 프리팹 생성

2. 프리팹 이펙트 관리 스크랩 작성 - (색, 크기, 이동)

3. 터치하면 프리팹이 생성하는 함수 작성

 

 

그럼 진짜 시작!

 

먼저 프리팹을 생성해 보았습니다. 

 

기본적인 png파일을 사용하여 머터리얼을 하나 생성한뒤

 

 

색과 쉐이더의 종류를 선택하여 줍시다. 

쉐이더 >> Legacy - particles - additive  

 

 

 

그 다음 png파일의 타입을 sprite로 변경후 월드에 설치하며 프리팹을 하나 만들어 주었습니다. 

 

 

 

 

이제 여기에 위 프리팹에 효과를 적용시켜줄 스크랩!

 

 

 

 

 

다음은 터치시 위의 프리팹을 생성할 함수!

 

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

public class TouchEffect : MonoBehaviour
{

    SpriteRenderer sprite;


    // 터치 이펙트
    Vector2 direction;
    float moveSpeed = 0.01f;
    float SizeSpeed = 1f;
    float ColorSpeed = 1f;



    float MinSize = 0.1f;
    float MaxSize = 0.5f;


    public Color[] colors;

    // Start is called before the first frame update
    void Start()
    {
        sprite=GetComponent<SpriteRenderer>();
        direction = new Vector2(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f));

        float size = Random.Range(MinSize, MaxSize);

        sprite.color = colors[Random.Range(0, colors.Length)];
    }

    // Update is called once per frame
    void Update()
    {
        //transform.Translate(direction * moveSpeed);
        transform.localScale = Vector2.Lerp(transform.localScale, Vector2.zero, Time.deltaTime * SizeSpeed);

        Color color = sprite.color;
        color.a = Mathf.Lerp(sprite.color.a, 0, Time.deltaTime * ColorSpeed);
        sprite.color = color;


        if (sprite.color.a <= 0.01f)
        {
            Destroy(gameObject);
        }
    }
}

 

차례대로 생성시 프리팹이 이동할 방향과 크기, 색을 설정해준뒤

update문을 이용하여 별이 생성되고 크기가 작아지며 없어지는 효과를 넣어 주었습니다 .

 

 

 

그리고 마지막으로 터치시 프리팹을 생성하는 함수

 

    float TouchTime;
    float defaultTime = 0.05f; // 이펙트 시간

void Update()
    {

        if((Input.touchCount == 1 || Input.GetMouseButton(0)) && TouchTime >= defaultTime)
        {
            TouchEffectFun();
            TouchTime = 0;
        }
        
        TouchTime += Time.deltaTime;
......


void TouchEffectFun()
    {
        GameObject Temp=null;

        Touch touch = Input.GetTouch(0);
        Vector3 point = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, 
        touch.position.y, -Camera.main.transform.position.z));

        Temp = Instantiate(TouchEffectOBJ, point, Quaternion.identity);
        

        Temp.transform.parent = TouchEffectPar.transform;

    }

 

 

여기까지 작성하면 끝! 이긴 한데....

 

 

3D 프로젝트에서는 다음과 같은 문제들이 있었습니다. 

 

1. 기존에 설치되어있던 프리팹과의 충돌 (해결해 보려 했으나 이펙트가 가려지는....)

2. 카메라의 방향에 따라 프리팹의 방향 변환 부족...

 

 

ScreenToWorldPoint 함수를 이용해서 스크린상 월드 좌표계를 받아와 그 위치에 프리팹을 설치하는 방법에는 무리가 있는 것 같습니다.... 

 

 

 

 

그래서 이번엔 이펙트를 캔버스 ui위에 설치하는 방법으로 구현해보았습니다. 

 

두번째! 캔버스 ui에 이펙트를 설치하는 방법! 


 

그럼 다시시작하겠습니다. 

 

가장 먼저 이펙트 역할을 해줄 이미지를 생성하여줍시다.

 

 

 

 

 

그다음 이미지를 프리팹화 한 다음 이펙트를 구성해줍시다!

(이펙트의 효과는 위에서 설명했던 방식과 동일)

 

하나 수정한 부분은 sprite를  >> image로 변경

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TouchEffect : MonoBehaviour
{


    Image Image;


    // 터치 이펙트
    Vector2 direction;
    float moveSpeed = 0.01f;
    float SizeSpeed = 1f;
    float ColorSpeed = 1f;


    float MinSize = 0.1f;
    float MaxSize = 0.5f;


    public Color[] colors;

    // Start is called before the first frame update
    void Start()
    {
        Image = GetComponent<Image>();
        direction = new Vector2(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f));

        float size = Random.Range(MinSize, MaxSize);

        Image.color = colors[Random.Range(0, colors.Length)];
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(direction * moveSpeed);
        transform.localScale = Vector2.Lerp(transform.localScale, Vector2.zero, Time.deltaTime * SizeSpeed);

        Color color = Image.color;
        color.a = Mathf.Lerp(Image.color.a, 0, Time.deltaTime * ColorSpeed);
        Image.color = color;


        if (Image.color.a <= 0.01f)
        {
            Destroy(gameObject);
        }
    }
}

 

 

 

그리고 다음으로는 터치시 캔버스에서의 위치를 찾아줍시다.

 

    // 터치 이펙트
    public GameObject TouchEffectOBJ;   // 이펙트
    public GameObject uiCanvas;         // UI 캔버스

    float TouchTime;
    float defaultTime = 0.05f; // 이펙트 시간
    
....... 
    
     void Update()
    {

        if((Input.touchCount == 1 || Input.GetMouseButton(0)) && TouchTime >= defaultTime)
        {
            TouchEffectFun();
            TouchTime = 0;
        }

        TouchTime += Time.deltaTime;
        
        
 .......
    
    public void TouchEffectFun()
    {
            RectTransform rt = uiCanvas.GetComponent<RectTransform>();

        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rt, Input.mousePosition, null, out Vector3 Point))
        {

            GameObject Temp = Instantiate(TouchEffectOBJ, Point, Quaternion.identity, uiCanvas.transform);
        }
    }

 

전체적으로는 위 코드처럼 이루어지는데 여기서 가장 중요한 부분은!

 

RectTransformUtility.ScreenPointToWorldPointInRectangle(rt, Input.mousePosition, null, out Vector3 Point)

 

ScreenPointToWorldPointInRectangle를 통해 Rectangle형식의 월드 좌표계를 Point변수로 받는 부분!

 

 

 

그리고 캔버스 하위에 이펙트를 생성하는부분!

GameObject Temp = Instantiate(TouchEffectOBJ, Point, Quaternion.identity, uiCanvas.transform);

 

 

이 두 줄의 코드만 작성하면 끝!

 

 

 

 

 

끝!

 

 

 

월드상에 프리팹을 Instantiate하여 생성하는 것도 방법이 될 수 있지만, 

터치 이펙트는 모든 요소들의 최상단에 보여져야하기에 캔버스에 생성하는 것이 최선인것 같습니다.

 

 

 

넵! 여기까지!

 

 

 

 

틀린점이 있다면 댓 달아주세요!

댓글