따라해야할 양이 많다보니 포스팅이 친절하지 못한점 양해바랍니다.^^;;
그럼 시작하겠습니다.
1. 프로젝트 세팅
- platformer폴더 생성 후 assets폴더를 복사해 넣습니다.
- assets 폴더에 이미지 등 소스 추가
- src 폴더 추가
2. Player 생성
- kinematicbody2D 추가
- Player로 변경
- CollisionShape2D추가 ->Rectangle shape 설정
- Player 이미지를 끌어오면 자동으로 sprite node가 추가되며 이름은 player로 설정됨
- magnetic을 클릭하여 snap 활성화
- pixel snap을 활성화하여 맨 바닥이 0에 오도록 설정
- Collisionshape2D의 크기 조정(캐릭터 이미지보다 약간 작도록 설정, 단 바닥은 0에 닿도록 함)
- Player Scene을 src/Actors폴더 안에 저장
- Player node에 script 추가(Empty template로 설정하여 추가)
- File menu에서 script 추가하여 Actor.gd(palyer와 enemy가 공유할 base script)를 추가 (player.gd는 현 단계에서는 필요 없음.
------Actor.gd script 1단계-------
extends KinematicBody2D
class_name Actor
const FLOOR_NORMAL: = Vector2.UP #플로어에 있는지에 관한 정보
export var speed: = Vector2(300.0, 1000.0)
export var gravity: = 3000.0
var velocity: = Vector2.ZERO
func _physics_process(delta:float) ->void: #매 프레임마다 수행
velocity.y += gravity * delta
#나중에 추가: velocity.y = max(velocity.y, speed.y) //if(velocity.y >speed.y){velocity.y=speed.y}
velocity = move_and_slide(velocity) #Player 스크립트로 이동
3. Level 생성(2D Node: LevelTemplate) 및 저장
- Tilemap 추가, Tileset 추가(미리 저장된 것 불러오기, 새로 생성하여 사용 가능)
- wall, floor 생성. 적당히 생성 후 Player를 불러와서 실행해본다.
4. 레이서 설정(Editor > Project Settings > 2D Physics)
- 설정의 2d physics 로 가서 Level 설정 추가(어떤 레벨과 반응하는지..충돌 등, 씬 안에있는 instance의 세팅을 변경할 경우 해당 instance만 변경되므로, 해당 씬을 수정해야함)
- Layer Names - 2D Physics
- Layer1: player
- Layer2: enemies
- Layer3: coins
- Layer4: world
-Tilemap: Layer-world, Mask-none
-Player:
예를 들면 TileMap같은 경우에는 Collision > Layer 메뉴의 ... 버튼에서 어떤 레이어인지 직접 지정해줄 수 있다. (마스크는 제외해줘야 함)
Player는 우선 4번 (world)를 마스크해서 감지하도록 해야함.
5. Project Setting - Input Map
-move_left (A, Left, Devide 0(Stick Left)
-move_right(D, Right, Device 0(Stick Right)
-jump(W, Up, Device 0(PS Cross, xBox A nintendo B)
--------Player.gd script----------
- 1단계 : 키 인식 확인용
extends Actor
func _physics_process(delta: float) -> void:
var direction: = Vector2(
Input.get_action_strength("move_right") -
Input.get_action_strength("move_left"),
1.0
)
velocity = speed * direction
velocity = move_and_slide(velocity)
- 최종 -
extends Actor
export var stomp_impulse: = 1000
func _on_EnemyDetector_area_entered(area: Area2D) ->void:
_velocity = calculate_stomp_velocity(_velocity, stomp_impulse) #enemy를 밟을때 충격으로 튀어오르는 기능
func _on_EnemyDetector_body_entered(body: PhysicsBody2D) -> void: #enemy와 부딛혔을 때 죽는 기능
queue_free()
#1단계
func _physics_process(delta: float)->void:
var is_jump_interrupted: = Input.is_action_just_released("jump") and velocity.y <0.0 #현재 점프상태가 끝나면 jump도 짧게 끝남. 키 누르는 시간에 비례하도록)
direction: = get_direction()
velocity = calculate_move_velocity(velocity, direction, speed, is_jump_interrupted)
velocity = move_and_slide(velocity, FLOOR_NORMAL) #현재 player가 frame 밖에 있으므로 안쪽으로 옮겨준 뒤 실행가능
#1단계
func get_direction() -> Vector2:
return Vector2(
Input.get_action_strength("move_right")-Input.get_action_strength("move_left"), -1.0 if Input.is_action_just_pressed("jump") and is_on_floor() else 1.0) #벽에서 점프한 경우에만 y 방향을 -1로 설정하고, 그 외에는 1로 설정함
#1단계
func calculate_move_velocity(
linear_velocity: Vector2,
direction: Vector2,
speed: Vector2
is_jump_interrupted: bool
) ->Vector2:
var new_velocity: = linear_velocity
new_velocity.x = speed.x * direction.x
new_velocity.y += gravity * get_physics_process_delta_time() //delta값을 호출해줌
if direction.y == -1.0:
new_velocity.y = speed.y * direction.y
if is_jump_interrupted:
new_velocity.y = 0.0
return new_velocity
func calculate_stomp_velocity(linear_velocity: vector2, impulse: float) -> Vector2:
var out: = linear_velocity
out.y = -impulse
return out
- player와 enemy속도 차이를 위해 player 600 설정
- Jump 함수 추가(방향함수를 추가하여 가독성 향상)
- Jump 함수에 FLOOR_NORMAL 상수를 추가로 전달하여야 JUMP가 가능함
- new_velocity 변수 일괄 변경: 선택-> Ctrl+R(대체)->out
- Ctrl+Shift+F: 파일 전체(전체프로젝트)에서 찾기: velocity찾기->whole word체크(전체일치)->replace->_velocity 로 변경(private:해당 script/class에서만 쓸 수 있음)
6. Enemy
- Player.tscn -> duplicate: 이름 변경 to Enemy, sprite 이름 enemy
- enemy.png를 sprite texture에 놓는다.
- Collisionshape2D 사이즈 변경
- extend script - actor.gd - enemy.gd생성
- layer를 enemy layer로, mask를 player/world로
<enemy.gd 스크립트>
extends "res://src/Actors/Actor.gd"
func _ready() ->void:
set_physices_process(false) #enemy가 밖에 있을 때 작동하지 않도록 하는 기능
_velocity.x = -speed.x
func _on_StompDetector_body_entered(body:
PhysicsBody2D) ->void:
if body.global_positioy.y < get_node("StompDetector").global_position.y:
return
get_node("CollisionShape2D").disabled = true # 죽이고도 내가 또 죽는 오류를 방지
queue_free() # 적 삭제
func _physics_process(delta: float) ->void: #1단계
_velocity.y +=gravity * delta
if is_on_wall(): #1단계
_velocity.x *= -1.0 #1단계
_velocity.y = move_and_slice(_velocity, FLOOR_NORMAL).y #1단계
- Frame 밖에 있을 때는 작동하지 않도록 하는 기능 ( 노드 추가: VisibilityEnabler2D )
- physics Process Par: on, process parent: on
- "physics Process Par: on" 옵션은 화면 밖으로 나가는 것에대해서만 Trigger역할을 합니다. 즉, 이미 오른쪽 밖에서 안으로 이동하는 녀석에 대해서는 작동하지 않습니다. 계속 왼쪽 (화면 안쪽)으로 이동합니다. 따라서 추가 함수가 필요합니다.
func _ready() ->void:
set_physices_process(false) #enemy가 이미 밖에 있을 때도 작동하지 않도록 하는 기능
_velocity.x = -speed.x
- Frame Trigger box 사이즈/위치 조절(-50, -50, 100, 60)
- Enemy에 Area2D 노드 추가(StompDetector로 이름 변경)
- Layer 체크 삭제
- Monitorable: off
- CollisionShape2D 노드 추가: rectangleshape/사이즈 조정
- StompDetector위치는 위로 올리고, 아래에서부터 부딛힐 때도 죽으면 안되니까..
- 내부의 CollisionShape2D는 아래로 내려서 위치를 조정한다.
- 박스 색깔을 조절한다.
- signal연결: body_entered(PhysicsBody2d)
7. 적을 밟아 제거하면 튀어오르는 모션 추가
이제 적당히 움직임이 구현되었습니다. 거기에 더해 Player 동작에 적을 밟았을 때 튀어오르는 모션을 추가해보겠습니다.
- player에 Area2D 노드 추가(EnemyDetector로 이름 변경)
- Layer: 없음, Mask: enemy
- Monitorable: off
- collisionshape2D - rectangleshape추가
- 사이즈 조절
- visibility tab에서 색깔 변경(파란색으로)
- 적 제거후 튀어오르는 애니메이션 구현 코드
8. 적과 충돌시 Player 죽는 기능 구현
- signal 연결: body_entered(PhysicsBody2D body) 적에 닿으면 죽는 기능 구현
_on_EnemyDetector_body_entered(body: PhysicsBody2D) 함수 추가
9. 적당한 시점에 Level TileMap을 수정해준다.
10. 카메라
- Player 노드에 Camera2D 추가
- current: on으로 설정해야 카메라 뷰로 보임
- w키로 프레임 위치 상향 조정
- 카메라 이동 제한
- player - camera2D -limit의 값 수정(left: 0, top: 0)
- Drag Margin: 카메라 이동 없이 player가 움직일 수 있는 공간, left 0, right 0
- Drag Margin H/V Enabled
- Smoothing - Enabled:on, Speed:2로 카메라가 따라오는 속도를 낮춤.. 7정도로 유지
- player-right click - Editable Children - Limit Right:3600으로 해당 레벨에서만 리밋 설정 가능
11. 배경 이미지 설정
- backgraound 이미지를 Texture Rectangle로 화면 안쪽으로 끌고 들어옵니다. (TextureRect노드안에 설정)
- Layout: Full Rect정
- 맨 위로 올리면 제일 뒤쪽에 보이도록 할 수 있다.
- CanvasLayer 추가후 background 를 자식으로 추가하면, 일일이 배경을 복사해서 추가하지 않아도, 게임 진행하면서 일관되게 배경을 추력해줍니다.
- layer에 -100으로 설정
- visible Collision Shapes 체크를 끔으로써 게임에서 Collision shape들이 안보이게 하여 마무리 해 줍니다.
'Programming > Godot' 카테고리의 다른 글
Godot 시작하기#2 - Mob Scene (0) | 2021.12.22 |
---|---|
Godot 시작하기#1 - 프로젝트 설정 및 Player Scene (0) | 2021.12.22 |
고도 엔진 횡스크롤 게임 예제 (Godot Platformer) - 3 (0) | 2020.01.29 |
고도 엔진 횡스크롤 게임 예제 (Godot Platformer) - 2 (0) | 2020.01.29 |
고도 엔진 횡스크롤 게임 예제 시작하기 (Godot Platformer) (0) | 2020.01.29 |