블록안에 TMP_Text를 넣었더니 캔버스가 뭔가 이상해진 것 같아서

수정해볼 필요가 있다.

 

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

public class AtlasManager : MonoBehaviour
{
    public static AtlasManager instance;
    public SpriteAtlas blockAtlas;
    //싱글톤
    private void Awake()
    {
        //AtlasManager 클래스의 인스턴스를 instance에 할당
        instance = this;
    }
}

 

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.U2D;
using Random = UnityEngine.Random;

public class Test : MonoBehaviour
{
    public Board board;
    private void Start()
    {
        board.CreateBoard();
    }
}

 

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Random = UnityEngine.Random;

public class Board : MonoBehaviour
{
    private Block[,] board; //1차원 배열이 Block들을 관리
    public GameObject blockPrefab;

    public void CreateBoard()
    {
        //크기가 9인 BlockType의 1차원 배열 만들기
        board = new Block[5, 9]; // 2차원 배열로 변경
        //5행 9열의 Block타입의 2차원 배열 만들기
        for (int i = 0; i < board.GetLength(0); i++)
        {
            for (int j = 0; j < board.GetLength(1); j++)
            {
                CreateBlock(i, j);
            }
        }
        PrintBoard();
    }

    public void CreateBlock(int row, int col)
    {
        Vector2 pos = new Vector2(col, row);
        Block.BlockType blockType = (Block.BlockType)Random.Range(0, 5);
        GameObject blockGo = Instantiate(blockPrefab);
        Block block = blockGo.GetComponent<Block>();
        block.Init(blockType);
        block.SetPosition(pos);

        //배열의 요소에 블록 넣기
        board[row, col] = block;
    }

    public void PrintBoard()
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < board.GetLength(0); i++)
        {
            for (int j = 0; j < board.GetLength(1); j++)
            {
                sb.Append($"({i},{j})"); // StringBuilder에 문자열 추가
            }
            sb.AppendLine(); // 새로운 행 추가
        }
        Debug.Log(sb); // StringBuilder에 저장된 문자열을 출력
    }
}

 

using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.Mathematics;
using UnityEngine;

public class Block : MonoBehaviour
{
    public enum BlockType
    {
        Blue, Gray, Green, Pink, Yellow
    }

    public BlockType blockType;
    public SpriteRenderer spriteRenderer;
    public TMP_Text debugText;
    public void Init(BlockType blockType)
    {
        this.blockType = blockType;
        //이미지 변경 
        ChangeSprite(blockType);
    }

    public void ChangeSprite(BlockType blockType)
    {
        //블록의 이름을 넣어서 아틀라스에서 같은 이름인 sprite를 찾고 할당
        Sprite sp =
            AtlasManager.instance.blockAtlas.GetSprite(blockType.ToString());
        spriteRenderer.sprite = sp;
    }

    public void SetPosition(Vector2 pos)
    {
        transform.position = pos;
        var index = Position2Index(pos);
        debugText.text = $"[{index.row}, {index.col}]";
    }

    public static (int row, int col) Position2Index(Vector2 pos)
    {
        return ((int)pos.y, (int)pos.x);
    }

    public static (int x, int y) Index2Position(Vector2 index)
    {
        return ((int)index.x, (int)index.y);
    }
}

StringBuilder를 사용하여

 

using System.Collections;
using System.Collections.Generic;
using System.Text;
using Unity.VisualScripting;
using UnityEngine;

public class Test : MonoBehaviour
{
    private Block[,] board; //1차원 배열이 Block들을 관리
    public GameObject blockPrefab;
    void Start()
    {
        CreateBoard();
        //PrintBoard();
    }

    private void CreateBoard()
    {
        //크기가 9인 BlockType의 1차원 배열 만들기
        board = new Block[5, 9]; // 2차원 배열로 변경
        Debug.LogFormat("현재 보드의 칸의 총 개수 : {0}", board.Length); // 전체 길이
        Debug.LogFormat("행의 개수 : {0} ", board.GetLength(0));
        Debug.LogFormat("열의 개수 : {0} ", board.GetLength(1));

        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < board.GetLength(0); i++)
        {
            for(int j = 0;  j < board.GetLength(1); j++)
            {
                sb.Append($"({i},{j})"); // StringBuilder에 문자열 추가
            }
            sb.AppendLine(); // 새로운 행 추가
        }
        Debug.Log(sb); // StringBuilder에 저장된 문자열을 출력
        //배열의 요소에 넣기(0~8까지의 랜덤한 값을 BlockType으로 바꿔서)
        //for (int i = 0; i < board.Length; i++)
        //{
        //    Block.BlockType blockType = (Block.BlockType)Random.Range(0, 5);

