diff --git a/client/danmaku!/Board.tscn b/client/danmaku!/Board.tscn index 20a1659..dd95b89 100644 --- a/client/danmaku!/Board.tscn +++ b/client/danmaku!/Board.tscn @@ -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") diff --git a/client/danmaku!/ScalableSprite2D.gd b/client/danmaku!/ScalableSprite2D.gd new file mode 100644 index 0000000..5eff03d --- /dev/null +++ b/client/danmaku!/ScalableSprite2D.gd @@ -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) diff --git a/client/danmaku!/network_manager.gd b/client/danmaku!/network_manager.gd index caa9214..cc21624 100644 --- a/client/danmaku!/network_manager.gd +++ b/client/danmaku!/network_manager.gd @@ -39,12 +39,21 @@ 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"]: var bullet = DanmakuBullet.new() @@ -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"]) diff --git a/client/danmaku!/player.gd b/client/danmaku!/player.gd index e78d73d..2e13b85 100644 --- a/client/danmaku!/player.gd +++ b/client/danmaku!/player.gd @@ -3,7 +3,18 @@ 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"): speed = 30 @@ -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 diff --git a/client/danmaku!/player.tscn b/client/danmaku!/player.tscn index 1cdb5a6..e49a7e2 100644 --- a/client/danmaku!/player.tscn +++ b/client/danmaku!/player.tscn @@ -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") diff --git a/client/test-bullet.png b/client/test-bullet.png index 6e2028c..5f44ab3 100644 Binary files a/client/test-bullet.png and b/client/test-bullet.png differ diff --git a/client/test-collision.png b/client/test-collision.png new file mode 100644 index 0000000..de20509 Binary files /dev/null and b/client/test-collision.png differ diff --git a/ffi-wrapper/src/ffi.rs b/ffi-wrapper/src/ffi.rs index 96773e7..a6dfb2e 100644 --- a/ffi-wrapper/src/ffi.rs +++ b/ffi-wrapper/src/ffi.rs @@ -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; } diff --git a/server/main.go b/server/main.go index dc172db..cd2526b 100644 --- a/server/main.go +++ b/server/main.go @@ -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