Player bounds checking, better scaling calc on client
This commit is contained in:
parent
07f02d5a32
commit
901c4b773b
11 changed files with 209 additions and 118 deletions
29
client/danmaku!/Board.tscn
Normal file
29
client/danmaku!/Board.tscn
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
[gd_scene load_steps=4 format=3 uid="uid://b1m2pclbncn68"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://danmaku!/scaling.gd" id="1_mxxs1"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cd3tqt7hr5pqs" path="res://danmaku!/player.tscn" id="2_d6n3g"]
|
||||||
|
[ext_resource type="Script" path="res://danmaku!/network_manager.gd" id="3_4fnyw"]
|
||||||
|
|
||||||
|
[node name="Board" type="AspectRatioContainer"]
|
||||||
|
anchors_preset = -1
|
||||||
|
anchor_right = 0.263889
|
||||||
|
anchor_bottom = 0.257716
|
||||||
|
offset_right = 14.0
|
||||||
|
offset_bottom = 27.0
|
||||||
|
ratio = 0.5625
|
||||||
|
script = ExtResource("1_mxxs1")
|
||||||
|
metadata/_edit_use_anchors_ = true
|
||||||
|
|
||||||
|
[node name="ReferenceRect" type="ReferenceRect" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
border_color = Color(0.995542, 0.845388, 0.421763, 1)
|
||||||
|
editor_only = false
|
||||||
|
|
||||||
|
[node name="Container" type="Node2D" parent="ReferenceRect"]
|
||||||
|
scale = Vector2(1.2125, 1.2125)
|
||||||
|
|
||||||
|
[node name="Player" parent="ReferenceRect/Container" instance=ExtResource("2_d6n3g")]
|
||||||
|
|
||||||
|
[node name="NetworkManager" type="Node2D" parent="ReferenceRect/Container" node_paths=PackedStringArray("player")]
|
||||||
|
script = ExtResource("3_4fnyw")
|
||||||
|
player = NodePath("../Player")
|
||||||
21
client/danmaku!/Game.tscn
Normal file
21
client/danmaku!/Game.tscn
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[gd_scene load_steps=2 format=3 uid="uid://3a8txh83qfu5"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://b1m2pclbncn68" path="res://danmaku!/Board.tscn" id="1_pv3ov"]
|
||||||
|
|
||||||
|
[node name="Game" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Board" parent="." instance=ExtResource("1_pv3ov")]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_right = 0.0
|
||||||
|
offset_bottom = 0.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
2
client/danmaku!/globals.gd
Normal file
2
client/danmaku!/globals.gd
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
class_name Globals
|
||||||
|
const SERVER_SIZE = Vector2(90.0, 160.0)
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
extends Node
|
extends Node2D
|
||||||
var nakama_client: NakamaClient
|
var nakama_client: NakamaClient
|
||||||
var nakama_session: NakamaSession
|
var nakama_session: NakamaSession
|
||||||
var nakama_socket: NakamaSocket
|
var nakama_socket: NakamaSocket
|
||||||
|
|
||||||
const SERVER_WIDTH = 90.0
|
@export var player: Player
|
||||||
const SERVER_HEIGHT = 160.0
|
|
||||||
|
|
||||||
var predicted_tick = 0
|
var predicted_tick = 0
|
||||||
var delta_counter = 0
|
var delta_counter = 0
|
||||||
|
|
@ -18,7 +17,7 @@ func _ready() -> void:
|
||||||
print("Attempting to create debug match.")
|
print("Attempting to create debug match.")
|
||||||
await create_and_join_debug_match()
|
await create_and_join_debug_match()
|
||||||
nakama_socket.received_match_state.connect(self._on_match_state)
|
nakama_socket.received_match_state.connect(self._on_match_state)
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if current_match_id == "":
|
if current_match_id == "":
|
||||||
return
|
return
|
||||||
|
|
@ -30,7 +29,7 @@ func _process(delta: float) -> void:
|
||||||
var next_pos = bullet.get_current_pos(predicted_tick + 1)
|
var next_pos = bullet.get_current_pos(predicted_tick + 1)
|
||||||
var interpolated_pos = prev_pos.lerp(next_pos, bullet_lerp_factor)
|
var interpolated_pos = prev_pos.lerp(next_pos, bullet_lerp_factor)
|
||||||
|
|
||||||
bullet.position = world_to_screen(interpolated_pos)
|
bullet.position = interpolated_pos
|
||||||
|
|
||||||
#var screen_size = get_viewport().size
|
#var screen_size = get_viewport().size
|
||||||
#bullets = bullets.filter(func(bullet):
|
#bullets = bullets.filter(func(bullet):
|
||||||
|
|
@ -40,22 +39,28 @@ func _process(delta: float) -> void:
|
||||||
|
|
||||||
func _on_match_state(p_state : NakamaRTAPI.MatchData):
|
func _on_match_state(p_state : NakamaRTAPI.MatchData):
|
||||||
match p_state.op_code:
|
match p_state.op_code:
|
||||||
2: # Server state update
|
2:
|
||||||
var data = JSON.parse_string(p_state.data)
|
var data = JSON.parse_string(p_state.data)
|
||||||
var bullet = DanmakuBullet.new()
|
# Set player position given server bounds-checking
|
||||||
bullet.setup_bullet(
|
if data["forcePlayerPos"]:
|
||||||
int(data["class"]),
|
player.position = Vector2(float(data["playerPos"]["x"]), float(data["playerPos"]["y"]))
|
||||||
int(data["tick"]),
|
|
||||||
data["x"],
|
# Spawn new bullets
|
||||||
data["y"],
|
for b in data["newBullets"]:
|
||||||
data["vel_x"],
|
var bullet = DanmakuBullet.new()
|
||||||
data["vel_y"])
|
bullet.setup_bullet(
|
||||||
bullet.position = world_to_screen(bullet.get_current_pos(int(data["tick"])))
|
int(b["class"]),
|
||||||
bullet.texture = load("res://test-bullet.png")
|
int(b["tick"]),
|
||||||
add_child(bullet)
|
b["x"],
|
||||||
bullets.append(bullet)
|
b["y"],
|
||||||
#delta_counter = 0
|
b["vel_x"],
|
||||||
#predicted_tick = int(data["tick"])
|
b["vel_y"])
|
||||||
|
bullet.texture = load("res://test-bullet.png")
|
||||||
|
bullet.position = bullet.get_current_pos(int(b["tick"]))
|
||||||
|
bullet.scale = Vector2(0.2, 0.2)
|
||||||
|
add_child(bullet)
|
||||||
|
bullets.append(bullet)
|
||||||
|
#predicted_tick = int(b["tick"])
|
||||||
|
|
||||||
func attempt_auth() -> void:
|
func attempt_auth() -> void:
|
||||||
nakama_client = Nakama.create_client("defaultkey", "127.0.0.1", 7350, "http")
|
nakama_client = Nakama.create_client("defaultkey", "127.0.0.1", 7350, "http")
|
||||||
|
|
@ -83,34 +88,14 @@ func create_and_join_debug_match() -> void:
|
||||||
else:
|
else:
|
||||||
current_match_id = response.payload
|
current_match_id = response.payload
|
||||||
|
|
||||||
func world_to_screen(server_pos: Vector2) -> Vector2:
|
|
||||||
var screen_size = get_viewport().size
|
|
||||||
var scale_x = screen_size.x / SERVER_WIDTH
|
|
||||||
var scale_y = screen_size.y / SERVER_HEIGHT
|
|
||||||
|
|
||||||
var client_x = server_pos.x * scale_x
|
|
||||||
var client_y = server_pos.y * scale_y
|
|
||||||
|
|
||||||
return Vector2(client_x, client_y)
|
|
||||||
|
|
||||||
func screen_to_world(client_pos: Vector2) -> Vector2:
|
|
||||||
var screen_size = get_viewport().size
|
|
||||||
var scale_x = SERVER_WIDTH / screen_size.x
|
|
||||||
var scale_y = SERVER_HEIGHT / screen_size.y
|
|
||||||
|
|
||||||
var server_x = client_pos.x * scale_x
|
|
||||||
var server_y = client_pos.y * scale_y
|
|
||||||
|
|
||||||
return Vector2(server_x, server_y)
|
|
||||||
|
|
||||||
func predict_tick_and_broadcast(delta):
|
func predict_tick_and_broadcast(delta):
|
||||||
delta_counter += delta
|
delta_counter += delta
|
||||||
|
|
||||||
# New tick, broadcast player inputs
|
# New tick, broadcast player inputs
|
||||||
if delta_counter >= 0.05:
|
if delta_counter >= 0.05:
|
||||||
predicted_tick += 1
|
predicted_tick += 1
|
||||||
delta_counter = 0
|
delta_counter -= 0.05
|
||||||
var position = screen_to_world(get_node("../Player").position)
|
var pos = get_node("../Player").position
|
||||||
var json_string = JSON.stringify({"x": position.x, "y": position.y})
|
var json_string = JSON.stringify({"x": pos.x, "y": pos.y})
|
||||||
nakama_socket.send_match_state_async(current_match_id, 0, json_string)
|
nakama_socket.send_match_state_async(current_match_id, 0, json_string)
|
||||||
bullet_lerp_factor = delta_counter / 0.05
|
bullet_lerp_factor = delta_counter / 0.05
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,22 @@
|
||||||
|
class_name Player
|
||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
@export var speed = 400
|
@export var speed = 80
|
||||||
var velocity = 0
|
var velocity := Vector2.ZERO
|
||||||
|
|
||||||
func get_input():
|
func get_input():
|
||||||
if Input.is_action_pressed("Slow Mode"):
|
if Input.is_action_pressed("Slow Mode"):
|
||||||
speed = 200
|
speed = 40
|
||||||
else:
|
else:
|
||||||
speed = 400
|
speed = 80
|
||||||
|
|
||||||
var input_direction = Input.get_vector("Left", "Right", "Up", "Down")
|
velocity = Input.get_vector("Left", "Right", "Up", "Down") * speed
|
||||||
velocity = input_direction * speed
|
|
||||||
|
|
||||||
func _physics_process(delta):
|
func _physics_process(delta: float):
|
||||||
get_input()
|
get_input()
|
||||||
position += velocity * delta
|
|
||||||
|
# Bounds checking
|
||||||
|
var attempted_position := position + (velocity * delta)
|
||||||
|
attempted_position = attempted_position.clamp(Vector2(0, 0), Globals.SERVER_SIZE)
|
||||||
|
|
||||||
|
position = attempted_position
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,5 @@
|
||||||
script = ExtResource("1_l6typ")
|
script = ExtResource("1_l6typ")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
scale = Vector2(0.09, 0.09)
|
||||||
texture = ExtResource("2_j7sx3")
|
texture = ExtResource("2_j7sx3")
|
||||||
|
|
|
||||||
6
client/danmaku!/scaling.gd
Normal file
6
client/danmaku!/scaling.gd
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
@tool
|
||||||
|
extends AspectRatioContainer
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
var board_screen_size = $ReferenceRect.get_rect()
|
||||||
|
$ReferenceRect/Container.scale = Vector2(board_screen_size.size.x / Globals.SERVER_SIZE.x, board_screen_size.size.y / Globals.SERVER_SIZE.y)
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://b1m2pclbncn68"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://cd3tqt7hr5pqs" path="res://danmaku!/player.tscn" id="1_jeq34"]
|
|
||||||
[ext_resource type="Script" path="res://danmaku!/network_manager.gd" id="2_3453q"]
|
|
||||||
|
|
||||||
[node name="Testworld" type="Node2D"]
|
|
||||||
|
|
||||||
[node name="Player" parent="." instance=ExtResource("1_jeq34")]
|
|
||||||
|
|
||||||
[node name="NetworkManager" type="Node" parent="."]
|
|
||||||
script = ExtResource("2_3453q")
|
|
||||||
|
|
@ -11,7 +11,7 @@ config_version=5
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="danmaku!"
|
config/name="danmaku!"
|
||||||
run/main_scene="res://danmaku!/testworld.tscn"
|
run/main_scene="res://danmaku!/Game.tscn"
|
||||||
config/features=PackedStringArray("4.3", "Forward Plus")
|
config/features=PackedStringArray("4.3", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
const (
|
|
||||||
BULLET_LINEAR = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
STAGE_WIDTH float64 = 90.0
|
|
||||||
STAGE_HEIGHT float64 = 160.0
|
|
||||||
BULLET_KILL_BUFFER_WIDTH float64 = 16.0
|
|
||||||
)
|
|
||||||
152
server/main.go
152
server/main.go
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
|
@ -26,26 +27,42 @@ const (
|
||||||
MATCH_END
|
MATCH_END
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BULLET_LINEAR = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
STAGE_WIDTH float64 = 90.0
|
||||||
|
STAGE_HEIGHT float64 = 160.0
|
||||||
|
BULLET_KILL_BUFFER_WIDTH float64 = 16.0
|
||||||
|
)
|
||||||
|
|
||||||
// Interface for registering match handlers
|
// Interface for registering match handlers
|
||||||
type BattleRoyaleMatch struct{}
|
type BattleRoyaleMatch struct{}
|
||||||
|
|
||||||
type PlayerStageState struct {
|
type Position struct {
|
||||||
xPos float64
|
|
||||||
yPos float64
|
|
||||||
bullets []*C.Bullet
|
|
||||||
}
|
|
||||||
|
|
||||||
type PlayerMessageData struct {
|
|
||||||
X float64 `json:"x"`
|
X float64 `json:"x"`
|
||||||
Y float64 `json:"y"`
|
Y float64 `json:"y"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PlayerStageState struct {
|
||||||
|
pos Position
|
||||||
|
bullets []*C.Bullet
|
||||||
|
updatePlayerPos bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type GameTickUpdate struct {
|
||||||
|
Tick int64 `json:"tick"`
|
||||||
|
PlayerPos Position `json:"playerPos"`
|
||||||
|
NewBullets []map[string]interface{} `json:"newBullets"`
|
||||||
|
ForcePlayerPos bool `json:"forcePlayerPos"`
|
||||||
|
}
|
||||||
|
|
||||||
type PresenceState struct { // present time! hahahahahahahah!
|
type PresenceState struct { // present time! hahahahahahahah!
|
||||||
presence runtime.Presence
|
presence runtime.Presence
|
||||||
stageState PlayerStageState
|
stageState PlayerStageState
|
||||||
}
|
}
|
||||||
|
|
||||||
// In-memory game state
|
|
||||||
type BattleRoyaleMatchState struct {
|
type BattleRoyaleMatchState struct {
|
||||||
tickRate int
|
tickRate int
|
||||||
currentMatchPhase int
|
currentMatchPhase int
|
||||||
|
|
@ -92,9 +109,12 @@ func (m *BattleRoyaleMatch) MatchJoin(ctx context.Context, logger runtime.Logger
|
||||||
lobbyState.presences[presences[i].GetSessionId()] = &PresenceState{
|
lobbyState.presences[presences[i].GetSessionId()] = &PresenceState{
|
||||||
presence: presences[i],
|
presence: presences[i],
|
||||||
stageState: PlayerStageState{
|
stageState: PlayerStageState{
|
||||||
xPos: STAGE_WIDTH * 0.5,
|
pos: Position{
|
||||||
yPos: STAGE_HEIGHT - STAGE_HEIGHT*0.1,
|
X: STAGE_WIDTH * 0.5,
|
||||||
bullets: []*C.Bullet{},
|
Y: STAGE_HEIGHT - STAGE_HEIGHT*0.1,
|
||||||
|
},
|
||||||
|
bullets: []*C.Bullet{},
|
||||||
|
updatePlayerPos: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +131,16 @@ func (m *BattleRoyaleMatch) MatchLeave(ctx context.Context, logger runtime.Logge
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(presences); i++ {
|
for i := 0; i < len(presences); i++ {
|
||||||
delete(lobbyState.presences, presences[i].GetSessionId())
|
sessionID := presences[i].GetSessionId()
|
||||||
|
|
||||||
|
playerState, exists := lobbyState.presences[sessionID]
|
||||||
|
if exists {
|
||||||
|
for _, bullet := range playerState.stageState.bullets {
|
||||||
|
C.destroy_bullet(bullet)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(lobbyState.presences, sessionID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lobbyState
|
return lobbyState
|
||||||
|
|
@ -158,9 +187,52 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test bullet spawning
|
// Respond to player input
|
||||||
if tick%1 == 0 {
|
for _, msg := range messages {
|
||||||
for _, v := range lobbyState.presences {
|
// Validate player existence
|
||||||
|
_, exists := lobbyState.presences[msg.GetSessionId()]
|
||||||
|
if !exists {
|
||||||
|
logger.Warn("Received input for non-existent player session ID: %v", msg.GetSessionId())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse player message
|
||||||
|
var pos Position
|
||||||
|
if err := json.Unmarshal(msg.GetData(), &pos); err != nil {
|
||||||
|
logger.Warn("Failed to parse input: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player movement bounds detection
|
||||||
|
clampedX := pos.X < 0 || pos.X > STAGE_WIDTH
|
||||||
|
clampedY := pos.Y < 0 || pos.Y > STAGE_HEIGHT
|
||||||
|
|
||||||
|
pos.X = math.Max(0, math.Min(pos.X, STAGE_WIDTH))
|
||||||
|
pos.Y = math.Max(0, math.Min(pos.Y, STAGE_HEIGHT))
|
||||||
|
|
||||||
|
lobbyState.presences[msg.GetSessionId()].stageState.pos.X = pos.X
|
||||||
|
lobbyState.presences[msg.GetSessionId()].stageState.pos.Y = pos.Y
|
||||||
|
|
||||||
|
if clampedX || clampedY {
|
||||||
|
lobbyState.presences[msg.GetSessionId()].stageState.updatePlayerPos = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute and broadcast per-presence state
|
||||||
|
for _, v := range lobbyState.presences {
|
||||||
|
// Clean up bullets when they pass off the board
|
||||||
|
v.stageState.bullets = slices.DeleteFunc(v.stageState.bullets, func(b *C.Bullet) bool {
|
||||||
|
if C.bullet_beyond_kill_boundary(b, C.int64_t(tick)) {
|
||||||
|
C.destroy_bullet(b)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
var newBulletsToBroadcast = []map[string]interface{}{}
|
||||||
|
|
||||||
|
// Test bullet spawning
|
||||||
|
if tick%1 == 0 {
|
||||||
velx := rand.Float64()*(STAGE_WIDTH/float64(lobbyState.tickRate)) + 1.0
|
velx := rand.Float64()*(STAGE_WIDTH/float64(lobbyState.tickRate)) + 1.0
|
||||||
vely := rand.Float64()*(STAGE_WIDTH/float64(lobbyState.tickRate)) + 1.0
|
vely := rand.Float64()*(STAGE_WIDTH/float64(lobbyState.tickRate)) + 1.0
|
||||||
vel_x_sign := 2*rand.Intn(2) - 1
|
vel_x_sign := 2*rand.Intn(2) - 1
|
||||||
|
|
@ -175,6 +247,8 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
||||||
C.double(float64(vel_y_sign)*vely),
|
C.double(float64(vel_y_sign)*vely),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
v.stageState.bullets = append(v.stageState.bullets, bullet)
|
||||||
|
|
||||||
var x, y C.double
|
var x, y C.double
|
||||||
C.bullet_get_current_pos(bullet, C.int64_t(tick), &x, &y)
|
C.bullet_get_current_pos(bullet, C.int64_t(tick), &x, &y)
|
||||||
|
|
||||||
|
|
@ -187,38 +261,28 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
||||||
"vel_y": float64(vel_y_sign) * vely,
|
"vel_y": float64(vel_y_sign) * vely,
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(bulletData)
|
newBulletsToBroadcast = append(newBulletsToBroadcast, bulletData)
|
||||||
if err != nil {
|
|
||||||
logger.Error("Error marshalling bullet data", err)
|
|
||||||
} else {
|
|
||||||
v.stageState.bullets = append(v.stageState.bullets, bullet)
|
|
||||||
reliable := true
|
|
||||||
dispatcher.BroadcastMessage(STATE_UPDATE, data, nil, nil, reliable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Respond to player input
|
|
||||||
for _, msg := range messages {
|
|
||||||
var pos PlayerMessageData
|
|
||||||
if err := json.Unmarshal(msg.GetData(), &pos); err != nil {
|
|
||||||
logger.Warn("Failed to parse input: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyState.presences[msg.GetSessionId()].stageState.xPos = pos.X
|
var tickData = GameTickUpdate{
|
||||||
lobbyState.presences[msg.GetSessionId()].stageState.yPos = pos.Y
|
Tick: tick,
|
||||||
}
|
PlayerPos: Position{
|
||||||
|
X: v.stageState.pos.X,
|
||||||
|
Y: v.stageState.pos.Y,
|
||||||
|
},
|
||||||
|
NewBullets: newBulletsToBroadcast,
|
||||||
|
ForcePlayerPos: v.stageState.updatePlayerPos,
|
||||||
|
}
|
||||||
|
|
||||||
// Bullet cleanup when off board
|
v.stageState.updatePlayerPos = false
|
||||||
for _, v := range lobbyState.presences {
|
|
||||||
v.stageState.bullets = slices.DeleteFunc(v.stageState.bullets, func(b *C.Bullet) bool {
|
data, err := json.Marshal(tickData)
|
||||||
if C.bullet_beyond_kill_boundary(b, C.int64_t(tick)) {
|
if err != nil {
|
||||||
C.destroy_bullet(b)
|
logger.Error("Error marshalling bullet data", err)
|
||||||
return true
|
} else {
|
||||||
}
|
reliable := true
|
||||||
return false
|
dispatcher.BroadcastMessage(STATE_UPDATE, data, nil, nil, reliable)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lobbyState
|
return lobbyState
|
||||||
|
|
|
||||||
Reference in a new issue