Archived
1
0
Fork 0

Player death and position reset. Also Godot 4.4

This commit is contained in:
Sebastian Benjamin 2025-03-04 18:36:01 -08:00
parent 0b8091b352
commit 6eec1f6181
32 changed files with 118 additions and 59 deletions

View file

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

View file

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

View file

@ -0,0 +1 @@
uid://2l8y628n8ukc

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,9 @@
[gd_scene load_steps=4 format=3 uid="uid://dsiowq0rnacln"]
[gd_scene load_steps=5 format=3 uid="uid://dsiowq0rnacln"]
[ext_resource type="PackedScene" uid="uid://cd3tqt7hr5pqs" path="res://danmaku!/Player.tscn" id="1_22cjd"]
[ext_resource type="Script" path="res://danmaku!/scaling.gd" id="1_o1mqp"]
[ext_resource type="Script" path="res://danmaku!/network_manager.gd" id="2_b2dol"]
[ext_resource type="Script" uid="uid://ggkxv1cb1bjk" path="res://danmaku!/scaling.gd" id="1_o1mqp"]
[ext_resource type="Script" uid="uid://cd67rrch5h4t7" path="res://danmaku!/network_manager.gd" id="2_b2dol"]
[ext_resource type="Script" uid="uid://ddc5iqgtyv2ns" path="res://danmaku!/BulletManager.gd" id="4_ubrrh"]
[node name="Board" type="Control"]
custom_minimum_size = Vector2(607.5, 1080)
@ -32,6 +33,11 @@ scale = Vector2(6.75, 6.75)
[node name="Player" parent="World" instance=ExtResource("1_22cjd")]
unique_name_in_owner = true
[node name="NetworkManager" type="Node2D" parent="World" node_paths=PackedStringArray("player")]
[node name="BulletManager" type="Node2D" parent="World"]
unique_name_in_owner = true
script = ExtResource("4_ubrrh")
[node name="NetworkManager" type="Node" parent="World" node_paths=PackedStringArray("player")]
unique_name_in_owner = true
script = ExtResource("2_b2dol")
player = NodePath("../Player")

View file

@ -0,0 +1,22 @@
extends Node2D
var bullet_intraframe_mov_delta := 0.0
var predicted_tick := 0
var bullets = []
func _ready() -> void:
child_exiting_tree.connect(_on_child_exiting_tree)
func _process(delta: float) -> void:
for bullet in bullets:
var prev_pos = bullet.get_current_pos(predicted_tick)
var next_pos = bullet.get_current_pos(predicted_tick + 1)
var interpolated_pos = prev_pos.lerp(next_pos, bullet_intraframe_mov_delta)
bullet.position = interpolated_pos
if bullet.beyond_kill_boundary(predicted_tick):
bullet.queue_free()
func _on_child_exiting_tree(node: DanmakuBullet):
bullets.erase(node)

View file

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

View file

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

View file

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

View file

