The main game scene

Now it's time to bring everything we did together into a playable game scene.

Create a new scene and add a Node named Main. (The reason we are using Node instead of Node2D is because this node will be a container for handling game logic. It does not require 2D functionality itself.)

Click the Instance button (represented by a chain link icon) and select your saved Player.tscn.

../../_images/instance_scene.png

Main 의 자식으로 다음의 노드들을 추가하고, 설명대로 이름을 지으세요 (값은 초 단위입니다):

  • Timer (MobTimer 라고 이름지음) - 얼마나 자주 몹이 스폰하는지를 조절하기 위해 사용

  • Timer (ScoreTimer 라고 이름지음) - 매 초마다 점수를 증가시키기 위해 사용

  • Timer (StratTimer 라고 이름지음) - 시작하기 전에 지연시간을 주기 위해 사용

  • Position2D (StartPosition 이라고 이름지음) - 플레이어의 시작 지점을 표시하기 위해 사용

Timer마다 Wait Time 속성을 다음과 같이 설정하세요:

  • MobTimer: 0.5

  • ScoreTimer: 1

  • StartTimer: 2

그리고, StartTimer 속성의 One Shot을 "사용(On)"으로 설정하고 StartPosition 노드의 Position(240, 450) 으로 설정하세요.

몹 스폰하기

메인 노드는 새로운 몹을 스폰할 것이고 우리는 몹이 화면 모서리 아무 위치에서나 나타나도록 만들고 싶습니다. Path2D 노드를 Main의 자식으로 추가하고 MobPath라고 이름지으세요. Path2D를 선택하면 편집기 위쪽에 새로운 버튼들이 나타납니다:

../../_images/path2d_buttons.png

가운데 버튼 "점 추가(Add Point)"을 선택하고 점을 추가하기 위해 표시된 모서리를 클릭해서 경로를 그리세요. 점이 그리드에 스냅(snap)되도록 하려면 "격자 스냅 사용(Use Grid Snap)" 및 "스냅 사용(Use Snap)"이 모두 선택되어 있는지 확인하세요. 이 옵션은 "잠금(Lock)" 버튼 왼쪽에서 찾을 수 있으며, 각각 점과 교차선 옆에 자석이 있는 모양입니다.

../../_images/grid_snap_button.png

중요

시계 방향 으로 그리세요, 그렇지 않으면 몹들은 안쪽 이 아닌 바깥쪽 으로 향할 것입니다!

../../_images/draw_path2d.gif

이미지에서 4개의 점을 찍고 난 후, "곡선 닫기(Close Curve)" 버튼을 누르면 곡선이 완성됩니다.

이제 경로를 정의하기 위해 PathFollow2D 노드를 MobPath의 자식으로 추가한 후 MobSpawnLocation이라고 이름지으세요. 이 노드는 자동으로 회전하고 이동하면서 경로를 따라갈 것입니다, 그러므로 경로를 따라 임의의 위치와 방향을 선택하기 위해 이것을 사용할 수 있습니다.

씬 트리는 다음과 같아야 합니다:

../../_images/main_scene_nodes.png

메인 스크립트

Main에 스크립트를 추가합니다. 스크립트의 위에 export (PackedScene)를 사용해서 우리가 인스턴스화하길 원하는 몹 씬을 고를 수 있도록 만듭니다.

extends Node

export(PackedScene) var mob_scene
var score

We also add a call to randomize() here so that the random number generator generates different random numbers each time the game is run:

func _ready():
    randomize()

Click the Main node and you will see the Mob Scene property in the Inspector under "Script Variables".

다음 두 가지 방법으로 이 속성의 값을 할당할 수 있습니다:

  • Drag Mob.tscn from the "FileSystem" dock and drop it in the Mob Scene property.

  • "[비었음]([empty])" 옆에 있는 아래쪽 화살표를 클릭하고 "불러오기(Load)"를 선택하세요. Mob.tscn을 선택하세요.

