팀에서 맡은 과제
차원 | 종류 | 이름 | 주소 |
---|---|---|---|
2 | UI | 캐주얼 아이콘 팩 | 링크 |
2 | Character | 후드 쓴 캐릭터 | 링크 |
2 | UI | 고전게임 느낌 체력바 | 링크 |
2 | UI | 픽셀 아트 UI | 링크 |
2 | Effect | 불타는 이펙트 | 링크 |
2 | Tileset | 따뜻한 느낌 숲 타일셋 | 링크 |
- | Audio | 양키 목소리 오디오팩 | 링크 |
2 | Tileset | 연구소 타일셋 | 링크 |
2 | UI | 어플 아이콘 팩 | 링크 |
2 | Background | 우주 픽셀 배경화면 | 링크 |
3 | Character | 복셀 로봇 캐릭터 | 링크 |
3 | Objects | 로우 폴리 나무, 바위 | 링크 |
3 | Animation | 캐릭터 애니메이션 모음 | 링크 |
3 | Tileset | 로우폴리 타일셋 | 링크 |
3 | Tileset | 계절별 로우폴리 나무, 풀, 바위 | 링크 |
2 | UI | 깔끔한 캐주얼 UI | 링크 |
2 | Objects | 포션 모음 | 링크 |
- | Audio | RPG BGM | 링크 |
3 | Objects | 로우폴리 차 모음 | 링크 |
2 | Character | 수인 캐릭터들 | 링크 |
2 | Background | 우주, 지구, 소행성 배경 | 링크 |
- | Audio | 미니 게임 BGM | 링크 |
2 | Effect | 픽셀 스킬 이펙트 | 링크 |
3 | Background | 하늘 배경 | 링크 |
2 | Effect | 피 효과 | 링크 |
3 | Asset Pack | 로우폴리 RPG 애셋팩 | 링크 |
3 | Objects | 나무 | 링크 |
2 | Asset Pack | 도시 애셋 팩 (8방향) | 링크 |
2 | Character | 중세 사람들 | 링크 |
2 | Tileset | 미래풍 타일셋 | 링크 |
3 | Asset Pack | 로우폴리 창고 | 링크 |
2 | Effect | 말풍선 효과 | 링크 |
3 | Objects | 미래 느낌 총 | 링크 |
3 | Character | 복셀 디스토피아 캐릭터 | 링크 |
3 | Asset Pack | 드론 경주 맵 | 링크 |
3 | Objects | 로우폴리 식물, 버섯, 바위 | 링크 |
3 | Asset Pack | 로우폴리 던전 애셋팩 | 링크 |
2 | Asset Pack | 중세 마을 애셋팩 | 링크 |
공포 게임 : 공포 잘 느끼는 사람들에게 잘 먹힐 것. 감정을 가장 쉽고 강렬하게 이끌어내는 데에는 공포만한게 없다. 근데 단순히 갑툭튀 원툴이 아니라 공포에 또 뭔가를 추가해야 됨. 근데 공포는 뭔가를 추가하면 할 수록 공포에서 멀어짐. 그냥 어두운 곳에서 우- 하고 쫓아오는 괴물이 무서운거. 연출을 얼마나 실감나게 하는지가 무서운거. 총같은거라도 들려줬다간 공포감 다 날아감. 그때부턴 그냥 슈팅게임 되는거. 에일리언:아이솔레이션 느낌을 멀티로? 공포게임 스킨 씌운 술래잡기 아님? 술래가 좀 많이 세고 나머지는 도망만 다녀야 하는 데바데? 기획적으로는 AI가 아니라 진짜 사람이 들어가니까 서로에게 전달하는 정보(발소리) 등을 어떻게 조절할 건지, 그걸 어떻게 공포심을 조장할 건지에 대해 생각해볼만한 여지가 있겠지만, 개발적 난이도는 전혀 올라가지 않음. 서버 추가하고 움직임만 구현하면 끝. 공포를 해치지 않으면서, 게임적으로 재미있으면서, 보여주는게 재미있으면서, 개발적 난이도가 있는 어떤 기믹을 추가해야 함. ㅇㅇ 불가능. 공포를 해치지 않는게 제일 불가능.
쫓는 사람은 점프로, 도망가는 사람은 로프 액션으로 답답한 통로를 지나감.
근데 쫓기는 사람이 빠져서 죽어버리면 팍 식을 것 같긴 한데? <- 어차피 죽는거 안 보여주면 괜찮을수도
아트 느낌 : Lorn's Lure
메이드 인 와리오, 미니게임천국 : 끊임없는 새로움. 폴가이즈처럼 탈락시키는 걸 1분에 1명씩 하면?
시연(시청)의 재미 요소 : 플레이 하는 사람이 잘 해야됨(스피드런 하는 사람들이나 리듬 게임 잘 하는 사람들 느낌. fps로 장우형 내세워서 도파민 주작?), 아트가 예뻐야됨, 로직이 새로워야(참신해야) 됨.
왜 이 게임을 하고 싶냐?가 아닌 왜 이 게임을 보고 싶냐? 가 돼야 하는 어이 없는 개발 목적. (근데 그러면서도 플레이가 재미는 있어야 됨)
조금 더 현실과 비타협 하자면, 왜 이 게임이 재미있어 보이냐? 왜 이 게임이 완성됐을 때가 기대되냐? 가 목적.
시연할 때 재미있는 것과 직접할 때 재미있는 게임의 차이점 : 일단 직접 플레이를 못하므로 몰입도가 떨어짐. 직접할 때 무엇을 느끼는지에 대한 정보의 쾌감을 느낄 수 없음. (그 순간에 무슨 판단을 했는지 말해주는 걸로는 도파민이 생기지 않음. 태어나서 그 게임을 처음 본 거니까. 와! 방금 거기서 리 신이 상대가 아래쪽이라는 걸 인지하고 3캠 카정을 친 후에 cs 빅 웨이브가 생성되는 적절한 타이밍에 시간 맞춰 다이브를 하는 판단을! 라고 해봤자 롤 모르는 사람은 그게 뭔데 씹덕아) 게임 시청을 하는 사람들은 대부분 자신이 로직을 아는 게임들을 봄. 그래야 더 몰입이 되니까. 그런데 단순히 '보여주는 것'만으로 게임의 재미를 전달한다? 이는 사실상 영화를 보여주는 것과 다름이 없다. 게임 행사 같은 건 직접 플레이하게 되는 기회를 제공하는데 이건 그런 것도 아니라 그냥 보여주고 끝. 심지어 게임 엔진도 막아놔서 게임의 완성도가 필연적으로 떨어짐. 가뜩이나 프로그래머 5명임. 즉, 시연을 할 때 재미있는 게임이라는 건 그 게임이 얼마나 재미있느냐에 달린게 아님. 막말로 프로토타입 대충 만들어놓고 1달 동안 알바한 다음에 알바비로 아트 외주 5명 고용해서 아트 채워넣는게 훨씬 시연에 좋음. 그럼에도 불구하고 재미있는 시연을 만들 한 가지 방안은 게임 로직이 여러개여야 함. 게임 로직이라는 요소 자체가 갖는 힘은 신선함(무언가를 알게되었다는 즐거움) 하나 뿐임. 각각에 직관적이고 시각적으로 재미있는 로직과 함께, 탈락한다는 요소를 넣으면 없는 살림에 최대한 도파민을 쥐어짜낼 수 있을 것. 개발도 각 사람이 맡아서 하면 공평하게 게임 로직 코드를 건드려보니 좋을듯? 브라우저의 한계를 이용하는 온갖 기믹을 떡칠? (https://zeehatcher.itch.io/windowframe 이런거?)
방향성 : 인상 깊어서 후속작을 기대하게 되는 데모? 시연 순간에 가장 빛나는 게임?
웹 서버 멀티의 문제 : 일반적인 기술력으로는 핑이 튈 것으로 예상됨. 그러면 실시간 멀티 게임에서 할 수 있는 것들이 엄청나게 제한됨. 일단 공정성이나 플레이의 일관성이 심각하게 망쳐질 것. 뚝 뚝 끊기면 일단 그냥 하기가 싫다.
좀 예술충 느낌으로 가면 동물원 수족관에 갇혀있던 물고기 두 마리가 펄떡거리며 탈출해서 온갖 인간 세상 일들 하는 미니게임(추격전 or 타이쿤 or FPS 등. 아니면 그냥 단순히 각 상황에 대한 묘사를 게임으로 옮겨도 좋다.) 하면서 바다로 가는 이야기. Journey + It takes two?
검은색 사람들이 아래에 지나가고 물고기들 있는데 그 중 두 개가 딱 멈추고 조작 가능해짐)
서사 부여를 탈출이라는 직선적 스토리로 해결 + 게임 로직 신선함을 잦게 공급
레퍼런스 게임이 있냐요? 라고 하면 It takes two(기본적으로는 플랫포머+퍼즐이지만 여러 게임 장르들을 섞어서 플레이하게 됨)라고 하면 됨. EA겜에다 GOTY였어서 당연히 아실듯?
근데 이건 아트가 좀 받춰줘야 게임의 힘이 올라올듯. 스타일을 판판야 느낌으로 하면 배경은 대충 AI로 떼우고 캐릭터만 어떻게든 하면 적은 아트 인원으로도 되지 않을까? <- 이를 근거로 어떻게든 엔진 쓰게 해달라 징징?
이상적으론 외부 선 굵어서 귀여운 캐주얼 느낌이 좋긴 함. (생각한 느낌에 딱 맞는 레퍼런스를 못 찾겠음. 약간 다르긴 하지만 https://rhosgfx.itch.io/vector-icon-pack 이런 느낌?)
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**6)
N = int(input()) # 도로의 개수
W = int(input()) # 사건의 개수
cases = [(1,1),(N,N)]
for _ in range(W):
ew, ns = map(int,input().split())
cases.append((ew,ns))
dp = [[-1]*(W+2) for _ in range(W+2)]
course = [[-1]*(W+2) for _ in range(W+2)]
# 규칙이 없는 경로들의 비용 최솟값이므로 모든 경로의 비용 중 최소를 구해야 함
# 모든 경로를 계산하려면 2의 n승. 불가능하므로 dp 사용.
# 필요한 정보 : (왼쪽 혹은 오른쪽에서) 경로가 정해진다면, 나머지 경로에서의 최소 경로 비용
# dp로 경로 계산을 생략하려면 공통되는 부분이 필요한데,
# 경찰차당 마지막으로 출동했던 사건의 번호를 인덱스로 설정하면 됨
# 자연스럽게 왼쪽에서 경로를 정한 다음 오른쪽의 정보를 요구하는 재귀가 됨.
def distance(a,b):
return abs(cases[a][0]-cases[b][0])+abs(cases[a][1]-cases[b][1])
def min_d(a,b):
next = max(a,b)+1
if next == W+2:
return 0
if dp[a][b] != -1:
return dp[a][b]
a_cost = min_d(next,b)+distance(a,next)
b_cost = min_d(a,next)+distance(b,next)
if a_cost < b_cost:
course[a][b] = 1
dp[a][b] = a_cost
else:
course[a][b] = 2
dp[a][b] = b_cost
return dp[a][b]
min_d(0,1) # 첫번째 경찰차는 1,1, 두번째 경찰차는 N,N에서 시작
print(dp[0][1])
a,b,cnt=0,1,2
while cnt < W+2:
car = course[a][b]
print(car)
if car == 1: a=cnt
else: b=cnt
cnt+=1
그리디로는 안된다. 반례 무수히 존재.
최소값을 구하려면 모든 경로에 대한 값을 비교해야 함.
그냥 풀면 2의 n승이므로 dp를 사용해야 함.
내가 갔던 경로를 저장하면서 쌓아나가기 : 상향식, for문
내가 앞으로 갈 경로의 값(미지의 값)을 요구하는거 : 하향식, 재귀
둘 중 하나 고르는 근거 : 각 경찰차가 마지막으로 출동했던 사건이 같으면 앞으로의 최소 경로도 같다.
필요한 정보는 이제까지의 경로가 아닌, 앞으로의 최소 경로이므로 하향식이어야 한다.
답을 뜯어보며 계속 보다가 거의 외우다시피 해서 풀긴 했는데
나름 많이 배우긴 함. 문제는 시간이 좀 느리다.
import sys
from collections import defaultdict
# 두 사건간의 거리를 저장
def get_diff(arr, i):
i -= 1
a = sum(arr[i]) - 2
return [[a, MAX_INDEX-a-2]] + [abs(arr[i][0] - arr[j][0]) + abs(arr[i][1] - arr[j][1]) for j in range(i)]
# 최단경로 역 추적
def backtrack(arr, i, j):
shor_path = []
for k in range(L-1, 0, -1):
if i == k:
shor_path.append(2)
i = arr[i][j]
else:
shor_path.append(1)
j = arr[i][j]
return shor_path[::-1]
def sol(incidents):
dp = {(0, 0): 0}
hist = [[0] * L for _ in range(L)]
maxi = float('inf')
for i in range(1, L):
dp2 = defaultdict(lambda: float('inf'))
diff = get_diff(incidents, i)
maxi2 = maxi + MAX_INDEX
maxi = float('inf')
for k, v in dp.items():
car2, car1 = k
d1 = (diff[0][0] if car1 == 0 else diff[car1]) + v
d2 = (diff[0][1] if car2 == 0 else diff[car2]) + v
if d1 < maxi2 and d1 < dp2[(car2, i)]:
dp2[(car2, i)] = d1
hist[car2][i] = car1
if d2 < maxi2 and d2 < dp2[(i, car1)]:
dp2[(i, car1)] = d2
hist[i][car1] = car2
maxi = min(maxi, d1, d2)
dp = dp2
k, v = sorted(dp.items(), key=lambda x: x[1])[0]
y, x = k
return [v] + backtrack(hist, y, x)
readline = sys.stdin.readline
N = int(readline())
W = int(readline())
incidents = [tuple(map(int, readline().split())) for _ in range(W)]
L = W + 1
MAX_INDEX = 2 * N
print(*sol(incidents), sep='\n')
제일 빠른 건 속도가 나보다 20배 가까이 차이 남.
내일 무슨 얘기인지 마저 봐야할듯.