Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,14 @@ locale/translations_pot_files=PackedStringArray("res://scenes/menus/title/compon
2d_physics/layer_6="interactable"
2d_physics/layer_7="players hitbox"
2d_physics/layer_8="enemies hitbox"
2d_physics/layer_9="projectiles"
2d_physics/layer_9="repellable"
2d_physics/layer_10="non_walkable_floor"
2d_physics/layer_13="hookable"

[physics]

2d/default_gravity=0.0

[rendering]

textures/canvas_textures/default_texture_filter=0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ func _unhandled_input(_event: InputEvent) -> void:
repelling = false


func _on_air_stream_body_entered(body: Projectile) -> void:
body.got_hit(owner)
func _on_air_stream_body_entered(body: Node2D) -> void:
if body.has_method("got_repelled"):
var direction := global_position.direction_to(body.global_position)
body.got_repelled(direction)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[gd_scene format=3 uid="uid://blnnwmrypq0a6"]

[node name="CustomRepellableObjects" type="Node2D" unique_id=324172432]
30 changes: 26 additions & 4 deletions scenes/game_elements/fx/shaker/components/shaker.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ signal started
## Emitted when the target stopped shaking
signal finished

## Node that will be shaked
@export var target: CanvasItem
## Node that will be shaked. If the parent node is a CanvasItem and target isn't set,
## the parent node will be automatically assigned to this variable.
@export var target: CanvasItem:
set = _set_target

## Maximum possible value in which the position of the node might be offset.
@export_range(1.0, 100.0, 1.0, "or_greater", "or_less") var shake_intensity: float = 30.0
## How much time (in seconds) the node will be shaken.
Expand Down Expand Up @@ -43,11 +46,28 @@ var current_intensity: float = 0.0
var shake_tween: Tween


func _enter_tree() -> void:
if not target and get_parent() is CanvasItem:
target = get_parent()


func _ready() -> void:
noise.noise_type = FastNoiseLite.TYPE_PERLIN
noise.frequency = 1.0


func _set_target(new_target: CanvasItem) -> void:
target = new_target
update_configuration_warnings()


func _get_configuration_warnings() -> PackedStringArray:
var warnings: PackedStringArray
if not target:
warnings.append("Target must be set.")
return warnings


## Shake the node's position by a maximum of [param intensity] and rotation by
## a maximum of [param intensity] * 0.01 during [param time].
## When the effect finishes, [member target]'s position and rotation end up
Expand All @@ -63,8 +83,10 @@ func _ready() -> void:
func shake(intensity: float = shake_intensity, time: float = duration) -> void:
noise.seed = randi()
started.emit()
if InputHelper.device_index >= 0:
Input.start_joy_vibration(InputHelper.device_index, 0.5, 0.5, time)
if not Engine.is_editor_hint():
# Don't vibrate the joypad when using the Test button in the editor:
if InputHelper.device_index >= 0:
Input.start_joy_vibration(InputHelper.device_index, 0.5, 0.5, time)

var shaking_already_in_progress: bool = shake_tween and shake_tween.is_valid()
if shaking_already_in_progress:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,12 @@ func _on_body_entered(body: Node2D) -> void:
queue_free()


func got_hit(player: Player) -> void:
## Called from the Repel component when this body
## enters the repel area.
func got_repelled(repel_direction: Vector2) -> void:
add_small_fx()
duration_timer.start()
var hit_vector: Vector2 = player.global_position.direction_to(global_position) * hit_speed
var hit_vector: Vector2 = repel_direction * hit_speed
hit_sound.play()
animated_sprite_2d.speed_scale = 2
if _trail_particles:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
extends AnimatableBody2D

const NEIGHBORS_FOR_AXIS: Dictionary[Vector2i, TileSet.CellNeighbor] = {
Vector2i.DOWN: TileSet.CELL_NEIGHBOR_BOTTOM_SIDE,
Vector2i.LEFT: TileSet.CELL_NEIGHBOR_LEFT_SIDE,
Vector2i.UP: TileSet.CELL_NEIGHBOR_TOP_SIDE,
Vector2i.RIGHT: TileSet.CELL_NEIGHBOR_RIGHT_SIDE,
}

@export var constrain_layer: TileMapLayer

var tween: Tween

@onready var shaker: Shaker = $Shaker


func global_position_to_tile_coordinate(global_pos: Vector2) -> Vector2i:
return constrain_layer.local_to_map(constrain_layer.to_local(global_pos))


func tile_coordinate_to_global_position(coord: Vector2i) -> Vector2:
return constrain_layer.map_to_local(coord)


func _ready() -> void:
# Put this object on the grid:
var coord := global_position_to_tile_coordinate(global_position)
global_position = tile_coordinate_to_global_position(coord)


func get_closest_axis(vector: Vector2) -> Vector2i:
if abs(vector.x) > abs(vector.y):
# Closer to Horizontal (X-axis)
return Vector2i(sign(vector.x), 0)

# Closer to Vertical (Y-axis)
return Vector2i(0, sign(vector.y))


func got_repelled(direction: Vector2) -> void:
var axis := get_closest_axis(direction)
var neighbor := NEIGHBORS_FOR_AXIS[axis]
var coord := global_position_to_tile_coordinate(global_position)
assert(constrain_layer.get_cell_tile_data(coord) != null)
var new_coord := constrain_layer.get_neighbor_cell(coord, neighbor)
var data := constrain_layer.get_cell_tile_data(new_coord)

if not data:
shaker.shake()
return

if tween:
if tween.is_running():
return
tween.kill()

tween = create_tween()
tween.set_ease(Tween.EASE_OUT)
# Assuming that the tile size is square:
var new_position := position + Vector2(axis) * constrain_layer.tile_set.tile_size.x
tween.tween_property(self, "position", new_position, .2)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://c334l8qftb4fy
44 changes: 44 additions & 0 deletions scenes/game_elements/props/repellable_box/repellable_box.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[gd_scene format=3 uid="uid://dqo4d6mp4hwhi"]

[ext_resource type="Script" uid="uid://c334l8qftb4fy" path="res://scenes/game_elements/props/repellable_box/components/repellable_box.gd" id="1_c0tix"]
[ext_resource type="Texture2D" uid="uid://c7oht7wudd8wa" path="res://assets/first_party/tiles/Cliff_Tiles.png" id="2_c0tix"]
[ext_resource type="Texture2D" uid="uid://dslom0xbe1if7" path="res://assets/third_party/tiny-swords/Terrain/Ground/Shadows.png" id="2_sbite"]
[ext_resource type="Script" uid="uid://dunsvrhq42214" path="res://scenes/game_elements/fx/shaker/components/shaker.gd" id="3_2i1pw"]

[sub_resource type="AtlasTexture" id="AtlasTexture_bu3x1"]
atlas = ExtResource("2_c0tix")
region = Rect2(192, 256, 64, 128)

[sub_resource type="RectangleShape2D" id="RectangleShape2D_8dti7"]
size = Vector2(64, 64)

[node name="RepellableBox" type="AnimatableBody2D" unique_id=1805651676]
editor_description = "A repellable box that moves in a fixed grid.

This is an AnimatableBody2D so it can move in the 64x64 tiles grid (using a Tweener for animating the position).

It needs a TileMapLayer and it is constrained to the painted tiles.

But also it doesn't collide with other bodies so it doesn't stop!"
collision_layer = 768
collision_mask = 531
script = ExtResource("1_c0tix")

[node name="Sprite2D2" type="Sprite2D" parent="." unique_id=1393129317]
texture = ExtResource("2_sbite")

[node name="Sprite2D" type="Sprite2D" parent="." unique_id=898668959]
position = Vector2(0, -32)
texture = SubResource("AtlasTexture_bu3x1")

[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=363689712]
rotation = -1.5707964
shape = SubResource("RectangleShape2D_8dti7")

[node name="Shaker" type="Node2D" parent="." unique_id=103380831 node_paths=PackedStringArray("target")]
script = ExtResource("3_2i1pw")
target = NodePath("..")
shake_intensity = 60.0
duration = 0.5
frequency = 30.0
metadata/_custom_type_script = "uid://dunsvrhq42214"
2 changes: 1 addition & 1 deletion scenes/globals/enums.gd
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ enum CollisionLayers {
INTERACTABLE = 6,
PLAYERS_HITBOX = 7,
ENEMIES_HITBOX = 8,
PROJECTILES = 9,
REPELLABLE = 9,
NON_WALKABLE_FLOOR = 10,
HOOKABLE = 13,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func _physics_process(_delta: float) -> void:
_is_sliding = false


func got_hit(player: Player) -> void:
func got_repelled(_direction: Vector2) -> void:
if _is_disabled:
return

Expand Down Expand Up @@ -123,13 +123,13 @@ func _configure_disabled_collision_layers() -> void:
set_collision_mask_value(Enums.CollisionLayers.PLAYERS_HITBOX, false)

# Change from PROJECTILES to NON_WALKABLE_FLOOR layer
set_collision_layer_value(Enums.CollisionLayers.PROJECTILES, false)
set_collision_layer_value(Enums.CollisionLayers.REPELLABLE, false)
set_collision_layer_value(Enums.CollisionLayers.NON_WALKABLE_FLOOR, true)

# Enable collisions with environment and entities
set_collision_mask_value(Enums.CollisionLayers.WALLS, true)
set_collision_mask_value(Enums.CollisionLayers.PLAYERS, true)
set_collision_mask_value(Enums.CollisionLayers.PROJECTILES, true)
set_collision_mask_value(Enums.CollisionLayers.REPELLABLE, true)
set_collision_mask_value(Enums.CollisionLayers.NON_WALKABLE_FLOOR, true)
set_collision_mask_value(Enums.CollisionLayers.ENEMIES_HITBOX, false)

Expand Down
Loading
Loading