티스토리 뷰

금일 공부 내용

  • 실습 공부용 개인 프로젝트 - 멍뭉이! 멍멍뭉! - 귀신 잡는 개멍대!
                                                 [Doggydogs! BowBowWow! - Ghost Hunting Barking Dogs!]
    • 이동 시스템 제작 [어제 제작 내용]
      • 마우스가 캐릭터에서 일정 거리 이상 멀어지면 마우스 방향으로 천천히 이동.
      • 마우스와 캐릭터의 거리가 일정 거리 이상 멀어지면 속도 상승.
    • 각종 게이지 시스템 제작
      • 병렬형 전투자원 시스템 구성
      • 단독 게이지 시스템 구성
    • 투사체 작성
      • 투사체 적중 시 피해를 입는다.
      • 관통 가능(영상에는 없습니다.)
      • 분열 가능(영상에 있습니다.)

 

결과물(영상)

※ 생명력은 마우스 좌클릭(자원 소모, 대량 회복), 우클릭(자원 미소모, 소량 회복)으로 회복하도록 구성하였습니다.

코드(일부분만)

더보기

캐릭터 이동

public void Move_Chara(float velocity)
{
    Vector2 Mouse_Pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    float x_Mou = Mouse_Pos.x;
    float y_Mou = Mouse_Pos.y;
    float x_Vec = x_Mou - transform.position.x;
    float y_Vec = y_Mou - transform.position.y;
    float distance = Mathf.Sqrt(Mathf.Pow(x_Vec, 2) + Mathf.Pow(y_Vec, 2));
    float x_Dir = x_Vec / distance;
    float y_Dir = y_Vec / distance;

    // Debug.Log($"{distance}, {x_Dir}, {y_Dir}");


    if (distance > 3.5)
    {
        transform.position += new Vector3(x_Dir, y_Dir, 0.0f) * 5.0f * velocity;
        Stamina.Dec_Gauge(1);
    }

    else if (distance > 1)
    {
        transform.position += new Vector3(x_Dir, y_Dir, 0.0f) * velocity;
    }

    else
    {
        Stamina.Inc_Gauge(1);
    }
}

 

게이지 (한줄)

using JetBrains.Annotations;
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

[System.Serializable]
public class Gauge
{
    public int Gauge_Max;
    public int Gauge_Cur;
    public float Gauge_Inc;
    public float Gauge_Dec;
    public bool is_Extreme;

    public float vel_Ext;
    public float vel_Nor;

    public Gauge(int _Max)
    {
        Gauge_Max = _Max;
        Gauge_Cur = Gauge_Max;
        Gauge_Inc = (float)Gauge_Max;
        Gauge_Dec = (float)Gauge_Max;
        is_Extreme = false;
        vel_Nor = 0.2f;
        vel_Ext = 2.0f;
    }

    public bool Dec_Gauge(int amount)
    {
        if (amount >= Gauge_Cur * 0.35f)
            is_Extreme = true;
        
        Gauge_Cur -= amount;

        if (Gauge_Cur <= 0)
        {
            Gauge_Cur = 0;
            return false;
        }
        else
            return true;
    }

    public void Inc_Gauge(int amount)
    {
        if (amount >= Gauge_Cur * 0.35f)
            is_Extreme = true;

        Gauge_Cur += amount;

        if (Gauge_Cur > Gauge_Max)
            Gauge_Cur = Gauge_Max;
    }

    public void Gauge_Update()
    {
        float vel_Cur;
        if (is_Extreme)
            vel_Cur = vel_Ext;
        else
            vel_Cur = vel_Nor;

        if (Gauge_Dec > Gauge_Cur)
            Gauge_Dec -= vel_Cur;

        if (Gauge_Inc < Gauge_Cur)
            Gauge_Inc += vel_Cur;

        if (Gauge_Dec < Gauge_Cur)
            Gauge_Dec = Gauge_Cur;

        else if (Gauge_Inc > Gauge_Cur)
            Gauge_Inc = Gauge_Cur;

        else if (Gauge_Inc == Gauge_Cur && Gauge_Dec == Gauge_Cur && is_Extreme)
            is_Extreme = false;

    }
}

 

게이지 (한줄) UI

public class Bar_Gauge : MonoBehaviour
{
    [SerializeField]
    Chara_Base Chara;
    Gauge Gauge_Target;

    [SerializeField]
    GameObject Bar_Cur;

    [SerializeField]
    GameObject Bar_Inc;

    [SerializeField]
    GameObject Bar_Dec;

    [SerializeField]
    bool is_Life;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (is_Life)
            Gauge_Target = Chara.Life;
        else
            Gauge_Target = Chara.Stamina;

        Bar_Inc.transform.localScale = new Vector3((float)((float)Gauge_Target.Gauge_Cur / Gauge_Target.Gauge_Max), 1.0f, 1.0f);
        Bar_Cur.transform.localScale = new Vector3((float)(Gauge_Target.Gauge_Inc / Gauge_Target.Gauge_Max), 1.0f, 1.0f);
        Bar_Dec.transform.localScale = new Vector3((float)(Gauge_Target.Gauge_Dec / Gauge_Target.Gauge_Max), 1.0f, 1.0f);
    }
}

 

게이지 (병렬) 

public class Point
{
    public float Gauge_Max;
    public float Gauge_Cur;
    public bool is_On;

    public Point(float _Max, float _Cur, bool _On)
    {
        Gauge_Max = _Max;
        Gauge_Cur = _Cur;
        is_On = _On;
    }

