Vertical rotating maze

Discussions related to graphics (2D and 3D), animation and games programming
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Vertical rotating maze

Post by Richard Russell »

I came across this vertical, rotating, maze in a Facebook post and decided to reproduce it as a BBC BASIC program.

It was exceptionally easy, because virtually everything is done by the Box2D physics engine; the BASIC program just has to create the various objects and then let the physics do its stuff! The only real-time activity of the program is to monitor the mouse and keyboard and adjust the speed of rotation.

There are only two objects in the Box2D model, the maze itself (which is a 'kinematic' object. i.e. it moves - in this case it rotates - but does not respond to forces) and the marble (which is a 'dynamic' object, i.e. it moves under the influence of gravity and other forces, such as collisions).

If anybody is interested in seeing the code just ask and I will list it and/or upload it, it really is simple (no more complicated, really, than the Hello_Box2D example supplied with BBC BASIC). You can run it yourself in your browser here.

spinmaze.jpg
You do not have the required permissions to view the files attached to this post.
DDRM
Posts: 14
Joined: Mon 17 Jun 2024, 08:02

Re: Vertical rotating maze

Post by DDRM »

I'd certainly be interested in seeing the code!

D
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Re: Vertical rotating maze

Post by Richard Russell »

DDRM wrote: Mon 04 Nov 2024, 09:06 I'd certainly be interested in seeing the code!
OK, listed below; if there's anything you want explained just ask.

As I mentioned before, all the code does is to set up the Box2D model (just two objects, the 'kinematic' maze and the 'dynamic' marble, plus their associated 'fixtures') and then let the physics engine loose. In the main loop all it does, in addition to running Box2D and rendering the output, is to adjust the rotation speed according to the keyboard/mouse.

I've also uploaded spinmaze.zip containing the code and the associated resource files (images and maze outline) so you can run it yourself. It's compatible with both BB4W and BBCSDL, but will run better in the latter (slightly less aliasing, and can be resized or run full-screen).

