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)
|
scale = Vector2(6.75, 6.75)
|
||||||
|
|
||||||
[node name="Player" parent="World" instance=ExtResource("1_22cjd")]
|
[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="NetworkManager" type="Node2D" parent="World" node_paths=PackedStringArray("player")]
|
||||||
script = ExtResource("2_b2dol")
|
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:
|
match p_state.op_code:
|
||||||
2:
|
2:
|
||||||
var data = JSON.parse_string(p_state.data)
|
var data = JSON.parse_string(p_state.data)
|
||||||
print(data)
|
|
||||||
|
|
||||||
# Set player position given server bounds-checking
|
# Set player position given server bounds-checking
|
||||||
if data["forcePlayerPos"]:
|
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
|
# Spawn new bullets
|
||||||
for b in data["newBullets"]:
|
for b in data["newBullets"]:
|
||||||
|
|
@ -53,12 +62,16 @@ func _on_match_state(p_state : NakamaRTAPI.MatchData):
|
||||||
int(b["tick"]),
|
int(b["tick"]),
|
||||||
b["x"],
|
b["x"],
|
||||||
b["y"],
|
b["y"],
|
||||||
b["radius"],
|
b["radius_multiplier"] * Globals.SERVER_SIZE.x,
|
||||||
b["vel_x"],
|
b["vel_x"],
|
||||||
b["vel_y"])
|
b["vel_y"])
|
||||||
bullet.texture = load("res://test-bullet.png")
|
bullet.texture = load("res://test-bullet.png")
|
||||||
bullet.position = bullet.get_current_pos(int(b["tick"]))
|
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)
|
add_child(bullet)
|
||||||
bullets.append(bullet)
|
bullets.append(bullet)
|
||||||
predicted_tick = int(b["tick"])
|
predicted_tick = int(b["tick"])
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,17 @@ extends Node2D
|
||||||
|
|
||||||
@export var speed = 80
|
@export var speed = 80
|
||||||
var velocity := Vector2.ZERO
|
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():
|
func get_input():
|
||||||
if Input.is_action_pressed("Slow Mode"):
|
if Input.is_action_pressed("Slow Mode"):
|
||||||
|
|
@ -13,10 +24,30 @@ func get_input():
|
||||||
velocity = Input.get_vector("Left", "Right", "Up", "Down") * speed
|
velocity = Input.get_vector("Left", "Right", "Up", "Down") * speed
|
||||||
|
|
||||||
func _physics_process(delta: float):
|
func _physics_process(delta: float):
|
||||||
|
# Temp
|
||||||
|
if flashing:
|
||||||
|
flash_timer -= delta
|
||||||
|
$BodySprite.modulate = Color(1, 1, 1, 1)
|
||||||
|
flashing = false
|
||||||
|
|
||||||
get_input()
|
get_input()
|
||||||
|
|
||||||
# Bounds checking
|
# Bounds checking
|
||||||
var attempted_position := position + (velocity * delta)
|
var attempted_position := position + (velocity * delta)
|
||||||
attempted_position = attempted_position.clamp(Vector2(0, 0), Globals.SERVER_SIZE)
|
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="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://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"]
|
[node name="Player" type="Node2D"]
|
||||||
script = ExtResource("1_r7xhp")
|
script = ExtResource("1_r7xhp")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="BodySprite" type="Sprite2D" parent="."]
|
||||||
scale = Vector2(0.09, 0.09)
|
|
||||||
texture = ExtResource("2_04s0l")
|
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]
|
#[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() {
|
if bullet.is_null() || c.is_null() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,11 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
STAGE_WIDTH float64 = 90.0
|
STAGE_WIDTH float64 = 90.0
|
||||||
STAGE_HEIGHT float64 = 160.0
|
STAGE_HEIGHT float64 = 160.0
|
||||||
BULLET_KILL_BUFFER_WIDTH float64 = 16.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
|
// Interface for registering match handlers
|
||||||
|
|
@ -58,6 +60,7 @@ type GameTickUpdate struct {
|
||||||
PlayerPos map[string]interface{} `json:"playerPos"`
|
PlayerPos map[string]interface{} `json:"playerPos"`
|
||||||
NewBullets []map[string]interface{} `json:"newBullets"`
|
NewBullets []map[string]interface{} `json:"newBullets"`
|
||||||
ForcePlayerPos bool `json:"forcePlayerPos"`
|
ForcePlayerPos bool `json:"forcePlayerPos"`
|
||||||
|
DeathTimer int `json:"deathTimer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PresenceState struct { // present time! hahahahahahahah!
|
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{
|
lobbyState.presences[presences[i].GetSessionId()] = &PresenceState{
|
||||||
presence: presences[i],
|
presence: presences[i],
|
||||||
stageState: PlayerStageState{
|
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{},
|
bullets: []*C.Bullet{},
|
||||||
updatePlayerPos: true,
|
updatePlayerPos: true,
|
||||||
health: 3,
|
health: 3,
|
||||||
|
|
@ -229,13 +232,21 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
||||||
return false
|
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{}{}
|
var newBulletsToBroadcast = []map[string]interface{}{}
|
||||||
|
|
||||||
// Test bullet spawning
|
// Test bullet spawning
|
||||||
if tick%10 == 0 {
|
if tick%10 == 0 {
|
||||||
velx := (rand.Float64() * STAGE_WIDTH) / float64(lobbyState.tickRate)
|
velx := (rand.Float64() * STAGE_WIDTH) / float64(lobbyState.tickRate)
|
||||||
vely := (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_x_sign := 2*rand.Intn(2) - 1
|
||||||
vel_y_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.int64_t(tick),
|
||||||
C.double(STAGE_WIDTH*rand.Float64()),
|
C.double(STAGE_WIDTH*rand.Float64()),
|
||||||
C.double(STAGE_HEIGHT*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_x_sign)*velx),
|
||||||
C.double(float64(vel_y_sign)*vely),
|
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)
|
C.bullet_get_current_pos(bullet, C.int64_t(tick), &x, &y)
|
||||||
|
|
||||||
bulletData := map[string]interface{}{
|
bulletData := map[string]interface{}{
|
||||||
"class": BULLET_LINEAR,
|
"class": BULLET_LINEAR,
|
||||||
"tick": tick,
|
"tick": tick,
|
||||||
"x": float64(x),
|
"x": float64(x),
|
||||||
"y": float64(y),
|
"y": float64(y),
|
||||||
"radius": float64(radius),
|
"radius_multiplier": float64(radius_multiplier),
|
||||||
"vel_x": float64(vel_x_sign) * velx,
|
"vel_x": float64(vel_x_sign) * velx,
|
||||||
"vel_y": float64(vel_y_sign) * vely,
|
"vel_y": float64(vel_y_sign) * vely,
|
||||||
}
|
}
|
||||||
|
|
||||||
newBulletsToBroadcast = append(newBulletsToBroadcast, bulletData)
|
newBulletsToBroadcast = append(newBulletsToBroadcast, bulletData)
|
||||||
|
|
@ -270,11 +281,13 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
||||||
var tickData = GameTickUpdate{
|
var tickData = GameTickUpdate{
|
||||||
Tick: tick,
|
Tick: tick,
|
||||||
PlayerPos: map[string]interface{}{
|
PlayerPos: map[string]interface{}{
|
||||||
"x": v.stageState.col.x,
|
"x": v.stageState.col.x,
|
||||||
"y": v.stageState.col.y,
|
"y": v.stageState.col.y,
|
||||||
|
"radius_multiplier": PLAYER_COL_RADIUS_MULTIPLIER,
|
||||||
},
|
},
|
||||||
NewBullets: newBulletsToBroadcast,
|
NewBullets: newBulletsToBroadcast,
|
||||||
ForcePlayerPos: v.stageState.updatePlayerPos,
|
ForcePlayerPos: v.stageState.updatePlayerPos,
|
||||||
|
DeathTimer: deathTimer,
|
||||||
}
|
}
|
||||||
|
|
||||||
v.stageState.updatePlayerPos = false
|
v.stageState.updatePlayerPos = false
|
||||||
|
|
|
||||||
Reference in a new issue