fix: Поправил физику коллизий

This commit is contained in:
2026-08-28 20:39:05 +05:00
parent cdadd72635
commit 99cc4a4ff7
2 changed files with 45 additions and 60 deletions
+19 -29
View File
@@ -10,13 +10,12 @@ Entity :: struct {
position: rl.Vector2, position: rl.Vector2,
hp: i32, hp: i32,
speed: f32, speed: f32,
walk_speed: f32,
col: f32, col: f32,
} }
Player :: struct { Player :: struct {
using ent: Entity, using ent: Entity,
walk_speed: f32,
run_speed: f32,
} }
Enemy :: struct { Enemy :: struct {
@@ -41,12 +40,6 @@ update_player :: proc(player: ^Player, dt: f32) {
} }
input = rl.Vector2Normalize(input) input = rl.Vector2Normalize(input)
if rl.IsKeyDown(.LEFT_SHIFT) {
player.speed = player.run_speed
} else {
player.speed = player.walk_speed
}
player.position += input * player.speed * dt player.position += input * player.speed * dt
} }
@@ -60,7 +53,9 @@ calc_col_box :: proc(center: rl.Vector2, side: f32) -> rl.Rectangle {
} }
resolve_entity_overlap :: proc(a, b: ^Entity) { // разводит пересёкшиеся боксы: b получает долю b_share правки, a — остаток.
// Враг-враг: пополам. Игрок-враг: враг поддаётся слабо (доля мала) — «вес»
resolve_entity_overlap :: proc(a, b: ^Entity, b_share: f32 = 0.5) {
ra := calc_col_box(a.position, a.col) ra := calc_col_box(a.position, a.col)
rb := calc_col_box(b.position, b.col) rb := calc_col_box(b.position, b.col)
@@ -69,39 +64,34 @@ resolve_entity_overlap :: proc(a, b: ^Entity) {
overlap_x := min(ra.x + ra.width - rb.x, rb.x + rb.width - ra.x) overlap_x := min(ra.x + ra.width - rb.x, rb.x + rb.width - ra.x)
overlap_y := min(ra.y + ra.height - rb.y, rb.y + rb.height - ra.y) overlap_y := min(ra.y + ra.height - rb.y, rb.y + rb.height - ra.y)
dx, dy: f32
if overlap_x < overlap_y { if overlap_x < overlap_y {
half := overlap_x / 2 dx = overlap_x if a.position.x < b.position.x else -overlap_x
if a.position.x < b.position.x {
a.position.x -= half
b.position.x += half
} else { } else {
a.position.x += half dy = overlap_y if a.position.y < b.position.y else -overlap_y
b.position.x -= half
}
} else {
half := overlap_y / 2
if a.position.y < b.position.y {
a.position.y -= half
b.position.y += half
} else {
a.position.y += half
b.position.y -= half
}
} }
a.position.x -= dx * (1 - b_share)
a.position.y -= dy * (1 - b_share)
b.position.x += dx * b_share
b.position.y += dy * b_share
} }
resolve_collisions :: proc(scene: ^Scene) { resolve_collisions :: proc(scene: ^Scene) {
it := hm.iterator_make(&scene.enemies) it := hm.iterator_make(&scene.enemies)
for i, _ in hm.iterate(&it) { for i, hi in hm.iterate(&it) {
// пары симметричны: пушим обе стороны, поэтому каждую обрабатываем один раз
it2 := hm.iterator_make(&scene.enemies) it2 := hm.iterator_make(&scene.enemies)
for j, _ in hm.iterate(&it2) { for j, hj in hm.iterate(&it2) {
if i == j do continue if hj.idx <= hi.idx do continue
resolve_entity_overlap(i, j) resolve_entity_overlap(i, j)
} }
} }
it = hm.iterator_make(&scene.enemies) it = hm.iterator_make(&scene.enemies)
for i, _ in hm.iterate(&it) { for i, _ in hm.iterate(&it) {
resolve_entity_overlap(&scene.player.ent, i) // «вес»: враг поддаётся на 80%, игрок на 20% — враг упирается в игрока,
// а игрок выдавливает врага перед собой
resolve_entity_overlap(&scene.player.ent, i, b_share = 0.6)
} }
} }
+21 -26
View File
@@ -28,7 +28,7 @@ create_scene :: proc() -> Scene {
position = rl.Vector2{100, 100}, position = rl.Vector2{100, 100},
hp = 100, hp = 100,
walk_speed = 300, walk_speed = 300,
run_speed = 500, speed = 300,
col = 32, col = 32,
}, },
camera = rl.Camera2D { camera = rl.Camera2D {
@@ -38,24 +38,24 @@ create_scene :: proc() -> Scene {
} }
// _ = hm.add( _ = hm.add(
// &scene.enemies, &scene.enemies,
// Enemy { Enemy {
// position = rl.Vector2{500, 500}, position = rl.Vector2{500, 500},
// hp = 100, hp = 100,
// speed = 100, speed = 100,
// col = 32, col = 32,
// }, },
// ) )
// _ = hm.add( _ = hm.add(
// &scene.enemies, &scene.enemies,
// Enemy { Enemy {
// position = rl.Vector2{600, 600}, position = rl.Vector2{600, 600},
// hp = 100, hp = 100,
// speed = 100, speed = 100,
// col = 32, col = 32,
// }, },
// ) )
scene.atlas = load_atlas() scene.atlas = load_atlas()
@@ -89,18 +89,12 @@ draw_scene :: proc(scene: ^Scene) {
rl.WHITE, rl.WHITE,
) )
// for tile in scene.tiles {
// if tile.atlas == nil do continue
// draw_tile(tile)
// }
rl.DrawCircle( rl.DrawCircle(
cast(i32)scene.player.position.x, cast(i32)scene.player.position.x,
cast(i32)scene.player.position.y, cast(i32)scene.player.position.y,
32, 32,
rl.GREEN, rl.GREEN,
) )
rl.DrawRectangle(300, 300, 100, 100, rl.BLUE)
it := hm.iterator_make(&scene.enemies) it := hm.iterator_make(&scene.enemies)
for i, _ in hm.iterate(&it) { for i, _ in hm.iterate(&it) {
@@ -121,7 +115,8 @@ render_map :: proc(atlas: ^Atlas, map_data: Map) -> rl.RenderTexture2D {
rl.BeginTextureMode(tex) rl.BeginTextureMode(tex)
for layer in map_data.layers { for layer in map_data.layers {
for row_data, row in layer.data { for row_data, row in layer.data {
dest_y := f32(i32(map_data.height) - 1 - i32(row)) * atlas.tile_size.y dest_y :=
f32(i32(map_data.height) - 1 - i32(row)) * atlas.tile_size.y
for tile_id, col in row_data { for tile_id, col in row_data {
offset, empty := get_offset(atlas, tile_id) offset, empty := get_offset(atlas, tile_id)
if empty do continue if empty do continue