일부 JSL을 관리하기 위해 프로젝트를 사용해 봅시다.
오래 전에 횡스크롤 작성을 제안했습니다. https://community.jmp.com/t5/Uncharted/Wild-Road-Map/bc-p/20996/highlight/true#M5 . 80년대에 게임을 하지 않았다면, https://en.wikipedia.org/wiki/Parallax_scrolling 몇 가지 예가 있습니다. 사이드 스크롤러는 캐릭터가 왼쪽에서 오른쪽으로 움직이는 2D 게임이며 배경에는 3D 깊이감을 주기 위해 서로 다른 속도로 미끄러지는 여러 레이어가 있을 수 있습니다. 다른 변형은 수직 스크롤 치수가 있는 플랫폼 점퍼일 수도 있습니다.
해결해야 할 문제가 있습니다.
- 게임 개발(JMP로 이것을 더 쉽게 작성할 수 있습니까?)
- 게임 그래픽(어떻게 생겼나요?)
- 게임 오디오 (들었습니까?)
- 게임 입력(어떻게 이동합니까?)
- 게임 플레이(무슨 일이라도 있나요?)
1. 게임 개발
저는 JMP 프로젝트를 사용하고 있습니다(최근에 JMP 16 독립형 프로젝트로 전환했습니다.). 5~10개의 독립 파일이 있는 프로젝트에 독립형 프로젝트가 마음에 들기 시작했습니다. 열려 있는 파일에 대한 탭과 로그 창에 대한 도킹 지점이 있습니다. 독립형 프로젝트는 모든 것을 하나의 파일(zip, undercover)에 저장하고 열리고 닫힐 때 자동으로 압축을 풀고 다시 포장합니다.
그래픽용 파일과 오디오용 파일, 게임 플레이용 파일은 별도의 비교적 작은 파일이기 때문에 이 게임을 실행하는 것이 더 쉬웠습니다. 따라서 게임 캐릭터 간의 게임 플레이를 관리하는 JSL과 같은 것을 쉽게 찾을 수 있습니다. 프로젝트는 다음과 같이 탭에 파일을 표시합니다.
A JMP project with several files.여러 파일이 있는 JMP 프로젝트.
이 프로젝트가 열리자 마자 9개의 파일이 열립니다. 게임에서 뱀파이어에 대한 클래스 정의가 있는 파일이 현재 표시됩니다. 나는 파일이 언제 프로젝트에 다시 저장되고 언제 프로젝트가 아직 저장되는지 완전히 편안하지 않으므로 프로젝트를 닫기 전에 왼쪽 상단에 강조 표시된 아이콘을 사용합니다. 나는 또한 왼쪽 하단에 로그를 도킹했습니다. 프로젝트는 JMP의 나머지 부분과 서로 격리된 것처럼 보이므로 자체 로그가 있습니다.
MakeAddin 파일은 게임의 일부가 아니라 게임 개발의 일부입니다. 해당 탭이 열려 있고 ^R(실행)하면 추가 기능이 다시 생성됩니다. 다른 탭을 실행하면 어떻게 됩니까? 해당 JSL이 실행되며 이는 게임 로직의 시작이 아닐 수 있습니다. 그러나 나는 실수로 항상 그렇게 했으므로 다음과 같이 수정했습니다.
- 합당한 순서로 다른 모든 파일을 포함하는 메인 파일인 game.jsl이 있습니다.
- 대부분의 파일은 독립적이며 클래스 또는 네임스페이스를 생성합니다.
- Sidescroller.jsl 파일은 다른 모든 파일을 로드해야 합니다(메인 게임 루프).
독립 파일 모두 끝 ~와 함께
try(include("game.jsl"),if(!contains(char(exception_msg),"includes itself through a closed path"),show(exception_msg)));현재 파일 다음에 game.jsl 파일을 실행합니다. game.jsl 파일은 현재 파일을 다시 포함하려고 시도하고 무시되는 재귀 포함 오류 또는 보고되는 다른 오류를 발생시킵니다. 마지막에 있어야 하는 사이드 스크롤러 파일에는 다음과 같은 try 문이 있습니다. 첫 번째 선. 그렇게 하면 나머지 사이드 스크롤러 파일이 실행되기 전에 game.jsl 파일에 다른 모든 것이 포함됩니다.
game.jsl 파일은 다음과 같습니다.
files = {"AUDIO.jsl", "RGBA.jsl", "ASSETS.jsl", "LAYERS.jsl", "VAMPIRE.jsl", "BEAR.jsl",
// currently SIDESCROLLER contains the game logic. All of the files include this file,
// at the end, except for SIDESCROLLER which include it at the start. SIDESCROLLER is
// dependent on all of the other files being loaded. The other files are not order-dependent.
"SIDESCROLLER.jsl"};
For( iFile = 1, iFile <= N Items( files ), iFile += 1,
Try(
Include( files[iFile] ), // this exception is EXPECTED if you start one of the other files; it is OK!
If( !Contains( Char( exception_msg ), "includes itself through a closed path" ),
Show( files[iFile], exception_msg )
)
)
);이제 편집된 파일을 실행할 수 있습니다. 예외... 둘 이상의 파일이 편집된 경우 명시적으로 실행되지 않는 파일을 저장해야 합니다! 포함은 편집 탭 사본이 아닌 디스크 사본을 가져옵니다. 그러나 하나의 파일만 변경하면 위의 포함 설정 방식 때문에 저장할 필요 없이 현재 편집 탭 사본을 사용합니다.
위시리스트:
- 실행하기 전에 모두 저장(또는 편집 탭 사본을 사용하도록 포함)
- 프로젝트를 실행할 때 시작 파일 지정(프로젝트 로드 시 파일 아님)
- 탭 저장과 프로젝트 저장이 어떻게 같거나 다른지 문서화
- JSL에서 프로젝트의 모두 저장 명령을 실행하는 방법
2. 게임 그래픽
이 프로젝트는 JSL 생성 그래픽과 다운로드된 비트맵 그래픽을 모두 사용합니다. 아래는 푸른 하늘, 산, 나무, 자갈길을 JSL로 만들어 놓았다. 암벽면은 바둑판식으로 배열된 비트맵이고 뱀파이어, 박쥐 및 곰은 애니메이션된 비트맵 시퀀스입니다. 끝에 크레딧.
The little bear is idling; the vampires are releasing bats or disappearing.꼬마 곰이 쉬고 있어요. 뱀파이어가 박쥐를 풀어 놓거나 사라지고 있습니다.
RGBA.jsl 파일은 JSL 그래픽의 중요한 부분입니다. JMP는 그래프에서 투명하게 그릴 수 있고 그래프에서 투명으로 비트맵을 사용할 수 있지만 예를 들어 투명한 배경에 선 그래프를 만들고 투명한 배경으로 해당 비트맵을 잡는 쉬운 방법은 없습니다. (그래프를 제외한 모든 것을 투명하게 저장하는 보고서 PNG 이미지의 투명 배경 옵션이 있습니다. 저장된 SVG를 편집하여 배경을 제거할 수 있지만 투명한 배경에서 다시 PNG로 변환하려면 다른 프로그램이 필요합니다.)
위시리스트
RGBA 파일은 아무것도 그려지지 않는 투명 픽셀로 비트맵을 만들기 위한 클래스를 만듭니다. 좋아하는 프리미티브를 확장해야 할 수도 있습니다. 불투명하지 않은 나뭇잎이 있는 나무와 나뭇잎 사이의 틈을 확인하세요. Path()를 사용하는 베지어 트리 나무 그리기에 대해 설명하지만 알파 채널로는 설명하지 않습니다. 산은 매개변수가 다른 언덕 그리기 알고리즘의 여러 레이어이며 하늘은 불투명한 파란색에서 검정색으로 음영 처리된 직사각형입니다. 자갈 경로는 생성하는 데 상당히 느릴 수 있지만 일단 실행하면 충분히 빠릅니다. 자갈의 각 비트는 비트맵으로 그려집니다.
ASSETS.jsl 파일은 게임에서 사용하는 비트맵 자산, 자산을 여는 방법, 정규화하는 방법 및 이름을 지정하는 방법에 대해 알고 있습니다. 애니메이션은 다른 사람이 그린 것이기 때문에 동일한 방식으로 중앙에 배치하려면 정규화가 필요합니다. 그 정보는 다음과 같은 구조로 보관됩니다.
Assets:vampire_images["hit"] = {{"attack/hit_1",.,.,0.80,0.5},이것은 뱀파이어를 풀어 놓는 박쥐가 비트맵에서 이동되어 추가 와이드 애니메이션을 처리한다는 것을 보여줍니다. 뱀파이어와 곰은 사이드 스크롤러에 고유한 레이어를 가져오고 투명도 덕분에 더 멀리 있는 레이어가 표시됩니다.
게임은 실제로 그래프에 있기 때문에 확대/축소 도구로 게임을 들여다보면 레이어를 이해할 수 있습니다. 여기에서 축소되어 하늘이 왼쪽에서 오른쪽으로 창보다 크지 않은 것을 볼 수 있습니다. 스크롤하지 않습니다. 그러나 가까울수록 레이어가 더 넓어지고 넓어져 더 많이 스크롤할 수 있습니다.
Normally the sky fills the display, left-to-right. Zoomed out, see the vampire about to enter the stage.일반적으로 하늘은 왼쪽에서 오른쪽으로 디스플레이를 채웁니다. 축소, 무대에 입장하려는 뱀파이어를 참조하십시오.
꼬마곰이 오른쪽으로 걸어가면서 비트맵의 위치가 조정됩니다...
Not afraid.두렵지 않다.
중간만 지나면...
The NPCs animate even when off the display.NPC는 디스플레이가 꺼져 있을 때도 애니메이션을 적용합니다.
그리고 맨 끝에...
The little bear has reached the right-hand end of his world.작은 곰은 자신의 세계의 오른쪽 끝에 도달했습니다.
뱀파이어는 곰보다 느리게 걷는다. 따라잡을 것입니다. 그리고 여기 배경 및 전경 이미지의 일부가 삭제되었습니다...
Without all the layers, the characters seem to float.모든 레이어가 없으면 문자가 떠 있는 것처럼 보입니다.
3. 게임 오디오
사운드는 몰입형 경험의 중요한 부분입니다. 나는 이 게임에서 사운드를 만들기 위해 LMMS를 사용했고 적절한 사운드 디자이너가 훨씬 더 잘할 수 있었습니다. 그러나 소리가 서로 끊기지 않고 겹칠 수 있기 때문에 여전히 꽤 좋습니다. Windows에서. Mac 사용자가 사운드를 재생할 수 있는 명령줄 프로그램을 찾으면 아마도 Mac에 있을 것입니다. 감사 @Jeff_Perkinson Mac 오디오 코드를 도와주셔서 감사합니다. Windows의 경우 AUDIO.jsl 파일은 RunProgram을 사용하여 Windows 사운드 시스템에 액세스할 수 있는 PowerShell을 실행합니다. Mac에서는 명령줄 사운드 플레이어인 /usr/bin/afplay를 사용합니다. 모든 재생 사운드가 끝나기 전에 JMP를 종료하려고 하면 JMP가 충돌할 수 있습니다. 마지막 진행률 표시줄이 시작된 모든 소리의 재생을 마치도록 하십시오.
4. 게임 입력
이 게임은 게임을 담고 있는 그래프 상자 주위에 MouseBox를 배치하여 키보드를 입력 장치로 사용합니다.
New Window( "overlay",
mb = MouseBox(
V List Box(
hlistbox(
leftSpacer=spacerbox(size(5,windowy),color("black")),
gb = Graph Box(
suppressaxes,
framesize( windowx + 1, windowy + 1 ),
X Scale( -1, windowx ),
Y Scale( -1, windowy )
),MouseBox는 키와 시간을 기억하는 작은 기능으로 키 입력을 전달합니다.
lastkey=empty();
lastkeyexpire=tickseconds();
spriteRunner = function({key},{},
lastkey=key;
lastkeyexpire=tickseconds()+1;
);다른 곳에서는 키의 동작이 1초 후에 부실해질 때까지 반복됩니다.
While( go,
if( tickseconds() > lastkeyexpire,
lastkey="";
);
…열쇠는 작은 곰을 조종합니다. 그것들은 곰의 유한 상태 기계(FSM)에서 구현됩니다. 곰을 유휴 상태에서 걷기로 변경하는 예는 BEAR.jsl cycle() 함수에 있습니다.
If( begin,
laststate=m_state;
if( keystroke=="LEFT" & ( pFaceLeft=="faceright" | (pFaceLeft=="faceleft" & pName=="idle") ),
m_state = m_stateWalkLeft;현재 애니메이션 주기가 시작 부분에 있으면 Begin이 true이므로 상태를 변경하기에 좋습니다. 점프 애니메이션의 중간을 아이들링 애니메이션으로 남겨두는 것은 이상하게 보입니다. 곰은 왼쪽을 바라보고 유휴 상태일 때만 왼쪽으로 움직이기 시작해야 하지만 오른쪽을 바라보면...그냥 왼쪽으로 움직이기 시작해야 한다는 논리를 쓴 지 오래되었습니다. 나는 그것이 걸을 때 즉각적인 반전을 허용하고 다른 방법으로도 처리될 수 있는 동일한 상태로의 변경을 방지할 수 있다고 생각합니다.
5. 게임 플레이
매력적인 게임을 만드는 것은 저에게 어려운 부분입니다. 이야기하기, 목표 만들기, 퍼즐 추가하기. 이 게임은 대부분 스토리텔러를 기다리는 환경입니다. 그러나 나는 약간의 게임 플레이를 추가했습니다.
,/*else if*/ keystroke=="DOWN" & m_NumRocks<6 & (m_state == m_stateWalkLeft | m_state==m_stateIdleLeft),
m_state = m_statePickLeft;
m_NumRocks = min(6,m_NumRocks+1);
// use SPACE to HIT
,/*else if*/ keystroke==" " & (m_state == m_stateWalkRight | m_state==m_stateIdleRight),
if(m_NumRocks,
m_NumRocks = max(0,m_NumRocks-1);
m_state = m_stateHitRight;
m_RockThrownRightFrom = m_x;
);아래쪽 화살표를 누르면 바위를 집습니다. 작은 곰은 최대 6마리를 잡을 수 있습니다. 스페이스바를 누르면 돌을 마주보는 방향으로 던집니다. 곰은 던져진 돌을 메모한다 RockThrownRight에서 또는 RockThrown 왼쪽 에서 이것은 뱀파이어와 곰을 볼 수 있는 메인 루프의 코드로 확인됩니다.
// check for interaction between bear and vampire
if(!ismissing(bearPlayer:m_RockThrownRightFrom),
if(bearPlayer:m_RockThrownRightFrom<GETPOS></GETPOS>
뱀파이어를 돌로 때리면 50픽셀 뒤로 밀려납니다. (사실, 내가 쓴 것처럼 하나의 돌로 두 명의 뱀파이어를 얻을 수 있습니다.) 뱀파이어는 아마도 두 개 이상을 지원할 수있는 목록에 있어야합니다. 실제로 모든 NPC(플레이어가 아닌 캐릭터)는 목록에 있어야 하며,
vampire1:cycle(stagepos);
vampire2:cycle(stagepos);
bearPlayer:cycle(stagepos,lastkey);
그러나 이것은 이 간단한 예제가 어떻게 작동하는지 모호하게 만들 것입니다.
프로젝트 파일과 추가 기능 파일의 두 가지 첨부 파일이 있어야 합니다. (지금은 커뮤니티에 프로젝트를 첨부할 수 없지만, 애드인을 설치하면 애드인 디렉토리에 프로젝트 사본이 있습니다.)
미술 크레딧
오픈 게임 아트 사이트에는 다양한 품질의 훨씬 더 많은 콘텐츠가 있습니다.