Massive work on level, UI, sound, and player functionality, small progress on netcode. Renamed project to Net Gunner.
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
12
scripts/blinker.gd
Normal 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
1
scripts/blinker.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dv3fk1ptmvltg
|
||||
12
scripts/hud.gd
Normal file
12
scripts/hud.gd
Normal 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
1
scripts/hud.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bm50jiya4s3ei
|
||||
@@ -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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
17
scripts/player_data.gd
Normal 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
|
||||
1
scripts/player_data.gd.uid
Normal file
1
scripts/player_data.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://6w608y2grdqb
|
||||
26
scripts/test_level.gd
Normal file
26
scripts/test_level.gd
Normal 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)
|
||||
1
scripts/test_level.gd.uid
Normal file
1
scripts/test_level.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d3t381vws7vns
|
||||
@@ -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
28
scripts/trap_display.gd
Normal 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()
|
||||
1
scripts/trap_display.gd.uid
Normal file
1
scripts/trap_display.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c85j4kxafibj4
|
||||
24
scripts/trap_icon.gd
Normal file
24
scripts/trap_icon.gd
Normal 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
1
scripts/trap_icon.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://54k4gu5skdur
|
||||
Reference in New Issue
Block a user