@ -1,4 +1,4 @@
extends Node2D
extends Node
var nakama_client: NakamaClient
var nakama_session: NakamaSession
var nakama_socket: NakamaSocket
@ -7,12 +7,9 @@ var nakama_socket: NakamaSocket
var predicted_tick = 0
var delta_counter = 0
var bullet_lerp_factor := 0.0
var bullets = []
var current_match_id = ""
func _ready() -> void:
child_exiting_tree.connect(_on_child_exiting_tree)
print("Attempting auth.")
await attempt_auth()
print("Attempting to create debug match.")
@ -23,24 +20,15 @@ func _process(delta: float) -> void:
if current_match_id == "":
return
predict_tick_and_broadcast(delta)
for bullet in bullets:
var prev_pos = bullet.get_current_pos(predicted_tick)
var next_pos = bullet.get_current_pos(predicted_tick + 1)
var interpolated_pos = prev_pos.lerp(next_pos, bullet_lerp_factor)
bullet.position = interpolated_pos
if bullet.beyond_kill_boundary(predicted_tick):
bullet.queue_free()
%BulletManager.bullet_intraframe_mov_delta = predict_tick_and_broadcast(delta)
%BulletManager.predicted_tick = predicted_tick
func _on_match_state(p_state : NakamaRTAPI.MatchData):
match p_state.op_code:
2:
var data = JSON.parse_string(p_state.data)
# Set player position given server bounds-checking
# Set player position if server demands a forced position
if data["forcePlayerPos"]:
player.set_position_data(
Vector2(
@ -49,10 +37,12 @@ func _on_match_state(p_state : NakamaRTAPI.MatchData):
),
float(data["playerPos"]["radius_multiplier"])
)
# Handle player death if there is an ongoing death timer
if int(data["deathTimer"]) > 0:
print("server says u died")
%Player.kill()
elif int(data["deathTimer"]) == 0:
%Player.resurrect()
# Spawn new bullets
for b in data["newBullets"]:
@ -72,8 +62,8 @@ func _on_match_state(p_state : NakamaRTAPI.MatchData):
var scale_ratio = ((b["radius_multiplier"] * 2) * Globals.SERVER_SIZE.x) / bullet.texture.get_width()
bullet.scale = Vector2(scale_ratio, scale_ratio)
add_child(bullet)
bullets.append(bullet)
%BulletManager.add_child(bullet)
%BulletManager.bullets.append(bullet)
predicted_tick = int(b["tick"])
delta_counter = 0
@ -103,7 +93,7 @@ func create_and_join_debug_match() -> void:
else:
current_match_id = response.payload
func predict_tick_and_broadcast(delta):
func predict_tick_and_broadcast(delta) -> float:
delta_counter += delta
# New tick (60 tick rate), broadcast player inputs
@ -111,10 +101,7 @@ func predict_tick_and_broadcast(delta):
if delta_counter >= tick_time:
predicted_tick += 1
delta_counter -= tick_time
var pos = get_node("../Player").position
var pos = %Player.position
var json_string = JSON.stringify({"x": pos.x, "y": pos.y})
nakama_socket.send_match_state_async(current_match_id, 0, json_string)
bullet_lerp_factor = delta_counter / tick_time
func _on_child_exiting_tree(node: DanmakuBullet):
bullets.erase(node)
return delta_counter / tick_time

View file

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

View file

@ -8,9 +8,7 @@ var collision: DanmakuCircle = DanmakuCircle.new()
# This is temporary, it should be defined per-sprite when I get to the skin system
const PLAYER_BODY_WIDTH_MULTIPLIER = 0.18
# Temp
var flash_timer = 0.0
var flashing = false
var alive: bool = true
func _ready() -> void:
$BodySprite.scale_sprite(PLAYER_BODY_WIDTH_MULTIPLIER)
@ -23,15 +21,12 @@ func get_input():
velocity = Input.get_vector("Left", "Right", "Up", "Down") * speed
func _physics_process(delta: float):
# Temp
if flashing:
flash_timer -= delta
$BodySprite.modulate = Color(1, 1, 1, 1)
flashing = false
func _physics_process(delta: float):
get_input()
if !alive:
return
# Bounds checking
var attempted_position := position + (velocity * delta)
attempted_position = attempted_position.clamp(Vector2(0, 0), Globals.SERVER_SIZE)
@ -47,7 +42,16 @@ func set_position_data(pos: Vector2, hurtcircle_scale_multiplier):
$HurtcircleSprite.scale_sprite(hurtcircle_scale_multiplier*2)
func kill():
# Temp
$BodySprite.modulate = Color(1, 0, 0, 1)
flash_timer = 0.5
flashing = true
if alive == false:
return
alive = false
$AudioStreamPlayer.play()
self.hide()
func resurrect():
if alive == true:
return
alive = true
self.show()

View file

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

View file

@ -1,9 +1,10 @@
[gd_scene load_steps=5 format=3 uid="uid://cd3tqt7hr5pqs"]
[gd_scene load_steps=6 format=3 uid="uid://cd3tqt7hr5pqs"]
[ext_resource type="Script" path="res://danmaku!/player.gd" id="1_r7xhp"]
[ext_resource type="Script" uid="uid://bhwiun72wpk6e" path="res://danmaku!/player.gd" id="1_r7xhp"]
[ext_resource type="Texture2D" uid="uid://bs3fntlmlqpt2" path="res://icon.svg" id="2_04s0l"]
[ext_resource type="Texture2D" uid="uid://c3deywcu4du2b" path="res://test-collision.png" id="3_gf44i"]
[ext_resource type="Script" path="res://danmaku!/ScalableSprite2D.gd" id="3_u0x7w"]
[ext_resource type="Script" uid="uid://v6jris184o8u" path="res://danmaku!/ScalableSprite2D.gd" id="3_u0x7w"]
[ext_resource type="AudioStream" uid="uid://c5n7x6q67tp78" path="res://test-death-noise.mp3" id="5_poktv"]
[node name="Player" type="Node2D"]
script = ExtResource("1_r7xhp")
@ -15,3 +16,7 @@ script = ExtResource("3_u0x7w")
[node name="HurtcircleSprite" type="Sprite2D" parent="."]
texture = ExtResource("3_gf44i")
script = ExtResource("3_u0x7w")
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("5_poktv")
volume_db = -20.0

