안녕하세요!
오늘은 요즘 핫한 캐주얼 게임인 사과 게임을 만들어 볼까 합니다.
만들게 된 이유는 이때까지 만든 게임이랑 다른 느낌이기도 하고 신기해서 제작해보았습니다.
다만, 그대로 따라하기 보다는 제 방식대로 변형해볼까 합니다.
먼저, 본래 사과 게임 링크부터 공유드립니다.
한번도 플레이하지 못하신 분들은 해보시길 바랍니다! 심플하지만 재밌는 게임입니다.
게임 링크 : https://www.gamesaien.com/game/fruit_box_a/
無料ゲーム「フルーツボックス」
画面上をマウスでドラッグして、数字の合計が10になるようにリンゴを囲むパズルゲームです。(説明) iPhone,iPadやAndroidでも動作します。
www.gamesaien.com
그리고 개발은 맨땅에 헤딩하면 오래 걸리니 레퍼런스를 찾아봤는데 마침 유튜브에 좋은 레퍼런스가 있었습니다.
유튜브 링크 : https://www.youtube.com/watch?v=YGd_wdlUqxE
본래 사과 게임을 만들고 싶다면 이 영상을 따라하시면 될 것 같습니다.
제가 변형한 버전 영상 올려드립니다.
기본적인 룰인 사용자가 터치하고 드래그해서 선택한 블록끼리 합이 10이 되면 없어지는 건 동일하지만 기존의 사각형 형태를 유지해서 범위가 포함되는 룰은 변경하였습니다.
이렇게 수정한 이유는 좀 더 난이도를 낮추기 위함입니다. 성인분들에게는 오히려 시시할 수도 있겠네요.
바뀐 룰은 꼭 사각형이 아니더라도 눌린 블록끼리 10이 되면 되는거니 자유도가 훨씬 높고 원하는 대로 연결하기 쉬워졌습니다.
이 규칙이 마음에 안 드신다면 아래 코드를 참고해서 자신만의 룰을 만들어봐도 좋을 것 같습니다.
참고로 따로 리소스없이 그냥 기본 이미지 사용했습니다.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class Apple : MonoBehaviour
{
[SerializeField]
private TextMeshProUGUI textNumber;
private Image image;
public bool isClick = false;
private int number = 0;
public int Number
{
set
{
number = value;
textNumber.text = number.ToString();
}
get => number;
}
public Vector3 Position => this.transform.localPosition;
private void Awake()
{
image = GetComponent<Image>();
}
public void OnSelected()
{
image.color = Color.blue;
}
public void OnDeselected()
{
image.color = Color.red;
}
}
첫 번째 스크립트는 Apple.cs 로 숫자가 들어있는 한 객체에 해당되는 스크립트입니다. 이 스크립트에서는 해당 객체의 숫자, 눌렸는지 안 눌렸는지 여부를 판단해주며 아래와 같이 프리팹으로 만들어 넣어줍니다.
한 블록에 들어가 있는 스크립트 모습 및 설정
프리팹 파일도 올려드립니다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MatchSpawner : MonoBehaviour
{
[SerializeField] private GameObject applePrefab;
[SerializeField] private Transform appleParent;
private readonly int width = 12, height = 8;
private readonly int spacing = 15;
private string gameSettingString = "";
[NonSerialized] public List<Apple> appleList = new List<Apple>();
// public void Start()
// {
// SpawnApples();
// }
public void SpawnApples()
{
// 기존에 남아있는 데이터 있으면 삭제 후 생성
if(appleList.Count > 0){
foreach(Apple item in appleList){
Destroy(item.gameObject);
}
appleList.Clear();
}
Vector2 size = applePrefab.GetComponent<RectTransform>().sizeDelta;
size += new Vector2(spacing, spacing);
int sum = 0;
for ( int y = 0; y < height; ++ y )
{
for ( int x = 0; x < width; ++ x )
{
GameObject clone = Instantiate(applePrefab, appleParent);
RectTransform rect = clone.GetComponent<RectTransform>();
float px = (-width * 0.5f + 0.5f + x) * size.x;
float py = (height * 0.5f - 0.5f - y) * size.y;
rect.anchoredPosition = new Vector2(px, py);
Apple apple = clone.GetComponent<Apple>();
apple.Number = UnityEngine.Random.Range(1, 10);
if ( y == height - 1 && x == width - 1 )
{
apple.Number = 10 - (sum % 10);
}
sum += apple.Number;
appleList.Add(apple);
}
}
for ( int x = 0; x < appleList.Count; x++ )
{
appleList[x].Number = gameSettingString[x] - '0';
}
//Debug.Log($"AppleSpawner::SpawnApples() : {sum}");
}
public void ReSetting(string gameSettingString)
{
Debug.Log("ReSetting : " + gameSettingString);
this.gameSettingString = gameSettingString;
}
public void DestroyApple(Apple removeItem)
{
appleList.Remove(removeItem);
Destroy(removeItem.gameObject);
}
}
두 번째 스크립트는 MatchSpawner.cs 으로 처음 맵 생성을 해주는 스크립트입니다.
원하는 width, height 를 입력하시면 거기에 맞게 위과 같이 생성됩니다.
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
public class MouseDragController : MonoBehaviour
{
[SerializeField] private Match_Game gameController;
[SerializeField] private MatchSpawner appleSpawner;
[SerializeField] private RectTransform rectTransform;
[SerializeField] private Canvas canvas;
private readonly int ANSWER = 10;
private int sum = 0;
private Vector2 start = Vector2.zero;
private Vector2 end = Vector2.zero;
//private AudioSource audioSource;
private List<Apple> selectedAppleList = new List<Apple>();
private void Update()
{
if ( gameController.IsGameStart == false ) return;
if ( Input.GetMouseButtonDown(0) )
{
Vector2 worldPosition = Input.mousePosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform.GetComponent<RectTransform>(),
worldPosition,
canvas.worldCamera,
out start
);
}
if ( Input.GetMouseButton(0) )
{
Vector2 worldPosition = Input.mousePosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform.GetComponent<RectTransform>(),
worldPosition,
canvas.worldCamera,
out end
);
SelectApples();
}
if ( Input.GetMouseButtonUp(0) )
{
if ( sum == ANSWER )
{
int score = 0;
foreach ( Apple apple in selectedAppleList )
{
score ++;
appleSpawner.DestroyApple(apple);
}
gameController.IncreaseScore(score);
}
else
{
foreach ( Apple apple in selectedAppleList )
{
apple.isClick = false;
apple.OnDeselected();
}
}
selectedAppleList.Clear();
sum = 0;
start = end = Vector2.zero;
}
}
private void SelectApples()
{
foreach ( Apple apple in appleSpawner.appleList )
{
float distance = Vector2.Distance(end, apple.Position);
if ( distance < 40)
{
if(apple.isClick == false){
apple.isClick = true;
apple.OnSelected();
selectedAppleList.Add(apple);
sum += apple.Number;
}
}
}
}
}
세 번째 스크립트는 MouseDragController.cs 입니다.
사용자가 클릭부터 드래그, 뗄 때까지 이벤트를 받아서 눌린 블록을 판별하고 합이 10인지 아닌지에 따라 점수를 획득하거나 못 획득합니다. 위 apple.cs 에서 선택될 때는 파란색, 선택이 틀렸다면 빨간색으로 블록이 바뀌도록 설정해놓았습니다. 이때, 유튜브 강의라 코드를 다르게 짰는데 그 이유는 제가 설정한 캔버스 크기랑 설정을 유튜브에서 가르쳐준 것대로 하지 않고 아래와 같이 설정했기 때문에 유튜브에서 알려준대로 하면 클릭 좌표가 블록과 일치하지 않아서 선택이 안되는 오류가 있어서 고쳤습니다.
여러분들도 제대로 블록이 선택이 안된다면 실제 오브젝트 위치와 터치 위치를 확인해보시길 바랍니다.
아마 제 코드를 그대로 붙여놓는다고 바로 작동하도록 설정하지 않아서 (게임 시작 버튼 등 설정 X / 일부 코드 오류) 참고만 해주시면 좋을 것 같습니다.
후에 시간이 된다면 아예 새롭게 만들어서 파일 채로 공유해보겠습니다.
여기까지 글 읽어주셔서 감사드리며 다들 간단하게 사과 게임을 만들어보시길 바라겠습니다.
'App && Game' 카테고리의 다른 글
[유니티] 랭크 보드에 이어 랭크 순위 변동 애니메이션 만들기 (0) | 2025.03.23 |
---|---|
[유니티 / Unity] 랭킹 보드 UI 및 기능 만들기 (1) | 2025.03.15 |
[유니티] 게임 시작하기 / 나가기 / 이어하기 버튼 스크립트 (0) | 2023.04.19 |
[유니티] 화면 드래그(스와이프/터치)에 따른 오브젝트 회전 (0) | 2023.04.17 |
[유니티] 애드몹 전면 광고 달기 / 추가하기 (0) | 2023.04.05 |
댓글