        //    //블록 프리팹 인스턴스를 생성
        //    GameObject blockGo = Instantiate(blockPrefab);
        //    //생성된 프리팹을 블록클래스의 블록에 할당
        //    Block block = blockGo.GetComponent<Block>();
        //    block.Init(blockType);
        //    block.SetPosition(i);
        //}
    }

    //private void PrintBoard()
    //{
    //    
    //    
    //    
    //    
    //    
    //    
    //}
}

 

 


 

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

public class AtlasManager : MonoBehaviour
{
    public static AtlasManager instance;
    public SpriteAtlas blockAtlas;
    //싱글톤
    private void Awake()
    {
        //AtlasManager 클래스의 인스턴스를 instance에 할당
        instance = this;
    }
}

 

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

public class Block : MonoBehaviour
{
    public enum BlockType
    {
        Blue, Gray, Green, Pink, Yellow
    }

    public BlockType blockType;
    public SpriteRenderer spriteRenderer;
    public void Init(BlockType blockType)
    {
        this.blockType = blockType;
        //이미지 변경 
        ChangeSprite(blockType);
    }

    public void ChangeSprite(BlockType blockType)
    {
        //블록의 이름을 넣어서 아틀라스에서 같은 이름인 sprite를 찾고 할당
        Sprite sp =
            AtlasManager.instance.blockAtlas.GetSprite(blockType.ToString());
        spriteRenderer.sprite = sp;
    }

    public void SetPosition(int x)
    {
        Vector2 pos = transform.position;
        pos.x = x;
        transform.position = pos;
    }
}
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Unity.VisualScripting;
using UnityEngine;

public class Test : MonoBehaviour
{
    private Block[,] board; //1차원 배열이 Block들을 관리
    public GameObject blockPrefab;
    void Start()
    {
        CreateBoard();
    }

    private void CreateBoard()
    {
        //크기가 9인 BlockType의 1차원 배열 만들기
        board = new Block[5, 9]; // 2차원 배열로 변경

        PrintBoard();

        

        
        //배열의 요소에 넣기(0~8까지의 랜덤한 값을 BlockType으로 바꿔서)
        //for (int i = 0; i < board.Length; i++)
        //{
        //    Block.BlockType blockType = (Block.BlockType)Random.Range(0, 5);

        //    //블록 프리팹 인스턴스를 생성
        //    GameObject blockGo = Instantiate(blockPrefab);
        //    //생성된 프리팹을 블록클래스의 블록에 할당
        //    Block block = blockGo.GetComponent<Block>();
        //    block.Init(blockType);
        //    block.SetPosition(i);
        //}
    }

    private void PrintBoard()
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < board.GetLength(0); i++)
        {
            for (int j = 0; j < board.GetLength(1); j++)
            {
                sb.Append($"({i},{j})"); // StringBuilder에 문자열 추가
            }
            sb.AppendLine(); // 새로운 행 추가
        }
        Debug.Log(sb); // StringBuilder에 저장된 문자열을 출력
    }
}

 

 

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

public class AtlasManager : MonoBehaviour
{
    public static AtlasManager instance;
    public SpriteAtlas blockAtlas;
    //싱글톤
    private void Awake()
    {
        //AtlasManager 클래스의 인스턴스를 instance에 할당
        instance = this;
    }
}

 

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

public class Block : MonoBehaviour
{
    public enum BlockType
    {
        Blue, Gray, Green, Pink, Yellow
    }

    public BlockType blockType;
    public SpriteRenderer spriteRenderer;
    public void Init(BlockType blockType)
    {
        this.blockType = blockType;
        //이미지 변경 
        ChangeSprite(blockType);
    }

    public void ChangeSprite(BlockType blockType)
    {
        //블록의 이름을 넣어서 아틀라스에서 같은 이름인 sprite를 찾고 할당
        Sprite sp =
            AtlasManager.instance.blockAtlas.GetSprite(blockType.ToString());
        spriteRenderer.sprite = sp;
    }

    public void SetPosition(int x)
    {
        Vector2 pos = transform.position;
        pos.x = x;
        transform.position = pos;
    }
}

 

using System.Collections;
using System.Collections.Generic;
using System.Text;
using Unity.VisualScripting;
using UnityEngine;

public class Test : MonoBehaviour
{
    private Block[] board; //1차원 배열이 Block들을 관리
    public GameObject blockPrefab;
    void Start()
    {
        CreateBoard();
        PrintBoard();
    }