Code: Select all

      REM. Spinmaze: spin the vertical maze to manoeuvre the marble to escape
      REM. v1.0 (C) Richard Russell, http://www.rtrussell.co.uk/, 01-Nov-2024.
      REM. This program is compatible with both BBCSDL & BB4W (plus libraries)

      REM!Embed @lib$+"box2dlib", @lib$+"box2ddbg", @lib$+"box2dgfx", @dir$+"bboard.jpg"
      REM!Embed @dir$+"spinmaze.png", @dir$+"spinmaze.dat", @dir$+"marble.png"

      MODE 8 : OFF
      MOUSE TO 100,100

      title$ = "Spinmaze - Left and Right to spin, Space to restart, D for debug graphics"

      INSTALL @lib$+"box2dlib" : PROC_b2Init
      INSTALL @lib$+"box2dgfx"
      IF HIMEM > PAGE + 48000 INSTALL @lib$+"box2ddbg"

      IF INKEY$(-256) = "W" THEN
        SYS "SetWindowText", @hwnd%, title$
      ELSE
        SYS "SDL_SetWindowTitle", @hwnd%, title$, @memhdc%
      ENDIF

      IF POS REM SDL thread sync
      ON MOVE PROCresize(@msg%, @lparam%, @size.x%, @size.y%) : RETURN
      ON ERROR PROCcleanup : IF ERR=17 CHAIN @lib$+"../examples/tools/touchide" ELSE ERROR 0,REPORT$
      ON CLOSE PROCcleanup : QUIT
      IF INSTR(@usr$, "rtrussell.spinmaze") OR INSTR(@lib$, @dir$) THEN *ESC OFF

      gravity_x = 0.0
      gravity_y = -10

      myWorld%% = FN_b2CreateWorld(gravity_x, gravity_y)
      PROC_gfxInit(gfx{}, 640, 512, 20)
      IF HIMEM > PAGE + 48000 PROC_b2DebugInit(myWorld%%, %01011, 20)

      PROC_gfxLoad(bgnd{}, @dir$+"bboard.jpg", 9.4)
      PROC_gfxLoad(maze{}, @dir$+"spinmaze.png", 20.8)
      PROC_gfxLoad(ball{}, @dir$+"marble.png", 36)

      ground%% = FN_b2StaticBox(myWorld%%, 16.0, -4.0, 0.0, 16.0, 0.1)

      REM Kinematic body:
      maze%% = FN_b2KinematicBody(myWorld%%, 16.0, 12.8, PI/2, 0.0, 0.0, 0, 0, 0)
      PROC_b2UserDataBody(maze%%, maze{})

      REM Rotating maze:
      f% = OPENIN(@dir$ + "spinmaze.dat")
      IF f% = 0 ERROR 100, "Couldn't load spinmaze.dat"
      INPUT #f%, n%
      DIM xc(n%-1), yc(n%-1)
      FOR i% = 0 TO n%-1
        INPUT #f%, xc(i%), yc(i%)
      NEXT
      CLOSE #f%
      edge%% = FN_b2ChainFixture(maze%%, n%, xc(), yc(), 1.0, 0.0, 1.0, TRUE)

      REM Dynamic bodies:
      ball%% = FN_b2DynamicBody(myWorld%%, 16.0, 12.8, 0, 0, 0, 0.1, 0, 0)
      mass%% = FN_b2CircleFixture(ball%%, 0.0, 0.0, 0.35, 1.0, 0.0, 1.0)
      PROC_b2UserDataBody(ball%%, ball{})
      PROC_b2SetBullet(ball%%, TRUE)

      velIterations% = 6
      posIterations% = 3
      speed = 0

      *REFRESH OFF
      IF INKEY$(-256) = "W" SYS "timeGetTime" TO Ticks% ELSE SYS "SDL_GetTicks" TO Ticks%
      REPEAT

        PROC_gfxBlit(gfx{}, bgnd{}, 15.9, 12.8, 0)
        PROC_gfxRender(gfx{}, myWorld%%)
        IF INKEY(-51) IF HIMEM > PAGE + 48000 PROC_b2DebugDraw(myWorld%%)
        PROC_gfxDisplay

        MOUSE X%, Y%, B%
        CASE TRUE OF
          WHEN INKEY(-122) OR (B% AND 1)<>0 OR (B% AND 4)<>0 AND X% >= 640: speed -= 0.01
          WHEN INKEY(-26)  OR (B% AND 4)<>0: speed += 0.01
          WHEN INKEY(-99): PROC_b2SetBody(ball%%, 16.0, 12.8, 0)
          OTHERWISE: speed /= 1.1
        ENDCASE
        IF ABS(speed) > 1.0 speed = SGN(speed)

        IF INKEY$(-256) = "W" SYS "timeGetTime" TO T% ELSE SYS "SDL_GetTicks" TO T%
        WHILE Ticks% < T%
          PROC_b2SetVelocity(maze%%, 0, 0, speed)
          PROC_b2WorldStep(myWorld%%, 0.002, velIterations%, posIterations%)
          Ticks% += 2
        ENDWHILE

        IF INKEY$(-256) = "W" WAIT 1

      UNTIL FALSE
      PROCcleanup
      END

      DEF PROCcleanup
      ON ERROR OFF
      *REFRESH ON
      VDU 23,22,640;500;8,20,16,128
      myWorld%% += 0 : IF myWorld%% PROC_b2DestroyWorld(myWorld%%) : myWorld%% = 0
      IF HIMEM > PAGE + 48000 PROC_b2DebugExit
      PROC_gfxExit
      PROC_b2Exit
      ENDPROC

      DEF PROCresize(M%, L%, X%, Y%) IF M% <> 5 OR INKEY$(-256) = "W" ENDPROC
      LOCAL W%, H%
      W% = L% AND &FFFF
      H% = L% >>> 16
      IF W%/H% > X%/Y% THEN
        @zoom% = &8000 * H% / Y%
      ELSE
        @zoom% = &8000 * W% / X%
      ENDIF
      IF @zoom% < &8000 @zoom% = &8000
      IF (@platform% AND 7) < 3 OR (@platform% AND 7) > 4 THEN
        @panx% = (X% - W% * &8000 / @zoom%) / 2
        @pany% = (Y% - H% * &8000 / @zoom%) / 2
      ENDIF
      ENDPROC