134 lines
3.1 KiB
GDScript
134 lines
3.1 KiB
GDScript
class_name Piece
|
|
extends MeshInstance3D
|
|
|
|
const BALL = preload("res://piece/ball.tscn")
|
|
const FLOOR_ICE = preload("res://piece/floor_ice.tscn")
|
|
const GOAL = preload("res://piece/goal.tscn")
|
|
const PLAYER = preload("res://piece/player.tscn")
|
|
const WALL = preload("res://piece/wall.tscn")
|
|
|
|
enum Type {
|
|
Wall,
|
|
Goal,
|
|
Ball,
|
|
Player,
|
|
FloorIce,
|
|
}
|
|
|
|
## 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
|
|
var lpos: Vector2i:
|
|
get:
|
|
return Vector2i(int(target_pos.x), int(target_pos.z))
|
|
set(val):
|
|
position = target_pos
|
|
start_pos = position
|
|
target_pos = Vector3(val.x, position.y, val.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
|
|
var move := lvel.clampi(-1, 1)
|
|
var new_pos := lpos + move
|
|
if board.solid_at(new_pos):
|
|
var ball := board.type_at(new_pos, Piece.Type.Ball)
|
|
if ball:
|
|
ball.do_push(lvel-move).call()
|
|
lvel = -move
|
|
else:
|
|
lpos = lpos
|
|
lvel -= move
|
|
return
|
|
lpos = new_pos
|
|
var on_ice := !!board.type_at(lpos, Piece.Type.FloorIce)
|
|
if not on_ice:
|
|
lvel -= move
|
|
|
|
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 ball(pos: Vector2i) -> Piece:
|
|
return BALL.instantiate().with_lpos(pos)
|
|
|
|
static func floor_ice(pos: Vector2i) -> Piece:
|
|
return FLOOR_ICE.instantiate().with_lpos(pos)
|
|
|
|
static func goal(pos: Vector2i) -> Piece:
|
|
return GOAL.instantiate().with_lpos(pos)
|
|
|
|
static func player(pos: Vector2i) -> Piece:
|
|
return PLAYER.instantiate().with_lpos(pos)
|
|
|
|
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
|
|
speedometer.font_size = 64
|
|
var font := SystemFont.new()
|
|
font.font_names = PackedStringArray(["monospace"])
|
|
speedometer.font = font
|
|
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)
|
|
|
|
# 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
|