@@ -264,21 +264,37 @@ end b2kClear
264264-- =====================================================================
265265-- Configuration
266266-- =====================================================================
267+ function b2kNumberOr pValue, pDefault
268+ if pValue is empty then return pDefault
269+ if pValue is not a number then return pDefault
270+ return pValue
271+ end b2kNumberOr
272+
273+ function b2kClamp pValue, pLo, pHi
274+ local tValue
275+ put b2kNumberOr(pValue , pLo ) into tValue
276+ if tValue < pLo then put pLo into tValue
277+ if tValue > pHi then put pHi into tValue
278+ return tValue
279+ end b2kClamp
280+
267281command b2kSetScale pPixelsPerMetre
268- put pPixelsPerMetre into sScale
282+ put b2kClamp( pPixelsPerMetre , 1 , 10000 ) into sScale
269283end b2kSetScale
270284
271285command b2kSetOrigin pScreenX, pScreenY
272- put pScreenX into sOriginX
273- put pScreenY into sOriginY
286+ put b2kNumberOr( pScreenX , sOriginX ) into sOriginX
287+ put b2kNumberOr( pScreenY , sOriginY ) into sOriginY
274288end b2kSetOrigin
275289
276290command b2kSetGravity pGx, pGy
291+ put b2kNumberOr(pGx , 0 ) into pGx
292+ put b2kNumberOr(pGy , - 10 ) into pGy
277293 if sWorld is not empty then b2SetGravity sWorld , pGx , pGy
278294end b2kSetGravity
279295
280296command b2kSetSubsteps pN
281- put pN into sSub
297+ put round (b2kClamp( pN , 1 , 64 )) into sSub
282298end b2kSetSubsteps
283299
284300-- World toggles: island sleeping (saves CPU) and continuous collision (CCD,
@@ -343,6 +359,7 @@ command b2kAddBox pControl, pDynamic
343359 else put 0 into tType
344360 put ((the width of pControl ) / 2 ) / sScale into tHw
345361 put ((the height of pControl ) / 2 ) / sScale into tHh
362+ if tHw <= 0 or tHh <= 0 then return 0
346363 put b2kToWorldX(item 1 of the loc of pControl ) into tWx
347364 put b2kToWorldY(item 2 of the loc of pControl ) into tWy
348365 put (word 1 of tRef is "graphic" ) into tGraphic
@@ -376,6 +393,7 @@ command b2kAddBall pControl, pDynamic
376393 if pDynamic then put 2 into tType
377394 else put 0 into tType
378395 put ((the width of pControl ) / 2 ) / sScale into tRad
396+ if tRad <= 0 then return 0
379397 put b2kToWorldX(item 1 of the loc of pControl ) into tWx
380398 put b2kToWorldY(item 2 of the loc of pControl ) into tWy
381399 put b2NewBody(sWorld , tType , tWx , tWy , 0 , false , false ) into tBody
@@ -400,6 +418,7 @@ command b2kAddCapsule pControl, pDynamic
400418 else put 0 into tType
401419 put (the width of pControl ) / sScale into tWm
402420 put (the height of pControl ) / sScale into tHm
421+ if tWm <= 0 or tHm <= 0 then return 0
403422 put (tWm >= tHm ) into tHoriz
404423 if tHoriz then
405424 put tHm / 2 into tR
@@ -486,7 +505,11 @@ end b2kRegister
486505command b2kSpawnBox pScreenX, pScreenY, pW, pH, pColor
487506 local tName , tRef
488507 if pW is empty then put 40 into pW
508+ put b2kClamp(pW , 1 , 10000 ) into pW
489509 if pH is empty then put pW into pH
510+ put b2kClamp(pH , 1 , 10000 ) into pH
511+ put b2kNumberOr(pScreenX , sOriginX ) into pScreenX
512+ put b2kNumberOr(pScreenY , sOriginY ) into pScreenY
490513 put "b2kspawn_" & the milliseconds & "_" & random (1000000 ) into tName
491514 create graphic (tName )
492515 put the long id of graphic (tName ) into tRef
@@ -505,6 +528,9 @@ end b2kSpawnBox
505528command b2kSpawnBall pScreenX, pScreenY, pDiameter, pColor
506529 local tName , tRef
507530 if pDiameter is empty then put 40 into pDiameter
531+ put b2kClamp(pDiameter , 1 , 10000 ) into pDiameter
532+ put b2kNumberOr(pScreenX , sOriginX ) into pScreenX
533+ put b2kNumberOr(pScreenY , sOriginY ) into pScreenY
508534 put "b2kspawn_" & the milliseconds & "_" & random (1000000 ) into tName
509535 create graphic (tName )
510536 put the long id of graphic (tName ) into tRef
@@ -526,6 +552,10 @@ command b2kSpawnCapsule pScreenX, pScreenY, pLength, pThickness, pColor
526552 local tName , tRef
527553 if pLength is empty then put 80 into pLength
528554 if pThickness is empty then put 40 into pThickness
555+ put b2kClamp(pLength , 1 , 10000 ) into pLength
556+ put b2kClamp(pThickness , 1 , 10000 ) into pThickness
557+ put b2kNumberOr(pScreenX , sOriginX ) into pScreenX
558+ put b2kNumberOr(pScreenY , sOriginY ) into pScreenY
529559 put "b2kspawn_" & the milliseconds & "_" & random (1000000 ) into tName
530560 create graphic (tName )
531561 put the long id of graphic (tName ) into tRef
@@ -552,18 +582,21 @@ end b2kSpawnCapsule
552582command b2kSetBounce pControl, pRestitution
553583 local s
554584 put sShapeH [the long id of pControl ] into s
585+ put b2kClamp(pRestitution , 0 , 2 ) into pRestitution
555586 if s is not empty then b2SetShapeRestitution s , pRestitution
556587end b2kSetBounce
557588
558589command b2kSetFriction pControl, pFriction
559590 local s
560591 put sShapeH [the long id of pControl ] into s
592+ put b2kClamp(pFriction , 0 , 10 ) into pFriction
561593 if s is not empty then b2SetShapeFriction s , pFriction
562594end b2kSetFriction
563595
564596command b2kSetDensity pControl, pDensity
565597 local s
566598 put sShapeH [the long id of pControl ] into s
599+ put b2kClamp(pDensity , 0 , 10000 ) into pDensity
567600 if s is not empty then b2SetShapeDensity s, pDensity
568601end b2kSetDensity
569602
@@ -585,12 +618,20 @@ command b2kReshape pControl, pShape
585618 switch pShape
586619 case "ball"
587620 put ((the width of pControl ) / 2 ) / sScale into tR
621+ if tR <= 0 then
622+ put tOld into sShapeH [tRef ]
623+ exit b2kReshape
624+ end if
588625 put b2AddCircle(tBody , 0 , 0 , tR , 1.0 , 0.4 , 0.4 ) into sShapeH [tRef ]
589626 put tR into sRad [tRef ]
590627 break
591628 case "capsule"
592629 put (the width of pControl ) / sScale into tWm
593630 put (the height of pControl ) / sScale into tHm
631+ if tWm <= 0 or tHm <= 0 then
632+ put tOld into sShapeH [tRef ]
633+ exit b2kReshape
634+ end if
594635 put (tWm >= tHm ) into tHoriz
595636 if tHoriz then
596637 put tHm / 2 into tR
@@ -628,6 +669,10 @@ command b2kReshape pControl, pShape
628669 default
629670 put ((the width of pControl ) / 2 ) / sScale into tHw
630671 put ((the height of pControl ) / 2 ) / sScale into tHh
672+ if tHw <= 0 or tHh <= 0 then
673+ put tOld into sShapeH [tRef ]
674+ exit b2kReshape
675+ end if
631676 put b2AddBox(tBody , tHw , tHh , 1.0 , 0.4 , 0.2 ) into sShapeH [tRef ]
632677 if sRender [tRef ] is "poly" then
633678 put ("-" & tHw ) & "," & ("-" & tHh ) & cr & tHw & "," & ("-" & tHh ) & cr \
@@ -1498,7 +1543,7 @@ command b2kRelease
14981543end b2kRelease
14991544
15001545-- =====================================================================
1501- -- The loop (fixed timestep, generation-guarded, screen-locked sync)
1546+ -- The loop (fixed timestep, generation-guarded; sync locks only rendering )
15021547-- =====================================================================
15031548on b2kStep pGen
15041549 if not sRunning then exit b2kStep
@@ -1518,12 +1563,10 @@ on b2kStep pGen
15181563 if sDragging then
15191564 b2MouseSetTarget sDragJoint , b2kToWorldX(the mouseH), b2kToWorldY(the mouseV)
15201565 end if
1521- lock screen
1522- b2kSync
1523- b2kDispatchContacts
1566+ b2kSync -- locks screen internally for render updates only
1567+ b2kDispatchContacts -- user handlers run after the screen is unlocked
15241568 b2kDispatchSensors
15251569 if sFrameObj is not empty then dispatch "b2kFrame" to sFrameObj
1526- unlock screen -- one redraw per frame: sync + events + app drawing
15271570 end if
15281571 send ("b2kStep " & sGen ) to me in 16 milliseconds
15291572end b2kStep
@@ -1535,12 +1578,10 @@ command b2kStepOnce
15351578 if sDragging then
15361579 b2MouseSetTarget sDragJoint , b2kToWorldX(the mouseH), b2kToWorldY(the mouseV)
15371580 end if
1538- lock screen
15391581 b2kSync
15401582 b2kDispatchContacts
15411583 b2kDispatchSensors
15421584 if sFrameObj is not empty then dispatch "b2kFrame" to sFrameObj
1543- unlock screen
15441585end b2kStepOnce
15451586
15461587command b2kSync
0 commit comments