From c711db5d3c26264e2ce1572a4d25d2dd3c533cce Mon Sep 17 00:00:00 2001 From: Julian Murgia Date: Sun, 8 Aug 2021 12:10:20 +0200 Subject: [PATCH] Add set_angle 'immediate' parameter. (#357) * Add set_angle 'immediate' parameter. Modified fade_in transition to happen between :setup and :ready so that :ready don't start before fade_in is finished. * docs: Automatic update of API docs * Same fixes in style and removed a useless test. Co-authored-by: StraToN --- .../core-scripts/behaviors/esc_movable.gd | 103 +++++++++++++++--- .../core-scripts/esc/commands/change_scene.gd | 10 +- .../core-scripts/esc/commands/set_angle.gd | 10 +- .../game/scenes/transitions/transition.gd | 2 +- docs/api/ESCMovable.md | 37 ++++--- docs/api/SetAngleCommand.md | 2 +- docs/api/transition.gd.md | 2 +- docs/esc.md | 2 +- game/rooms/room01/esc/room01.esc | 5 + game/rooms/room01/room01.tscn | 11 +- 10 files changed, 142 insertions(+), 42 deletions(-) diff --git a/addons/escoria-core/game/core-scripts/behaviors/esc_movable.gd b/addons/escoria-core/game/core-scripts/behaviors/esc_movable.gd index 81cb126f..a219dd0a 100644 --- a/addons/escoria-core/game/core-scripts/behaviors/esc_movable.gd +++ b/addons/escoria-core/game/core-scripts/behaviors/esc_movable.gd @@ -59,7 +59,7 @@ onready var task = MovableTask.NONE # the destination position was reached func _ready() -> void: parent.add_user_signal("arrived") - + # Main processing loop # @@ -70,8 +70,7 @@ func _process(delta: float) -> void: if Engine.is_editor_hint(): return - if task == MovableTask.WALK or \ - task == MovableTask.SLIDE: + if task == MovableTask.WALK or task == MovableTask.SLIDE: var pos = parent.get_position() var old_pos = pos var next @@ -247,7 +246,9 @@ func walk_stop(pos: Vector2) -> void: ) pose_scale = -1 if parent.animations.idles[orientation].mirrored else 1 else: - parent.animation_sprite.play(parent.animations.idles[last_dir].animation) + parent.animation_sprite.play( + parent.animations.idles[last_dir].animation + ) pose_scale = -1 if parent.animations.idles[last_dir].mirrored else 1 update_terrain() @@ -351,7 +352,10 @@ func _get_dir_deg(deg: int, animations: ESCAnimationResource) -> int: # - direction_angle: ESCDirectionAngle resource, containing the starting angle, # and the size of interval # eg: angle_start=90, angle_size=40 corresponds to angle between 90° and 130° -func is_angle_in_interval(angle: float, direction_angle: ESCDirectionAngle) -> bool: +func is_angle_in_interval( + angle: float, + direction_angle: ESCDirectionAngle +) -> bool: angle = wrapi(angle, 0, 360) if angle == 0: angle = 360 @@ -379,8 +383,8 @@ func is_angle_in_interval(angle: float, direction_angle: ESCDirectionAngle) -> b # # - deg int angle to set the character # - immediate -# If true, direction is switched immediately. Else, successive animations are -# used so that the character turns to target angle. +# If true, direction is switched immediately. Else, successive +# animations are used so that the character turns to target angle. func set_angle(deg: int, immediate = true) -> void: if deg < 0 or deg > 360: escoria.logger.report_errors( @@ -388,18 +392,87 @@ func set_angle(deg: int, immediate = true) -> void: ["Invalid degree to turn to " + str(deg)] ) moved = true - last_deg = deg - last_dir = _get_dir_deg(deg, parent.animations) + + if immediate: + last_deg = deg + last_dir = _get_dir_deg(deg, parent.animations) - # The character may have a state animation from before, which would be - # resumed, so we immediately force the correct idle animation - if parent.animation_sprite.animation != \ - parent.animations.idles[last_dir].animation: - parent.animation_sprite.play(parent.animations.idles[last_dir].animation) - pose_scale = -1 if parent.animations.idles[last_dir].mirrored else 1 + # The character may have a state animation from before, which would be + # resumed, so we immediately force the correct idle animation + if parent.animation_sprite.animation != \ + parent.animations.idles[last_dir].animation: + parent.animation_sprite.play( + parent.animations.idles[last_dir].animation + ) + pose_scale = -1 if parent.animations.idles[last_dir].mirrored else 1 + else: + var current_dir = last_dir + last_deg = deg + var target_dir = _get_dir_deg(deg, parent.animations) + + var way_to_turn = get_shortest_way_to_dir(current_dir, target_dir) + + var dir = current_dir + while dir != target_dir: + dir += way_to_turn + if dir >= parent.animations.dir_angles.size(): + dir = 0 + if dir < 0: + dir = parent.animations.dir_angles.size() - 1 + + parent.animation_sprite.play( + parent.animations.idles[dir].animation + ) + yield(parent.animation_sprite, "animation_finished") + pose_scale = -1 if parent.animations.idles[dir].mirrored else 1 + update_terrain() + # Returns the angle that corresponds to the current direction of the object. func _get_angle() -> int: return parent.animations.dir_angles[last_dir].animation + + +# Return the shortest way to turn from a direction to another. Returned way is +# either: +# -1 (shortest way is to turn anti-clockwise) +# 0 (already at the right direction) +# 1 (clockwise). +# +# ####Parameters +# - current_dir: integer corresponding to the starting direction as defined in +# the attached ESCAnimationResource.directions. +# - target_dir: integer corresponding to the target direction as defined in +# the attached ESCAnimationResource.directions. +# +# *Returns* +# Integer: -1 (anti-clockwise), 1 (clockwise) or 0 (no movement needed). +func get_shortest_way_to_dir(current_dir: int, target_dir: int) -> int: + if current_dir < 0 or current_dir > parent.animations.dir_angles.size() - 1: + escoria.logger.report_errors( + "esc_movable.gd:get_shortest_way_to_dir()", + ["Invalid direction (current_dir) %s" % str(current_dir)] + ) + if target_dir < 0 or target_dir > parent.animations.dir_angles.size() - 1: + escoria.logger.report_errors( + "esc_movable.gd:get_shortest_way_to_dir()", + ["Invalid direction (target_dir) %s " % str(target_dir)] + ) + + if current_dir == target_dir: + return 0 + + var internal = false + if max(current_dir, target_dir) - min(current_dir, target_dir) \ + < parent.animations.dir_angles.size() / 2: + internal = true + else: + internal = false + + if internal and current_dir < target_dir or \ + (not internal and current_dir > target_dir): + return 1 + else: + return -1 diff --git a/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd b/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd index 71ffc151..43504541 100644 --- a/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd +++ b/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd @@ -92,7 +92,7 @@ func run(command_params: Array) -> int: var script = escoria.esc_compiler.load_esc_file( room_scene.esc_script ) - + if script.events.has("setup"): escoria.event_manager.queue_event(script.events["setup"]) var rc = yield(escoria.event_manager, "event_finished") @@ -100,7 +100,10 @@ func run(command_params: Array) -> int: rc = yield(escoria.event_manager, "event_finished") if rc[0] != ESCExecution.RC_OK: return rc[0] - + + escoria.main.scene_transition.fade_in() + yield(escoria.main.scene_transition, "transition_done") + # If scene was never visited, add "ready" event to the events stack if not command_params[0] in self.readied_scenes \ and script.events.has("ready"): @@ -111,9 +114,6 @@ func run(command_params: Array) -> int: if rc[0] != ESCExecution.RC_OK: return rc[0] - escoria.main.scene_transition.fade_in() - yield(escoria.main.scene_transition, "transition_done") - self.readied_scenes.append(command_params[0]) # Clear queued resources diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd index 28fd2f6c..9a210111 100644 --- a/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd +++ b/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd @@ -1,4 +1,4 @@ -# `set_angle object degrees` +# `set_angle object degrees [immediate]` # # Turns object to a degrees angle without animations. 0 sets object facing # forward, 90 sets it 90 degrees clockwise ("east") etc. When turning to the @@ -16,8 +16,8 @@ class_name SetAngleCommand func configure() -> ESCCommandArgumentDescriptor: return ESCCommandArgumentDescriptor.new( 2, - [TYPE_STRING, TYPE_INT], - [null, null] + [TYPE_STRING, TYPE_INT, TYPE_BOOL], + [null, null, true] ) @@ -36,10 +36,12 @@ func validate(arguments: Array): # Run the command func run(command_params: Array) -> int: + var immediate = command_params[2] + # HACK Countering the fact that angle_to_point() function gives # angle against X axis not Y, we need to check direction using (angle-90°). # Since the ESC command already gives the right angle, we add 90. escoria.object_manager.get_object(command_params[0]).node\ - .set_angle(wrapi(int(command_params[1]) + 90, 0, 360)) + .set_angle(wrapi(int(command_params[1]) + 90, 0, 360), immediate) return ESCExecution.RC_OK diff --git a/addons/escoria-core/game/scenes/transitions/transition.gd b/addons/escoria-core/game/scenes/transitions/transition.gd index 6ef59579..3df22249 100644 --- a/addons/escoria-core/game/scenes/transitions/transition.gd +++ b/addons/escoria-core/game/scenes/transitions/transition.gd @@ -2,7 +2,7 @@ extends ColorRect -# Emitted when the transition was player +# Emitted when the transition was played signal transition_done diff --git a/docs/api/ESCMovable.md b/docs/api/ESCMovable.md index bcb2551a..34298b63 100644 --- a/docs/api/ESCMovable.md +++ b/docs/api/ESCMovable.md @@ -181,20 +181,10 @@ Update the sprite scale and lighting func is_angle_in_interval(angle: float, direction_angle: ESCDirectionAngle) -> bool ``` -Returns true if given angle is inside the interval given by a starting_angle -and the size. - -#### Parameters - -- angle: Angle to test -- direction_angle: ESCDirectionAngle resource, containing the starting angle, - and the size of interval -eg: angle_start=90, angle_size=40 corresponds to angle between 90° and 130° - ### set\_angle ```gdscript -func set_angle(deg: int, immediate = true) -> void +func set_angle(deg: int, immediate = true) -> var ``` Sets character's angle and plays according animation. @@ -203,5 +193,26 @@ Sets character's angle and plays according animation. - deg int angle to set the character - immediate - If true, direction is switched immediately. Else, successive animations are - used so that the character turns to target angle. \ No newline at end of file + If true, direction is switched immediately. Else, successive + animations are used so that the character turns to target angle. + +### get\_shortest\_way\_to\_dir + +```gdscript +func get_shortest_way_to_dir(current_dir: int, target_dir: int) -> int +``` + + Return the shortest way to turn from a direction to another. Returned way is +either: +-1 (shortest way is to turn anti-clockwise) +0 (already at the right direction) +1 (clockwise). + +####Parameters +- current_dir: integer corresponding to the starting direction as defined in +the attached ESCAnimationResource.directions. +- target_dir: integer corresponding to the target direction as defined in +the attached ESCAnimationResource.directions. + +*Returns* +Integer: -1 (anti-clockwise), 1 (clockwise) or 0 (no movement needed). \ No newline at end of file diff --git a/docs/api/SetAngleCommand.md b/docs/api/SetAngleCommand.md index 3082ff3a..9f23bdd3 100644 --- a/docs/api/SetAngleCommand.md +++ b/docs/api/SetAngleCommand.md @@ -6,7 +6,7 @@ ## Description -`set_angle object degrees` +`set_angle object degrees [immediate]` Turns object to a degrees angle without animations. 0 sets object facing forward, 90 sets it 90 degrees clockwise ("east") etc. When turning to the diff --git a/docs/api/transition.gd.md b/docs/api/transition.gd.md index 6ac4a749..13a636fa 100644 --- a/docs/api/transition.gd.md +++ b/docs/api/transition.gd.md @@ -36,4 +36,4 @@ Fade in the transition ## Signals -- signal transition_done(): Emitted when the transition was player +- signal transition_done(): Emitted when the transition was played diff --git a/docs/esc.md b/docs/esc.md index d03c758f..8cbdeb20 100644 --- a/docs/esc.md +++ b/docs/esc.md @@ -266,7 +266,7 @@ event ends. Changes the "active" state of the object, value can be true or false. Inactive objects are hidden in the scene. -#### `set_angle object degrees` [API-Doc](api/SetAngleCommand.md) +#### `set_angle object degrees [immediate]` [API-Doc](api/SetAngleCommand.md) Turns object to a degrees angle without animations. 0 sets object facing forward, 90 sets it 90 degrees clockwise ("east") etc. When turning to the diff --git a/game/rooms/room01/esc/room01.esc b/game/rooms/room01/esc/room01.esc index d04b04fd..8aceeb02 100755 --- a/game/rooms/room01/esc/room01.esc +++ b/game/rooms/room01/esc/room01.esc @@ -12,4 +12,9 @@ :ready set_sound_state bg_music res://game/sfx/contemplation.ogg true + walk player r1_destination_point +wait 2 +walk player r1_destination_point2 +wait 2 +set_angle player 225 false diff --git a/game/rooms/room01/room01.tscn b/game/rooms/room01/room01.tscn index db766f70..17fb883a 100644 --- a/game/rooms/room01/room01.tscn +++ b/game/rooms/room01/room01.tscn @@ -58,6 +58,7 @@ is_exit = true tooltip_name = "Exit" default_action = "walk" dialog_color = Color( 1, 1, 1, 1 ) +animations = null [node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Hotspots/r_door"] polygon = PoolVector2Array( 1177.94, 348.61, 1175.95, 45.3759, 1276.06, 92.0953, 1277.95, 399.407 ) @@ -74,6 +75,7 @@ esc_script = "res://game/rooms/room01/esc/wall_item.esc" tooltip_name = "Item on the wall" default_action = "look" dialog_color = Color( 1, 1, 1, 1 ) +animations = null [node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Hotspots/item"] polygon = PoolVector2Array( 635.586, 253.345, 568.928, 60.1716, 709.047, 120.028, 699.524, 247.903 ) @@ -109,6 +111,7 @@ esc_script = "res://game/rooms/room01/esc/wall_item_popupdialog.esc" tooltip_name = "Item on the wall" default_action = "look" dialog_color = Color( 1, 1, 1, 1 ) +animations = null [node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Hotspots/item2"] polygon = PoolVector2Array( 635.586, 253.345, 568.928, 60.1716, 709.047, 120.028, 699.524, 247.903 ) @@ -137,7 +140,7 @@ __meta__ = { } [node name="player_start" type="Position2D" parent="."] -position = Vector2( 76.7617, 437.649 ) +position = Vector2( 653.761, 443.306 ) script = ExtResource( 7 ) global_id = "r1_start" @@ -146,3 +149,9 @@ position = Vector2( 476.984, 487.146 ) script = ExtResource( 7 ) global_id = "r1_destination_point" interaction_direction = 4 + +[node name="destination_point2" type="Position2D" parent="."] +position = Vector2( 994.586, 458.862 ) +script = ExtResource( 7 ) +global_id = "r1_destination_point2" +player_orients_on_arrival = false