Menu, options with changeable controls, fade transition, placeholder background
This commit is contained in:
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
uid://csxxlnq74fej4
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 296 KiB |
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bxv1uuymonrp6"
|
||||||
|
path="res://.godot/imported/menu_bg.png-3906063022fa3c81090e3c663f8866b0.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/menu_bg.png"
|
||||||
|
dest_files=["res://.godot/imported/menu_bg.png-3906063022fa3c81090e3c663f8866b0.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
+252
@@ -0,0 +1,252 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://bmnmenu0intr1"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://main_menu.gd" id="1_menu"]
|
||||||
|
[ext_resource type="VideoStream" path="res://Assets/intro_bg.ogv" id="2_video"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="sb_normal"]
|
||||||
|
content_margin_left = 16.0
|
||||||
|
content_margin_top = 8.0
|
||||||
|
content_margin_right = 16.0
|
||||||
|
content_margin_bottom = 8.0
|
||||||
|
bg_color = Color(0, 0, 0, 0.4)
|
||||||
|
corner_radius_top_left = 8
|
||||||
|
corner_radius_top_right = 8
|
||||||
|
corner_radius_bottom_right = 8
|
||||||
|
corner_radius_bottom_left = 8
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="sb_hover"]
|
||||||
|
content_margin_left = 16.0
|
||||||
|
content_margin_top = 8.0
|
||||||
|
content_margin_right = 16.0
|
||||||
|
content_margin_bottom = 8.0
|
||||||
|
bg_color = Color(0, 0, 0, 0.65)
|
||||||
|
border_width_left = 2
|
||||||
|
border_width_top = 2
|
||||||
|
border_width_right = 2
|
||||||
|
border_width_bottom = 2
|
||||||
|
border_color = Color(1, 0.85, 0.2, 1)
|
||||||
|
corner_radius_top_left = 8
|
||||||
|
corner_radius_top_right = 8
|
||||||
|
corner_radius_bottom_right = 8
|
||||||
|
corner_radius_bottom_left = 8
|
||||||
|
|
||||||
|
[node name="MainMenu" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_menu")
|
||||||
|
|
||||||
|
[node name="VideoStreamPlayer" type="VideoStreamPlayer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
stream = ExtResource("2_video")
|
||||||
|
expand = true
|
||||||
|
|
||||||
|
[node name="MainPanel" type="Control" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="PlayButton" type="Button" parent="MainPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchor_left = 0.459
|
||||||
|
anchor_top = 0.449
|
||||||
|
anchor_right = 0.459
|
||||||
|
anchor_bottom = 0.449
|
||||||
|
offset_left = -120.0
|
||||||
|
offset_top = -55.0
|
||||||
|
offset_right = 120.0
|
||||||
|
offset_bottom = 55.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 8
|
||||||
|
theme_override_font_sizes/font_size = 56
|
||||||
|
theme_override_styles/normal = SubResource("sb_normal")
|
||||||
|
theme_override_styles/hover = SubResource("sb_hover")
|
||||||
|
theme_override_styles/pressed = SubResource("sb_hover")
|
||||||
|
theme_override_styles/focus = SubResource("sb_hover")
|
||||||
|
text = "PLAY"
|
||||||
|
|
||||||
|
[node name="OptionsButton" type="Button" parent="MainPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchor_left = 0.11
|
||||||
|
anchor_top = 0.94
|
||||||
|
anchor_right = 0.11
|
||||||
|
anchor_bottom = 0.94
|
||||||
|
offset_left = -100.0
|
||||||
|
offset_top = -28.0
|
||||||
|
offset_right = 100.0
|
||||||
|
offset_bottom = 28.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 6
|
||||||
|
theme_override_font_sizes/font_size = 30
|
||||||
|
theme_override_styles/normal = SubResource("sb_normal")
|
||||||
|
theme_override_styles/hover = SubResource("sb_hover")
|
||||||
|
theme_override_styles/pressed = SubResource("sb_hover")
|
||||||
|
theme_override_styles/focus = SubResource("sb_hover")
|
||||||
|
text = "OPTIONS"
|
||||||
|
|
||||||
|
[node name="CreditsButton" type="Button" parent="MainPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchor_left = 0.489
|
||||||
|
anchor_top = 0.951
|
||||||
|
anchor_right = 0.489
|
||||||
|
anchor_bottom = 0.951
|
||||||
|
offset_left = -100.0
|
||||||
|
offset_top = -28.0
|
||||||
|
offset_right = 100.0
|
||||||
|
offset_bottom = 28.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 6
|
||||||
|
theme_override_font_sizes/font_size = 30
|
||||||
|
theme_override_styles/normal = SubResource("sb_normal")
|
||||||
|
theme_override_styles/hover = SubResource("sb_hover")
|
||||||
|
theme_override_styles/pressed = SubResource("sb_hover")
|
||||||
|
theme_override_styles/focus = SubResource("sb_hover")
|
||||||
|
text = "CREDITS"
|
||||||
|
|
||||||
|
[node name="ExitButton" type="Button" parent="MainPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchor_left = 0.92
|
||||||
|
anchor_top = 0.951
|
||||||
|
anchor_right = 0.92
|
||||||
|
anchor_bottom = 0.951
|
||||||
|
offset_left = -100.0
|
||||||
|
offset_top = -28.0
|
||||||
|
offset_right = 100.0
|
||||||
|
offset_bottom = 28.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 6
|
||||||
|
theme_override_font_sizes/font_size = 30
|
||||||
|
theme_override_styles/normal = SubResource("sb_normal")
|
||||||
|
theme_override_styles/hover = SubResource("sb_hover")
|
||||||
|
theme_override_styles/pressed = SubResource("sb_hover")
|
||||||
|
theme_override_styles/focus = SubResource("sb_hover")
|
||||||
|
text = "EXIT"
|
||||||
|
|
||||||
|
[node name="OptionsPanel" type="CenterContainer" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Backdrop" type="ColorRect" parent="OptionsPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
color = Color(0, 0, 0, 0.55)
|
||||||
|
mouse_filter = 2
|
||||||
|
|
||||||
|
[node name="VBox" type="VBoxContainer" parent="OptionsPanel"]
|
||||||
|
custom_minimum_size = Vector2(560, 480)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 16
|
||||||
|
|
||||||
|
[node name="TitleLabel" type="Label" parent="OptionsPanel/VBox"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 8
|
||||||
|
theme_override_font_sizes/font_size = 44
|
||||||
|
text = "Controls"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Hint" type="Label" parent="OptionsPanel/VBox"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 4
|
||||||
|
text = "Click a key, then press a new key. Esc cancels."
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Scroll" type="ScrollContainer" parent="OptionsPanel/VBox"]
|
||||||
|
custom_minimum_size = Vector2(0, 340)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
horizontal_scroll_mode = 0
|
||||||
|
|
||||||
|
[node name="RebindList" type="VBoxContainer" parent="OptionsPanel/VBox/Scroll"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
|
||||||
|
[node name="BackButton" type="Button" parent="OptionsPanel/VBox"]
|
||||||
|
custom_minimum_size = Vector2(0, 48)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 24
|
||||||
|
text = "Back"
|
||||||
|
|
||||||
|
[node name="CreditsPanel" type="CenterContainer" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Backdrop" type="ColorRect" parent="CreditsPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
color = Color(0, 0, 0, 0.55)
|
||||||
|
mouse_filter = 2
|
||||||
|
|
||||||
|
[node name="VBox" type="VBoxContainer" parent="CreditsPanel"]
|
||||||
|
custom_minimum_size = Vector2(520, 360)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 20
|
||||||
|
|
||||||
|
[node name="TitleLabel" type="Label" parent="CreditsPanel/VBox"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 8
|
||||||
|
theme_override_font_sizes/font_size = 44
|
||||||
|
text = "Credits"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="Names" type="Label" parent="CreditsPanel/VBox"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/outline_size = 4
|
||||||
|
theme_override_font_sizes/font_size = 24
|
||||||
|
text = "Bullosseum
|
||||||
|
|
||||||
|
A game by Siim & Richard"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="BackButton" type="Button" parent="CreditsPanel/VBox"]
|
||||||
|
custom_minimum_size = Vector2(0, 48)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 24
|
||||||
|
text = "Back"
|
||||||
|
|
||||||
|
[node name="FadeRect" type="ColorRect" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
color = Color(0, 0, 0, 0)
|
||||||
+1
-7
@@ -14,7 +14,6 @@ extends Camera3D
|
|||||||
var _shake_amount: float = 0.0
|
var _shake_amount: float = 0.0
|
||||||
var _shake_decay: float = 0.0
|
var _shake_decay: float = 0.0
|
||||||
var _user_size: float = 0.0
|
var _user_size: float = 0.0
|
||||||
var _charge_active: bool = false
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@@ -34,8 +33,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
var zoom_target := _user_size * DP.f("charge_zoom_factor") if _charge_active else _user_size
|
size = lerpf(size, _user_size, delta * 8.0)
|
||||||
size = lerpf(size, zoom_target, delta * 8.0)
|
|
||||||
|
|
||||||
var angle_rad := deg_to_rad(horizontal_angle_deg)
|
var angle_rad := deg_to_rad(horizontal_angle_deg)
|
||||||
var offset := Vector3(
|
var offset := Vector3(
|
||||||
@@ -63,10 +61,6 @@ func trigger_hit(strength: float) -> void:
|
|||||||
_shake_decay = _shake_amount / 0.4
|
_shake_decay = _shake_amount / 0.4
|
||||||
|
|
||||||
|
|
||||||
func set_charge_active(active: bool) -> void:
|
|
||||||
_charge_active = active
|
|
||||||
|
|
||||||
|
|
||||||
func _update_ortho_tilt_shift_dof(target_pos: Vector3) -> void:
|
func _update_ortho_tilt_shift_dof(target_pos: Vector3) -> void:
|
||||||
var cam_attr: CameraAttributesPractical = null
|
var cam_attr: CameraAttributesPractical = null
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
## Global keybinding manager (autoload `Controls`).
|
||||||
|
## Loads saved keyboard bindings on startup and applies them to InputMap so
|
||||||
|
## rebinds made in the intro menu persist into the game scene. Only the
|
||||||
|
## keyboard event of each action is overridden; joypad/mouse events are kept.
|
||||||
|
|
||||||
|
const SAVE_PATH := "user://controls.cfg"
|
||||||
|
const SECTION := "keybinds"
|
||||||
|
|
||||||
|
## Actions the options menu lets the player rebind (keyboard only).
|
||||||
|
const REBINDABLE_ACTIONS: PackedStringArray = [
|
||||||
|
&"move_forward",
|
||||||
|
&"move_back",
|
||||||
|
&"move_left",
|
||||||
|
&"move_right",
|
||||||
|
&"charge",
|
||||||
|
&"ability_kick",
|
||||||
|
&"ability_slam",
|
||||||
|
&"ability_dash",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
load_saved()
|
||||||
|
|
||||||
|
|
||||||
|
## Returns the first keyboard event bound to an action, or null.
|
||||||
|
func get_key_event(action: StringName) -> InputEventKey:
|
||||||
|
for event: InputEvent in InputMap.action_get_events(action):
|
||||||
|
if event is InputEventKey:
|
||||||
|
return event
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
## Human-readable label for the action's current key (e.g. "W", "Space").
|
||||||
|
func get_key_label(action: StringName) -> String:
|
||||||
|
var event := get_key_event(action)
|
||||||
|
if event == null:
|
||||||
|
return "—"
|
||||||
|
return event.as_text_physical_keycode()
|
||||||
|
|
||||||
|
|
||||||
|
## Replaces the primary keyboard event of `action` with `event`, keeping
|
||||||
|
## every other event (e.g. arrow-key alternates, joypad) in its place.
|
||||||
|
func rebind(action: StringName, event: InputEventKey) -> void:
|
||||||
|
rebind_no_save(action, event)
|
||||||
|
save()
|
||||||
|
|
||||||
|
|
||||||
|
func save() -> void:
|
||||||
|
var cfg := ConfigFile.new()
|
||||||
|
for action: StringName in REBINDABLE_ACTIONS:
|
||||||
|
var event := get_key_event(action)
|
||||||
|
if event != null:
|
||||||
|
cfg.set_value(SECTION, String(action), event.physical_keycode)
|
||||||
|
cfg.save(SAVE_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
func load_saved() -> void:
|
||||||
|
var cfg := ConfigFile.new()
|
||||||
|
if cfg.load(SAVE_PATH) != OK:
|
||||||
|
return
|
||||||
|
for action: StringName in REBINDABLE_ACTIONS:
|
||||||
|
var key := String(action)
|
||||||
|
if not cfg.has_section_key(SECTION, key):
|
||||||
|
continue
|
||||||
|
var keycode: int = cfg.get_value(SECTION, key)
|
||||||
|
var event := InputEventKey.new()
|
||||||
|
event.physical_keycode = keycode as Key
|
||||||
|
rebind_no_save(action, event)
|
||||||
|
|
||||||
|
|
||||||
|
## Rebuilds the action's event list, swapping the first keyboard event for
|
||||||
|
## `event` in place so ordering (and thus the "primary" key) is preserved.
|
||||||
|
func rebind_no_save(action: StringName, event: InputEventKey) -> void:
|
||||||
|
var events := InputMap.action_get_events(action)
|
||||||
|
InputMap.action_erase_events(action)
|
||||||
|
var replaced := false
|
||||||
|
for existing: InputEvent in events:
|
||||||
|
if not replaced and existing is InputEventKey:
|
||||||
|
InputMap.action_add_event(action, event)
|
||||||
|
replaced = true
|
||||||
|
else:
|
||||||
|
InputMap.action_add_event(action, existing)
|
||||||
|
if not replaced:
|
||||||
|
InputMap.action_add_event(action, event)
|
||||||
|
|
||||||
|
|
||||||
|
func reset_defaults() -> void:
|
||||||
|
InputMap.load_from_project_settings()
|
||||||
|
if FileAccess.file_exists(SAVE_PATH):
|
||||||
|
DirAccess.remove_absolute(SAVE_PATH)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dvxx75l5re2mf
|
||||||
@@ -12,7 +12,7 @@ const _ABILITY_ICONS: Array[String] = [
|
|||||||
"res://HUD/HUD_0001_ability_SLAM.png",
|
"res://HUD/HUD_0001_ability_SLAM.png",
|
||||||
"res://HUD/HUD_0002_ability_DASH.png",
|
"res://HUD/HUD_0002_ability_DASH.png",
|
||||||
]
|
]
|
||||||
const _ABILITY_KEYS: Array[String] = ["F", "G", "H"]
|
const _ABILITY_ACTIONS: Array[StringName] = [&"ability_kick", &"ability_slam", &"ability_dash"]
|
||||||
|
|
||||||
var _controls_visible: bool = true
|
var _controls_visible: bool = true
|
||||||
var _controls_panel: PanelContainer
|
var _controls_panel: PanelContainer
|
||||||
@@ -68,6 +68,14 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
if event is InputEventKey and event.pressed and not event.echo:
|
if event is InputEventKey and event.pressed and not event.echo:
|
||||||
if event.physical_keycode == KEY_TAB:
|
if event.physical_keycode == KEY_TAB:
|
||||||
_toggle_controls()
|
_toggle_controls()
|
||||||
|
elif event.physical_keycode == KEY_ESCAPE:
|
||||||
|
_return_to_menu()
|
||||||
|
|
||||||
|
|
||||||
|
func _return_to_menu() -> void:
|
||||||
|
get_tree().paused = false
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
get_tree().change_scene_to_file("res://MainMenu.tscn")
|
||||||
|
|
||||||
|
|
||||||
func _toggle_controls() -> void:
|
func _toggle_controls() -> void:
|
||||||
@@ -208,7 +216,7 @@ func _build_ability_slot(idx: int) -> Control:
|
|||||||
_cd_labels.append(cd_lbl)
|
_cd_labels.append(cd_lbl)
|
||||||
|
|
||||||
var key_lbl := Label.new()
|
var key_lbl := Label.new()
|
||||||
key_lbl.text = _ABILITY_KEYS[idx]
|
key_lbl.text = Controls.get_key_label(_ABILITY_ACTIONS[idx])
|
||||||
key_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
key_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
key_lbl.add_theme_color_override("font_color", _GOLD)
|
key_lbl.add_theme_color_override("font_color", _GOLD)
|
||||||
key_lbl.add_theme_font_size_override("font_size", 12)
|
key_lbl.add_theme_font_size_override("font_size", 12)
|
||||||
@@ -250,15 +258,23 @@ func _build_controls_panel() -> void:
|
|||||||
vbox.add_theme_constant_override("separation", 5)
|
vbox.add_theme_constant_override("separation", 5)
|
||||||
_controls_panel.add_child(vbox)
|
_controls_panel.add_child(vbox)
|
||||||
|
|
||||||
_row(vbox, "WASD / Arrows", "Move (not intended)", _MUTED)
|
var move_keys := "%s %s %s %s" % [
|
||||||
|
Controls.get_key_label(&"move_forward"),
|
||||||
|
Controls.get_key_label(&"move_left"),
|
||||||
|
Controls.get_key_label(&"move_back"),
|
||||||
|
Controls.get_key_label(&"move_right"),
|
||||||
|
]
|
||||||
|
_row(vbox, move_keys, "Move (not intended)", _MUTED)
|
||||||
_row(vbox, "LMB (hold)", "Right horn", _CREAM)
|
_row(vbox, "LMB (hold)", "Right horn", _CREAM)
|
||||||
_row(vbox, "RMB (hold)", "Left horn", _CREAM)
|
_row(vbox, "RMB (hold)", "Left horn", _CREAM)
|
||||||
_row(vbox, "F", "Kick", _CREAM)
|
_row(vbox, Controls.get_key_label(&"charge"), "Charge", _CREAM)
|
||||||
_row(vbox, "G", "Slam", _CREAM)
|
_row(vbox, Controls.get_key_label(&"ability_kick"), "Kick", _CREAM)
|
||||||
_row(vbox, "H", "Dash", _CREAM)
|
_row(vbox, Controls.get_key_label(&"ability_slam"), "Slam", _CREAM)
|
||||||
|
_row(vbox, Controls.get_key_label(&"ability_dash"), "Dash", _CREAM)
|
||||||
_row(vbox, "Scroll", "Zoom", _CREAM)
|
_row(vbox, "Scroll", "Zoom", _CREAM)
|
||||||
_row(vbox, "R", "Respawn matadors (cooldown)", _MUTED)
|
_row(vbox, "R", "Respawn matadors (cooldown)", _MUTED)
|
||||||
_row(vbox, "Tab", "Toggle controls", _MUTED)
|
_row(vbox, "Tab", "Toggle controls", _MUTED)
|
||||||
|
_row(vbox, "Esc", "Back to menu", _MUTED)
|
||||||
|
|
||||||
var sep := HSeparator.new()
|
var sep := HSeparator.new()
|
||||||
var sep_style := StyleBoxFlat.new()
|
var sep_style := StyleBoxFlat.new()
|
||||||
|
|||||||
+147
@@ -0,0 +1,147 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
## Intro menu: Siim's arena mockup as a looping video background with an
|
||||||
|
## overlaid Play / Options / Credits / Exit UI positioned over his sketch.
|
||||||
|
## Play fades to black and loads the game; Options rebinds controls.
|
||||||
|
|
||||||
|
const GAME_SCENE := "res://scene.tscn"
|
||||||
|
const FADE_TIME := 0.6
|
||||||
|
|
||||||
|
## Friendly labels for the rebindable actions (order defines list order).
|
||||||
|
const ACTION_LABELS: Dictionary = {
|
||||||
|
&"move_forward": "Move Forward",
|
||||||
|
&"move_back": "Move Back",
|
||||||
|
&"move_left": "Move Left",
|
||||||
|
&"move_right": "Move Right",
|
||||||
|
&"charge": "Charge",
|
||||||
|
&"ability_kick": "Kick",
|
||||||
|
&"ability_slam": "Slam",
|
||||||
|
&"ability_dash": "Dash",
|
||||||
|
}
|
||||||
|
|
||||||
|
@onready var main_panel: Control = $MainPanel
|
||||||
|
@onready var options_panel: Control = $OptionsPanel
|
||||||
|
@onready var credits_panel: Control = $CreditsPanel
|
||||||
|
@onready var rebind_list: VBoxContainer = $OptionsPanel/VBox/Scroll/RebindList
|
||||||
|
@onready var fade_rect: ColorRect = $FadeRect
|
||||||
|
@onready var play_button: Button = $MainPanel/PlayButton
|
||||||
|
@onready var options_button: Button = $MainPanel/OptionsButton
|
||||||
|
@onready var credits_button: Button = $MainPanel/CreditsButton
|
||||||
|
@onready var exit_button: Button = $MainPanel/ExitButton
|
||||||
|
@onready var options_back: Button = $OptionsPanel/VBox/BackButton
|
||||||
|
@onready var credits_back: Button = $CreditsPanel/VBox/BackButton
|
||||||
|
@onready var video: VideoStreamPlayer = $VideoStreamPlayer
|
||||||
|
|
||||||
|
var _listening_action: StringName = &""
|
||||||
|
var _listening_button: Button = null
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
options_panel.visible = false
|
||||||
|
credits_panel.visible = false
|
||||||
|
fade_rect.color = Color(0, 0, 0, 0)
|
||||||
|
if video.stream != null:
|
||||||
|
video.play()
|
||||||
|
video.finished.connect(video.play) # loop the background clip
|
||||||
|
|
||||||
|
play_button.pressed.connect(_on_play_pressed)
|
||||||
|
options_button.pressed.connect(_on_options_pressed)
|
||||||
|
credits_button.pressed.connect(_on_credits_pressed)
|
||||||
|
exit_button.pressed.connect(_on_exit_pressed)
|
||||||
|
options_back.pressed.connect(_close_subpanels)
|
||||||
|
credits_back.pressed.connect(_close_subpanels)
|
||||||
|
_build_rebind_rows()
|
||||||
|
play_button.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
|
func _build_rebind_rows() -> void:
|
||||||
|
for child in rebind_list.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
for action: StringName in ACTION_LABELS:
|
||||||
|
var row := HBoxContainer.new()
|
||||||
|
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
|
||||||
|
var name_label := Label.new()
|
||||||
|
name_label.text = ACTION_LABELS[action]
|
||||||
|
name_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
name_label.add_theme_color_override("font_outline_color", Color.BLACK)
|
||||||
|
name_label.add_theme_constant_override("outline_size", 4)
|
||||||
|
row.add_child(name_label)
|
||||||
|
|
||||||
|
var key_button := Button.new()
|
||||||
|
key_button.custom_minimum_size = Vector2(160, 0)
|
||||||
|
key_button.text = Controls.get_key_label(action)
|
||||||
|
key_button.pressed.connect(_on_rebind_pressed.bind(action, key_button))
|
||||||
|
row.add_child(key_button)
|
||||||
|
|
||||||
|
rebind_list.add_child(row)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_play_pressed() -> void:
|
||||||
|
_set_buttons_disabled(true)
|
||||||
|
var tween := create_tween()
|
||||||
|
tween.tween_property(fade_rect, "color:a", 1.0, FADE_TIME)
|
||||||
|
tween.tween_callback(func() -> void:
|
||||||
|
get_tree().change_scene_to_file(GAME_SCENE))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_options_pressed() -> void:
|
||||||
|
main_panel.visible = false
|
||||||
|
options_panel.visible = true
|
||||||
|
options_back.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_credits_pressed() -> void:
|
||||||
|
main_panel.visible = false
|
||||||
|
credits_panel.visible = true
|
||||||
|
credits_back.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_exit_pressed() -> void:
|
||||||
|
get_tree().quit()
|
||||||
|
|
||||||
|
|
||||||
|
func _close_subpanels() -> void:
|
||||||
|
_cancel_listening()
|
||||||
|
options_panel.visible = false
|
||||||
|
credits_panel.visible = false
|
||||||
|
main_panel.visible = true
|
||||||
|
play_button.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
|
func _set_buttons_disabled(value: bool) -> void:
|
||||||
|
play_button.disabled = value
|
||||||
|
options_button.disabled = value
|
||||||
|
credits_button.disabled = value
|
||||||
|
exit_button.disabled = value
|
||||||
|
|
||||||
|
|
||||||
|
func _on_rebind_pressed(action: StringName, button: Button) -> void:
|
||||||
|
_cancel_listening()
|
||||||
|
_listening_action = action
|
||||||
|
_listening_button = button
|
||||||
|
button.text = "Press a key…"
|
||||||
|
|
||||||
|
|
||||||
|
func _cancel_listening() -> void:
|
||||||
|
if _listening_button != null:
|
||||||
|
_listening_button.text = Controls.get_key_label(_listening_action)
|
||||||
|
_listening_action = &""
|
||||||
|
_listening_button = null
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if _listening_action == &"":
|
||||||
|
return
|
||||||
|
if event is InputEventKey and event.pressed and not event.echo:
|
||||||
|
if event.physical_keycode == KEY_ESCAPE:
|
||||||
|
_cancel_listening()
|
||||||
|
else:
|
||||||
|
var new_event := InputEventKey.new()
|
||||||
|
new_event.physical_keycode = event.physical_keycode
|
||||||
|
Controls.rebind(_listening_action, new_event)
|
||||||
|
_listening_button.text = Controls.get_key_label(_listening_action)
|
||||||
|
_listening_action = &""
|
||||||
|
_listening_button = null
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://46y10alai56q
|
||||||
@@ -33,6 +33,7 @@ var _bull_anim: AnimationPlayer = null
|
|||||||
|
|
||||||
var _charge_ready_emitter: CPUParticles3D = null
|
var _charge_ready_emitter: CPUParticles3D = null
|
||||||
var _slam_pending: bool = false
|
var _slam_pending: bool = false
|
||||||
|
var _charge_trail_emitter: CPUParticles3D = null
|
||||||
|
|
||||||
const MAX_HEALTH: int = 10
|
const MAX_HEALTH: int = 10
|
||||||
var health: int = MAX_HEALTH
|
var health: int = MAX_HEALTH
|
||||||
@@ -161,6 +162,49 @@ func _setup_charge_indicators() -> void:
|
|||||||
_charge_ready_emitter.scale_amount_curve = burst_scale
|
_charge_ready_emitter.scale_amount_curve = burst_scale
|
||||||
cube_guy.add_child(_charge_ready_emitter)
|
cube_guy.add_child(_charge_ready_emitter)
|
||||||
|
|
||||||
|
# Blue energy trail — streams backward during charge
|
||||||
|
var trail_mat := StandardMaterial3D.new()
|
||||||
|
trail_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
trail_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
trail_mat.vertex_color_use_as_albedo = true
|
||||||
|
trail_mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
|
|
||||||
|
var trail_sphere := SphereMesh.new()
|
||||||
|
trail_sphere.radius = 0.065
|
||||||
|
trail_sphere.height = 0.13
|
||||||
|
trail_sphere.radial_segments = 4
|
||||||
|
trail_sphere.rings = 2
|
||||||
|
trail_sphere.material = trail_mat
|
||||||
|
|
||||||
|
var trail_ramp := Gradient.new()
|
||||||
|
trail_ramp.set_color(0, Color(0.30, 0.65, 1.0, 1.0))
|
||||||
|
trail_ramp.set_color(1, Color(0.30, 0.65, 1.0, 0.0))
|
||||||
|
|
||||||
|
var trail_scale := Curve.new()
|
||||||
|
trail_scale.add_point(Vector2(0.0, 1.0))
|
||||||
|
trail_scale.add_point(Vector2(0.6, 0.8))
|
||||||
|
trail_scale.add_point(Vector2(1.0, 0.0))
|
||||||
|
|
||||||
|
_charge_trail_emitter = CPUParticles3D.new()
|
||||||
|
_charge_trail_emitter.position = Vector3(0.0, 0.25, 0.3)
|
||||||
|
_charge_trail_emitter.emitting = false
|
||||||
|
_charge_trail_emitter.one_shot = false
|
||||||
|
_charge_trail_emitter.amount = 18
|
||||||
|
_charge_trail_emitter.lifetime = 0.30
|
||||||
|
_charge_trail_emitter.randomness = 0.4
|
||||||
|
_charge_trail_emitter.local_coords = false
|
||||||
|
_charge_trail_emitter.direction = Vector3(0.0, 0.2, 1.0).normalized()
|
||||||
|
_charge_trail_emitter.spread = 25.0
|
||||||
|
_charge_trail_emitter.gravity = Vector3(0.0, 2.0, 0.0)
|
||||||
|
_charge_trail_emitter.initial_velocity_min = 4.0
|
||||||
|
_charge_trail_emitter.initial_velocity_max = 9.0
|
||||||
|
_charge_trail_emitter.scale_amount_min = 0.4
|
||||||
|
_charge_trail_emitter.scale_amount_max = 1.2
|
||||||
|
_charge_trail_emitter.mesh = trail_sphere
|
||||||
|
_charge_trail_emitter.color_ramp = trail_ramp
|
||||||
|
_charge_trail_emitter.scale_amount_curve = trail_scale
|
||||||
|
cube_guy.add_child(_charge_trail_emitter)
|
||||||
|
|
||||||
|
|
||||||
func _setup_audio() -> void:
|
func _setup_audio() -> void:
|
||||||
if ResourceLoader.exists("res://sounds/bull_huff.ogg"):
|
if ResourceLoader.exists("res://sounds/bull_huff.ogg"):
|
||||||
@@ -205,6 +249,8 @@ func _set_dust_state(new_state: DustState) -> void:
|
|||||||
p.initial_velocity_min = DP.f("charge_vel_min")
|
p.initial_velocity_min = DP.f("charge_vel_min")
|
||||||
p.initial_velocity_max = DP.f("charge_vel_max")
|
p.initial_velocity_max = DP.f("charge_vel_max")
|
||||||
p.emitting = true
|
p.emitting = true
|
||||||
|
if _charge_trail_emitter:
|
||||||
|
_charge_trail_emitter.emitting = _dust_state == DustState.CHARGE
|
||||||
|
|
||||||
|
|
||||||
func _on_dp_changed(_key: String, _val: Variant) -> void:
|
func _on_dp_changed(_key: String, _val: Variant) -> void:
|
||||||
@@ -296,6 +342,7 @@ func _activate_dash() -> void:
|
|||||||
_dash_dir = Vector3(raw.x, 0.0, raw.z).normalized()
|
_dash_dir = Vector3(raw.x, 0.0, raw.z).normalized()
|
||||||
velocity.x = _dash_dir.x * DP.f("dash_speed")
|
velocity.x = _dash_dir.x * DP.f("dash_speed")
|
||||||
velocity.z = _dash_dir.z * DP.f("dash_speed")
|
velocity.z = _dash_dir.z * DP.f("dash_speed")
|
||||||
|
_spawn_dash_burst()
|
||||||
_legs.set(&"charge_pitch_target", DP.f("charge_head_pitch"))
|
_legs.set(&"charge_pitch_target", DP.f("charge_head_pitch"))
|
||||||
if _huff_player:
|
if _huff_player:
|
||||||
_huff_player.pitch_scale = randf_range(0.9, 1.1)
|
_huff_player.pitch_scale = randf_range(0.9, 1.1)
|
||||||
@@ -421,6 +468,8 @@ func _spawn_kick_fx(back_dir: Vector3) -> void:
|
|||||||
var origin := global_position + back_dir * 0.55 + Vector3(0.0, -0.25, 0.0)
|
var origin := global_position + back_dir * 0.55 + Vector3(0.0, -0.25, 0.0)
|
||||||
_spawn_kick_dust(origin, back_dir)
|
_spawn_kick_dust(origin, back_dir)
|
||||||
_spawn_kick_stones(origin, back_dir)
|
_spawn_kick_stones(origin, back_dir)
|
||||||
|
_spawn_kick_sparks(origin, back_dir)
|
||||||
|
_spawn_kick_flash(origin)
|
||||||
camera_pivot.call(&"trigger_hit", 0.35)
|
camera_pivot.call(&"trigger_hit", 0.35)
|
||||||
|
|
||||||
|
|
||||||
@@ -520,6 +569,129 @@ func _spawn_kick_stones(origin: Vector3, back_dir: Vector3) -> void:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _spawn_kick_flash(origin: Vector3) -> void:
|
||||||
|
var mat := StandardMaterial3D.new()
|
||||||
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
mat.albedo_color = Color(1.0, 0.97, 0.40, 0.0)
|
||||||
|
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
|
|
||||||
|
var sphere := SphereMesh.new()
|
||||||
|
sphere.radius = 1.0
|
||||||
|
sphere.height = 2.0
|
||||||
|
sphere.radial_segments = 8
|
||||||
|
sphere.rings = 4
|
||||||
|
sphere.material = mat
|
||||||
|
|
||||||
|
var mi := MeshInstance3D.new()
|
||||||
|
mi.mesh = sphere
|
||||||
|
mi.material_override = mat
|
||||||
|
mi.scale = Vector3(0.05, 0.05, 0.05)
|
||||||
|
get_parent().add_child(mi)
|
||||||
|
mi.global_position = origin
|
||||||
|
|
||||||
|
var tween := create_tween()
|
||||||
|
tween.set_parallel(true)
|
||||||
|
tween.tween_property(mi, "scale", Vector3(0.7, 0.7, 0.7), 0.13)\
|
||||||
|
.set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
|
||||||
|
var fade := func(a: float) -> void: mat.albedo_color.a = a
|
||||||
|
tween.tween_method(fade, 0.92, 0.0, 0.14)\
|
||||||
|
.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
||||||
|
tween.tween_callback(mi.queue_free).set_delay(0.16)
|
||||||
|
|
||||||
|
|
||||||
|
func _spawn_dash_burst() -> void:
|
||||||
|
var mat := StandardMaterial3D.new()
|
||||||
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
mat.vertex_color_use_as_albedo = true
|
||||||
|
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
|
|
||||||
|
var box := BoxMesh.new()
|
||||||
|
box.size = Vector3(0.045, 0.045, 0.30)
|
||||||
|
box.material = mat
|
||||||
|
|
||||||
|
var ramp := Gradient.new()
|
||||||
|
ramp.set_color(0, Color(0.50, 0.82, 1.0, 1.0))
|
||||||
|
ramp.set_color(1, Color(0.50, 0.82, 1.0, 0.0))
|
||||||
|
|
||||||
|
var scale_curve := Curve.new()
|
||||||
|
scale_curve.add_point(Vector2(0.0, 1.0))
|
||||||
|
scale_curve.add_point(Vector2(1.0, 0.0))
|
||||||
|
|
||||||
|
var p := CPUParticles3D.new()
|
||||||
|
p.one_shot = true
|
||||||
|
p.explosiveness = 0.92
|
||||||
|
p.amount = 18
|
||||||
|
p.lifetime = 0.22
|
||||||
|
p.randomness = 0.15
|
||||||
|
p.local_coords = false
|
||||||
|
p.direction = _dash_dir
|
||||||
|
p.spread = 15.0
|
||||||
|
p.gravity = Vector3.ZERO
|
||||||
|
p.initial_velocity_min = 18.0
|
||||||
|
p.initial_velocity_max = 35.0
|
||||||
|
p.scale_amount_min = 0.8
|
||||||
|
p.scale_amount_max = 2.8
|
||||||
|
p.mesh = box
|
||||||
|
p.color_ramp = ramp
|
||||||
|
p.scale_amount_curve = scale_curve
|
||||||
|
get_parent().add_child(p)
|
||||||
|
p.global_position = global_position + Vector3(0.0, 0.2, 0.0)
|
||||||
|
p.restart()
|
||||||
|
get_tree().create_timer(0.6).timeout.connect(func() -> void:
|
||||||
|
if is_instance_valid(p): p.queue_free()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _spawn_kick_sparks(origin: Vector3, back_dir: Vector3) -> void:
|
||||||
|
var mat := StandardMaterial3D.new()
|
||||||
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
mat.vertex_color_use_as_albedo = true
|
||||||
|
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
|
|
||||||
|
var sphere := SphereMesh.new()
|
||||||
|
sphere.radius = 0.04
|
||||||
|
sphere.height = 0.08
|
||||||
|
sphere.radial_segments = 3
|
||||||
|
sphere.rings = 1
|
||||||
|
sphere.material = mat
|
||||||
|
|
||||||
|
var ramp := Gradient.new()
|
||||||
|
ramp.set_color(0, Color(1.0, 0.98, 0.60, 1.0))
|
||||||
|
ramp.set_color(1, Color(1.0, 1.0, 1.0, 0.0))
|
||||||
|
|
||||||
|
var scale_curve := Curve.new()
|
||||||
|
scale_curve.add_point(Vector2(0.0, 1.0))
|
||||||
|
scale_curve.add_point(Vector2(0.5, 0.6))
|
||||||
|
scale_curve.add_point(Vector2(1.0, 0.0))
|
||||||
|
|
||||||
|
var p := CPUParticles3D.new()
|
||||||
|
p.one_shot = true
|
||||||
|
p.explosiveness = 0.95
|
||||||
|
p.amount = 22
|
||||||
|
p.lifetime = 0.28
|
||||||
|
p.randomness = 0.4
|
||||||
|
p.local_coords = false
|
||||||
|
p.direction = (back_dir + Vector3(0.0, 0.5, 0.0)).normalized()
|
||||||
|
p.spread = 30.0
|
||||||
|
p.gravity = Vector3(0.0, -14.0, 0.0)
|
||||||
|
p.initial_velocity_min = 8.0
|
||||||
|
p.initial_velocity_max = 18.0
|
||||||
|
p.scale_amount_min = 0.6
|
||||||
|
p.scale_amount_max = 2.0
|
||||||
|
p.mesh = sphere
|
||||||
|
p.color_ramp = ramp
|
||||||
|
p.scale_amount_curve = scale_curve
|
||||||
|
get_parent().add_child(p)
|
||||||
|
p.global_position = origin
|
||||||
|
p.restart()
|
||||||
|
get_tree().create_timer(1.0).timeout.connect(func() -> void:
|
||||||
|
if is_instance_valid(p): p.queue_free()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _make_slam_ring_mesh() -> ArrayMesh:
|
func _make_slam_ring_mesh() -> ArrayMesh:
|
||||||
const INNER_R: float = 0.82
|
const INNER_R: float = 0.82
|
||||||
const OUTER_R: float = 1.00
|
const OUTER_R: float = 1.00
|
||||||
@@ -616,7 +788,6 @@ func _physics_process(delta: float) -> void:
|
|||||||
# Right only → thrust NW (forward-left diagonal)
|
# Right only → thrust NW (forward-left diagonal)
|
||||||
var left_held := Input.is_action_pressed(&"thrust_left")
|
var left_held := Input.is_action_pressed(&"thrust_left")
|
||||||
var right_held := Input.is_action_pressed(&"thrust_right")
|
var right_held := Input.is_action_pressed(&"thrust_right")
|
||||||
camera_pivot.call(&"set_charge_active", left_held and right_held)
|
|
||||||
|
|
||||||
if left_held and right_held:
|
if left_held and right_held:
|
||||||
_thrust_left_charge = 0.0
|
_thrust_left_charge = 0.0
|
||||||
@@ -716,6 +887,12 @@ func _physics_process(delta: float) -> void:
|
|||||||
else:
|
else:
|
||||||
_set_dust_state(DustState.NONE)
|
_set_dust_state(DustState.NONE)
|
||||||
|
|
||||||
|
# ── Charge trail direction ────────────────────────────────────────────────
|
||||||
|
if _dust_state == DustState.CHARGE and _charge_trail_emitter:
|
||||||
|
var vel_flat := Vector3(velocity.x, 0.0, velocity.z)
|
||||||
|
if vel_flat.length_squared() > 0.1:
|
||||||
|
_charge_trail_emitter.direction = (-vel_flat.normalized() + Vector3(0.0, 0.25, 0.0)).normalized()
|
||||||
|
|
||||||
# ── Hoof sounds ───────────────────────────────────────────────────────────
|
# ── Hoof sounds ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+3
-8
@@ -11,15 +11,16 @@ config_version=5
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="Bullosseum"
|
config/name="Bullosseum"
|
||||||
run/main_scene="res://scene.tscn"
|
run/main_scene="res://MainMenu.tscn"
|
||||||
config/features=PackedStringArray("4.7", "Forward Plus")
|
config/features=PackedStringArray("4.7", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
config/run/main_scene="res://scene.tscn"
|
config/run/main_scene="res://MainMenu.tscn"
|
||||||
|
|
||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
DP="*res://debug_params.gd"
|
DP="*res://debug_params.gd"
|
||||||
DebugMenu="*res://debug_menu.gd"
|
DebugMenu="*res://debug_menu.gd"
|
||||||
|
Controls="*res://controls_manager.gd"
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
@@ -59,12 +60,6 @@ move_right={
|
|||||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
jump={
|
|
||||||
"deadzone": 0.2,
|
|
||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
|
||||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
zoom_in={
|
zoom_in={
|
||||||
"deadzone": 0.2,
|
"deadzone": 0.2,
|
||||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(726, 8),"global_position":Vector2(735, 56),"factor":1.0,"button_index":4,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(726, 8),"global_position":Vector2(735, 56),"factor":1.0,"button_index":4,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
||||||
|
|||||||
Reference in New Issue
Block a user