    public void Use_Point(float _Cool)
    {
        Gauge_Max = _Cool;
        Gauge_Cur = 0;
        is_On = false;
    }

    public float Charge_Point(float _Time)
    {
        float result = -1.0f;

        Gauge_Cur += _Time;
        if(Gauge_Cur > Gauge_Max)
        {
            result = Gauge_Cur - Gauge_Max;
            Gauge_Max = 0;
            Gauge_Cur = 0;
            is_On = true;
        }

        return result;
    }
}

 

게이지 (병렬) UI

public class FP_Gauge : MonoBehaviour
{
    [SerializeField]
    Chara_Base Chara;

    [SerializeField]
    int Point_Num;

    [SerializeField]
    Image Gauge_Cur;

    [SerializeField]
    GameObject Gauge_OFF;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        Gauge_Cur.fillAmount = Chara.Point_Unit[Point_Num].Gauge_Cur / Chara.Point_Unit[Point_Num].Gauge_Max;
        Gauge_OFF.SetActive(!Chara.Point_Unit[Point_Num].is_On);
    }
}

 

투사체

public class Projectile : MonoBehaviour
{
    public bool is_friendly;

    public int[] Damage = new int[5];
    public int Pierce_Max;
    public int Pierce_Cur;
    public List<int> Fork;

    public float velocity;
    public Vector3 Size;
    public Vector3 Direction;
    public Sprite Shape;
    SpriteRenderer Rend;

    List<GameObject> Hitted_Units = new List<GameObject>();

    private void Start()
    {
        Pierce_Cur = Pierce_Max;
        Rend = GetComponent<SpriteRenderer>();
        Rend.sprite = Shape;
        transform.localScale = Size;
        transform.rotation = Quaternion.Euler(Direction);
    }

    private void Update()
    {
        transform.position += Direction * velocity;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        bool Affective = false;

        if (is_friendly)
        {
            if (collision.gameObject.CompareTag("Enemy"))
                Affective = true;
        }

        else
        {
            if (collision.gameObject.CompareTag("Player"))
                Affective = true;
        }

        if (Affective && !Hitted_Units.Contains(collision.gameObject))
        {
            collision.gameObject.GetComponent<Chara_Base>().Get_Damage(Damage);
            Hitted_Units.Add(collision.gameObject);

            if (Pierce_Cur > 0)
                Pierce_Cur--;

            else if (Fork.Count > 0)
            {
                Pierce_Cur = Pierce_Max;

                int Fork_Temp = Fork[0];
                Fork.RemoveAt(0);

                for (int j = 0; j < Fork_Temp; j++)
                {
                    Vector3 Fork_Direction = new Vector3(Direction.x + (((Fork_Temp / 2) - j) * 0.15f), Direction.y - (((Fork_Temp / 2) - j) * 0.15f), Direction.z);

                    GameObject Sub_Projectile = Instantiate(this.gameObject, position: transform.position, rotation: Quaternion.identity);

                    Projectile Sub_Proj_Script = Sub_Projectile.gameObject.GetComponent<Projectile>();
                    Sub_Proj_Script.Direction = Fork_Direction;
                    Sub_Proj_Script.Hitted_Units = Hitted_Units;
                }

                Destroy(this.gameObject);
            }

            else
                Destroy(this.gameObject);
        }
    }
}

 

정리하며

실습 겸 실전용 게임으로 구상했던 멍뭉이! 멍멍뭉! - 귀신 잡는 개멍대!의 제작을 시작했습니다.

일단 UI 배치는 앞전에 해 놓은 고로, 이번에는 관련 시스템을 제작해서 UI에 적용하는 것을 작업하고, 기본적인 테스트를 하기 위해서 투사체 클래스를 작업했습니다.

 

전체적으로는 어지간한 게임에는 기본적으로 들어가는 요소이긴 하나, 제가 직접 구상해서 작성한다는 것이 상당히 새롭고 즐거운 작업이었습니다. 전체적으로는 만족스러운 결과물인 거 같아요.

다만, 아무래도 전체적으로 다듬기는 해야할 거 같습니다. 테스트 가능할 정도로만 작업했더니 전체적으로 좀 엉성하네요.

(특히 각도 변경 관련 부분은 테스트용이라 대충 적었더니 많이 엉성하네요. 더 공부하고, 고민 해 봐야 할 거 같습니다.)

 

다음에는 저 투사체를 플레이어 조작으로 발사하도록 변경하면서 파장형 공격을 추가할 예정입니다.

(내일이 될지는 모르겠습니다. 다른 거 해야할 거 있으면 그걸 할 예정인지라.)

이후 근접 공격을 추가하고, 대시를 비롯한 각종 조작을 구현한 뒤, 상태이상과 기본적인 몬스터를 제작하면 전투 시스템은 완성. 이후에 기본적인 장비 시스템(= 스킬 시스템)을 추가하고, 타이틀 같은 자잘한 요소들을 제작하면 완성이지 싶네요.

 

물론, 게임의 기본 바탕을 이야기 하는 거고, 실제로는 저기서 에셋이나 컨텐츠, 시나리오 같은 작업을 더 해야 하지만, 일단 실습용으로는 저 정도로 끝내고 [멍뭉이! 멍멍뭉! - 개를놔 전선!]으로 넘어가지 싶습니다.

이 이상은 개발 공부 보다는 개인 제작에 해당하는 영역인 거 같아서, 실습이라는 느낌 보다는 개인적인 제작 활동으로 진행하지 싶네요.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
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
글 보관함