First commit

Add simple player movement with a finite state machine.
Add enemy that can move to target point.
Add ground through a tilemap and wall that player and enemy cannot
cross.
This commit is contained in:
Mathilde Grapin 2023-06-11 23:38:54 +02:00
commit 7038d29d87
34 changed files with 883 additions and 0 deletions

36
scripts/enemy.gd Normal file
View file

@ -0,0 +1,36 @@
extends CharacterBody2D
@onready var tile_map: TileMap = get_parent()
@onready var animation_player = $AnimationPlayer
@export var speed = 80
var y_spawn_offset = -8
var is_moving = false
var destination: Vector2 = Vector2.ZERO
func _ready():
var spawn_cell: Vector2i = tile_map.get_top_spawn_cell()
position = tile_map.map_to_local(spawn_cell)
position.y += y_spawn_offset
func _process(_delta):
if is_moving:
animation_player.play("walk")
else:
animation_player.stop()
func _physics_process(delta):
move_to_rand_cell(delta)
func move_to_rand_cell(delta):
if !is_moving:
var rand_cell: Vector2i = tile_map.get_random_top_cell()
tile_map.set_cell(0, Vector2i(rand_cell.x, rand_cell.y), 1, Vector2i(0, 0), 0) # debug purpose
destination = tile_map.map_to_local(rand_cell)
destination.y += y_spawn_offset
is_moving = true
position = position.move_toward(destination, delta * speed)
if position == destination:
is_moving = false

13
scripts/player.gd Normal file
View file

@ -0,0 +1,13 @@
class_name Player
extends CharacterBody2D
@export var speed = 120
var y_spawn_offset = -8
@onready var animation_player = $AnimationPlayer
@onready var sprite = $Sprite2D
@onready var tile_map: TileMap = get_parent()
func _ready():
var spawn_cell: Vector2i = tile_map.get_bottom_spawn_cell()
position = tile_map.map_to_local(spawn_cell)
position.y += y_spawn_offset

View file

@ -0,0 +1,13 @@
class_name PlayerIdleState
extends PlayerState
func enter(_msg := {}):
player.velocity = Vector2.ZERO
player.animation_player.play("idle")
func update(_delta):
if get_input_direction() != Vector2.ZERO:
state_machine.transition_to("Walk")
func get_input_direction():
return Input.get_vector("move_left", "move_right", "move_up", "move_down")

9
scripts/player_state.gd Normal file
View file

@ -0,0 +1,9 @@
class_name PlayerState
extends State
var player: Player
func _ready():
await owner.ready
player = owner as Player
assert(player != null)

View file

@ -0,0 +1,24 @@
class_name PlayerWalkState
extends PlayerState
func enter(_msg := {}):
player.animation_player.play("walk")
func physics_update(_delta):
var direction = get_input_direction()
player.velocity = direction * player.speed
player.move_and_slide() # this method calculate with delta, we dont need to do it
if player.velocity == Vector2.ZERO:
state_machine.transition_to("Idle")
func get_input_direction():
var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
if Input.is_action_pressed("move_left"):
player.sprite.flip_h = true
elif Input.is_action_pressed("move_right"):
player.sprite.flip_h = false
return direction

19
scripts/state.gd Normal file
View file

@ -0,0 +1,19 @@
class_name State
extends Node
var state_machine = null
func handle_input(_event: InputEvent):
pass
func update(_delta: float):
pass
func physics_update(_delta: float):
pass
func enter(_msg: Dictionary = {}):
pass
func exit():
pass

34
scripts/state_machine.gd Normal file
View file

@ -0,0 +1,34 @@
class_name StateMachine
extends Node
signal transitioned(state_name)
@export var state: State
func _ready():
await owner.ready
for child in get_children():
child.state_machine = self
state.enter()
func _unhandled_input(event):
state.handle_input(event)
func _process(delta):
state.update(delta)
func _physics_process(delta):
state.physics_update(delta)
func transition_to(target_state_name: String, msg: Dictionary = {}):
if not has_node(target_state_name):
push_warning("No state with name " + target_state_name)
return
state.exit()
state = get_node(target_state_name)
state.enter(msg)
emit_signal("transitioned", state.name)

38
scripts/tile_map.gd Normal file
View file

@ -0,0 +1,38 @@
extends TileMap
@export var map_width = 13 # keep to a odd value
@export var map_height = 19 # keep to a odd value
func _ready():
draw_map()
func draw_map():
draw_ground()
draw_separation()
get_random_top_cell()
func draw_ground():
for x in range(map_width):
for y in range(map_height):
set_cell(0, Vector2i(x, y), 0, Vector2i(0, 0), 0)
# The tilemap is initially divided in two section
# One for the player (bottom section)
# One for the enemy (top section)
func draw_separation():
var middle_height = floor(map_height / 2.0)
for x in range(map_width):
set_cell(1, Vector2i(x - 1, middle_height - 1), 1, Vector2i(0, 0), 0) # why have we to add -1?
func get_top_spawn_cell() -> Vector2i:
return Vector2i(floor(map_width / 2.0), 1)
func get_bottom_spawn_cell() -> Vector2i:
return Vector2i(floor(map_width / 2.0), map_height - 2)
func get_random_top_cell() -> Vector2i:
var middle_height = floor(map_height / 2.0)
var rand_width = randi_range(0, map_width - 1)
var rand_height = randi_range(0, middle_height - 1)
#set_cell(0, Vector2i(rand_width, rand_height), 1, Vector2i(0, 0), 0)
return Vector2i(rand_width, rand_height)