    private void CreateBoard()
    {
        //크기가 9인 BlockType의 1차원 배열 만들기
        board = new Block[9];
        //배열의 요소에 넣기(0~8까지의 랜덤한 값을 BlockType으로 바꿔서)
        for (int i = 0; i < board.Length; i++)
        {
            Block.BlockType blockType = (Block.BlockType)Random.Range(0, 5);

            //블록 프리팹 인스턴스를 생성
            GameObject blockGo = Instantiate(blockPrefab);
            //생성된 프리팹을 블록클래스의 블록에 할당
            Block block = blockGo.GetComponent<Block>();
            block.Init(blockType);
            block.SetPosition(i);
        }
    }

    private void PrintBoard()
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < board.Length; i++)
        {
            sb.Append($"{board[i]}");
        }
        Debug.Log(sb);
    }
}

 

https://learn.microsoft.com/ko-kr/dotnet/api/system.text.stringbuilder?view=net-8.0

 

StringBuilder 클래스 (System.Text)

변경할 수 있는 문자열을 나타냅니다. 이 클래스는 상속될 수 없습니다.

learn.microsoft.com

 

 

 

해야 할 것

스크립트를 하나로 합쳤는데

2개 클릭 시 다시 다른 버튼 클릭을 막으려다

현재 클릭된 버튼도 클릭이 막힌 상태

클릭이 된 2개를 기준으로 클릭을 해제하면 다른 것을 클릭할 수 있도록 수정하기

 

 

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

public class SelectSkillPopUp : MonoBehaviour
{
    public GameObject[] selectSkills;
    public Image[] skillImgs;
    public TMP_Text[] skillIds;
    public TMP_Text[] skillNames;
    public TMP_Text[] skillDescs;

    public Button shuffleSkills;
    public Button selectBtn;
    public SpriteAtlas skillsAtlas;
    List<SkillData> skillList = new List<SkillData>();

    private int selectedCount = 0;
    private List<int> selectedIndexes = new List<int>();

    void Start()
    {
        selectBtn.gameObject.SetActive(false);
        ShowLevelUp();

        foreach (var data in SkillManager.instance.skillDatas)
        {
            skillList.Add(data);
        }
        shuffleSkills.onClick.AddListener(ShuffleSkills);

        // 각 스킬 오브젝트에 대해 클릭 이벤트 추가
        for (int i = 0; i < selectSkills.Length; i++)
        {
            int index = i;
            selectSkills[i].GetComponent<Button>().onClick.AddListener(() =>
            {
                ToggleSkill(index);
            });
        }
    }

    void ShowLevelUp()
    {
        selectedIndexes.Clear();

        for (int i = 0; i < skillImgs.Length; i++)
        {
            int randomIndex = SkillManager.instance.GetSkillsRandomNum();
            selectedIndexes.Add(randomIndex);

            skillImgs[i].sprite = SkillManager.instance.GetRandomAtlasImg(randomIndex);
            skillIds[i].text = SkillManager.instance.GetRandomAtlasImgId(randomIndex).ToString();
            skillNames[i].text = SkillManager.instance.GetRandomAtlasName(randomIndex);
            skillDescs[i].text = SkillManager.instance.GetRandomAtlasDesc(randomIndex);
        }
    }

    void ShuffleSkills()
    {
        selectedCount = 0;

        for (int i = 0; i < skillImgs.Length; i++)
        {
            int randomIndex = GetUniqueRandomIndex();
            selectedIndexes[i] = randomIndex;

            skillIds[i].text = SkillManager.instance.GetRandomAtlasImgId(randomIndex).ToString();
            skillNames[i].text = SkillManager.instance.GetRandomAtlasName(randomIndex);
            skillDescs[i].text = SkillManager.instance.GetRandomAtlasDesc(randomIndex);
            skillImgs[i].sprite = SkillManager.instance.GetRandomAtlasImg(randomIndex);
            SetImageAlpha(skillImgs[i], 1f); // 알파 값을 원래대로 초기화
        }

        UpdateSelectBtn();
    }

    int GetUniqueRandomIndex()
    {
        int randomIndex;
        do
        {
            randomIndex = Random.Range(0, skillList.Count);
        } while (selectedIndexes.Contains(randomIndex));

        return randomIndex;
    }

    void SetImageAlpha(Image image, float alpha)
    {
        Color color = image.color;
        color.a = alpha;
        image.color = color;
    }

