From 3bd07cc437f9f91889ec503f767b86b6e78ea04c Mon Sep 17 00:00:00 2001 From: Manu Date: Tue, 27 Apr 2021 21:22:03 +0200 Subject: [PATCH] add undo feature --- Script/Level.gd | 57 +++++++++++++++++++++++++++++++----------------- Script/Player.gd | 19 +++++++++++----- project.godot | 5 +++++ 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Script/Level.gd b/Script/Level.gd index 9155326..b48cb6e 100644 --- a/Script/Level.gd +++ b/Script/Level.gd @@ -21,19 +21,37 @@ export var stairs_x := 0 export var stairs_y := 0 var completed := false -var initial_state +var saved_steps := [] + +class StepSnap: + var waste := {} + var reservoir : int + var player_position : Vector2 + var player_direction : Player.Movement + + static func snap(var l : Level) -> StepSnap: + var step = StepSnap.new() + for w in l._waste.get_used_cells(): + step.waste[w] = l._waste.get_cellv(w) + step.reservoir = l._player.reservoir + step.player_position = l._player.tile_position + step.player_direction = l._player.current_direction + return step + + func restore(var l : Level) -> void: + l._waste.clear() + for w in self.waste: + l._waste.set_cellv(w, self.waste[w]) + l._player.reservoir = self.reservoir + l._player.tile_position = self.player_position + l._player.current_direction = self.player_direction + func _ready(): _player.level = self _player.tile_position = Vector2(start_x, start_y) _stairs.visible = false _stairs.modulate = Color.white - initial_state = { - waste = {}, - reservoir = _player.reservoir - } - for w in _waste.get_used_cells(): - initial_state.waste[w] = _waste.get_cellv(w) func _process(_delta): @@ -145,6 +163,8 @@ class Tile: func dash(var direction: Vector2, var tile_limit = INF, var waste_limit = INF) -> Tile: var waste_line = get_waste_line(direction, true, tile_limit) waste_line.resize(min(waste_limit, waste_line.size())) + if not waste_line.empty(): + level.take_snap() for tile in waste_line: tile.set_tile(level._waste, -1) level.check_completed() @@ -184,29 +204,26 @@ func waste_sound(var number :int): func player_initial_position(): _player.level = self _player.tile_position = Vector2(start_x, start_y) - _player.update_position() if not Engine.editor_hint: _player.current_direction = _player.movements.back() - _player.update_animation() -func reset(): +func take_snap(): if not completed: + saved_steps.push_back(StepSnap.snap(self)) + +func undo(): + if not completed and not saved_steps.empty(): + saved_steps.pop_back().restore(self) - _waste.clear() - for w in initial_state.waste: - _waste.set_cellv(w, initial_state.waste[w]) - - player_initial_position() - - _player.reservoir = initial_state.reservoir - update_reservoir() +func reset(): + if not completed and not saved_steps.empty(): + saved_steps.front().restore(self) + saved_steps.clear() func check_player_stairs(): if get_tile_v(_player.tile_position).is_stairs(): _player.tile_position = Vector2(stairs_x - 1, stairs_y - 2) _player.current_direction = _player.movements.back() - _player.update_position() - _player.update_animation() func end_of_level(): _player.visible = false diff --git a/Script/Player.gd b/Script/Player.gd index 1a873ac..93a5fab 100644 --- a/Script/Player.gd +++ b/Script/Player.gd @@ -12,7 +12,7 @@ var level onready var footsteps = $FootSteps onready var deny = $Deny -var tile_position := Vector2(0,0) +var tile_position := Vector2(0,0) setget update_position var last_move_time := 0.0 var step_count := 0 var stepped := false @@ -56,7 +56,7 @@ onready var sweeps = [ var movement_queue = [] var current_target = null -var current_direction : Movement = movements.back() +var current_direction : Movement = movements.back() setget update_animation onready var sprite = $AnimatedSprite as AnimatedSprite func _process(delta): @@ -64,8 +64,11 @@ func _process(delta): if Engine.editor_hint: return - if Input.is_action_pressed("reset"): + if Input.is_action_just_pressed("reset"): level.reset() + + if Input.is_action_just_pressed("undo"): + level.undo() if (last_move_time + rest) * 1000 < OS.get_ticks_msec(): for movement in movements: @@ -75,7 +78,6 @@ func _process(delta): var target = level.get_tile_v(tile_position + movement.direction) if target.can_walk(movement.direction) or target.can_push(movement.direction): movement_queue.push_back(movement) - update_animation() @@ -92,6 +94,7 @@ func _process(delta): else: tile.push(current_movement.direction) footsteps.play() + level.take_snap() if current_target != null: tile_position += current_movement.direction * delta * (speed_dash if dashing else speed) @@ -143,9 +146,13 @@ func _process(delta): deny.play() -func update_position(): +func update_position(var new_pos = false): + if new_pos is Vector2: + tile_position = new_pos position = level._floor.cell_custom_transform * (tile_position + Vector2.ONE / 2 ) -func update_animation(): +func update_animation(var new_dir = false): + if new_dir is Movement: + current_direction = new_dir sprite.animation = current_direction.animation sprite.frame = step_count % 2 + (0 if reservoir > 0 else 2) diff --git a/project.godot b/project.godot index 0551205..25b37db 100644 --- a/project.godot +++ b/project.godot @@ -105,6 +105,11 @@ reset={ , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":3,"pressure":0.0,"pressed":false,"script":null) ] } +undo={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":90,"unicode":0,"echo":false,"script":null) + ] +} [physics]