Example

Air Hockey

6

nathanielbabiak 2022-10-02 04:38

I can't find a way to analyze 3-body collisions using this discrete approach. I'll probably need an event-based approach instead...

airhockey.nx | Open in app
2022-10-06 03:05
airhockey.nx | Open in app
2022-10-02 04:38

SP4CEBAR 2022-10-02 07:34

Some balls managed to glitch into each other and form a blob that later exploded with nuclear force


was8bit 2022-10-02 16:10

If you REM WAIT VBL and let it run long enough, you eventually end up with just one ball...

airhockey 0.1.nx | Open in app
2022-10-02 16:10

was8bit 2022-10-02 16:12

Balls getting stuck in the sides sometimes move beyond the wall and outside the visible screen....


was8bit 2022-10-02 16:13

other programs do billiards just fine, what's their secret ???


nathanielbabiak 2022-10-02 20:44 (Edited)

Other billiards programs are pretty similar to the link I posted in the description. I was envisioning something like that, but wanted to get this uploaded first, just to mess around with it.


was8bit 2022-10-03 02:09

Ah... great link... I just now saw it... it is the first time I’ve read any amount of depth into this topic :)


was8bit 2022-10-03 04:03 (Edited)

If you carefully watch my slowmo version, the bounces sometimes seem not correct..

airhockey Slowmo.nx | Open in app
2022-10-03 04:03

nathanielbabiak 2022-10-05 04:11 (Edited)

Well crap! It appears the link at the top considers floating point stability as an essential element of the programming language (Python) and it's using 64-bit doubles, not 32-bit floats. With LowRes NX, I'll need to address it myself... this is going to take a while.


SP4CEBAR 2022-10-05 10:13 (Edited)

Could you make a double using two floats? Or using 8 bytes in RAM?

Accessible with functions like:
Note: this code has never been tested, and is a little rushed


GLOBAL A_DOUBLE 
A_DOUBLE=$A000

SUB DOUBLE_A(N,A)
  A=A_DOUBLE+N*8
END SUB

SUB U_PEEKW(A0,V)
  'UNSIGNED PEEKW, WITH MSB LAST
  V=PEEK(A0)+256*PEEK(A0+1)
END SUB

SUB U_POKEW(A0,V)
  'UNSIGNED POKEW, WITH MSB LAST
  POKE A0,V MOD 256
  POKE A0+1,V\256
END SUB

SUB MULT_DOUBLE(N0,N1,NR)
  'MULTIPLIES DOUBLES N0 AND N1 TO NR
  A0=0
  A1=0
  AR=0
  CALL DOUBLE_A(N0,A0)
  CALL DOUBLE_A(N1,A1)
  CALL DOUBLE_A(NR,AR)
  V0=0
  V1=0
  DIM RESULTS(2,2)

  'MULTIPLY EVERY COMBINATION
  FOR I0=0 TO 5 STEP 2
    CALL U_PEEKW(A0+I0,V0)
    FOR I1=0 TO 5 STEP 2
      CALL U_PEEKW(A1+I1,V1)
      RESULTS(I0\2,I1\2)=V1*V0
    NEXT I1
  NEXT I0

  'ADD VALUES OF THE SAME EXPONENT TOGETHER (CARRY VALUES HAVE BEEN FORGOTTEN)
  DIM ADDED(2)
  FOR I0=0 TO 5 STEP 2
    FOR I1=0 TO 5 STEP 2
      EXPONENT=I0*I1
      ADD ADDED(EXPONENT),RESULTS(I0\2,I1\2)
    NEXT I1
  NEXT I0

  'SAVE
  FOR I=0 TO 2
    CALL U_POKEW(AR+I*2,ADDED(I))
  NEXT I
END SUB

SUB ADD_DOUBLE
  'ADDS DOUBLES N0 AND N1 TO NR
  A0=0
  A1=0
  AR=0
  CALL DOUBLE_A(N0,A0)
  CALL DOUBLE_A(N1,A1)
  CALL DOUBLE_A(NR,AR)
  V0=0
  V1=0
  'CARRY
  C=0

  'ADD VALUES OF THE SAME EXPONENT TOGETHER
  FOR I=0 TO 5 STEP 2
    CALL U_PEEKW(A0+I,V0)
    CALL U_PEEKW(A1+I,V1)
    V=V0+V1+C
    VR=V MOD 65536
    C=V\65536
    CALL U_POKEW(AR+I,VR)
  NEXT I
END SUB

Conclusion: it's a huge pain, RAM makes it more complicated, using multiple variables or an array would probably be better


SP4CEBAR 2022-10-05 12:24 (Edited)

I think this approach would be better:
STEP_=2^23
((V2*STEP_+V1)*STEP_+V0) * SIGN * 2^EXPONENT


nathanielbabiak 2022-10-06 03:07

The update is numerically stable. Sp4acebar, I like your thinking, those are some super cool topics - I'll post some stuff to the forum in a bit on both topics, let's keep chatting there (numeric stability and float-float data types).


nathanielbabiak 2022-10-07 02:51 (Edited)

I'm discovering it's a tedious exercise to develop the event handler for instantaneous events (due to the floating point instabilities). That's especially true because there's so little payoff - I'm not interested in making a physics game right now. I'm going to stop working on it, and get back to other interests instead. But, if anybody wants to pursue it, here's the pseudo-code:

DO...

DO... Step through all objects, determining time-to-object's-soonest-event (assuming no other events occur between the present and the future). ...LOOP

Take minimum of all times. DO... run animation ...LOOP until that time.

Evaluate the event. Evaluation consists of updating mechanics (for example, momentum, instantaneous velocity/acceleration, stress, force/work/energy, etc.). Evaluation must exclude updating dynamics (position, rotation, strain), which is essentially the animation that will occur next loop.

...LOOP


was8bit 2022-10-07 03:17

Ok, my brain just flat-lined!!!


nathanielbabiak 2022-10-07 03:38

Yeah the geometry's horrible. Honestly it's no easier than a ray caster or a raster racer!


nathanielbabiak 2022-10-07 04:15 (Edited)

I edited my pseudo-code to add the inner-loops explicitly. Hope it's clearer!


was8bit 2022-10-07 05:01

I suppose its not fair trying to get a simulated low resolution simulator to behave like a modern high end computer ;)


SP4CEBAR 2022-10-07 09:30 (Edited)

In my billiards simulations I've used the gravity formula (C*G*g/(R*R)) which generates an attractive force, which when negated, becomes a repulsive force, this calculation is only performed when SPRITE HIT returns true

I've also made a linear variant which is simpler:

FY=0
FX=0
...
M=0.01  
DX=SPRITE.X (I) - SPRITE.X (HIT)  
DY=SPRITE.Y (I) - SPRITE.Y (HIT)  
ADD FX, DX*M  
ADD FY, DY*M  


nathanielbabiak 2022-10-07 12:44 (Edited)

If you could process many more objects, you’d find you’ve created a fluid simulator rather than a billiards simulator. See if you can get it running with one pixel sprites, and use all 64, you might see what I mean. (Or, 64 might not be enough to see it.)


SP4CEBAR 2022-10-07 15:22 (Edited)

How did I not think of that, thank you! I just posted it: https://lowresnx.inutilis.com/topic.php?id=2652

Due to the modular nature of the code, it was as easy as changing a few variables


Log in to reply.