class_name Piece extends MeshInstance3D const WALL = preload("res://model/wall.tres") const GOAL = preload("res://model/goal.tres") const BALL = preload("res://model/ball.tres") const PLAYER = preload("res://model/player.tres") const FLOOR_ICE = preload("res://model/floor_ice.tres") enum Type { Wall, Goal, Ball, Player, FloorIce, } # idea: SLOW MO KEY!!!!!!!!!!!!!!! ## squares per second @export_range(0.1, 50) var anim_speed := 10.0 @export_range(0.1, 50) var anim_speed_slow := 2.0 ## logical position @export var lpos: Vector2i: get: return lpos set(val): lpos = val position = target_pos start_pos = position target_pos = Vector3(lpos.x, position.y, lpos.y) anim_progress = 0 ## 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: this is *complex*, transfer momentum and stuff func do_step(board: Board): if lvel == Vector2i.ZERO: return if board.solid_at(lpos + lvel.clampi(-1, 1)): lpos = lpos lvel -= lvel.clampi(-1, 1) return lpos += lvel.clampi(-1, 1) var on_ice := !!board.type_at(lpos, Piece.Type.FloorIce) if not on_ice: lvel -= lvel.clampi(-1, 1) func undo_step() -> Callable: var old_pos := lpos var old_vel := lvel return func(): lpos = old_pos lvel = old_vel func do_move(move: Vector2i) -> Callable: return func(): lpos += move func undo_move() -> Callable: var old_pos := lpos return func(): lpos = old_pos 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 static func make(lpos: Vector2i, type: Piece.Type, mesh: Mesh) -> Piece: var piece := Piece.new() piece.lpos = lpos piece.mesh = mesh piece.type = type return piece static func wall(lpos: Vector2i) -> Piece: return make(lpos, Piece.Type.Wall, WALL) static func goal(lpos: Vector2i) -> Piece: return make(lpos, Piece.Type.Goal, GOAL) static func ball(lpos: Vector2i) -> Piece: return make(lpos, Piece.Type.Ball, BALL) static func player(lpos: Vector2i) -> Piece: return make(lpos, Piece.Type.Player, PLAYER) static func floor_ice(lpos: Vector2i) -> Piece: return make(lpos, Piece.Type.FloorIce, FLOOR_ICE) func _ready() -> void: lpos = lpos anim_progress = 1 speedometer = Label3D.new() speedometer.billboard = BaseMaterial3D.BILLBOARD_ENABLED speedometer.no_depth_test = true speedometer.font_size = 64 add_child(speedometer) #TODO: arrow! func format_vel(vel: Vector2) -> String: if vel.is_zero_approx(): return "" else: 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)