ON ERROR IF ERR = 17 CHAIN @lib$+"../examples/tools/touchide" ELSE REPORT : END REM Box2D (v2.3.1) Physics Engine: Ball Bearing Clock with rotor REM by Richard Russell, http://www.rtrussell.co.uk/, 13-May-2020 REM Suitable for BBC BASIC for SDL 2.0 and BBC BASIC for Windows MODE 20 : OFF ORIGIN 320,150 Width% = 800 Height% = 600 INSTALL @lib$+"box2dlib" : PROC_b2Init INSTALL @lib$+"box2dgfx" INSTALL @lib$+"box2ddbg" ON ERROR PROCcleanup : IF ERR = 17 CHAIN @lib$+"../examples/tools/touchide" ELSE REPORT : END ON CLOSE PROCcleanup : QUIT gravity_x = 0.0 gravity_y = -98 scale = 100 myWorld%% = FN_b2CreateWorld(gravity_x, gravity_y) PROC_gfxInit(gfx{}, Width%, Height%, scale) PROC_gfxLoad(Ball{}, @dir$+".bbclockpics/ball.png", 100) PROC_gfxLoad(rotor{}, @dir$+".bbclockpics/rotor.png", 180) PROC_gfxLoad(overlay{}, @dir$+".bbclockpics/overlay.png", 100) PROC_gfxLoad(machine{}, @dir$+".bbclockpics/machine.png", 100) PROC_gfxLoad(tipper1{}, @dir$+".bbclockpics/tipper1.png", 480) PROC_gfxLoad(tipper2{}, @dir$+".bbclockpics/tipper2.png", 520) PROC_gfxLoad(tipper3{}, @dir$+".bbclockpics/tipper3.png", 480) PROC_gfxLoad(tipper4{}, @dir$+".bbclockpics/tipper4.png", 520) PROC_b2DebugInit(myWorld%%, %01011, scale) IF INKEY$(-256) = "W" THEN PROC_gfxMultiply(Ball{}) PROC_gfxMultiply(rotor{}) PROC_gfxMultiply(overlay{}) PROC_gfxMultiply(machine{}) PROC_gfxMultiply(tipper1{}) PROC_gfxMultiply(tipper2{}) PROC_gfxMultiply(tipper3{}) PROC_gfxMultiply(tipper4{}) ENDIF ground%% = FN_b2StaticBox(myWorld%%, 2.4, 0.02, 0.0, 4.0, 0.02) floor%% = FN_b2BoxFixture(ground%%, -0.04, 0.04, -0.02, 2.17, 0.02, 0.1, 0, 1.0) corner%% = FN_b2BoxFixture(ground%%, -2.2, 0.16, -PI/4, 0.25, 0.02, 0.5, 0, 1.0) wall1%% = FN_b2BoxFixture(ground%%, -2.39, 2.3, 0.0, 0.02, 2.3, 0.5, 0, 1.0) wall2%% = FN_b2BoxFixture(ground%%, 2.36, 2.24, 0.0, 0.02, 1.84, 0.5, 0, 1.0) wall3%% = FN_b2BoxFixture(ground%%, 2.36, 0.10, -0.25, 0.02, 0.10, 0.5, 0, 1.0) wall4%% = FN_b2BoxFixture(ground%%, 1.95, 4.45, 0.85, 0.02, 0.56, 0.5, 0, 1.0) REM Overlay (in front of everything): overlay%% = FN_b2StaticBox(myWorld%%, 4.65, 2.25, 0.0, 0, 0) PROC_b2UserDataBody(overlay%%, overlay{}) REM Initialise to current clock-time: Time$ = TIME$ REM RIGHT$(Time$,8) = "12:59:50" secs% = VAL(MID$(Time$,23)) mins% = VAL(MID$(Time$,20)) hours% = (VAL(MID$(Time$,17)) + 11) MOD 12 b% = 0 IF secs% DIV 10 : FOR i% = 1 TO secs% DIV 10 : PROCnewball(b%, 4+i%, 4.3) : NEXT IF mins% MOD 10 : FOR i% = 1 TO mins% MOD 10 : PROCnewball(b%, i%, 3.1) : NEXT IF mins% DIV 10 : FOR i% = 1 TO mins% DIV 10 : PROCnewball(b%, 4+i%, 1.9) : NEXT IF hours% : FOR i% = 1 TO hours% : PROCnewball(b%, 1+i%, 0.7) : NEXT WHILE b% < 32 PROCnewball(b%, b%/2, 0.2) : ENDWHILE REM Ballast balls and fixed hours ball: body11%% = FN_b2DynamicBody(myWorld%%, 0.5, 4.30, 0, 0, 0, 0, 0, 0) ballast1%% = FN_b2CircleFixture(body11%%, 0.0, 0.0, 0.08, 0.2, 0.0, 3.2) PROC_b2UserDataBody(body11%%, Ball{}) body31%% = FN_b2DynamicBody(myWorld%%, 0.5, 1.90, 0, 0, 0, 0, 0, 0) ballast3%% = FN_b2CircleFixture(body31%%, 0.0, 0.0, 0.08, 0.2, 0.0, 3.2) PROC_b2UserDataBody(body31%%, Ball{}) body41%% = FN_b2DynamicBody(myWorld%%, 0.5, 0.7, 0, 0, 0, 0, 0, 0) ballast4%% = FN_b2CircleFixture(body41%%, 0.0, 0.0, 0.08, 0.2, 0.0, 3.2) PROC_b2UserDataBody(body41%%, Ball{}) REM Seconds tens: ramp1%% = FN_b2BoxFixture(ground%%, 0.50, 4.70, 0.1, 1.04, 0.02, 0.5, 0, 1.0) body1%% = FN_b2DynamicBody(myWorld%%, 1.05, 4.20, 0.1, 0, 0, 0, 0, 0) tipper1%% = FN_b2BoxFixture(body1%%, 0.0, 0.0, 0.0, 0.79, 0.05, 0.5, 0.0, 1.0) stop11%% = FN_b2BoxFixture(body1%%, -0.73*COS.1 + 0.07*SIN.1, 0.07*COS.1 + 0.73*SIN.1, 0.0, 0.07, 0.1, 0.1, 0, 0.65) stop12%% = FN_b2BoxFixture(body1%%, -0.09*COS.1 + 0.14*SIN.1, 0.14*COS.1 + 0.09*SIN.1, 0.0, 0.07, 0.1, 0.1, 0, 0.65) lip1%% = FN_b2BoxFixture(body1%%, 0.61*COS.1 + 0.40*SIN.1, 0.40*COS.1 - 0.61*SIN.1, -0.1, 0.01, 0.1, 0.5, 0, 1.0) pivot1%% = FN_b2RevoluteJoint(myWorld%%, ground%%, body1%%, 1.05, 4.20, -0.4, 0.0) PROC_b2UserDataBody(body1%%, tipper1{}) DIM x(3), y(3) x() = -0.52, 1.99, 1.99, -0.52 y() = 4.28, 4.10, 4.14, 4.30 wedge1%% = FN_b2PolygonFixture(ground%%, 4, x(), y(), 0.5, 0, 1.0) strut1%% = FN_b2BoxFixture(ground%%, 1.25, 4.06, 0.0, 0.02, 0.12, 0.5, 0, 1.0) chute1%% = FN_b2BoxFixture(ground%%, 0.0, 3.82, 0.1, 2.0, 0.02, 0.5, 0, 1.0) REM Minutes units: ramp2%% = FN_b2BoxFixture(ground%%, 0.91, 3.50, 0.1, 1.45, 0.02, 0.5, 0, 1.0) body2%% = FN_b2DynamicBody(myWorld%%, 1.05, 3.00, 0.1, 0, 0, 0, 0, 0) tipper2%% = FN_b2BoxFixture(body2%%, 0.0, 0.0, 0.0, 0.79, 0.05, 0.5, 0.0, 1.0) stop2%% = FN_b2BoxFixture(body2%%, -0.73*COS.1 + 0.07*SIN.1, 0.07*COS.1 + 0.73*SIN.1, 0.0, 0.07, 0.1, 0.5, 0, 1.05) lip2%% = FN_b2BoxFixture(body2%%, 0.61*COS.1 + 0.40*SIN.1, 0.40*COS.1 - 0.61*SIN.1, -0.1, 0.01, 0.1, 0.5, 0, 1.0) pivot2%% = FN_b2RevoluteJoint(myWorld%%, ground%%, body2%%, 1.05, 3.00, -0.4, 0.0) PROC_b2UserDataBody(body2%%, tipper2{}) y() -= 1.2 wedge2%% = FN_b2PolygonFixture(ground%%, 4, x(), y(), 0.5, 0, 1.0) strut2%% = FN_b2BoxFixture(ground%%, 1.25, 2.86, 0.0, 0.02, 0.12, 0.5, 0, 1.0) chute2%% = FN_b2BoxFixture(ground%%, 0.0, 2.62, 0.1, 2.0, 0.02, 0.5, 0, 1.0) REM Minutes tens: ramp3%% = FN_b2BoxFixture(ground%%, 0.91, 2.30, 0.1, 1.45, 0.02, 0.5, 0, 1.0) body3%% = FN_b2DynamicBody(myWorld%%, 1.05, 1.80, 0.1, 0, 0, 0, 0, 0) tipper3%% = FN_b2BoxFixture(body3%%, 0.0, 0.0, 0.0, 0.79, 0.05, 0.5, 0.0, 1.0) stop31%% = FN_b2BoxFixture(body3%%, -0.73*COS.1 + 0.07*SIN.1, 0.07*COS.1 + 0.73*SIN.1, 0.0, 0.07, 0.1, 0.1, 0, 0.65) stop32%% = FN_b2BoxFixture(body3%%, -0.09*COS.1 + 0.14*SIN.1, 0.14*COS.1 + 0.09*SIN.1, 0.0, 0.07, 0.1, 0.1, 0, 0.65) lip3%% = FN_b2BoxFixture(body3%%, 0.61*COS.1 + 0.40*SIN.1, 0.40*COS.1 - 0.61*SIN.1, -0.1, 0.01, 0.1, 0.5, 0, 1.0) pivot3%% = FN_b2RevoluteJoint(myWorld%%, ground%%, body3%%, 1.05, 1.80, -0.4, 0.0) PROC_b2UserDataBody(body3%%, tipper3{}) y() -= 1.2 wedge3%% = FN_b2PolygonFixture(ground%%, 4, x(), y(), 0.5, 0, 1.0) strut3%% = FN_b2BoxFixture(ground%%, 1.25, 1.66, 0.0, 0.02, 0.12, 0.5, 0, 1.0) chute3%% = FN_b2BoxFixture(ground%%, 0.0, 1.42, 0.1, 2.0, 0.02, 0.5, 0, 1.0) REM Hours: ramp4%% = FN_b2BoxFixture(ground%%, 1.17, 1.15, 0.1, 1.19, 0.02, 0.5, 0, 1.0) body4%% = FN_b2DynamicBody(myWorld%%, 1.31, 0.65, 0.1, 0, 0, 0, 0, 0) tipper4%% = FN_b2BoxFixture(body4%%, 0.0, 0.0, 0.0, 1.04, 0.05, 0.5, 0.0, 1.0) stop41%% = FN_b2BoxFixture(body4%%, -0.98*COS.1 + 0.06*SIN.1, 0.06*COS.1 + 0.98*SIN.1, 0.0, 0.07, 0.1, 0.5, 0, 1.05) stop42%% = FN_b2BoxFixture(body4%%, -0.74*COS.1 + 0.06*SIN.1, 0.06*COS.1 + 0.74*SIN.1, 0.0, 0.01, 0.1, 0.5, 0, 1.05) lip4%% = FN_b2BoxFixture(body4%%, 0.86*COS.1 + 0.24*SIN.1, 0.42*COS.1- 0.86*SIN.1, -0.1, 0.01, 0.1, 0.5, 0, 1.0) pivot4%% = FN_b2RevoluteJoint(myWorld%%, ground%%, body4%%, 1.24, 0.65, -0.3, 0.0) PROC_b2UserDataBody(body4%%, tipper4{}) REM Static machine: machine%% = FN_b2StaticBox(myWorld%%, 2.4, 2.25, 0.0, 0, 0) PROC_b2UserDataBody(machine%%, machine{}) REM Rotor (behind machine): Speed = PI / 10 : w = 0.10 : l = 0.12 : r = 0.04 rotor%% = FN_b2KinematicBody(myWorld%%, 2.4, 2.3, PI/4, 0, 0, Speed, 0, 0) x = 3.19 : a = PI/4 - 0.4 cupb1%% = FN_b2BoxFixture(rotor%%, x, y, a, w, 0.01, 0.5, 0.0, 1.0) cupl1%% = FN_b2BoxFixture(rotor%%, x - l*SINa + w*COSa, w*SINa + l*COSa, a, 0.001, l, 0.0, 0.0, 1.0) cupr1%% = FN_b2BoxFixture(rotor%%, x - r*SINa - w*COSa, -w*SINa + r*COSa, a, 0.001, r, 0.0, 0.0, 1.0) x = -3.19 : a = PI/4 - 0.4 + PI cupb2%% = FN_b2BoxFixture(rotor%%, x, y, a, w, 0.01, 0.5, 0.0, 1.0) cupl2%% = FN_b2BoxFixture(rotor%%, x - l*SINa + w*COSa, w*SINa + l*COSa, a, 0.001, l, 0.0, 0.0, 1.0) cupr2%% = FN_b2BoxFixture(rotor%%, x - r*SINa - w*COSa, -w*SINa + r*COSa, a, 0.001, r, 0.0, 0.0, 1.0) PROC_b2UserDataBody(rotor%%, rotor{}) REM Run simulation: velIterations% = 9 posIterations% = 4 COLOR 8,&A2,&9A,&90 COLOR 128+8 CLS PROC_gfxRender(gfx{}, myWorld%%) *REFRESH OFF IF INKEY$(-256) = "W" SYS "timeGetTime" TO T% ELSE SYS "SDL_GetTicks" TO T% Ticks% = T% REPEAT CLS PROC_gfxRender(gfx{}, myWorld%%) IF INKEY(-51) PROC_b2DebugDraw(myWorld%%) PROC_gfxDisplay oldT% = T% IF INKEY$(-256) = "W" SYS "timeGetTime" TO T% ELSE SYS "SDL_GetTicks" TO T% WHILE Ticks% < T% IF NOT INKEY(-1) PROC_b2WorldStep(myWorld%%, 0.001, velIterations%, posIterations%) Ticks% += 1 ENDWHILE REM Reduce rotor angle to the range -PI to +PI: PROC_b2GetBody(rotor%%, x, y, a) : PROC_b2SetBody(rotor%%, x, y, a) UNTIL FALSE PROCcleanup END DEF PROCnewball(RETURN B%, i, y) LOCAL b%%, d%% b%% = FN_b2DynamicBody(myWorld%%, 0.35+0.16*i, y+0.016*i, 0, 0, 0, 0, 0, 0) d%% = FN_b2CircleFixture(b%%, 0, 0, 0.08, 0.1, 0.0, 1.0) PROC_b2UserDataBody(b%%, Ball{}) B% += 1 ENDPROC DEF PROCcleanup ON ERROR OFF *REFRESH ON myWorld%% += 0 : IF myWorld%% PROC_b2DestroyWorld(myWorld%%) : myWorld%% = 0 PROC_b2DebugExit PROC_gfxExit PROC_b2Exit ENDPROC