Server-based collision and player death
This commit is contained in:
parent
5d11565a4d
commit
0b8091b352
9 changed files with 96 additions and 26 deletions
|
|
@ -30,6 +30,7 @@ unique_name_in_owner = true
|
|||
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")]
|
||||
script = ExtResource("2_b2dol")
|
||||
|
|
|
|||
6
client/danmaku!/ScalableSprite2D.gd
Normal file
6
client/danmaku!/ScalableSprite2D.gd
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
class_name ScalableSprite2D
|
||||
extends Sprite2D
|
||||
|
||||
func scale_sprite(world_space_multiple: float):
|
||||
var scale_factor = (world_space_multiple * Globals.SERVER_SIZE.x) / self.texture.get_width()
|
||||
self.scale = Vector2(scale_factor, scale_factor)
|
||||
|
|
@ -39,11 +39,20 @@ func _on_match_state(p_state : NakamaRTAPI.MatchData):
|
|||
match p_state.op_code:
|
||||
2:
|
||||
var data = JSON.parse_string(p_state.data)
|
||||
print(data)
|
||||
|
||||
# Set player position given server bounds-checking
|
||||
if data["forcePlayerPos"]:
|
||||
player.position = Vector2(float(data["playerPos"]["x"]), float(data["playerPos"]["y"]))
|
||||
player.set_position_data(
|
||||
Vector2(
|
||||
float(data["playerPos"]["x"]),
|
||||
float(data["playerPos"]["y"])
|
||||
),
|
||||
float(data["playerPos"]["radius_multiplier"])
|
||||
)
|
||||
|
||||
if int(data["deathTimer"]) > 0:
|
||||
print("server says u died")
|
||||
%Player.kill()
|
||||
|
||||
# Spawn new bullets
|
||||
for b in data["newBullets"]:
|
||||
|
|
@ -53,12 +62,16 @@ func _on_match_state(p_state : NakamaRTAPI.MatchData):
|
|||
int(b["tick"]),
|
||||
b["x"],
|
||||
b["y"],
|
||||
b["radius"],
|
||||
b["radius_multiplier"] * Globals.SERVER_SIZE.x,
|
||||
b["vel_x"],
|
||||
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)
|
||||
|
||||
# Reimplemented from ScalableSprite2D here atm
|
||||
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)
|
||||
predicted_tick = int(b["tick"])
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@ extends Node2D
|
|||
|
||||
@export var speed = 80
|
||||
var velocity := Vector2.ZERO
|
||||
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
|
||||
|
||||
func _ready() -> void:
|
||||
$BodySprite.scale_sprite(PLAYER_BODY_WIDTH_MULTIPLIER)
|
||||
|
||||
func get_input():
|
||||
if Input.is_action_pressed("Slow Mode"):
|
||||
|
|
@ -13,10 +24,30 @@ 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
|
||||
|
||||
get_input()
|
||||
|
||||
# Bounds checking
|
||||
var attempted_position := position + (velocity * delta)
|
||||
attempted_position = attempted_position.clamp(Vector2(0, 0), Globals.SERVER_SIZE)
|
||||
|
||||
position = attempted_position
|
||||
set_position_data(attempted_position, null)
|
||||
|
||||
func set_position_data(pos: Vector2, hurtcircle_scale_multiplier):
|
||||
position = pos
|
||||
collision.set_position(pos.x, pos.y)
|
||||
|
||||
if hurtcircle_scale_multiplier:
|
||||
collision.set_radius(Globals.SERVER_SIZE.x*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
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://cd3tqt7hr5pqs"]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://cd3tqt7hr5pqs"]
|
||||
|
||||
[ext_resource type="Script" 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"]
|
||||
|
||||
[node name="Player" type="Node2D"]
|
||||
script = ExtResource("1_r7xhp")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
scale = Vector2(0.09, 0.09)
|
||||
[node name="BodySprite" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("2_04s0l")
|
||||
script = ExtResource("3_u0x7w")
|
||||
|
||||
[node name="HurtcircleSprite" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("3_gf44i")
|
||||
script = ExtResource("3_u0x7w")
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 743 B After Width: | Height: | Size: 1.2 KiB |
BIN
client/test-collision.png
Normal file
BIN
client/test-collision.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -47,7 +47,7 @@ pub extern "C" fn destroy_bullet(bullet: *mut Bullet) {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn bullet_collides_with(tick: i64, bullet: *mut Bullet, c: *const Circle) -> bool {
|
||||
pub extern "C" fn bullet_collides_with(bullet: *mut Bullet, tick: i64, c: *const Circle) -> bool {
|
||||
if bullet.is_null() || c.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,11 @@ const (
|
|||
)
|
||||
|
||||
const (
|
||||
STAGE_WIDTH float64 = 90.0
|
||||
STAGE_HEIGHT float64 = 160.0
|
||||
BULLET_KILL_BUFFER_WIDTH float64 = 16.0
|
||||
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_DEATH_TIMER_MAX int = 180
|
||||
)
|
||||
|
||||
// Interface for registering match handlers
|
||||
|
|
@ -58,6 +60,7 @@ type GameTickUpdate struct {
|
|||
PlayerPos map[string]interface{} `json:"playerPos"`
|
||||
NewBullets []map[string]interface{} `json:"newBullets"`
|
||||
ForcePlayerPos bool `json:"forcePlayerPos"`
|
||||
DeathTimer int `json:"deathTimer"`
|
||||
}
|
||||
|
||||
type PresenceState struct { // present time! hahahahahahahah!
|
||||
|
|
@ -111,7 +114,7 @@ func (m *BattleRoyaleMatch) MatchJoin(ctx context.Context, logger runtime.Logger
|
|||
lobbyState.presences[presences[i].GetSessionId()] = &PresenceState{
|
||||
presence: presences[i],
|
||||
stageState: PlayerStageState{
|
||||
col: C.new_circle(C.double(STAGE_WIDTH*0.5), C.double(STAGE_HEIGHT-STAGE_HEIGHT*0.1), C.double(STAGE_WIDTH*0.09)),
|
||||
col: C.new_circle(C.double(STAGE_WIDTH*0.5), C.double(STAGE_HEIGHT-STAGE_HEIGHT*0.1), C.double(STAGE_WIDTH*PLAYER_COL_RADIUS_MULTIPLIER)),
|
||||
bullets: []*C.Bullet{},
|
||||
updatePlayerPos: true,
|
||||
health: 3,
|
||||
|
|
@ -229,13 +232,21 @@ 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
|
||||
}
|
||||
|
||||
var newBulletsToBroadcast = []map[string]interface{}{}
|
||||
|
||||
// Test bullet spawning
|
||||
if tick%10 == 0 {
|
||||
velx := (rand.Float64() * STAGE_WIDTH) / float64(lobbyState.tickRate)
|
||||
vely := (rand.Float64() * STAGE_WIDTH) / float64(lobbyState.tickRate)
|
||||
radius := 0.03
|
||||
radius_multiplier := 0.03 + rand.Float64()*(0.1-0.03)
|
||||
vel_x_sign := 2*rand.Intn(2) - 1
|
||||
vel_y_sign := 2*rand.Intn(2) - 1
|
||||
|
||||
|
|
@ -244,7 +255,7 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
|||
C.int64_t(tick),
|
||||
C.double(STAGE_WIDTH*rand.Float64()),
|
||||
C.double(STAGE_HEIGHT*rand.Float64()),
|
||||
C.double(radius),
|
||||
C.double(radius_multiplier*STAGE_WIDTH),
|
||||
C.double(float64(vel_x_sign)*velx),
|
||||
C.double(float64(vel_y_sign)*vely),
|
||||
)
|
||||
|
|
@ -255,13 +266,13 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
|||
C.bullet_get_current_pos(bullet, C.int64_t(tick), &x, &y)
|
||||
|
||||
bulletData := map[string]interface{}{
|
||||
"class": BULLET_LINEAR,
|
||||
"tick": tick,
|
||||
"x": float64(x),
|
||||
"y": float64(y),
|
||||
"radius": float64(radius),
|
||||
"vel_x": float64(vel_x_sign) * velx,
|
||||
"vel_y": float64(vel_y_sign) * vely,
|
||||
"class": BULLET_LINEAR,
|
||||
"tick": tick,
|
||||
"x": float64(x),
|
||||
"y": float64(y),
|
||||
"radius_multiplier": float64(radius_multiplier),
|
||||
"vel_x": float64(vel_x_sign) * velx,
|
||||
"vel_y": float64(vel_y_sign) * vely,
|
||||
}
|
||||
|
||||
newBulletsToBroadcast = append(newBulletsToBroadcast, bulletData)
|
||||
|
|
@ -270,11 +281,13 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
|||
var tickData = GameTickUpdate{
|
||||
Tick: tick,
|
||||
PlayerPos: map[string]interface{}{
|
||||
"x": v.stageState.col.x,
|
||||
"y": v.stageState.col.y,
|
||||
"x": v.stageState.col.x,
|
||||
"y": v.stageState.col.y,
|
||||
"radius_multiplier": PLAYER_COL_RADIUS_MULTIPLIER,
|
||||
},
|
||||
NewBullets: newBulletsToBroadcast,
|
||||
ForcePlayerPos: v.stageState.updatePlayerPos,
|
||||
DeathTimer: deathTimer,
|
||||
}
|
||||
|
||||
v.stageState.updatePlayerPos = false
|
||||
|
|
|
|||
Reference in a new issue