View file

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

View file

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

View file

@ -12,7 +12,7 @@ config_version=5
config/name="danmaku!"
run/main_scene="res://danmaku!/Game.tscn"
config/features=PackedStringArray("4.3", "Forward Plus")
config/features=PackedStringArray("4.4", "Forward Plus")
config/icon="res://icon.svg"
[autoload]

BIN
client/test-death-noise.mp3 Normal file

Binary file not shown.

View file

@ -35,7 +35,7 @@ const (
STAGE_WIDTH float64 = 90.0
STAGE_HEIGHT float64 = 160.0
BULLET_KILL_BUFFER_WIDTH float64 = 16.0
PLAYER_COL_RADIUS_MULTIPLIER float64 = 0.04
PLAYER_COL_RADIUS_MULTIPLIER float64 = 0.01
PLAYER_DEATH_TIMER_MAX int = 180
)
@ -48,6 +48,7 @@ type PlayerStageState struct {
updatePlayerPos bool
health int
graze int
deathTimer int
}
type PlayerUpdate struct {
@ -118,6 +119,7 @@ func (m *BattleRoyaleMatch) MatchJoin(ctx context.Context, logger runtime.Logger
bullets: []*C.Bullet{},
updatePlayerPos: true,
health: 3,
deathTimer: -1,
},
}
}
@ -232,21 +234,30 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
return false
})
// Check if the player collided with a bullet and kill them if so
deathTimer := 0
if slices.ContainsFunc(v.stageState.bullets, func(b *C.Bullet) bool {
return bool(C.bullet_collides_with(b, C.int64_t(tick), v.stageState.col))
}) {
deathTimer = PLAYER_DEATH_TIMER_MAX
// If the player is dead. Decrement the death timer
if v.stageState.deathTimer >= 0 {
v.stageState.deathTimer -= 1
}
if v.stageState.deathTimer == 0 { // If the player's death timer has run out, reset them. 0 is a special deathTimer tick that indicates reset to the clients.
v.stageState.col.x = C.double(STAGE_WIDTH * 0.5)
v.stageState.col.y = C.double(STAGE_HEIGHT - STAGE_HEIGHT*0.1)
v.stageState.updatePlayerPos = true
} else { // If the player is alive, check if the player collided with a bullet and kill them if so
if slices.ContainsFunc(v.stageState.bullets, func(b *C.Bullet) bool {
return bool(C.bullet_collides_with(b, C.int64_t(tick), v.stageState.col))
}) {
v.stageState.deathTimer = PLAYER_DEATH_TIMER_MAX
}
}
var newBulletsToBroadcast = []map[string]interface{}{}
// Test bullet spawning
if tick%10 == 0 {
// Test bullet spawning, only when player is alive
if tick%10 == 0 && v.stageState.deathTimer == -1 {
velx := (rand.Float64() * STAGE_WIDTH) / float64(lobbyState.tickRate)
vely := (rand.Float64() * STAGE_WIDTH) / float64(lobbyState.tickRate)
radius_multiplier := 0.03 + rand.Float64()*(0.1-0.03)
radius_multiplier := 0.01 + rand.Float64()*(0.1-0.01)
vel_x_sign := 2*rand.Intn(2) - 1
vel_y_sign := 2*rand.Intn(2) - 1
@ -287,7 +298,7 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
},
NewBullets: newBulletsToBroadcast,
ForcePlayerPos: v.stageState.updatePlayerPos,
DeathTimer: deathTimer,
DeathTimer: v.stageState.deathTimer,
}
v.stageState.updatePlayerPos = false