; Extended mode. Automatic colliders, gravity and stacking in a single world.
Const SCENERY=1, CRATES=2, BODY_STATIC=0
Global paused=False
Dim crate(5)
test_mode=GetEnv("B3D_ENTITY_SAMPLE_TEST")="1"
Graphics3D 800,480,0,2
SetBuffer BackBuffer(): SetCollisionBackend 1
camera=CreateCamera(): PositionEntity camera,9,8,-14
target=CreatePivot(): PositionEntity target,0,1.5,0: PointEntity camera,target
light=CreateLight(): RotateEntity light,40,-25,0: AmbientLight 75,75,85
ground=CreateCube(): ScaleEntity ground,12,.5,12: PositionEntity ground,0,-.5,0
EntityColor ground,65,85,100: EntityType ground,SCENERY: EntityPhysics ground,BODY_STATIC
For i=0 To 5
    crate(i)=CreateCube(): ScaleEntity crate(i),.5,.5,.5
    EntityColor crate(i),240-20*i,135+15*i,65+20*i
    EntityType crate(i),CRATES
    EntityMass crate(i),2
    EntityFriction crate(i),.7
    PositionEntity crate(i),(i Mod 3-1)*2.4,3+Int(i/3)*1.15,0
    EntityPhysics crate(i)
Next
Physics CRATES,SCENERY
Physics CRATES,CRATES
timer=CreateTimer(60)
While Not KeyDown(1)
    If KeyHit(25) Then paused=Not paused
    If KeyHit(19) Then ResetCrates()
    If KeyHit(57) And paused=0 Then KickCrate()
    If paused=0 Then UpdateWorld 1
    frame=frame+1
    If test_mode
        If frame=240
            For i=0 To 5
                If Abs(EntityY(crate(i))-(.5+Int(i/3)))>.06 Or CountCollisions(crate(i))=0 Then RuntimeError "A crate is missing from its settled pile"
            Next
            ResetCrates()
            If Abs(EntityY(crate(5))-4.15)>.001 Then RuntimeError "Crate reset failed"
        EndIf
        If frame=270
            For i=0 To 5
                If EntityY(crate(i))>2.8+Int(i/3)*1.15 Then RuntimeError "Reset crate stayed asleep in the air"
            Next
            KickCrate()
        EndIf
        If frame=300
            If EntityX(crate(0))<-2.3 Then RuntimeError "Kick did not move the crate"
            paused=True: pause_x#=EntityX(crate(0))
        EndIf
        If frame=310
            If EntityX(crate(0))<>pause_x Then RuntimeError "Pause moved the crate"
            paused=False
        EndIf
    EndIf
    If test_mode=0 Or frame Mod 60=0
        RenderWorld
        Text 16,16,"Six falling crates | Space: kick left pile | R: reset | P: pause | Esc: exit"
        Text 16,38,"Paused: "+paused+" | Bottom crate contacts: "+CountCollisions(crate(0))
        If test_mode And frame=60 Then CaptureScreenshot "sample-preview.png"
        Flip
    EndIf
    If test_mode
        If frame=360
            marker=WriteFile("entity-physics-sample.passed"): WriteLine marker,"Six distinct crates settle; sleeping reset resumes falling; impulse and pause passed": CloseFile marker
            Exit
        EndIf
    Else
        WaitTimer timer
    EndIf
Wend
FreeTimer timer: ClearWorld
End

Function ResetCrates()
    paused=False
    For i=0 To 5
        PositionEntity crate(i),(i Mod 3-1)*2.4,3+Int(i/3)*1.15,0: RotateEntity crate(i),0,0,0
        ResetEntity crate(i)
    Next
End Function

Function KickCrate()
    EntityImpulse crate(0),8,2,0
End Function