다음으로 씬(Scene) 독에서 Player 노드를 선택하고 사이드바에서 노드(Node) 독에 접근하세요. 노드(Node) 독에서 시그널(Signal) 탭을 선택하세요.

Player 노드에 대한 시그널 목록이 표시되어야 합니다. 목록에서 hit 시그널을 찾아 두 번 클릭하세요(또는 마우스 오른쪽 단추로 클릭하고 "연결...(Connect...)" 선택). 그러면 시그널 연결 대화 상자가 열립니다. 우리는 게임이 끝났을 때 일어날 일을 처리할 game_over라는 새로운 함수를 만들고 싶습니다. 신호 연결 대화 상자 아래쪽의 "받는 메서드(Receiver Method)" 상자에 "game_over"를 입력하고 "연결(Connect)"을 클릭하세요. 다음 코드를 새 함수에 추가하고 새 게임에 대한 모든 것을 설정하는 new_game 함수를 추가합니다:

func game_over():
    $ScoreTimer.stop()
    $MobTimer.stop()

func new_game():
    score = 0
    $Player.start($StartPosition.position)
    $StartTimer.start()

이제 각 Timer 노드(StartTimer, ScoreTimerMobTimer)의 timeout() 시그널을 메인 스크립트에 연결하세요. StartTimer는 다른 두 타이머를 작동시킵니다. ScoreTimer는 점수를 1씩 증가시킵니다.

func _on_ScoreTimer_timeout():
    score += 1

func _on_StartTimer_timeout():
    $MobTimer.start()
    $ScoreTimer.start()

In _on_MobTimer_timeout(), we will create a mob instance, pick a random starting location along the Path2D, and set the mob in motion. The PathFollow2D node will automatically rotate as it follows the path, so we will use that to select the mob's direction as well as its position. When we spawn a mob, we'll pick a random value between 150.0 and 250.0 for how fast each mob will move (it would be boring if they were all moving at the same speed).

새로운 인스턴스는 add_child()를 사용해야 추가할 수 있습니다.

func _on_MobTimer_timeout():
    # Create a new instance of the Mob scene.
    var mob = mob_scene.instance()

    # Choose a random location on Path2D.
    var mob_spawn_location = get_node("MobPath/MobSpawnLocation")
    mob_spawn_location.offset = randi()

    # Set the mob's direction perpendicular to the path direction.
    var direction = mob_spawn_location.rotation + PI / 2

    # Set the mob's position to a random location.
    mob.position = mob_spawn_location.position

    # Add some randomness to the direction.
    direction += rand_range(-PI / 4, PI / 4)
    mob.rotation = direction

    # Choose the velocity for the mob.
    var velocity = Vector2(rand_range(150.0, 250.0), 0.0)
    mob.linear_velocity = velocity.rotated(direction)

    # Spawn the mob by adding it to the Main scene.
    add_child(mob)

중요

Why PI? In functions requiring angles, Godot uses radians, not degrees. Pi represents a half turn in radians, about 3.1415 (there is also TAU which is equal to 2 * PI). If you're more comfortable working with degrees, you'll need to use the deg2rad() and rad2deg() functions to convert between the two.

씬 테스트하기

Let's test the scene to make sure everything is working. Add this new_game call to _ready():

func _ready():
    randomize()
    new_game()

게임이 시작될 때 자동으로 실행되는 "Main Scene"으로 Main을 지정해 보겠습니다. "재생(Play)" 버튼을 누르고 메시지가 표시되면 Main.tscn을 선택하세요.

If you had already set another scene as the "Main Scene", you can right click Main.tscn in the FileSystem dock and select "Set As Main Scene".

플레이어를 움직이고, 몹들이 스폰되는 것을 보고, 플레이어가 몹과 충돌할 때 사라지는 것을 볼 수 있어야 합니다.

모든 것이 제대로 작동한다고 확신한다면 '_ready()'에서 new_game() 함수 호출을 제거하세요.

What's our game lacking? Some user interface. In the next lesson, we'll add a title screen and display the player's score.