    void UpdateSelectBtn()
    {
        selectBtn.gameObject.SetActive(selectedCount == 2);
    }

    public void ToggleSkill(int index)
    {
        if (selectedCount >= 2)
        {
            // 이미 2개의 스킬이 선택되었으므로 다른 스킬 선택을 막음
            return;
        }

        Image skillImage = skillImgs[index].GetComponent<Image>();
        if (GetImageAlpha(skillImage) != 65f / 255f)
        {
            SetImageAlpha(skillImage, 65f / 255f);
            selectedCount++;
        }
        else
        {
            SetImageAlpha(skillImage, 1f);
            selectedCount--;
        }

        UpdateSelectBtn();
    }

    float GetImageAlpha(Image image)
    {
        return image.color.a;
    }
}

 

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;

public class SkillManager : MonoBehaviour
{
    public static SkillManager instance; // 싱글톤

    public SpriteAtlas skillsAtlas;
    public Button levelUpBtn;
    public Button closeBtn;
    public GameObject selectSkillPopUp;
    public SkillData[] skillDatas;
    private List<int> rememberRandomIndex = new List<int>();

    private void Awake() // 싱글톤
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
    }

    public void Start()
    {
        levelUpBtn.onClick.RemoveAllListeners();
        OnClickLevelUpBtn();
        OnClickCloseBtn();
        TextAsset asset = Resources.Load<TextAsset>("data/skills_data");
        string json = asset.text;

        skillDatas = JsonConvert.DeserializeObject<SkillData[]>(json);
    }

    public SkillData GetDataById(int id)
    {
        SkillData foundSkillData = null;
        foreach (SkillData skillData in skillDatas)
        {
            if (skillData.id == id)
            {
                foundSkillData = skillData;
                break;
            }
        }
        return foundSkillData;
    }

    public int GetRandomAtlasImgId(int randomIndex)
    {
        return skillDatas[randomIndex].id;
    }

    public string GetRandomAtlasName(int randomIndex)
    {
        return skillDatas[randomIndex].name;
    }

    public string GetRandomAtlasDesc(int randomIndex)
    {
        return skillDatas[randomIndex].desc;
    }

    public Sprite GetRandomAtlasImg(int randomIndex)
    {
        return skillsAtlas.GetSprite(skillDatas[randomIndex].name);
    }

    public int GetSkillsRandomNum()
    {
        int randomIndex;
        do
        {
            randomIndex = Random.Range(0, skillDatas.Length);
        } while (rememberRandomIndex.Contains(randomIndex));

        rememberRandomIndex.Add(randomIndex);

        Debug.Log("랜덤으로 선택된 스킬 인덱스: " + randomIndex);
        return randomIndex;
    }

    public void OnClickLevelUpBtn()
    {
        levelUpBtn.onClick.AddListener(() =>
        {
            selectSkillPopUp.SetActive(true);

            int randomIndex = GetSkillsRandomNum();

            GetRandomAtlasImg(randomIndex);
            GetRandomAtlasName(randomIndex);
            GetRandomAtlasDesc(randomIndex);
        });
    }

    public void OnClickCloseBtn()
    {
        closeBtn.onClick.AddListener(() =>
        {
            selectSkillPopUp.SetActive(false);
        });
    }
}

카드를 획득할 때 인벤토리에서 원하는 위치에서 생성되게 할 것이고,

하이어라이키 관점에서 봤을때는 부모와 같은 위치에서 생성되어야 Canvas 안에 적용이 될 것이다.

 

https://docs.unity3d.com/ScriptReference/Object.Instantiate.html

 

Unity - Scripting API: Object.Instantiate

