149 lines
5.4 KiB
GDScript
149 lines
5.4 KiB
GDScript
class_name OperatorGallery
|
|||
|
|
extends PanelContainer
|
||
|
|
|
||
|
|
var ui: GameUI
|
||
|
|
var viewport := SubViewport.new()
|
||
|
|
var world := Node3D.new()
|
||
|
|
var model: ImportedOperator
|
||
|
|
var camera := Camera3D.new()
|
||
|
|
var clips := OptionButton.new()
|
||
|
|
var scrub := HSlider.new()
|
||
|
|
var status := Label.new()
|
||
|
|
var playing := true
|
||
|
|
var elapsed := 0.0
|
||
|
|
var selected := "steve"
|
||
|
|
var yaw := 0.0
|
||
|
|
var distance := 2.5
|
||
|
|
|
||
|
|
func _ready() -> void:
|
||
|
|
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||
|
|
var background := StyleBoxFlat.new()
|
||
|
|
background.bg_color = Color("101820")
|
||
|
|
add_theme_stylebox_override("panel", background)
|
||
|
|
var margin := MarginContainer.new()
|
||
|
|
for side: String in ["left", "right", "top", "bottom"]: margin.add_theme_constant_override("margin_" + side, 24)
|
||
|
|
add_child(margin)
|
||
|
|
var column := VBoxContainer.new()
|
||
|
|
column.add_theme_constant_override("separation", 12)
|
||
|
|
margin.add_child(column)
|
||
|
|
var title := Label.new()
|
||
|
|
title.text = "OPERATOR / ANIMATIONSSTUDIO"
|
||
|
|
title.add_theme_font_size_override("font_size", 28)
|
||
|
|
column.add_child(title)
|
||
|
|
var row := HBoxContainer.new()
|
||
|
|
column.add_child(row)
|
||
|
|
var select := OptionButton.new()
|
||
|
|
select.add_item("STEVE / SOLDAT")
|
||
|
|
select.add_item("GAS MASK / SWAT")
|
||
|
|
select.selected = 1 if ui.game.operator_id == "gas_mask" else 0
|
||
|
|
row.add_child(select)
|
||
|
|
select.item_selected.connect(func(index: int): select_model("gas_mask" if index == 1 else "steve"))
|
||
|
|
var equip := Button.new()
|
||
|
|
equip.text = "OPERATOR AUSRÜSTEN"
|
||
|
|
row.add_child(equip)
|
||
|
|
equip.pressed.connect(func():
|
||
|
|
ui.game.operator_id = selected
|
||
|
|
ui.preferences_changed.emit()
|
||
|
|
status.text = "Gespeichert. Dein Operator ist im nächsten Match aktiv.")
|
||
|
|
var preview := SubViewportContainer.new()
|
||
|
|
preview.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||
|
|
preview.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
|
preview.stretch = true
|
||
|
|
preview.custom_minimum_size = Vector2(300, 220)
|
||
|
|
column.add_child(preview)
|
||
|
|
viewport.own_world_3d = true
|
||
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||
|
|
viewport.msaa_3d = get_viewport().msaa_3d
|
||
|
|
preview.add_child(viewport)
|
||
|
|
viewport.add_child(world)
|
||
|
|
preview.gui_input.connect(inspect_input)
|
||
|
|
world.add_child(camera)
|
||
|
|
camera.fov = 45
|
||
|
|
camera.make_current()
|
||
|
|
var environment := WorldEnvironment.new()
|
||
|
|
environment.environment = Environment.new()
|
||
|
|
environment.environment.background_mode = Environment.BG_COLOR
|
||
|
|
environment.environment.background_color = Color("151e29")
|
||
|
|
environment.environment.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
|
||
|
|
environment.environment.ambient_light_color = Color("b4cae2")
|
||
|
|
environment.environment.ambient_light_energy = 0.75
|
||
|
|
world.add_child(environment)
|
||
|
|
var key := DirectionalLight3D.new()
|
||
|
|
key.rotation_degrees = Vector3(-35, -30, 0)
|
||
|
|
key.light_energy = 1.6
|
||
|
|
key.shadow_enabled = true
|
||
|
|
world.add_child(key)
|
||
|
|
var fill := DirectionalLight3D.new()
|
||
|
|
fill.rotation_degrees = Vector3(-20, 145, 0)
|
||
|
|
fill.light_energy = 0.8
|
||
|
|
fill.light_color = Color("8cb8ed")
|
||
|
|
world.add_child(fill)
|
||
|
|
var floor_mesh := MeshInstance3D.new()
|
||
|
|
var plane := PlaneMesh.new()
|
||
|
|
plane.size = Vector2(8, 8)
|
||
|
|
floor_mesh.mesh = plane
|
||
|
|
var mat := StandardMaterial3D.new()
|
||
|
|
mat.albedo_color = Color("283440")
|
||
|
|
mat.roughness = 0.9
|
||
|
|
floor_mesh.material_override = mat
|
||
|
|
world.add_child(floor_mesh)
|
||
|
|
select_model("gas_mask" if select.selected == 1 else "steve")
|
||
|
|
for clip: String in OperatorPose.library.get_animation_list():
|
||
|
|
clips.add_item(clip.replace("__", " / ").replace("_", " "))
|
||
|
|
clips.set_item_metadata(clips.item_count - 1, clip)
|
||
|
|
if clip == "pro_rifle__idle_aiming": clips.selected = clips.item_count - 1
|
||
|
|
clips.item_selected.connect(func(_index: int): elapsed = 0)
|
||
|
|
column.add_child(clips)
|
||
|
|
var playback := HBoxContainer.new()
|
||
|
|
column.add_child(playback)
|
||
|
|
var pause := Button.new()
|
||
|
|
pause.text = "PAUSE / PLAY"
|
||
|
|
pause.pressed.connect(func(): playing = not playing)
|
||
|
|
playback.add_child(pause)
|
||
|
|
scrub.min_value = 0
|
||
|
|
scrub.max_value = 1
|
||
|
|
scrub.step = 0.001
|
||
|
|
scrub.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
|
scrub.value_changed.connect(func(value: float):
|
||
|
|
playing = false
|
||
|
|
elapsed = value * model.pose.clip(clip_key()).length)
|
||
|
|
playback.add_child(scrub)
|
||
|
|
status.text = "%d Clips · Ziehen: drehen · Mausrad: zoomen · Zeitleiste: Einzelpose" % clips.item_count
|
||
|
|
column.add_child(status)
|
||
|
|
var back := Button.new()
|
||
|
|
back.text = "← ZURÜCK"
|
||
|
|
back.pressed.connect(ui.main_menu)
|
||
|
|
column.add_child(back)
|
||
|
|
|
||
|
|
func select_model(variant: String) -> void:
|
||
|
|
if model != null:
|
||
|
|
world.remove_child(model)
|
||
|
|
model.queue_free()
|
||
|
|
selected = variant
|
||
|
|
model = ImportedOperator.new()
|
||
|
|
world.add_child(model)
|
||
|
|
model.setup(variant)
|
||
|
|
model.weapon_mount.add_child(WeaponModels.build(ui.game.loadout))
|
||
|
|
elapsed = 0
|
||
|
|
|
||
|
|
func clip_key() -> String:
|
||
|
|
return str(clips.get_item_metadata(clips.selected)) if clips.item_count > 0 else "pro_rifle__idle_aiming"
|
||
|
|
|
||
|
|
func _process(delta: float) -> void:
|
||
|
|
if model == null: return
|
||
|
|
var key := clip_key()
|
||
|
|
var length := model.pose.clip(key).length
|
||
|
|
if playing: elapsed = fposmod(elapsed + delta, length + 0.5)
|
||
|
|
model.preview(key, minf(elapsed, length))
|
||
|
|
scrub.set_value_no_signal(minf(1, elapsed / length))
|
||
|
|
model.rotation.y = yaw
|
||
|
|
camera.position = Vector3(0.4, 1.25, -distance)
|
||
|
|
camera.look_at(Vector3(0, 0.9, 0))
|
||
|
|
|
||
|
|
func inspect_input(event: InputEvent) -> void:
|
||
|
|
if event is InputEventMouseMotion and event.button_mask & MOUSE_BUTTON_MASK_LEFT:
|
||
|
|
yaw += event.relative.x * 0.012
|
||
|
|
if event is InputEventMouseButton and event.pressed:
|
||
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_UP: distance = maxf(1.2, distance - 0.2)
|
||
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: distance = minf(5, distance + 0.2)
|