Massive work on level, UI, sound, and player functionality, small progress on netcode. Renamed project to Net Gunner.

This commit is contained in:
2025-12-22 09:04:22 -05:00
parent 9a8f06437d
commit 3b6407d6e5
566 changed files with 42735 additions and 183 deletions

View File

@@ -1,14 +1,43 @@
extends Node
enum TrapType{
BOMB,
MINE,
GAS,
FORCE_PANEL,
SWITCH,
PITFALL
}
const blinder_template = preload("res://templates/blinder.tscn")
const vs_man_level = preload("res://scenes/multiplayer_test.tscn")
var player : Player
var hud : HUD
var level : Level
func setup_player(player : Player) -> void:
self.player = player
if hud:
hud.register_player(player)
func switch_scene(packed_scene : PackedScene) -> void:
var blinder = blinder_template.instantiate() as TextureRect
var tween = create_tween()
blinder.self_modulate.a = 0
add_child(blinder)
tween.tween_property(blinder, "self_modulate:a", 1, .15)
tween.tween_callback(Callable(get_tree().change_scene_to_packed).bind(packed_scene))
tween.tween_property(blinder, "self_modulate:a", 0, .15)
tween.tween_callback(blinder.queue_free)
pass
@rpc("call_local", "any_peer", "reliable")
func start_vs_man() -> void:
var setup = get_tree().get_first_node_in_group("scenes")
setup.queue_free()
var level = vs_man_level.instantiate()
var spawner = get_tree().get_first_node_in_group("level_spawner") as MultiplayerSpawner
spawner.add_child(level)
if Multiplayer.is_server():
var level = vs_man_level.instantiate()
var spawner = get_tree().get_first_node_in_group("level_spawner") as MultiplayerSpawner
spawner.add_child(level)

View File

@@ -33,7 +33,8 @@ func join_game(new_handle : String) -> Error:
print("%s %d" % [handle, multiplayer.get_unique_id()])
return !error
func is_server() -> bool:
return multiplayer && multiplayer.is_server()
func _add_player_to_game(id : int) -> void:
print("Player %s joined the game!" % id)

12
scripts/blinker.gd Normal file
View File

@@ -0,0 +1,12 @@
extends TextureRect
@export var blink_time : float = 0.2
var tween : Tween
func _ready() -> void:
tween = create_tween()
tween.tween_property(self, "modulate:a", 0, 0)
tween.tween_interval(blink_time)
tween.tween_property(self, "modulate:a", 1, 0)
tween.tween_interval(blink_time)
tween.set_loops(-1)

1
scripts/blinker.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://dv3fk1ptmvltg

12
scripts/hud.gd Normal file
View File

@@ -0,0 +1,12 @@
class_name HUD extends Control
@onready var trap_display : TrapDisplay = %TrapDisplay
func _ready() -> void:
Game.hud = self
func register_player(player : Player) -> void:
trap_display._on_trap_list_changed(player.data.traps, player.data.active_trap)
player.trap_cycled.connect(trap_display._on_trap_cycled)
player.trap_quantity_changed.connect(trap_display._on_trap_quantity_changed)
player.trap_list_changed.connect(trap_display._on_trap_list_changed)

1
scripts/hud.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://bm50jiya4s3ei

View File

@@ -10,7 +10,8 @@ func _enter_tree() -> void:
func register_player() -> void:
target = Game.player
offset = global_position - target.global_position
if target:
offset = global_position - target.global_position
func _process(delta: float) -> void:

View File

@@ -5,11 +5,15 @@ class_name MultiplayerPC extends Player
player_id = id
func _enter_tree() -> void:
print("Player %d adding Controller for %d" % [Multiplayer.id, player_id])
#Game.player = self
pass
func setup(id) -> void:
name = "Player " + str(id)
player_id = id
if Multiplayer.is_server() == (id == 1):
Game.player = self
func _physics_process(delta: float) -> void:
var dir = Input.get_vector("west", "east", "north", "south")

View File

@@ -2,12 +2,13 @@ extends Node3D
const multiplayer_pc_template = preload("res://templates/multiplayer_pc.tscn")
const camera_template = preload("res://templates/camera.tscn")
@onready var spawner = %Spawner
@onready var player_spawner = %Spawner
func _ready() -> void:
print("LEVEL LOADING, ID: " + str(Multiplayer.id))
for key in Multiplayer.players.values():
var pc = multiplayer_pc_template.instantiate()
pc.setup(key)
spawner.add_player(pc)
print("LEVEL LOADING, ID: " + str(Multiplayer.id) + " with " + str(Multiplayer.players.size()) + " keys recognized")
if Multiplayer.is_server():
for key in Multiplayer.players.values():
var pc = multiplayer_pc_template.instantiate()
player_spawner.add_player(pc, key)
pc.setup(key)
var camera = camera_template.instantiate()
add_child(camera)