This function makes a copy of an object in a similar way to the Duplicate command in the editor. If you are cloning a GameObject you can specify its position and rotation (these default to the original GameObject's position and rotation otherwise). If you

docs.unity3d.com

 

 

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

public class PreparedCard : MonoBehaviour
{
    private Button btn;
    private float spacing = 11.8f;

    void Start()
    {
        btn = GetComponent<Button>();

        btn.onClick.AddListener(() =>
        {
            Debug.Log("버튼이 눌림");

            // 새로운 오브젝트를 생성하고, 원본의 부모에 붙이기
            GameObject newObject = Instantiate(gameObject, transform.parent);

            // 새로운 오브젝트의 로컬 위치 조정
            newObject.transform.localPosition += new Vector3(spacing, 0, 0);
        });
    }
}

 

하지만 그리드 레이아웃을 설정할 때 이 spacing을 조절하였으므로

따로 spacing을 조절하지 않아도 되서 주석처리하였다.

 

시작을 하면 플레이어의 카드 인포를 찾아서 값을 가져올 수 있도록 변경

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

public class PreparedCard : MonoBehaviour
{
    private Button btn;
    //private float spacing = 11.8f;
    public TMP_Text value;

    void Start()
    {
        PlayerManager.Instance.LoadPreparedCardData();
        PlayerManager.Instance.LoadPreparedCardInfo();
        this.value.text = PlayerManager.Instance.dicPreparedCardInfo[2000].value.ToString();

        btn = GetComponent<Button>();

        btn.onClick.AddListener(() =>
        {
            Debug.Log("버튼이 눌림");

            // 새로운 오브젝트를 생성하고, 원본의 부모에 붙이기
            GameObject newObject = Instantiate(gameObject, transform.parent);

            // 새로운 오브젝트의 로컬 위치 조정
            //newObject.transform.localPosition += new Vector3(spacing, 0, 0);
            Debug.Log(value.text);

        });


    }

}

 

 

녹화_2024_03_12_00_12_33_796.mp4
0.91MB

 

 

 

적들은 피해를 입어야하니 콜라이더  를 부착해야 되는데

이런 삼각형 물체는 박스콜라이더가 아닌 폴리건 콜라이더로 크기 조절을 할 수 있다.

 

그리고 이제 움직이는 속도가 있을 것이니 리지드바디 2D + 중력 0

 

그 후 태그 추가후 부착

적들이 필요한 요소추가와 지정한 속도로 내려올수 있도록 초기화

스프라이트 렌더러는 피격시 색이 흐려지므로 2개의 텍스쳐를 받기위하여 선언

피해를 받았을떄 체력은 데미지로 비례해서 감소하고

피격시 스프라이트 1번을 출력

그리고 0.1초후에 평상시 스프라이트인 0번을 출력할 것이고

체력이 0이하면 사라지고

또한 내려가다 벽과 부딫히거나 총알에 맞으면 파괴시킨다.

그런데 체력이 0이어야 사라져야 하므로 총알을 맞았을 경우와 그 데미지를 정해야한다.

 

각 총알에 파워 입력

적에게 체력과 스피드 부여

]

스프라이트도 각각 2개씩 넣어준다.

 

 

부딫히면 튕겨가는 것을 방지하기 위해 isTrigger체크

총알이 적과 부딫히면 관통하지 않고 사라지게 코드를 추가하였다.

피격시 스프라이트 변경과 Invoke함수를 통해 시간설정

 

만들어진 적들은 프리팹화 후 삭제

 

여기서 중요한건 프리팹화 할때 기존에 있던 자리가 저장되므로 모두 0 0 0 으로 초기화

게임을 관리할 게임매니저 생성

적을 정해진 시간동안 리스폰 할것이고

적의 수와 위치를 각각 지정

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

public class GameManager : MonoBehaviour
{
    public GameObject[] enemyObjs;
    public Transform[] spawnPoints;

    public float maxSpawnDelay;
    public float curSpawnDelay;

    private void Update()
    {
        curSpawnDelay += Time.deltaTime;

        if(curSpawnDelay > maxSpawnDelay)
        {
            SpawnEnemy();
            maxSpawnDelay = Random.Range(0.5f, 3f);
            curSpawnDelay = 0;
        }
    }
    void SpawnEnemy()
    {
        int ranEnemy = Random.Range(0, 3); //소환될 적
        int ranPoint = Random.Range(0, 5); //소환될 위치
        Instantiate(enemyObjs[ranEnemy],
            spawnPoints[ranPoint].position,
            spawnPoints[ranPoint].rotation);
    }
}

 

적들의 비행선이 보더에 걸리면사라지므로 씬보다 위 보더보다 아래에 에너미포인트 그룹을 위치시킨다.

각각의 포인트의 x좌표를 -1.8부터 1.8까지 위치

각각을 어싸인

 

using System.Collections;
using System.Collections.Generic;
using System.Net.Http.Headers;
using UnityEngine;

public class Player : MonoBehaviour
{
    public bool isTouchTop;
    public bool isTouchBottom;
    public bool isTouchRight;
    public bool isTouchLeft;
    private Animator anim;

    public float speed;
    public float power;
    public float maxShotDelay; //실제 딜레이
    public float curShorDelay; //한발 쏜 후 딜레이

