106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
package physics
|
||
|
||
import "testing"
|
||
|
||
// planeWorld 测试世界:y < 63 全固体,y >= 63 空气;x == 5 一堵墙。
|
||
type planeWorld struct{}
|
||
|
||
func (planeWorld) Solid(x, y, z int32) bool {
|
||
return y < 63 || x == 5
|
||
}
|
||
func (planeWorld) Fluid(x, y, z int32) bool { return false }
|
||
|
||
// TestFallOntoGround 下落 → 停在 63 层顶部(浮点余量内),OnGround 置位。
|
||
func TestFallOntoGround(t *testing.T) {
|
||
w := planeWorld{}
|
||
p := NewPlayer(0.5, 80, 0.5)
|
||
for i := 0; i < 200; i++ {
|
||
p.Tick(w, 1.0/20)
|
||
}
|
||
if p.Pos[1] < 63 || p.Pos[1] >= 63.5 {
|
||
t.Fatalf("脚底期望 [63, 63.5),实际 %v", p.Pos[1])
|
||
}
|
||
if !p.OnGround {
|
||
t.Fatal("应判定落地")
|
||
}
|
||
}
|
||
|
||
// TestWallBlock 水平移动撞墙不穿墙(物理与碰撞.md §8 踩坑)。
|
||
func TestWallBlock(t *testing.T) {
|
||
w := planeWorld{}
|
||
p := NewPlayer(4.0, 63, 0.5) // 墙在 x=5,玩家宽 0.6(右缘 4.3)
|
||
p.Vel[0] = 10
|
||
p.Tick(w, 1.0/20)
|
||
if p.Pos[0]+p.Width/2 > 5 {
|
||
t.Fatalf("穿墙:右缘 %v 超过墙 x=5", p.Pos[0]+p.Width/2)
|
||
}
|
||
}
|
||
|
||
// TestJump 起跳与回落。
|
||
func TestJump(t *testing.T) {
|
||
w := planeWorld{}
|
||
p := NewPlayer(0.5, 63, 0.5)
|
||
p.Tick(w, 1.0/20) // 先落地判定
|
||
if !p.OnGround {
|
||
t.Fatal("初始应在地面")
|
||
}
|
||
p.Jump()
|
||
peak := 0.0
|
||
for i := 0; i < 100; i++ {
|
||
p.Tick(w, 1.0/20)
|
||
if p.Pos[1] > peak {
|
||
peak = p.Pos[1]
|
||
}
|
||
if p.OnGround && i > 5 {
|
||
break
|
||
}
|
||
}
|
||
if peak < 64.0 {
|
||
t.Fatalf("起跳高度过低: %v", peak)
|
||
}
|
||
}
|
||
|
||
type waterWorld struct{}
|
||
|
||
func (waterWorld) Solid(x, y, z int32) bool { return y < 50 }
|
||
func (waterWorld) Fluid(x, y, z int32) bool { return y >= 50 && y <= 56 }
|
||
|
||
func TestOxygenDrainAndRefill(t *testing.T) {
|
||
w := waterWorld{}
|
||
p := NewPlayer(0.5, 52, 0.5) // 眼睛约 53.6,在水中
|
||
p.updateFluid(w)
|
||
if !p.EyeInWater {
|
||
t.Fatal("眼睛应在水中")
|
||
}
|
||
p.TickAir(1)
|
||
if p.Air >= AirMax {
|
||
t.Fatalf("水下氧气应递减,实际 %v", p.Air)
|
||
}
|
||
for i := 0; i < 20; i++ {
|
||
p.TickAir(1)
|
||
}
|
||
if p.Air != 0 {
|
||
t.Fatalf("长时间潜水氧气应为 0,实际 %v", p.Air)
|
||
}
|
||
p.Pos[1] = 60 // 出水
|
||
p.updateFluid(w)
|
||
p.TickAir(0.05)
|
||
if p.Air != AirMax {
|
||
t.Fatalf("出水应回满氧气,实际 %v", p.Air)
|
||
}
|
||
}
|
||
|
||
func TestSwimUpWithoutGround(t *testing.T) {
|
||
w := waterWorld{}
|
||
p := NewPlayer(0.5, 53, 0.5)
|
||
p.updateFluid(w)
|
||
if !p.InWater {
|
||
t.Fatal("应在水中")
|
||
}
|
||
p.OnGround = false
|
||
p.SwimUp()
|
||
if p.Vel[1] <= 0 {
|
||
t.Fatal("水中上浮速度应 > 0")
|
||
}
|
||
}
|