Player death and position reset. Also Godot 4.4
This commit is contained in:
parent
0b8091b352
commit
6eec1f6181
32 changed files with 118 additions and 59 deletions
1
client/addons/com.heroiclabs.nakama/Nakama.gd.uid
Normal file
1
client/addons/com.heroiclabs.nakama/Nakama.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b3os1t7djg0c7
|
||||
1
client/addons/com.heroiclabs.nakama/api/NakamaAPI.gd.uid
Normal file
1
client/addons/com.heroiclabs.nakama/api/NakamaAPI.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://hebdk7gx1u8c
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://2l8y628n8ukc
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d4lu87a2trueb
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://ckcep8xcypxhx
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bqgpnrx3ym11e
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://csqmo268gf217
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://do7ks66xlkvqg
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://chnrd7u5qamlq
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://iy2uo326og1p
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c8tfobve6b0k4
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dqyr6q4tquve3
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dp68cesoggrb4
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://duqqgdiqwur2g
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c35k2c0pg7csr
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dldoidphr80mb
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bnxd5hq82ncyw
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
22
client/danmaku!/BulletManager.gd
Normal file
22
client/danmaku!/BulletManager.gd
Normal 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)
|
||||
1
client/danmaku!/BulletManager.gd.uid
Normal file
1
client/danmaku!/BulletManager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ddc5iqgtyv2ns
|
||||
1
client/danmaku!/ScalableSprite2D.gd.uid
Normal file
1
client/danmaku!/ScalableSprite2D.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://v6jris184o8u
|
||||
1
client/danmaku!/globals.gd.uid
Normal file
1
client/danmaku!/globals.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ca3lryv0wsoat
|
||||
|
|
@ -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
|
||||
|
|
|
|||
1
client/danmaku!/network_manager.gd.uid
Normal file
1
client/danmaku!/network_manager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cd67rrch5h4t7
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
1
client/danmaku!/player.gd.uid
Normal file
1
client/danmaku!/player.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bhwiun72wpk6e
|
||||
|
|
@ -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
|
||||
|
|
|
|||
1
client/danmaku!/scaling.gd.uid
Normal file
1
client/danmaku!/scaling.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ggkxv1cb1bjk
|
||||
1
client/danmaku-shared.gdextension.uid
Normal file
1
client/danmaku-shared.gdextension.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b4v43qwewcg37
|
||||
|
|
@ -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
BIN
client/test-death-noise.mp3
Normal file
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
Reference in a new issue