    public GameObject bulletObjA;
    public GameObject bulletObjB;

    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    void Move()
    {
        float h = Input.GetAxisRaw("Horizontal");
        if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
            h = 0;
        float v = Input.GetAxisRaw("Vertical");
        if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
            v = 0;
        Vector3 curPos = this.transform.position;
        Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;
        transform.position = curPos + nextPos;

        if (Input.GetButtonDown("Horizontal") ||
            Input.GetButtonDown("Vertical"))
        {
            anim.SetInteger("Input", (int)h);
        }
    }

    private void Update()
    {
        Move();
        Fire();
        Reload();
    }

    void Fire()
    {
        if (!Input.GetButton("Fire1"))
            return;
        if (curShorDelay < maxShotDelay)
            return;

        switch (power)
        {

            case 1://Power One
                GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
                Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
                rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                break;
            case 2:
                GameObject bulletR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.1f, transform.rotation);
                GameObject bulletL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.1f, transform.rotation);
                Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
                rigidR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);

                break;
            case 3:
                GameObject bulletRR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.3f, transform.rotation);
                GameObject bulletCC = Instantiate(bulletObjB, transform.position, transform.rotation);
                GameObject bulletLL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.3f, transform.rotation);
                Rigidbody2D rigidRR = bulletRR.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidCC = bulletCC.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidLL = bulletLL.GetComponent<Rigidbody2D>();
                rigidRR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidCC.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidLL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);

                break;
        }
                curShorDelay = 0;
    }

    void Reload()
    {
        curShorDelay += Time.deltaTime;

    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Border")
        {
            switch(collision.gameObject.name)
            {
                case "Top":
                    isTouchTop = true;
                    break;
                case "Bottom":
                    isTouchBottom = true;
                    break;
                case "Right":
                    isTouchRight = true;
                    break;
                case "Left":
                    isTouchLeft = true;
                    break;
            }
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        switch (collision.gameObject.name)
        {
            case "Top":
                isTouchTop = false;
                break;
            case "Bottom":
                isTouchBottom = false;
                break;
            case "Right":
                isTouchRight = false;
                break;
            case "Left":
                isTouchLeft = false;
                break;
        }
    }
}

 

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

public class Bullet : MonoBehaviour
{
    public int dmg;
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "BorderBullet")
        Destroy(gameObject); //모노비헤이어에 들어 있는 자체 함수 => 매개변수 오브젝트를 삭제하는 함수
    }
}

 

using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public float speed;
    public int health;
    public Sprite[] sprites;

    SpriteRenderer spriteRenderer;
    Rigidbody2D rigid;

    private void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        rigid = GetComponent<Rigidbody2D>();
        rigid.velocity = Vector2.down * speed;
    }

    private void OnHit(int dmg)
    {
        health -= dmg;
        spriteRenderer.sprite = sprites[1]; //피격시 1번
        Invoke("ReturnSprite", 0.1f);
        if(health <= 0)
        {
            Destroy(gameObject);
        }
    }

    void ReturnSprite()
    {
        spriteRenderer.sprite = sprites[0];
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "BorderBullet")
        {
            Destroy(gameObject );
        }
        else if(collision.gameObject.tag == "PlayerBullet")
        {
            Bullet bullet = collision.gameObject.GetComponent<Bullet>();
            OnHit(bullet.dmg);

            Destroy(collision.gameObject);
        }
    }

}

 

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

public class GameManager : MonoBehaviour
{
    public GameObject[] enemyObjs;
    public Transform[] spawnPoints;

    public float maxSpawnDelay;
    public float curSpawnDelay;

    private void Update()
    {
        curSpawnDelay += Time.deltaTime;

        if(curSpawnDelay > maxSpawnDelay)
        {
            SpawnEnemy();
            maxSpawnDelay = Random.Range(0.5f, 3f);
            curSpawnDelay = 0;
        }
    }
    void SpawnEnemy()
    {
        int ranEnemy = Random.Range(0, 3); //소환될 적
        int ranPoint = Random.Range(0, 5); //소환될 위치
        Instantiate(enemyObjs[ranEnemy],
            spawnPoints[ranPoint].position,
            spawnPoints[ranPoint].rotation);
    }
}

 

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

2D Airplane - 원근감있는 무한 배경 만들  (0) 2024.03.17
2D Airplane - 5  (1) 2024.03.14
2D Airplane - 4  (0) 2024.03.12
2D Airplane - 2  (0) 2024.03.10
2D Airplane - 1  (0) 2024.03.09

총알도 똑같이 잘라준다.

 

총알 충돌 시 이벤트가 생기므

총알에 박스콜라이더와 리지드바디 추가

에드포스로 날릴것이므로 리지드바디 -> 다이나믹

