Writing Multiple Scripts
This tutorial builds off the Simple Runner game introduced in Your First Extension and will introduce you to working with multiple scripts and interacting with Godot’s existing signals to teleport the player, creating an infinite runner.
Writing Multiple Scripts.tutorialHandle vertical movement
The player currently only moves along the horizontal axis, but remains in place vertically. Let’s adjust the player code to include vertical motion.
In
PlayerController.swift
, find themovementVector
computed property and update its y value to include a constant speed of one.PlayerController.swift
PlayerController-multiscript-2.swift// // PlayerController.swift // // // Created by Marquis Kurt on 7/19/23. // import SwiftGodot @Godot class PlayerController: CharacterBody2D { var acceleration: Float = 100 var friction: Double = 100 var speed: Double = 200 var movementVector: Vector2 { var movement = Vector2.zero movement.x = Float( Input.getActionStrength(action: "move_right") - Input.getActionStrength(action: "move_left")) movement.y = 1.0 return movement.normalized() } override func _physicsProcess(delta: Double) { if Engine.isEditorHint() { return } if movementVector != .zero { let acceleratedVector = Vector2(x: acceleration, y: acceleration) let acceleratedMovement = movementVector * acceleratedVector self.velocity = acceleratedMovement.limitLength(speed) } else { velocity = velocity.moveToward(to: .zero, delta: friction) } self.moveAndSlide() super._physicsProcess(delta: delta) } }
In the terminal, navigate to the SimpleRunnerDriver package and run
swift build
to build the package.Open the
.build/{arch}/debug
directory in the Finder using theopen
command, replacingarch
with your Mac’s architecture folder.Copy the
libSimpleRunnerDriver.dylib
file into thebin
directory of the SimpleRunner Godot project.Open the project in the Godot editor and open the
main.tscn
scene file.Run the project by pressing the Play button in the toolbar. The player should now be moving down the screen, past the edges of the level.
Teleport the player
Now that the player can run down the screen, let’s allow the player to teleport to the top of the level when they reach the bottom.
To do so, you will create a new node class that represents the main level logic and detect when the player has reached the bottom and teleport them to the top.
Create a new Swift file called MainLevel in the SimpleRunnerDriver package and import the SwiftGodot library.
MainLevel.swift
MainLevel-multiscript-init.swift// // MainLevel.swift // // // Created by Marquis Kurt on 7/22/23. // import SwiftGodot
Write a new
MainLevel
class that inherits fromNode2D
and has the@Godot
attributeMainLevel.swift
MainLevel-multiscript-2.swift// // MainLevel.swift // // // Created by Marquis Kurt on 7/22/23. // import SwiftGodot @Godot class MainLevel: Node2D { }
Add the
player
,spawnpoint
, andteleportArea
properties toMainLevel
, using the@SceneTree
macro to list their names in the scene tree.Note that these properties are marked optional, as they may not exist in the scene tree.
MainLevel.swift
MainLevel-multiscript-3.swift// // MainLevel.swift // // // Created by Marquis Kurt on 7/22/23. // import SwiftGodot @Godot class MainLevel: Node2D { @SceneTree(path: "CharacterBody2D") var player: PlayerController? @SceneTree(path: "Spawnpoint") var spawnpoint: Node2D? @SceneTree(path: "Telepoint") var teleportArea: Area2D? }
Create a new
teleportPlayerToTop()
method and add a guard statement to check that the player and spawn point exist.GD.pushWarning(_:)
allows us to send warning messages to Godot’s console.MainLevel.swift
MainLevel-multiscript-4.swift// // MainLevel.swift // // // Created by Marquis Kurt on 7/22/23. // import SwiftGodot @Godot class MainLevel: Node2D { @SceneTree(path: "CharacterBody2D") var player: PlayerController? @SceneTree(path: "Spawnpoint") var spawnpoint: Node2D? @SceneTree(path: "Telepoint") var teleportArea: Area2D? private func teleportPlayerToTop() { guard let player, let spawnpoint else { GD.pushWarning("Player or spawnpoint is missing.") return } } }
Set the player’s position so that their horizontal coordinate is kept, but the vertical coordinate is that of the spawn point.
This will effectively teleport the player to the top of the map, preserving where the player was on the horizontal axis.
MainLevel.swift
MainLevel-multiscript-5.swift// // MainLevel.swift // // // Created by Marquis Kurt on 7/22/23. // import SwiftGodot @Godot class MainLevel: Node2D { @SceneTree(path: "CharacterBody2D") var player: PlayerController? @SceneTree(path: "Spawnpoint") var spawnpoint: Node2D? @SceneTree(path: "Telepoint") var teleportArea: Area2D? private func teleportPlayerToTop() { guard let player, let spawnpoint else { GD.pushWarning("Player or spawnpoint is missing.") return } player.position = Vector2(x: player.position.x, y: spawnpoint.position.y) } }
In the
_ready()
method, connect the teleport area’sbodyEntered
signal method to check if the player has entered the area and teleport them when necessary.MainLevel.swift
MainLevel-multiscript-6.swift// // MainLevel.swift // // // Created by Marquis Kurt on 7/22/23. // import SwiftGodot @Godot class MainLevel: Node2D { @SceneTree(path: "CharacterBody2D") var player: PlayerController? @SceneTree(path: "Spawnpoint") var spawnpoint: Node2D? @SceneTree(path: "Telepoint") var teleportArea: Area2D? override func _ready() { teleportArea?.bodyEntered.connect { [self] enteredBody in if enteredBody.isClass("\(PlayerController.self)") { teleportPlayerToTop() } } super._ready() } private func teleportPlayerToTop() { guard let player, let spawnpoint else { GD.pushWarning("Player or spawnpoint is missing.") return } player.position = Vector2(x: player.position.x, y: spawnpoint.position.y) } }
Register the class type in
SimpleRunnerDriver.swift
to expose it to Godot.SimpleRunnerDriver.swift
SimpleRunnerDriver-multiscript-2.swift// The Swift Programming Language // https://docs.swift.org/swift-book import SwiftGodot let allNodes: [Wrapped.Type] = [PlayerController.self, MainLevel.self] #initSwiftExtension(cdecl: "swift_entry_point", types: allNodes)
Using the new main level node
Now that the main level code has been added, let’s replace the current main level node with its new instance provided by your extension.
Rebuild the extension and copy over
libSimpleRunnerDriver.dylib
as before.Open the project in the Godot editor and open the
main.tscn
scene file.Right click on the Main Level node and select Change Type.
Search for “MainLevel” and set the node’s type to the new MainLevel node you created.
If the node doesn’t appear in the search results, retry the steps for registering the class, rebuilding the extension, and re-opening Godot.
Run the project by pressing the Play button in the toolbar. The player should now be moving down the screen, teleporting to the top of the screen once the player reaches the bottom. 🎉