diff --git a/main.gd b/main.gd index 0219278..e410cf1 100644 --- a/main.gd +++ b/main.gd @@ -19,7 +19,13 @@ var levels: Array[PackedScene] = [ preload("res://level/level_03.tscn"), preload("res://level/level_04.tscn"), ] -var time := 0 +# TODO: screen transition to hide awkward animations lol +var time := 0: + set(new_time): + var tween := get_tree().create_tween() + var anim_time = 1 if slowmo() else 0.1 + tween.tween_property($Sun, "rotation_degrees:y", -20*new_time, anim_time) + time = new_time var advancing := false @onready var sound: AudioStreamPlayer = $Sound @@ -35,10 +41,9 @@ func _process(delta: float) -> void: $RedoButton.disabled = not hist.has_redo() $RestartButton.disabled = not hist.has_undo() $Clock.text = "T = %d" % time - $Sun.rotation_degrees.y = -10*time - if $TopLeft.is_on_screen() and $BottomRight.is_on_screen(): - return - camera.position.y += 10*delta + $SlowmoIndicator.text = "slowmo" if slowmo() else "" + if not $TopLeft.is_on_screen() or not $BottomRight.is_on_screen(): + camera.position.y += 10*delta func _input(event: InputEvent) -> void: if event.is_action_pressed("u", true, true): @@ -72,6 +77,11 @@ func redo(): func restart(): while hist.has_undo(): hist.undo() + # HACK: avoid an inconsistent visual board state + for piece in board.pieces(): + for tween in piece.tweens: + tween.kill() + piece.tween_to_target() # i think it's unintuitive to be able to redo from restart # scratch that i like that, don't clear the history # you can like replay your steps up to a point @@ -83,19 +93,12 @@ func board_step(): hist.add_undo_method(board.undo_step()) hist.add_undo_property(self, "time", time) -# TODO: OH MY GOSH OG MY GOSH OH MY GOSH -# CONSOLIDATE ALL MOVEMENT INTO APPLYING VELOCITY -# INCLUDING PLAYER MOVEMENT -# I REALLY REALLY REALLY REALLY LIKE ADDING VELOCITY WITH TIME -# NOT CHANGING OH MY GOSH THAT IS *GOOD* func step(move: Vector2i): if advancing: return if won(): advance_level() return - # the ability to wait removes some parity stuff - # but that stuff kinda sucks if move == Vector2i.ZERO: hist.create_action("wait") board_step() @@ -139,6 +142,7 @@ func advance_level(): print("level won") await get_tree().create_timer(1).timeout advancing = false + $Sun.rotation.y = 0 time = 0 level_num += 1 if level_num >= levels.size(): @@ -167,3 +171,6 @@ func audio_stream_randomizer_from_dir(dir: String) -> AudioStreamRandomizer: stream.add_stream(-1, load(dir+"/"+file_name)) file_name = hit_dir.get_next() return stream + +func slowmo() -> bool: + return Input.is_action_pressed("slowmo") diff --git a/main.tscn b/main.tscn index c9ee173..30b1114 100644 --- a/main.tscn +++ b/main.tscn @@ -24,7 +24,7 @@ albedo_color = Color(0.250136, 0.493198, 0.284902, 1) [sub_resource type="PlaneMesh" id="PlaneMesh_1bvp3"] material = SubResource("StandardMaterial3D_1bvp3") -size = Vector2(200, 200) +size = Vector2(64, 64) [node name="Main" type="Node3D"] script = ExtResource("1_ig7tw") @@ -90,6 +90,15 @@ theme_override_font_sizes/normal_font_size = 32 text = "T = 0" fit_content = true +[node name="SlowmoIndicator" type="Label" parent="."] +offset_left = 1065.0 +offset_top = 615.0 +offset_right = 1150.0 +offset_bottom = 659.0 +text = "slowmo" +horizontal_alignment = 1 +vertical_alignment = 1 + [node name="Ground" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.1, 0) mesh = SubResource("PlaneMesh_1bvp3") diff --git a/piece.gd b/piece.gd index 6fae8f3..22418ab 100644 --- a/piece.gd +++ b/piece.gd @@ -16,37 +16,45 @@ enum Type { } ## squares per second -@export_range(0.1, 50) var anim_speed := 10.0 +@export_range(0.1, 50) var anim_speed_normal := 10.0 @export_range(0.1, 50) var anim_speed_slow := 1.0 +var tweens: Array[Tween] = [] + +func anim_speed() -> float: + return anim_speed_slow if Input.is_action_pressed("slowmo") else anim_speed_normal + +func anim_time() -> float: + return 1/anim_speed() + #TODO: {un,}do_bump animation method (good visual clarity) +func pos_of_lpos(pos: Vector2i, y := 0.0) -> Vector3: + return Vector3(pos.x, y, pos.y) + +func target_pos() -> Vector3: + return pos_of_lpos(lpos, position.y) + Vector3(0.5, 0, 0.5) + +func tween_to_target(tween := create_tween()): + tween.tween_property(self, "position", target_pos(), anim_time()) + tweens.push_back(tween) + +func lpos_of_pos(pos: Vector3) -> Vector2i: + return Vector2i(int(pos.x), int(pos.z)) + ## logical position -var lpos: Vector2i: - get: - return Vector2i(int(target_pos.x), int(target_pos.z)) - set(val): - position = target_pos - start_pos = position - # we offset by 0.5 to be in the middle of the square (for easier editing) - target_pos = Vector3(val.x + 0.5, position.y, val.y + 0.5) - anim_progress = 0 +@onready var lpos := lpos_of_pos(position) ## logical velocity @export var lvel := Vector2i.ZERO @export var type: Piece.Type -@onready var start_pos := position -@onready var target_pos := position -@onready var anim_progress := 1.0 var speedometer: Label3D # TODO: much, *much* better animation is needed. ESPECIALLY if we're doing slowmo # (we're doing slowmo because it is SICK) func do_step(board: Board): - if lvel == Vector2i.ZERO: - return var move := lvel.clampi(-1, 1) var new_pos := lpos + move # ball being collided *with* gets the remainder of the momentum @@ -65,6 +73,7 @@ func do_step(board: Board): var on_ice := !!board.type_at(lpos, Piece.Type.FloorIce) if not on_ice: lvel -= move + tween_to_target() func undo_step() -> Callable: var old_pos := lpos @@ -72,35 +81,39 @@ func undo_step() -> Callable: return func(): lpos = old_pos lvel = old_vel + tween_to_target() func do_move(move: Vector2i) -> Callable: return func(): + for tween in tweens: + tween.kill() + position = target_pos() lpos += move + tween_to_target() func undo_move() -> Callable: var old_pos := lpos return func(): lpos = old_pos + tween_to_target() func do_push(move: Vector2i) -> Callable: return func(): lvel += move - anim_progress = 1 func undo_push() -> Callable: var old_vel := lvel return func(): lvel = old_vel - anim_progress = 1 # no logical effect, purely for aesthetics # (and communicating !!!! player yes) func do_bump(move: Vector2i) -> Callable: - var real_lpos := lpos return func(): - lpos += move - lpos = real_lpos - anim_progress = 0.5 + var tween := create_tween() + tween.tween_property(self, "position", target_pos() + pos_of_lpos(move)/2, anim_time()) + tween_to_target(tween) + tweens.push_back(tween) # TODO?: maybe fix? maybe the bump should be more complicated? func undo_bump(move: Vector2i) -> Callable: @@ -122,7 +135,6 @@ static func wall(pos: Vector2i) -> Piece: return WALL.instantiate().with_lpos(pos) func _ready() -> void: - anim_progress = 1 speedometer = Label3D.new() speedometer.billboard = BaseMaterial3D.BILLBOARD_ENABLED speedometer.no_depth_test = true @@ -137,14 +149,4 @@ func format_vel(vel: Vector2) -> String: return "%d,%d" % [vel.x,vel.y] func _process(delta: float) -> void: - var speed := anim_speed_slow if Input.is_action_pressed("slowmo") else anim_speed - anim_progress = min(1, anim_progress + speed*delta) - position = start_pos.lerp(target_pos, anim_progress) speedometer.text = format_vel(lvel) - -# weird hack only necessary for the soon to be gone text parser -func with_lpos(pos: Vector2i) -> Piece: - lpos = pos - lpos = pos - anim_progress = 1 - return self