중력은 받지 않으므로 - 그래비티 스케일 0

재사용해서 사용할것이므로 프리팹화

총알 A를 복사해서 만든후 스프라이트에 다른 모양을 넣은 후 콜라이더 크기 조절

 

총알B를 저장하면 A를 복사해서 만든 것이므로 다시 프리팹화할때 알림 문구가 뜨는데

새로운 것이면 Original클릭

 

총알이 나중에 무수히 많아질 수 있으므로 지울 수 있는 또 다른 경계선 생성할 것인데

Bullet이라는 스크립트를 새로 생성

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

public class Bullet : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "BorderBullet")
        Destroy(gameObject); //모노비헤이어에 들어 있는 자체 함수 => 매개변수 오브젝트를 삭제하는 함수
    }
}

기존에 만들어 놓았던 Border를 복사해서 이름을 바꾸고

경계선을 재설정

 

태그를 새로 만든 후 할당

 

그럼 총알이 경계선에 닿으면 사라진다.

 

이제 총알을 만들 로직을 Player 스크립트에 작성할 것이다.

전 페이지에서 만들었던 업데이트문안에 있는 함수를 따로 캡슐화로 분리한 후 이름을 Move로 바꾸었고,

총알을 만들며 총알이 충돌을 일으켜야하므로 리지드바디를 사용

 

https://docs.unity3d.com/ScriptReference/ForceMode2D.html

 

Unity - Scripting API: ForceMode2D

Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. Close

docs.unity3d.com

퍼블릭으로 만들어둔 공간에 프리팹 할당

실행해보면 무수히 만들어진다.

 

그림과 같이 총알끼리 물리적 충돌로 인해 여러뱡항으로 나오는데

이것은 프리팹에서 isTrigger를 체크하면 해결된다.

 

총알이 눌렀을 때만 발사되게 조건을 넣어줄 것인데

!를 사용하는것이 아닌 조건일때만 실행되게 코드를 변경해줘도 된다.(코드 스타일)

이제 다음은 총알 딜레이를 추가할 것이다.

시간에 따라 현재 딜레이에 추가해줄것이고 

발사는 딜레이에 영향을 받아줄 것이므로 Fire문 안에 넣는다.

그리고 발사 후 딜레이를 없애주기 위해 마지막엔 딜레이를 0으로 초기화

총알을 쏠 때마다 딜레이를 변경해줄 수 있다.

 

총알의 파워를 입력해줄 것인데

케이스로 나눠서 각각 파워1, 2, 3일때 다르게 나오게 수치 변경

그리고 총알마다 간격을 조절하여

현재 위치해서 벡터값을 더해주면

총알의 생성위치를 원하는 간격으로 조절할 수 있다.

 

완성된 코드

using System.Collections;
using System.Collections.Generic;
using System.Net.Http.Headers;
using UnityEngine;

public class Player : MonoBehaviour
{
    public bool isTouchTop;
    public bool isTouchBottom;
    public bool isTouchRight;
    public bool isTouchLeft;
    private Animator anim;

    public float speed;
    public float power;
    public float maxShotDelay; //실제 딜레이
    public float curShorDelay; //한발 쏜 후 딜레이

    public GameObject bulletObjA;
    public GameObject bulletObjB;

    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    void Move()
    {
        float h = Input.GetAxisRaw("Horizontal");
        if ((isTouchRight && h == 1) || (isTouchLeft && h == -1))
            h = 0;
        float v = Input.GetAxisRaw("Vertical");
        if ((isTouchTop && v == 1) || (isTouchBottom && v == -1))
            v = 0;
        Vector3 curPos = this.transform.position;
        Vector3 nextPos = new Vector3(h, v, 0) * speed * Time.deltaTime;
        transform.position = curPos + nextPos;

        if (Input.GetButtonDown("Horizontal") ||
            Input.GetButtonDown("Vertical"))
        {
            anim.SetInteger("Input", (int)h);
        }
    }

    private void Update()
    {
        Move();
        Fire();
        Reload();
    }

