JS로 사과게임 만들기 1편 (제작 배경 및 로직)
- github repo: https://github.com/dpwls02142/drag-make-11
- 게임 하러가기: https://drag-make-11-front.vercel.app/
- 제작기간: 25년 2월 22일 ~ 25년 3월 2일 (7일)
(기본적인 로직을 제작한 기간은 위와 같으며, 다른 기능들은 점차 업데이트 할 예정.)
이번에 내가 좋아하는 스트리머를 메인으로 canvas와 javascript를 활용해 사과게임을 모작하여 제작했다.
본편은 사이트 제작 배경과 자바스크립트를 사용한 이유, 로직을 설명할 예정이다.
고로 코드 해부는 다음 편에서 할 예정이다.
제작 배경
일단 사과 게임이 뭔지부터 알아보자.
사과게임이란, 마우스를 드래그하여 2개 이상의 블록의 합을 10으로 만드는 게임을 말한다. 25년 2월?쯤 치지직에서 갑자기 엄청난 유행을 탔었다.
- 원작 게임 하러가기: https://www.gamesaien.com/game/fruit_box_a/
개인적인 이야기지만 나는 게임 방송을 되게 많이 본다. 내가 하는 것 보다는 남이 하는게 재밌다더라.. 쨌든 2월달 저녁에 치지직을 켜면 다들 사과게임을 하고 있었다. 근데 사과게임 자체가 딱히 엔딩이 없고, 그냥 점수를 높게 받으면 받을 수록 좋은 게임이라서, 스트리머들 사이에서는 100점 이상을 넘겨야 클리어라는 기준이 암묵적으로(?) 생겼었다.
근데 이 때 당시 내가 보는 스트리머는 사과게임을 하긴 했는데, 100점을 넘기진 못했어서 지금은 깨심 ㅋㅋ 간단하게 팬게임으로 만들면 재밌을 것 같다는 생각에 제작하게 됐다.
자바스크립트를 사용한 이유는 다음과 같다.
이 게임의 재미 포인트는 제한시간 안에 누가 더 사과를 많이 지웠는지, 그 스코어를 비교하는 것이 이 게임의 포인트이자 재미라고 생각했다.
따라서 이 게임을 할 사람들, 즉 스트리머 시청자들의 접근성이 용이해야 된다고 생각했다.
원랜 명색이 “팬게임” 이니까 유니티를 활용해서 만들어 볼까? 도 생각했지만, 게임 자체가 간단한 로직을 갖고 있는데, 유니티 같이 무거운 엔진을 사용하는건 불필요하다고 느껴졌다.
그래서 유니티는 제외했고, 심지어 사과게임 원작 자체도 캔버스로 제작했기 때문에, 나 또한 자바스크립트랑 캔버스를 활용해서 만들면 되지 않을까 라는 생각에… 제작하게 됐다.
참고로 캔버스란 HTML의 요소 중 하나로, js를 활용해 그림을 그릴 수 있는 api를 말한다.
로직 세우기
코드는 크게 아래의 조건을 세우고 작성했다.
- 게임의 제한시간은 120초.
- 블록 생성은 행 기준 10개, 열 기준 20개 해서 총 200개의 블록이 생성되도록 하였으며 블록 안의 숫자는 1-9 사이의 정수를 랜덤하게 생성하도록 했다.
- 블록 제거 조건은 마우스로 블록을 드래그 했을 때 2개 이상의 블록의 합이 “11”이 되는 경우에만 블록이 지워지도록 했다.
- 왜 원작이랑 다르게 11로 설정했나요?
- 제가 좋아하는 스트리머의 팬게임이다 보니, 스트리머의 밈을 참고하여 11로 제작했습니다. ㅎㅎ
이미지 누르면 영상으로 이동됩니다. 짱재밌으니 시청 추천드림.
- 하지만 여기서 발생하는 문제점이 있었으니 …
- 선택하는 블록의 개수가 최대 4개라고 할 때,
- 합이 10이면 총 22가지의 조합이 있고,
- 합이 11이면 총 25가지의 조합이 있다.
- 어떻게 아냐면.. 아래 코드로 알 수 있습니다.
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
def find_combinations(target_sum, pick):
lst = list(range(1, 10))
result = []
def backtrack(start, current_combination, current_sum):
# 현재 합이 target_sum이면 유효한 조합
if current_sum == target_sum and len(current_combination) == pick:
result.append(tuple(sorted(current_combination)))
return
if len(current_combination) >= pick or current_sum >= target_sum:
return
for i in range(start, len(lst)):
current_combination.append(lst[i])
backtrack(i, current_combination, current_sum + lst[i]) # 중복 허용
current_combination.pop() # 백트래킹
backtrack(0, [], 0)
return result
for pick in range(2, 10):
valid_combinations = find_combinations(10, pick)
unique_combinations = sorted(set(valid_combinations)) # 중복 제거 및 정렬
print(f"{pick}개 조합({len(unique_combinations)})")
print(" / ".join(["".join(map(str, comb)) for comb in unique_combinations]))
print()
- 개수로만 보면 11의 조합이 더 많기에 쉬워 보일 수 있다. 그러나 수가 아예 랜덤하게 생성해서 그런지, 오히려 10보다 어렵다는 느낌이 들었다.
- 왜냐하면 보통 블록을 제거할 때 2개의 합을 위주로 보기 마련이다.
시야 이슈로 인해..근데 2개를 pick할 때의 조건 합은 11이 4가지로 더 작기 때문에 더 어렵다고 느껴졌다. 물론, 나만 그런거일 수도 있다. - 그래서 15%의 확률로 합이 11이 되는 경우의 수를 행에다가 랜덤하게 만들었다.
- 근데 어떤 분이 팬카페에 후기글을 올려주셔서 읽어봤는데, 플레이타임이 1시간 40분이 걸렸다고 하셔서 이게 난이도 보정에 그리 영향을 준 것 같지는 않다.. ㅋㅋㅋ
또한 드래그 ux에 조금 신경을 썼다. 사과게임을 하다보면 제한시간이 다가올 수록 심장이 떨려서 마우스 커서도 같이 떨리면서 지울 수 있는 사과 마저 제대로 못 지우는 경우가 있다 ㅋㅋ. 그래서 마치 마그넷처럼 드래그할 때 블록에 드래그 위치가 딱 붙게끔? 했다.
점수의 경우엔 원작과 동일하게 max score값은 따로 존재하지 않고 그냥 많이 지우면 지울수록 좋도록 했다. 허나, 100점 이상을 넘길 시 팬아트를 볼 수 있도록 했다.
그럼 다음 2편, 코드 해부편에서 만나염 ㅃㅇ