View File

@@ -42,7 +42,7 @@ func _on_hosting_back_button_pressed() -> void:
func _on_start_game_button_pressed() -> void:
Game.start_vs_man()
Game.start_vs_man.rpc()
func _on_waiting_back_button_pressed() -> void:

View File

@@ -1,18 +1,14 @@
extends MultiplayerSpawner
@onready var spawn_node = get_node(spawn_path)
var spawn_points : Array = []
func _enter_tree() -> void:
spawn_points = $SpawnPoints.get_children()
func add_player(player : MultiplayerPC) -> void:
add_child(player)
if player.player_id == 1:
func add_player(player : MultiplayerPC, key) -> void:
spawn_node.add_child(player)
if key == 1: #Server
player.global_position = spawn_points[0].global_position
if Multiplayer.multiplayer.is_server():
Game.player = player
else:
player.global_position = spawn_points[1].global_position
if !Multiplayer.multiplayer.is_server():
Game.player = player

View File

@@ -2,9 +2,16 @@ class_name Player extends CharacterBody3D
@export var speed : float = 10
@onready var body = $Body
@onready var data : PlayerData = $Data
var current_square : Vector3i
var detecting : bool
var detect_squares : Dictionary[Vector3i, bool] = {}
signal trap_cycled(trap_index)
signal trap_quantity_changed(trap_index, quantity)
signal trap_list_changed(traps)
func _enter_tree() -> void:
Game.player = self
func _physics_process(delta: float) -> void:
var dir = Input.get_vector("west", "east", "north", "south")
@@ -12,4 +19,98 @@ func _physics_process(delta: float) -> void:
if dir.length_squared() > 0:
body.look_at(body.global_position - dir)
velocity = speed * dir
if detecting:
velocity /= 3
if !is_on_floor():
velocity += get_gravity()
move_and_slide()
if detecting:
update_detecting()
if Input.is_action_just_pressed("left cycle trap"):
cycle_active_trap(-1)
if Input.is_action_just_pressed("right cycle trap"):
cycle_active_trap(1)
if Input.is_action_just_pressed("detect"):
start_detecting()
elif Input.is_action_just_released("detect"):
stop_detecting()
func update_detecting() -> void:
var new_square : Vector3i = (global_position - Vector3.ONE * .5).round()
if new_square == current_square:
return
current_square = new_square
var new_squares : Dictionary[Vector3i, bool] = {}
for i in range(-2, 3):
for j in range(-2, 3):
for k in range(-2, 2):
if abs(i) + abs(j) < 3:
var sq = current_square + Vector3i(i, k, j)
new_squares[sq] = true
for sq in detect_squares.keys():
if !new_squares.has(sq):
Game.level.detect_square(sq, false)
var remove_list = []
for sq in new_squares.keys():
if detect_squares.has(sq):
continue
if !Game.level.detect_square(sq, true):
remove_list.append(sq)
detect_squares = new_squares
for key in remove_list:
detect_squares.erase(key)
func start_detecting() -> void:
detecting = true
current_square = (global_position - Vector3.ONE * .5).round()
detect_squares = {}
for i in range(-2, 3):
for j in range(-2, 3):
for k in range(-2, 2):
if abs(i) + abs(j) < 3:
var sq = current_square + Vector3i(i, k, j)
detect_squares[sq] = true
var remove_list = []
for sq in detect_squares.keys():
if !Game.level.detect_square(sq, true):
remove_list.append(sq)
for key in remove_list:
detect_squares.erase(key)
func stop_detecting() -> void:
detecting = false
for sq in detect_squares.keys():
Game.level.detect_square(sq, false)
detect_squares = {}
func setup(traps) -> void:
$Data.traps = traps
Game.setup_player(self)
func cycle_active_trap(dir) -> void:
var prev = data.active_trap
data.active_trap += dir
if data.active_trap < 0:
data.active_trap = 0
if data.active_trap >= len(data.traps):
data.active_trap = len(data.traps) - 1
if prev != data.active_trap:
trap_cycled.emit(data.active_trap)

17
scripts/player_data.gd Normal file
View File

@@ -0,0 +1,17 @@
class_name PlayerData extends Node
class TrapData:
var type : Game.TrapType
var quantity : int
var max : int
func _init(type : Game.TrapType, quantity : int, max : int) -> void:
self.type = type
self.quantity = quantity
self.max = max
var traps : Array[TrapData] = []
var active_trap : int = 0
var life : int = 100
var max_life : int = 100

View File

@@ -0,0 +1 @@
uid://6w608y2grdqb

26
scripts/test_level.gd Normal file
View File