    void Fire()
    {
        if (!Input.GetButton("Fire1"))
            return;
        if (curShorDelay < maxShotDelay)
            return;

        switch (power)
        {

            case 1://Power One
                GameObject bullet = Instantiate(bulletObjA, transform.position, transform.rotation);
                Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
                rigid.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                break;
            case 2:
                GameObject bulletR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.1f, transform.rotation);
                GameObject bulletL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.1f, transform.rotation);
                Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
                rigidR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);

                break;
            case 3:
                GameObject bulletRR = Instantiate(bulletObjA, transform.position + Vector3.right * 0.3f, transform.rotation);
                GameObject bulletCC = Instantiate(bulletObjB, transform.position, transform.rotation);
                GameObject bulletLL = Instantiate(bulletObjA, transform.position + Vector3.left * 0.3f, transform.rotation);
                Rigidbody2D rigidRR = bulletRR.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidCC = bulletCC.GetComponent<Rigidbody2D>();
                Rigidbody2D rigidLL = bulletLL.GetComponent<Rigidbody2D>();
                rigidRR.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidCC.AddForce(Vector2.up * 10, ForceMode2D.Impulse);
                rigidLL.AddForce(Vector2.up * 10, ForceMode2D.Impulse);

                break;
        }
                curShorDelay = 0;
    }

    void Reload()
    {
        curShorDelay += Time.deltaTime;

    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Border")
        {
            switch(collision.gameObject.name)
            {
                case "Top":
                    isTouchTop = true;
                    break;
                case "Bottom":
                    isTouchBottom = true;
                    break;
                case "Right":
                    isTouchRight = true;
                    break;
                case "Left":
                    isTouchLeft = true;
                    break;
            }
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        switch (collision.gameObject.name)
        {
            case "Top":
                isTouchTop = false;
                break;
            case "Bottom":
                isTouchBottom = false;
                break;
            case "Right":
                isTouchRight = false;
                break;
            case "Left":
                isTouchLeft = false;
                break;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "BorderBullet")
        Destroy(gameObject); //모노비헤이어에 들어 있는 자체 함수 => 매개변수 오브젝트를 삭제하는 함수
    }
}

 

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

2D Airplane - 원근감있는 무한 배경 만들  (0) 2024.03.17
2D Airplane - 5  (1) 2024.03.14
2D Airplane - 4  (0) 2024.03.12
2D Airplane - 3  (0) 2024.03.12
2D Airplane - 1  (0) 2024.03.09

 

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

public class Player : MonoBehaviour
{
    public float speed = 1f;
    public Rigidbody playerRigidbody;
    public GameObject bulletPrefab;

    void Update()
    {
        PlayerMove();
    }

    private void PlayerMove()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 movement = new Vector3(h, 0, v) * speed;
        transform.Translate(movement * Time.deltaTime);
    }

    private void OnTriggerEnter(Collider other)
    {
        // 충돌한 오브젝트가 총알인지 확인
        if (other.CompareTag("Bullet"))
        {
            // 플레이어를 파괴
            Destroy(gameObject);
            Debug.Log("Game over");
        }
    }

}

 

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

public class Enemy : MonoBehaviour
{
    [SerializeField] GameObject player;
    [SerializeField] public GameObject bulletPrefab;
    private float spawnInterval = 3f; // 총알 생성 간격
    private Vector3 spawnPosition; // 총알이 생성될 위치
    void Start()
    {
        spawnPosition = this.gameObject.transform.position; // 총알이 생성될 위치 초기화
        StartCoroutine(SpawnBullet()); // 코루틴 시작
    }

    IEnumerator SpawnBullet()
    {
        while (player != null)
        {
            // 총알 생성
            Instantiate(bulletPrefab, spawnPosition, Quaternion.identity);

            // 일정한 간격 기다리기
            yield return new WaitForSeconds(spawnInterval);
        }
    }
}

 

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

public class Bullet : MonoBehaviour
{
    public float speed = 2f;
    public GameObject player;
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");
            // Rigidbody 컴포넌트 가져오기
            Rigidbody bullets = GetComponent<Rigidbody>();
            Vector3 direction = (player.transform.position - transform.position).normalized;
            transform.forward = direction;
            // 총알의 이동 방향 설정 및 속도 적용
            bullets.velocity = transform.forward * speed;

            // 5초 후에 총알 파괴
            Destroy(gameObject, 4.5f);
    }
    private void OnTriggerEnter(Collider other)
    {
        // 충돌한 오브젝트가 총알인지 확인
        if (other.CompareTag("Player"))
        {
            Destroy(gameObject);
        }
        if (other.CompareTag("Wall"))
        {
            Destroy(gameObject);
        }
    }

}

'산대특 > 게임 클라이언트 프로그래밍' 카테고리의 다른 글

UniRun  (4) 2024.03.05
Quaternion  (1) 2024.03.04
코루틴 연습  (0) 2024.03.03
StarCraft - Tank  (0) 2024.02.29
StarCraft - DropShip Logic  (0) 2024.02.28

+ Recent posts