오늘은 이렇게 얼불춤 맵을 지메로 그리는 짓거리를 해볼거임
저렇게 맵에 있는 타일들만 따와서
이렇게 지메로 옮기는거임
이펙트인지 뭔지는 구현 안했고 실제로 플레이하는건 아직까지는 불가능
일단 가장 기본이 되는 옵젝들은 얘네들임
얘들을 합치면
짠
타일 하나가 완성되었어요
여기서 쓰는 오브젝트는 히트박스 없는 사각형(ID:211)과 동그라미 장식(ID:1764)이고 노란 부분의 뒤에 Z레이어가 1 낮은 검은 옵젝을 1.1배 크기로 덧대서 쓰는 방식임
즉 1타일=6옵젝 이라 보면 됨
그래서 이걸 어떻게 할 거냐
노가다로 하나하나씩 설치하자고?
ㄴㄴ 그딴짓을 왜함
얼불의 레벨 파일은 감사하게도 지메와는 다르게 암호화가 안된 JSON 형식으로 이루어져 있음 그래서 지메보다 파일 뜯어보기가 훨씬 쉬움
우리에게 필요한 건 저기 있는 pathData 스트링인데 요즘 맵들은 아마 angleData로 되어있을거임
일단 나는 전자의 경우를 기준으로 해볼거임
딱히 이유는 없고 내가 아는 유명한 맵들이 다 전자거든 ㅋㅋ
pathData의 스트링은 정말 정말 간단하게도 한 글자는 한 타일이 어느 방향으로 뻗어있는지를 나타냄
이 방향을 각도로 바꿔줄 건데 이런거 할 때는 오른쪽이 0도고 각도는 반시계 방향인 게 국룰임
'R': 0,
'U': 90,
'L': 180,
'D': 270,
'E': 45,
'Q': 135,
'Z': 225,
'C': 315,
'J': 30,
'T': 60,
'G': 120,
'H': 150,
'N': 210,
'F': 240,
'B': 300,
'M': 330
'!': Midspin
미드스핀 타일(공이 안착하지 않고 지나가는 타일, 오각형 )은 따로 그리기 귀찮아서 유턴타일(말 그대로 360도 회전하는 타일)과 똑같은 모양으로 처리함
불편하면 직접 구현하셈
이제 파일에 대한 분석을 마쳤으니 몇 가지 고려할 점을 생각해보면
- 지메에서 한 칸의 길이는 30이다.
- 기본 크기에서, 원의 중심과 사각형의 중심 사이의 거리는 15이다.
- 다음 타일의 각도가 θ일 경우, 사각형은 원에서부터 x방향으로 15cosθ, y방향으로 15sinθ 떨어진 곳에 배치하면 된다.
- 그리고 다음 타일의 원은 원에서부터 x방향으로 60cosθ, y방향으로 60sinθ 떨어진 곳에 배치하면 된다. 원들 사이의 거리가 60이기 때문이다.
- 사각형이 기울어진 각도는 -θ이다. 지메는 오브젝트가 기울어진 각도를 저장할 때 시계방향이 양수로 저장된다.
- 동그라미 장식은 블럭보다 3.75배 작다. 즉 스케일을 3.75배 더 키워야 한다.
- 얼불춤에서는 먼저 설치한 타일이 나중에 설치한 타일보다 위에 표시된다. 즉 먼저 설치한 타일의 z레이어를 높게 잡아야 한다. 타일의 검은 오브젝트가 노란 오브젝트보다 z레이어가 1 낮도록 하고, 한 타일씩 진행할 때마다 레이어를 2씩 낮추면 된다. (지메에서 손으로 조작하면 z레이어는 ±100까지만 움직일 수 있지만 파일 조작으로 바꾸면 계속해서 낮출 수 있다.)
- 맵이 위아래로 길면 지메 에디터 상에서 맵이 모두 보이지 않게 될 수 있으니, 출력된 오브젝트의 크기를 조정할 수 있게 만들자.
- 미드스핀 타일은 유턴 타일처럼 구현하면 된다. 원래는 외형도 다르게 만들어야 하지만 귀찮다.
- 처음 위치랑 맵의 사이즈가 에디터창을 안 넘어가게 자동 조정 할 수는 없을까? 있을 것 같긴 한데 귀찮으니 누가 구현해주면 좋겠다.
이런 식으로 어찌어찌해서 이런 코드를 짤 수가 있음
import json
import math
SIZE = 0.5
SIGNUM = 2
file = open("FILE_NAME.adofai",'r',encoding='utf-8-sig')
level = json.loads(file.read().replace(', }','}'))
pathDict = {
'R': 0,
'U': 90,
'L': 180,
'D': 270,
'E': 45,
'Q': 135,
'Z': 225,
'C': 315,
'J': 30,
'T': 60,
'G': 120,
'H': 150,
'N': 210,
'F': 240,
'B': 300,
'M': 330
}
pos = [300,600]
GDlevel = 'kS38,1_40_2_125_3_255_11_255_12_255_13_255_4_-1_6_1000_7_1_15_1_18_0_8_1|1_0_2_102_3_255_11_255_12_255_13_255_4_-1_6_1001_7_1_15_1_18_0_8_1|1_0_2_102_3_255_11_255_12_255_13_255_4_-1_6_1009_7_1_15_1_18_0_8_1|1_255_2_255_3_255_11_255_12_255_13_255_4_-1_6_1002_5_1_7_1_15_1_18_0_8_1|1_125_2_255_3_0_11_255_12_255_13_255_4_-1_6_1005_5_1_7_1_15_1_18_0_8_1|1_0_2_255_3_255_11_255_12_255_13_255_4_-1_6_1006_5_1_7_1_15_1_18_0_8_1|1_255_2_222_3_167_11_255_12_255_13_255_4_-1_6_1_7_1_15_1_18_0_8_1|1_0_2_0_3_0_11_255_12_255_13_255_4_-1_6_2_7_1_15_1_18_0_8_1|,kA13,0,kA15,0,kA16,0,kA14,,kA6,0,kA7,0,kA17,0,kA18,0,kS39,0,kA2,0,kA3,0,kA8,0,kA4,0,kA9,0,kA10,0,kA11,0;'
degree = 0
tilenum = 0
for i in level['pathData']:
if i == "!":
nextDeg = degree+180
print(i, degree-180, nextDeg)
else:
nextDeg = pathDict[i]
print(i, degree-180, nextDeg)
GDlevel += f'''
1, 1764, 2, {round(pos[0],SIGNUM)}, 3, {round(pos[1],SIGNUM)}, 108, 1, 25, {-2*tilenum}, 21, 1, 24, 5, 32, {3.75*SIZE};
1, 211, 2, {round(pos[0]+15*math.cos(math.radians(degree-180)) * SIZE,2)}, 3, {round(pos[1]+15*math.sin(math.radians(degree-180)) * SIZE,SIGNUM)}, 25, {-2*tilenum}, 6, {-degree+90}, 21, 1, 24, 5, 32, {SIZE};
1, 211, 2, {round(pos[0]+15*math.cos(math.radians(nextDeg)) * SIZE,2)}, 3, {round(pos[1]+15*math.sin(math.radians(nextDeg)) * SIZE,SIGNUM)}, 25, {-2*tilenum}, 6, {-nextDeg-90}, 21, 1, 24, 5, 32, {SIZE};
1, 1764, 2, {round(pos[0],SIGNUM)}, 3, {round(pos[1],SIGNUM)}, 108, 2, 25, {-2*tilenum-1}, 21, 2, 24, 5, 32, {round(1.1*3.75*SIZE,SIGNUM)};
1, 211, 2, {round(pos[0]+15*math.cos(math.radians(degree-180)) * SIZE,SIGNUM)}, 3, {round(pos[1]+15*math.sin(math.radians(degree-180)) * SIZE,SIGNUM)}, 25, {-2*tilenum-1}, 6, {-degree+90}, 21, 2, 24, 5, 32, {round(1.1 * SIZE,SIGNUM)};
1, 211, 2, {round(pos[0]+15*math.cos(math.radians(nextDeg)) * SIZE,SIGNUM)}, 3, {round(pos[1]+15*math.sin(math.radians(nextDeg)) * SIZE,SIGNUM)}, 25, {-2*tilenum-1}, 6, {-nextDeg-90}, 21, 2, 24, 5, 32, {round(1.1 * SIZE,SIGNUM)};
'''
pos[0] += round(60 * math.cos(math.radians(nextDeg)),SIGNUM) * SIZE
pos[1] += round(60 * math.sin(math.radians(nextDeg)),SIGNUM) * SIZE
degree = nextDeg
tilenum += 1
file = open("AdofGD.txt","w")
file.write(GDlevel.replace('\n','').replace(' ',''))
SIZE, SIGNUM, FILE_NAME은 레벨의 사이즈, 맵 데이터의 유효숫자 개수, 얼불춤 맵 파일명임
이걸 돌리게 되면 AdofGD.txt 파일에 이런식으로 스트링이 막 뜨는데
알아서 세이브파일에 집어넣으면 됨
자세한 건 여기 참조
지메 레벨의 세이브파일 구조를 알아보자여느 게임이 다 그렇듯 지메는 유저의 데이터를 파일로 저장해서 보관하는데그게 바로 CCGameManager.dat와 CCLocalLevels.dat임gall.dcinside.com아 그런데 저렇게 하면 첫타일만 검은색으로 나오는 오류가 있는데
저렇게 하면 첫타일 노란부분이 z레이어가 0이 되는데 지메에는 z레이어 0이 없어서 초기값으로 되돌아가기 때문임
원인도 알고 고칠 수도 있지만 간지나서 냅뒀음
정성추
한국의 spu7nix;
신기하노
시험기간에 돌아버린 대학생의 모습인가 - dc App
고3임
수능보고 미쳐버린거냐
이런건 대체 어떻게 하는거노
봐도 모르겠지만 개추
뭣 - dc App
진짜 미쳐버린건가 - dc App
진짜 미친새끼노 이런건 아케 알아내는거노?
?이게뭐임개미친