@@ -0,0 +1,26 @@
class_name Level extends Node3D
const player_controller = preload("res://templates/singleplayer_pc.tscn")
@onready var floor_layer : GridMap = %Floor
@onready var marker_layer : GridMap = %Markers
func detect_square(crd : Vector3i, mark : bool) -> bool:
var cell = floor_layer.get_cell_item(crd)
if cell == GridMap.INVALID_CELL_ITEM:
return false
marker_layer.set_cell_item(crd, 0 if mark else GridMap.INVALID_CELL_ITEM)
return true
func _ready() -> void:
Game.level = self
var player = player_controller.instantiate()
var traps : Array[PlayerData.TrapData] = [
PlayerData.TrapData.new(Game.TrapType.BOMB, 3, 3),
PlayerData.TrapData.new(Game.TrapType.SWITCH, 3, 3),
PlayerData.TrapData.new(Game.TrapType.MINE, 3, 3)
]
add_child(player)
player.setup(traps)

View File

@@ -0,0 +1 @@
uid://d3t381vws7vns

View File

@@ -2,6 +2,8 @@ extends Control
var opened : bool = false
var menu_choice : int = 0
var shot_tween : Tween
var glow_tween : Tween
@onready var menu_list : Array = [
%STORY,
%"VS-COM",
@@ -10,6 +12,21 @@ var menu_choice : int = 0
%OPTION
]
var vs_com_scene = preload("res://scenes/character_select.tscn")
func _ready() -> void:
shot_tween = create_tween()
%Target.scale = Vector2(2,2)
%Target.modulate.a = 0
shot_tween.set_parallel(true)
shot_tween.tween_property(%Target, "modulate:a", 1, 1)
shot_tween.tween_property(%Target, "scale", Vector2(1,1), 1)
shot_tween.tween_property(%Target, "rotation", PI / 4, 1)
glow_tween = create_tween()
glow_tween.set_loops(-1)
glow_tween.tween_property(%Target, "modulate:a", .8, .5)
glow_tween.tween_property(%Target, "modulate:a", 1, .5)
func _process(delta: float) -> void:
if Input.is_action_just_pressed("ui_menu"):
opened = !opened
@@ -33,6 +50,8 @@ func _process(delta: float) -> void:
menu_choice = 0
%SwitchSound.play()
switch_menu()
elif Input.is_action_just_pressed("ui_accept"):
Game.switch_scene(vs_com_scene)
func switch_menu() -> void:

28
scripts/trap_display.gd Normal file
View File

@@ -0,0 +1,28 @@
class_name TrapDisplay extends PanelContainer
const trap_hud_icon = preload("res://templates/trap_icon.tscn")
@onready var trap_container : HBoxContainer = %TrapsContainer
@onready var cycle_sound : AudioStreamPlayer = %CycleSound
func clear_traps() -> void:
for child in trap_container.get_children():
child.queue_free()
func _on_trap_list_changed(traps, trap_index) -> void:
clear_traps()
for trap in traps:
var ticon = trap_hud_icon.instantiate()
trap_container.add_child(ticon)
ticon.setup(trap.type, trap.quantity)
%LeftArrow.visible = (trap_index != 0)
%RightArrow.visible = (trap_index != trap_container.get_children().size() - 1)
func _on_trap_quantity_changed(trap_index, qty) -> void:
var ticon = trap_container.get_child(trap_index) as TrapIcon
ticon.set_quantity(qty)
func _on_trap_cycled(trap_index) -> void:
trap_container.position.x = -trap_index * 150
%LeftArrow.visible = (trap_index != 0)
%RightArrow.visible = (trap_index != trap_container.get_children().size() - 1)
cycle_sound.play()

View File

@@ -0,0 +1 @@
uid://c85j4kxafibj4

24
scripts/trap_icon.gd Normal file
View File

@@ -0,0 +1,24 @@
class_name TrapIcon extends Control
const trap_icons : Dictionary = {
Game.TrapType.BOMB : preload("res://visuals/images/icons/bomb.png"),
Game.TrapType.GAS : preload("res://visuals/images/icons/gas.png"),
Game.TrapType.PITFALL : preload("res://visuals/images/icons/pitfall.png"),
Game.TrapType.FORCE_PANEL : preload("res://visuals/images/icons/force_panel.png"),
Game.TrapType.SWITCH : preload("res://visuals/images/icons/switch.png"),
Game.TrapType.MINE : preload("res://visuals/images/icons/mine.png"),
}
@onready var icon_image : TextureRect = %Icon
@onready var qty_label : Label = %Label
func setup(type : Game.TrapType, qty : int) -> void:
icon_image.texture = trap_icons[type]
set_quantity(qty)
func set_quantity(qty : int) -> void:
qty_label.text = str(qty)
if qty < 1:
icon_image.modulate = Color.DIM_GRAY
else:
icon_image.modulate = Color.WHITE

1
scripts/trap_icon.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://54k4gu5skdur