이 튜토리얼에서는 다이아몬드, 체크 포인트, 움직이는 플랫폼, 함정이 있는 작은 플랫 포머를 만들 것입니다! 충돌을 감지하고 이를 사용하여 사이드 뷰 이동을 만드는 방법과 스프라이트를 조작하고 레벨간에 플레이어를 이동하는 방법을 배웁니다.
https://docs.ctjs.rocks/tut-making-platformer.html#creating-a-project
우리가 할 일은 다음과 같습니다.
Creating a Project
ct.js를 열고 시작 창의 하단 필드에 프로젝트 이름을 입력합니다. "플랫 포머"라고 합시다. 그런 다음 "만들기"버튼을 클릭하고 ct.js가 저장할 폴더를 선택합니다 (예 : "문서"폴더 안에 있습니다.
Importing Textures
Kenney의 단순화 된 플랫 포머 팩의 일부 자산이 필요합니다. ctjs / examples / Platformer_assets / 폴더에서 적절한 이름으로 필요한 자산을 찾을 수 있습니다.
"Textures"탭을 열고 "Import"버튼을 누른 다음 ctjs / examples / Platformer_assets / 폴더로 이동하여 모든 이미지를 선택하십시오. 텍스처 패널에 나타납니다.
가장 먼저 눈에 띄는 것은 Robot_Walking 애니메이션이 두 개의 개별 프레임이 아니라 하나의 이미지로 간주된다는 것입니다. Robot_Walking 자산을 클릭하십시오.
이미지는 작은 보더입니다. 하나의 행과 두 개의 열이 있습니다. Columns 및 Rows 필드를 설정 한 다음 Width 필드를 보정하여 ct.js에게 이러한 방식으로 이미지를 분할하도록 지시 할 수 있습니다.
전체 이미지의 너비는 192 픽셀이므로 한 프레임은 192 : 2 = 96 픽셀입니다. 로봇의 프레임은 이제 두 개의 직사각형으로 윤곽이 그려져야 합니다.
이제 충돌 마스크를 편집 해 보겠습니다. 이미지에서 단색으로 계산되는 영역과 그렇지 않은 영역을 결정하고 스프라이트 위에 노란색 사각형으로 표시됩니다.
첫째, 축을 이동하여 하단 중간 지점에 배치합니다.
설명
96x96 픽셀 이미지가 있으므로 가로축에 48 픽셀, 세로축에 96 픽셀이 필요합니다. 픽셀은 왼쪽 상단 모서리에서 측정되며 포인트의 첫 번째 값은 일반적으로 수평 구성 요소 또는 X 값이고 두 번째는 Y 구성 요소라고 합니다.
로봇은 멋진 직사각형 모양이므로 직사각형으로 표시하는 것이 더 현명합니다. 직사각형 모양이 선택되어 있는지 확인하고 '채우기'버튼을 클릭 한 다음 오프셋을 보정하여 로봇의 몸체가 노란색 직사각형으로 덮이도록 합니다.
몸과 손을 모두 가리거나 몸만 선택할 수 있습니다.
왼쪽 하단에 있는 "저장"버튼을 클릭합니다.
이제 Robot_Idle 및 Robot_Jump에도 충돌 마스크를 설정해야 합니다. 축을 48x96으로 이동하고 둘 모두에 대해 충돌 마스크를 보정해야 합니다.
팁
세 개의 스프라이트 각각에 대해 충돌 오프셋을 동일하게 만드는 것도 좋습니다. 따라서 로봇은 애니메이션을 전환 할 때 표면에 끼지 않고 갑자기 충돌 모양으로 커집니다.
이제 크리스탈과 심장 보너스의 충돌 모양을 설정하겠습니다. 원으로 정의 할 수 있습니다. GreenCrystal을 열고 충돌 모양을 "원"으로 설정 한 다음 "이미지 중심"이라는 버튼을 클릭하여 축이 필요한 값에 자동으로 스냅되도록 하고 충돌 모양의 반경을 보정합니다.
Heart 자산에 대해서도 똑같이 하십시오.
수정해야 할 마지막 자산은 스파이크입니다. 이러한 방식으로 맵에서 잘못 정렬 된 것처럼 보이기 때문에 축을 이동할 필요는 없지만 여전히 충돌 모양을 설정해야 합니다. 이미지의 위쪽 부분이 노란색으로 채워지지 않도록 위쪽 오프셋을 음수 값으로 설정합니다.
자산을 저장하십시오. 다른 텍스처를 살펴보면 모든 텍스처가 전체 이미지를 채우는 직사각형 모양임을 알 수 있습니다. 다른 모든 이미지에 적합하므로 그대로 두겠습니다.
Creating a Robot Character and Ground
팁
유형은 복사본이 생성되는 템플릿과 같습니다. 우리는 레벨 (일명 방)을 복사본으로 채우고 화면에서 서로 상호 작용하지만 각 복사본은 특정 유형에서 만들어졌습니다.
같은 방법으로 추가 유형을 만듭니다.
Adding a Room
상단의 "방"탭을 클릭하고 새 방을 만듭니다. 이름을 "Level_01"로 설정합니다. 톱니 바퀴 아이콘이 있는 "속성"탭에서 보기 크기를 1024x576으로 설정합니다.
그런 다음 왼쪽의 유형을 클릭 한 다음 마우스로 오른쪽의 큰 영역에 배치하여 레벨을 그립니다. 한 번에 여러 복사본을 추가하려면 Shift 키를 누릅니다. 로봇을 잊지 마세요!
레벨을 어느 쪽으로 든 확장 할 수 있으며 복사본이 파란색 프레임 안에 있을 필요는 없습니다. 뷰의 크기로 조작되는 이 프레임은 레벨의 처음 보이는 부분을 설정합니다.
나는 이것을 그렸다. 플레이어로서 여기에 갇히기는 어렵지만 점프하는 방법을 가르쳐줍니다. 나중에 바위 플랫폼에 수정을 추가하고 마지막 언덕 아래 창에 비밀을 추가 할 수도 있습니다.
이제 배경을 추가하겠습니다. 왼쪽의 "배경"탭을 클릭하고 "추가"를 누른 다음 BG 자산을 선택하십시오. 이제 새 배경 근처의 톱니 바퀴를 클릭하고 깊이를 -10으로 변경합니다. 따라서 엔진에 배경은 기본 0 레이어 아래에 10 개의 레이어를 그려야 한다고 알려줍니다.
지금 프로젝트를 저장하고 상단의 "Launch"버튼을 클릭하면 디버거 창에 그려진 레벨의 작은 부분을 볼 수 있습니다. 아직 움직일 수 있는 것은 없지만 여전히 좋은 시작입니다!
키보드 및 충돌을 위한 모듈 추가
키보드 이벤트를 듣고 로봇과 지면 사이의 충돌을 감지해야 합니다. 그러한 초강대국을 위해서는 Catmod가 필요합니다! "프로젝트"탭을 클릭 한 다음 왼쪽의 "Catmods"탭을 클릭하십시오. 사용 가능한 모듈 섹션에서 키보드 모듈을 클릭하여 녹색 확인란과 주위에 약간의 회전 원이 표시되도록 합니다. (이미 활성화되어있을 수 있습니다!) place 모듈에서도 똑같이 하십시오.
프로 팁 ✨
fittoscreen이라는 catmod를 활성화 한 다음 설정 탭으로 이동하여 자동 전체 화면보기를 위해 "레터 박스로 빠른 크기 조정"이라는 옵션을 활성화합니다.
각 모듈에는 "참조"탭에 자체 설명서가 있습니다. 나중에 일부 부분을 강조하겠습니다.
Adding Actions for Keyboard Events
액션을 사용하면 키보드, 마우스, 게임 패드 등의 이벤트를 수신 할 수 있습니다. 여기에서 자세한 내용을 읽을 수 있습니다. 그들과 함께 WASD 키와 화살표에 대한 청취자를 만들 것입니다.
프로젝트 패널로 이동 한 다음 왼쪽의 "작업 및 입력 방법"탭을 누릅니다.
그런 다음 아래 그림과 같이 입력 체계를 만듭니다. 이를 수행하려면 먼저 "작업 추가"버튼을 누르고 이름을 지정한 다음 오른쪽 열에 입력 방법을 추가합니다. 검색을 사용하여 필요한 키를 빠르게 추가 할 수 있습니다.
팁
이 체계는 두 가지 작업으로 단순화 될 수 있지만 (작업 페이지의 예 참조) 자습서를 과도하게 복잡하게하지 않도록 왼쪽 또는 오른쪽으로 이동하는 두 개의 별도 작업이 있습니다. # 코딩 충돌
Coding Collision Detection and Movement
이제 화면 상단의 "유형"탭으로 이동하여 Rocks 유형을 엽니다. 왼쪽 열에서 "충돌 그룹"이라는 필드를 단색으로 채 웁니다.
이것은 ct.place catmod에게 이 특정 유형이 "Solid"라는 특수 충돌 그룹에 속함을 알려줍니다. 이 그룹의 이름은 임의의 값이 될 수 있으며 이러한 그룹의 수는 무제한입니다. 지금은 한 그룹이면 충분합니다.
Rocks_Top 및 Rocks_Platform에 동일한 행을 추가하십시오.
이제 로봇 유형을 엽니 다. 이전에 "Space Shooter"튜토리얼을 완료했다면 복사본의 매개 변수를 직접 조작하거나 this.speed 또는 this.direction과 같은 내장 변수를 사용하여 이동이 이루어 졌다는 것을 기억할 수 있습니다. 사실 후자는 ct.js 외부에서도 플랫폼 사용자와 함께 일한 적이 없다는 것입니다! 좀 더 복잡한 것을 써야 할 것입니다. 준비하십시오! ?
사이드 뷰 이동의 개념은 우리가 이동하고 싶은 값을 갖게 될 것이고, 우리는 픽셀 단위로 무언가와 충돌하는지 여부를 확인할 것입니다.
"On Create"탭에서 몇 가지 변수를 설정해 보겠습니다.
this.jumpSpeed = -9;
this.gravity = 0.5;
this.hspd = 0; // Horizontal speed
this.vspd = 0; // Vertical speed
팁
이것은 작성된 코드를 실행하는 복사본입니다. 이 경우 로봇 카피입니다.
이제 "On Step"탭으로 이동하여 다음 코드를 추가하십시오.
this.speed = 4 * ct.delta; // Max horizontal speed
if (ct.actions.MoveLeft.down) {
// If the A key or left arrow on a keyboard is down, then move to left
this.hspd = -this.speed;
} else if (ct.actions.MoveRight.down) {
// If the D key or right arrow on a keyboard is down, then move to right
this.hspd = this.speed;
} else {
// Don't move horizontally if no input
this.hspd = 0;
}
// If there is ground underneath the Robot…
if (ct.place.occupied(this, this.x, this.y + 1, 'Solid')) {
// …and the W key or the spacebar is down…
if (ct.actions.Jump.down) {
// …then jump!
this.vspd = this.jumpSpeed;
} else {
// Reset our vspeed. We don't want to be buried underground!
this.vspd = 0;
}
} else {
// If there is no ground
this.vspd += this.gravity * ct.delta;
}
팁
"On Step"코드는 각 사본에 대해 각 프레임에서 실행됩니다. 이동 및 기타 게임 논리는 일반적으로 여기에 있습니다.
팁
ct.actions.YourAction.down은이 작업에 나열된 키가 현재 눌러져 있는지 확인합니다. ct.actions.YourAction.pressed 및 ct.actions.YourAction.released도 있습니다. ct.place.occupied (copy, x, y, group)은 주어진 사본이 특정 그룹과 주어진 좌표에서 충돌이 있는지 확인합니다. 필요하지 않은 경우 그룹을 생략 할 수 있습니다. 이 메서드는 false (충돌 없음) 또는 처음으로 충돌 한 복사본을 반환합니다.
팁
ct.delta는 이전 프레임이 처리하는 데 걸린 시간을 설명합니다. 모든 것이 정상이고 게임이 부드러운 FPS로 수행되면 1과 동등하고 게임이 목표 FPS 값에 도달 할 수 없으면 더 커집니다. 값을 ct.delta에 곱하여 모든 프레임 속도에서 모든 것이 균일하게 이동하는지 확인합니다.
이렇게 하면 hspd 및 vspd 변수가 설정되지만 있는 그대로 아무 작업도 수행하지 않습니다. 실제로 로봇을 움직일 수 있는 코드를 더 추가합니다.
// Move by horizontal axis, pixel by pixel
for (var i = 0; i < Math.abs(this.hspd); i++) {
if (ct.place.free(this, this.x + Math.sign(this.hspd), this.y, 'Solid')) {
this.x += Math.sign(this.hspd);
} else {
break;
}
}
// Do the same for vertical speed
for (var i = 0; i < Math.abs(this.vspd); i++) {
if (ct.place.free(this, this.x, this.y + Math.sign(this.vspd), 'Solid')) {
this.y += Math.sign(this.vspd);
} else {
break;
}
}
팁
ct.place.free는 ct.place.occupied와 반대입니다. 동일한 매개 변수를 가지며 true 또는 false를 리턴합니다. Math.abs는 주어진 숫자의 절대 값을 반환합니다. 즉, 음수가 양수가됩니다. Math.sign은 주어진 값이 음수이면 -1을, 양수이면 1을, 0이면 0을 반환합니다. 함께 결합하면 양방향으로 작동하고 픽셀 단위로 충돌을 확인하는 for 루프가 생성됩니다.
이제 로봇을 움직일 수 있습니다!
경고
캐릭터는 그리드 셀 너비가 하나 인 구멍을 무시할 수 있습니다. 그것을 테스트하십시오. 발생하면 로봇의 충돌 모양을 좀 더 얇게 만들어야 합니다.
Making Camera Follow the Robot
지금 게임을 시작하면 로봇을 움직일 수 있습니다. 하지만 문제가 있습니다. 카메라가 움직이지 않습니다!
하지만 어려운 문제는 아닙니다. ct.js 문서를 자세히 살펴보면 ct.camera.follow, ct.camera.borderX 및 ct.camera.borderY가있는 ct.camera 엔티티를 정확하게 찾을 수 있습니다.
로봇 유형과 "생성시"코드를 엽니다. 이 코드를 끝에 추가하십시오.
ct.camera.follow = this;
ct.camera.borderX = 450;
ct.camera.borderY = 200;
이제 카메라가 로봇을 따라갑니다.
Adding Traps and Checkpoints
이제 치명적인 함정과 해자, 체크 포인트를 추가하여 플레이어가 레벨 시작이 아닌 다시 시작하도록 할 것입니다.
Water, Water_Top, Spikes 및 Checkpoint 자산에 대한 새로운 유형을 만듭니다.
새 방을 만들고 Level_02라고 합니다. 크기를 1024x576으로 설정하고 배경을 추가합니다. 스파이크와 호수로 위험한 레벨을 만드십시오.
위험 장소 전후에 체크 포인트 상자를 배치하십시오. 실수로 플레이어를 처벌하는 것은 결코 좋은 생각이 아니므로 많은 것을 넣는 것을 두려워하지 마십시오! ?
여기서 가정 된 레벨의 끝은 상단 중간 플랫폼에 배치됩니다. 또한 미래의 크리스탈을 수집하기 위해 스크린 샷 외부에 플랫폼을 배치했습니다.
이제 Checkpoint의 유형으로 이동하여 "On Step"코드를 편집 해 보겠습니다.
로봇과의 충돌을 확인하고 충돌이 발생하면 로봇 사본 내부에 구조 지점을 저장합니다. this.move (); 줄을 제거하십시오. 다음 코드를 추가하십시오.
var robot = ct.place.meet(this, this.x, this.y, 'Robot');
if (robot) {
robot.savedX = this.x + 32;
robot.savedY = this.y + 32;
}
팁
this.move (); 라인 표준 ct 변수를 사용하는 복사본을 이동합니다. 이 경우 체크 포인트는 전혀 움직이지 않아야 합니다. ? ct.place.meet은 ct.place.occupied와 거의 동일하지만 충돌 그룹이 아닌 복사본의 유형을 확인합니다.
체크 포인트의 축은 왼쪽 상단 모서리에 있지만 로봇의 축은 중간 하단 지점에 있기 때문에 여기서도 저장된 지점을 32x32 픽셀만큼 이동합니다. 그 때문에 로봇은 원하는 중앙 지점에서 약간 왼쪽과 위쪽으로 리스폰 됩니다.
"On Create"탭으로 이동하여 this.visible = false; 행을 추가하십시오. 이렇게 하면 게임 플레이 중에 체크 포인트가 보이지 않게 됩니다.
이제 Spikes 유형으로 이동하여 "Deadly"충돌로 표시합니다.
this.ctype = 'Deadly';
Water 및 Water_Top도 동일하게 수행하십시오.
이제 로봇 유형을 다시 열고 이 코드를 On Step 코드 맨 위에 추가합니다.
if (ct.place.occupied(this, this.x, this.y, 'Deadly')) {
this.x = this.savedX;
this.y = this.savedY;
this.hspd = 0;
this.vspd = 0;
return;
}
팁
여기, 반환; 문은 함수 실행을 중지합니다. 로봇을 다른 위치에서 리스폰 해야 하는 경우 이동 및 기타 확인이 필요하지 않습니다.
또한 무언가 잘못 될 경우를 대비하여 리스폰 지점이 기본적으로 생성 위치에 있도록 "On Create"탭에 이 코드를 작성해야 합니다.
this.savedX = this.x;
this.savedY = this.y;
특정 방을 테스트하려면 상단의 "방"탭을 연 다음 원하는 방을 마우스 오른쪽 버튼으로 클릭하고 "시작 방으로 설정"을 누르십시오.
Transforming and Animating the Robot
이 시점에서 로봇에 약간의 애니메이션을 추가하는 것이 현명 할 것입니다. 기억 하시겠지만 Robot_Idle, Robot_Jump 및 Robot_Walking이라는 세 가지 애셋이 있습니다.
로봇의 "On Create"코드에 다음 줄을 추가합니다.
this.animationSpeed = 0.2;
0.2는 초당 0.2 × 60 (12) 프레임을 재생한다는 의미입니다. 가독성을 높이기 위해 12/60으로 작성할 수도 있습니다.
로봇의 "On Step"코드를 열고 이동 섹션을 수정하여 사용자 입력과 로봇의 공간 위치에 따라 그려진 텍스처를 변경합니다.
if (ct.actions.MoveLeft.down) {
// If the A key on keyboard is down, then move to left
this.hspd = -this.speed;
// Set the walking animation and transform the robot to the left
if (this.tex !== 'Robot_Walking') {
this.tex = 'Robot_Walking';
this.play();
}
this.scale.x = -1;
} else if (ct.actions.MoveRight.down) {
// If the D key on keyboard is down, then move to right
this.hspd = this.speed;
// Set the walking animation and transform the robot to the right
if (this.tex !== 'Robot_Walking') {
this.tex = 'Robot_Walking';
this.play();
}
this.scale.x = 1;
} else {
// Don't move horizontally if no input
this.hspd = 0;
this.tex = 'Robot_Idle';
}
// If there is ground underneath the Robot…
if (ct.place.occupied(this, this.x, this.y + 1, 'Solid')) {
// …and the W key or the spacebar is down…
if (ct.actions.Jump.down) {
// …then jump!
this.vspd = this.jumpSpeed;
} else {
// Reset our vspeed. We don't want to be buried underground!
this.vspd = 0;
}
} else {
// If there is no ground
this.vspd += this.gravity;
// Set jumping animation!
this.tex = 'Robot_Jump';
}
우리의 수직 이동은 수평 이동에 의존하지 않기 때문에 로봇 아래에 땅이 없으면 애니메이션이 점프 상태로 재정의 됩니다.
로봇은 이제 현재 방향으로 뒤집고 움직임에 따라 텍스처를 변경합니다. 저 소년 좀 봐!
Adding level transitions
아이디어는 다음과 같습니다.
새 유형을 생성하고 이탈이라고 합니다. 텍스처를 설정하십시오. 그런 다음 "On Step"탭을 열고 다음 코드를 작성하십시오.
// Are there next rooms defined?
if (ct.room.nextRoom) {
// Do we collide with the Robot?
if (ct.place.meet(this, this.x, this.y, 'Robot')) {
// Switch to the next room
ct.rooms.switch(ct.room.nextRoom);
}
}
팁
여기서 ct.room은 현재 방을 가리킵니다. ct.rooms.switch는 현재 방을 종료하고 주어진 이름으로 다른 방을 엽니다.
이제 상단에 있는 "Rooms"탭으로 이동하여 Level_01을 열고 "Room 's events"라는 버튼을 클릭 한 다음 "On Create"코드에 다음을 작성합니다.
this.nextRoom = 'Level_02';
방에 출구를 놓습니다.
이제 방을 저장하고 Level_01을 마우스 오른쪽 버튼으로 클릭하여 시작 방으로 표시하고 전환이 있는지 테스트합니다.
스스로!
비밀 하위 수준으로 이어지는 추가 출구를 만들고 뒤로 이동하십시오. 필요한 경우 여기에서 더 많은 자산을 얻으십시오.
Collectibles: Counting and Drawing
Adding Crystals
GreenCrystal이라는 새 유형을 만들고 해당 스프라이트를 설정합니다. "On Step"이벤트에 다음 코드를 작성합니다.
if (ct.place.meet(this, this.x, this.y, 'Robot')) {
ct.room.crystals ++;
this.kill = true;
}
팁
this.kill = true; 현재 룸에서 현재 복사본을 제거해야 함을 나타냅니다. 모든 "On Step"이벤트 후 "Draw"이벤트 전에 발생합니다.
이미 짐작 하셨겠지만, 수집 된 수정의 수는 방에 저장됩니다.
그러나 방별 코드에 더 많은 기능을 계속 추가하면 곧 일부 스니펫을 복사하여 붙여 넣는 것을 잊는 버그가 있는 함정에 빠질 것입니다. 어쨌든 세 번째 방까지 그렇게 하는 것은 지루한 일이 될 것입니다. (그리고 우리는 세 번째 방을 가질 것입니다!)
따라서 이제 재사용 가능한 함수를 만들어야 합니다. 이상하게 보일 수 있지만 실제로는 그렇게 어렵지 않습니다.
화면 상단의 "프로젝트"탭으로 이동 한 다음 왼쪽의 "사용자 지정 스크립트"탭을 클릭합니다. "새 스크립트 추가"버튼을 누릅니다.
inGameRoomStart로 새 스크립트를 호출합니다. 이 코드를 작성하십시오.
var inGameRoomStart = function (room) {
room.crystals = 0;
room.crystalsTotal = ct.types.list['GreenCrystal'].length;
};
팁
ct.types.list [ 'TypeName']은 방에있는 지정된 유형의 모든 복사본 배열을 반환합니다. length는 배열의 크기를 반환합니다.
이제 각 룸의 "On Create"코드로 이동하여 다음 행을 추가하십시오.
inGameRoomStart(this);
흠… 익숙해 보입니다! ct.place.free (this, this.x, this.y)처럼! 이것이 실제로 대부분의 ct.js 메서드가 작동하는 방식입니다. 메서드가 있고 이 메서드에 해당 복사본 또는 해당 공간으로 작업을 수행하도록 지시합니다.
때 inGameRoomStart (this); 방에 직접 코드를 작성할 필요 없이 자체적으로 crystals 및 crystalsTotal 매개 변수를 설정합니다.
그것이 우리가 크리스탈을 모으고 세는 방법이지만, 우리는 또한 그 수를 그리고 스타일로 하기 위해 간단한 인터페이스를 만들어야 합니다. ✨
다행스럽게도 ct.js 안에 멋진 텍스트 스타일을 디자인 할 수 있는 도구가 있습니다. 화면 상단의 "UI"탭을 열고 새 스타일을 만듭니다. 그것을 CrystalCounter라고 부릅니다.
그런 다음 "글꼴"섹션을 활성화하고 글꼴 크기를 24로 설정하고 두께를 600으로 설정합니다. 왼쪽에 맞춥니다.
그런 다음 "채우기"탭을 열고 활성화 한 다음 채우기 색상을 녹색으로 설정합니다. # 00A847을 선택했습니다. 다른 좋은 선택으로는 # 2ECC71 및 # 28B463과 같은 크리스탈의 주요 색상이 있습니다.
텍스트에 두꺼운 흰색 선을 추가 할 수도 있습니다. "Stroke"탭을 열고 색상을 흰색으로, 선의 너비를 5로 설정하십시오. 오른쪽에 결과가 표시되지 않으면 상단의 햄버거 메뉴를 클릭하여 잠시 동안 어두운 UI 테마로 전환 해보십시오.
이제 CrystalsWidget이라는 새 유형을 만들어야 합니다. 크리스탈 아이콘과 카운터가 표시됩니다. Sprite를 GreenCrystal로 설정하고 OnCreate 코드에 다음을 작성합니다.
this.text = new PIXI.Text('0 / ' + ct.room.crystalsTotal, ct.styles.get('CrystalCounter'));
this.text.x = 32;
this.text.anchor.y = 0.5;
this.addChild(this.text);
여기에서 새 텍스트 레이블을 만들어 아이콘에 첨부합니다. this.text.anchor.y = 0.5; 라벨의 세로 축이 아이콘 중앙에 정렬되어야 함을 나타냅니다.
이제 UI 요소를 위한 특별한 공간을 만들어야 합니다. "Rooms"탭에서 만들고 LayerUI라고 합니다. 다른 방의 1024x576과 동일하게 크기를 설정합니다. 그런 다음 새로 생성 된 CrystalsWidget을 방의 왼쪽 상단 모서리에 추가합니다.
별도의 공간에 UI 요소를 추가하면 UI를 시각적으로 디자인 한 다음 코드를 통해 다른 공간으로 가져올 수 있습니다. 또한 Ct.js에는 UI 레이어를 제자리에 고정하는 특수 플래그가 있으므로 카메라를 자유롭게 이동, 크기 조정 및 회전 할 수 있으며 UI 요소는 적절한 위치에 유지됩니다. 이제 UI 룸을 다른 룸으로 가져 오려면 이전에 Project-> Custom scripts 탭에서 만든 GameRoomStart의 스크립트로 이동하여 함수의 닫는 중괄호 앞에 다음 코드를 추가합니다.
ct.rooms.append('LayerUI', {
isUi: true
});
다음과 같아야 합니다.
팁
ct.rooms.append (및 ct.rooms.prepend) 메서드는 UI 레이어가 아닌 다른 항목을 재사용 하는데도 사용할 수 있습니다. 예를 들어, 모든 배경을 별도의 방에 배치 한 다음 ct.rooms.prepend ( "YourBackgroundRoom");을 호출 할 수 있습니다. 가져옵니다. 시차 효과가 있는 복잡한 레이어 배경을 만들 때 특히 유용합니다. 그러나 중요한 것은 isUi : true 플래그입니다. 이 특정 매개 변수는 UI 레이어를 다른 레이어와 구별합니다. 그 배경 방에서.
이제 게임을 실행하면 왼쪽 상단 모서리에 크리스탈 카운터가 표시됩니다.
Adding Lives and Heart Bonuses
이것은 수정을 모으는 것과 거의 비슷하지만 몇 가지 변경 사항이 있습니다.
스스로!
혼자서 만들어보세요! 길을 잃은 경우 아래 지침을 찾으십시오. 이제 스크롤을 중지하세요! ?
Heart라는 새 유형을 만들고 해당 스프라이트를 설정합니다. 이 코드를 "On Step"탭에 추가합니다.
if (ct.place.meet(this, this.x, this.y, 'Robot')) {
if (ct.room.lives < 3) {
ct.room.lives++;
this.kill = true;
}
}
레벨에 실제 심장 보너스를 배치하는 것을 잊지 마십시오!
카운터 스타일도 필요합니다. 과정은 동일하며 적절한 색상은 # E85017입니다. 기존 스타일을 복제 할 수도 있습니다! 이 스타일을 HeartCounter라고 합시다.
건강을 위한 또 다른 위젯이 필요합니다. HeartsWidget이라는 새 유형을 만들고 해당 스프라이트를 Heart로 설정하고 OnCreate 코드를 다음과 같이 설정합니다.
this.text = new PIXI.Text(ct.room.lives, ct.styles.get('HeartCounter'));
this.text.x = -32;
this.text.anchor.y = 0.5;
this.text.anchor.x = 1;
this.addChild(this.text);
그런 다음이 유형의 사본을 Room LayerUI에 추가합니다.
이제 로봇의 부활 코드를 수정하여 부활 할 때마다 하트 하나를 잃게 합니다.
if (ct.place.occupied(this, this.x, this.y, 'Deadly')) {
this.x = this.savedX;
this.y = this.savedY;
this.hspd = 0;
this.vspd = 0;
// remove one life
ct.room.lives --;
if (ct.room.lives <= 0) {
// Restart a room: switch to the room of its own name
ct.rooms.switch(ct.room.name);
}
return;
}
그게 다야! 약간의 테스트를 위한 시간
Adding moving platforms
Platform이라는 새 유형을 만들고 해당 스프라이트를 선택합니다. 넓은 해자 또는 긴 함정이 있는 Level_03이라는 새 레벨을 만들고 플랫폼을 움직여보세요.
움직이는 플랫폼은 다음과 같이 작동합니다.
플랫폼의 유형을 열고 속도 및 충돌 그룹을 초기화하겠습니다.
this.speed = 2;
this.ctype = 'Solid';
그런 다음 "On Step"탭에 코드를 추가하여 로봇을 이동합니다.
var robot = ct.place.meet(this, this.x, this.y - 1, 'Robot');
if (robot) {
robot.x += this.speed;
}
그리고 이동 논리 :
if (ct.place.occupied(this, this.x + this.speed * ct.delta, this.y, 'Solid')) {
// Flip direction
this.direction += 180;
}
this.move();
간단 해 보인다! 너무 간단 할 수도 있습니다. 그리고 여기에 문제가 있습니다. 로봇이 플랫폼의 왼쪽이나 오른쪽에 닿으면 영원히 멈춰 있습니다! 플랫폼이 겹치지 않을 때만 견고하게 만들어야 합니다.
더 나은 코드는 다음과 같습니다.
var robot = ct.place.meet(this, this.x, this.y, 'Robot');
if (robot) {
this.ctype = undefined;
} else {
this.ctype = 'Solid';
robot = ct.place.meet(this, this.x, this.y - 1, 'Robot');
if (robot) {
robot.x += ct.u.ldx(this.speed, this.direction);
}
}
if (ct.place.occupied(this, this.x + this.speed * ct.delta, this.y, 'Solid')) {
// Flip direction
this.direction += 180;
}
this.move();
여기서 무슨 일이 일어나나요? 먼저 로봇이 이미 플랫폼과 겹치는 지 확인합니다. 만약 그렇다면, 우리는 로봇이 플랫폼에 갇히지 않고 넘어 질 수 있도록 this.ctype = undefined;에 의해 플랫폼이 단단 해지는 것을 멈춰야 한다고 알려줍니다. 그러나 플랫폼과 로봇 사이에 충돌이 없으면 플랫폼은 단단해지며 (this.ctype = 'Solid';) 우리는 다시 한 번 로봇을 찾지 만 이제 플랫폼 위의 한 픽셀이 됩니다. 픽셀 완벽한 충돌이 있으므로 한 픽셀이면 충분합니다.
스스로!
수직으로 움직이는 플랫폼을 추가하십시오! 그리고 그들이 로봇을 짓밟 지 않도록 하십시오. ?
그게 다야!
아휴! 꽤 긴 튜토리얼이었습니다. 그래도 개선의 여지가 많습니다.
이 게임을 개선하는 방법은 다음과 같습니다.
참고 사항
코드의 새로운 기능이 레벨에 어떻게 점진적으로 나타나는지 보세요! 이것은 플레이어에게 새로운 것을 소개하는 좋은 방법이기도 합니다. 한 번에 하나의 새로운 개념을 제공하지만 점점 어려워지는 이전 개념을 보존하십시오. Comigo의 레벨 디자인에 대한 전문가 팁이었습니다 ?
등록된 댓글이 없습니다.