-
Notifications
You must be signed in to change notification settings - Fork 16
At the end of this chapter, your will be able to move pc
sprite by arrow keys.
Check out commit: 11fbf11.
Godot provides several ways to handle inputs on different levels. The topic is covered in Tutorials/Inputs. Our approach in this demo involves two steps. First register inputs with a specific name in Project Settings/Input Map
. Then respond to input events in scripts by implementing _unhandled_input()
.
Open Input Map
(official tutorial). Bind arrow keys and Vi keys (hjkl) to one of four actions: move_left
, move_right
, move_up
and move_down
.
Add PCMove
(Node2D
node) to MainScene
node. Attach PCMove.gd
to the newly created node. Add InputName.gd
to library/
folder to store action names as string constants. Inside PCMove.gd
, write code to respond to keyboard inputs by printing messages in the console window.
# InputName.gd
const MOVE_LEFT: String = "move_left"
# PCMove.gd
var _new_InputName := preload("res://library/InputName.gd").new()
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(_new_InputName.MOVE_LEFT):
print("move left")
Check out commit: fb307f1.
Moving PC involves three steps:
- Get a reference to
pc
node inPCMove.gd
. - Convert inputs to a pair of integers.
- Set PC's new position based on the two integers.
Let's solve step two first.
# PCMove.gd
func _unhandled_input(event: InputEvent) -> void:
var x: int = 0
var y: int = 0
if event.is_action_pressed(_new_InputName.MOVE_LEFT):
x -= 1
elif event.is_action_pressed(_new_InputName.MOVE_RIGHT):
x += 1
elif event.is_action_pressed(_new_InputName.MOVE_UP):
y -= 1
elif event.is_action_pressed(_new_InputName.MOVE_DOWN):
y += 1
In order to get a reference to pc
node, we can call get_tree().get_nodes_in_group("pc")[0]
. Because according to InitWorld.gd
, pc
group has only one member, that is, pc
node. However, I think this is a good chance to introduce signal
. Let InitWorld.gd
emit a signal, sprite_created
, whenever a new sprite is instanced. PCMove.gd
receives and decodes the signal and gets a reference to pc
.
# InitWorld.gd
signal sprite_created(new_sprite)
func _create_sprite(prefab: PackedScene, group: String, x: int, y: int,
x_offset: int = 0, y_offset: int = 0) -> void:
# Add this line to the end.
emit_signal("sprite_created", new_sprite)
# PCMove.gd
var _pc: Sprite
func _ready() -> void:
var __ = get_node("../InitWorld").connect("sprite_created", self,
"_on_InitWorld_sprite_created")
print("connect: {0}".format([__]))
func _unhandled_input(event: InputEvent) -> void:
print("pc: {0}".format([_pc]))
var source: Array = _new_ConvertCoord.vector_to_array(_pc.position)
var x: int = source[0]
var y: int = source[1]
if event.is_action_pressed(_new_InputName.MOVE_LEFT):
x -= 1
elif event.is_action_pressed(_new_InputName.MOVE_RIGHT):
x += 1
elif event.is_action_pressed(_new_InputName.MOVE_UP):
y -= 1
elif event.is_action_pressed(_new_InputName.MOVE_DOWN):
y += 1
_pc.position = _new_ConvertCoord.index_to_vector(x, y)
func _on_InitWorld_sprite_created(new_sprite: Sprite) -> void:
if new_sprite.is_in_group(_new_GroupName.PC):
_pc = new_sprite
When testing the game, it turns out that even though connect
returns 0, which means that sprite_created
is successfully connected with _on_InitWorld_sprite_created()
, the reference to pc
node is still null. This is due to the fact that PCMove._ready()
is called after InitWorld._ready()
. The signal is connected to the function, but it is not received even once. One possible solution is to move initialization code from InitWorld._ready()
to InitWorld._process()
.
# InitWorld.gd
var _initialized: bool = false
func _process(_delta) -> void:
if not _initialized:
_initialized = true
_init_floor()
_init_wall()
_init_dwarf()
_init_PC()
_init_indicator()
The full code at current stage is available at the start of this part. We will take another approach to this problem in the next part.