2D Elastic Collision Spheres

Henko
Posts: 814
Joined: Tue Apr 09, 2013 12:23 pm
My devices: iPhone,iPad
Windows
Location: Groningen, Netherlands
Flag: Netherlands

Re: 2D Elastic Collision Spheres

Post by Henko »

Marble @ https://www.dropbox.com/s/fvu405zeqkb7wu0/marble.png

Aarch.. Here's the Dropbox misery again. Cannot run the app. I quit, sorry.

User avatar
Mr. Kibernetik
Site Admin
Posts: 4786
Joined: Mon Nov 19, 2012 10:16 pm
My devices: iPhone, iPad, MacBook
Location: Russia
Flag: Russia

Re: 2D Elastic Collision Spheres

Post by Mr. Kibernetik »

This version runs with or without sprite image.
Also fixes fps counter.

Code: Select all

rem 2D elastic collision with spheres v1.2
rem 1.1 avoiding double calculations : ) to speed a bit
rem 1.2 using sprites, 53-56 fps with 20 marbles
rem 2.0 using complex numbers
rem based on:
rem http://www.vobarian.com/collisions/2dcollisions2.pdf
rem http://blogs.love2d.org/content/circle-collisions
rem 
rem SB 3.4 / iPad mini 1.gen. / iOS 7.0.4 / Operator
rem mod by Mr.K.


graphics
graphics clear 0,0,1
option sprite pos central
option base 1
draw color 1,1,1
draw font name "Chalkduster"

endd = 0
sch = screen_height()
scw = screen_width()
init_speed = 5
max_balls = 20
dim balls_xy(max_balls), balls_v(max_balls), balls_m(max_balls)
dim marb$(max_balls)
ball_r = 15
ball_d = ball_r * 2
f$ = "/Sprites/marble.png"
if file_exists(f$) then 
  sprite "marble" load f$
else
  sprite "marble" begin ball_d, ball_d
  fill color 1,1,0
  fill circle ball_r, ball_r size ball_r
  sprite "marble" end
end if

fill color 0,0,1

'preload balls array x,y,vx,vy,mass and marbles (sprites)
for i = 1 to max_balls
  balls_xy(i) = ball_r + rnd(scw - ball_d) + (ball_r + rnd(sch - ball_d)) * 1i
  balls_v(i) = (-1 + 2*rndc(2))*rnd(init_speed)
  balls_m(i) = 1
  sprite "marble" copy "marble"&i
  marb$(i) = "marble"&i
  sprite marb$(i) show
next i

draw font size 50
t$ = "smart BASIC"
draw text t$ AT scw - text_width(t$),sch - text_height(t$)

draw font size 20
timer reset
total_loops = 0

do
'graphics lock
'graphics clear 0,0,0

'draw balls
for i = 1 to max_balls
  'draw balls
    'ab_v = abs(balls_v(i))/2
    'fill color ab_v,ab_v,ab_v
    'fill circle balls(i,x),balls(i,y) size ball_r

   'sprite marb$(i) alpha ab_v 'un mark but cost some fps!
   pos = balls_xy(i)
   sprite marb$(i) at real(pos),imag(pos)

  'move balls
   balls_xy(i) += balls_v(i)

  'wall (screen margin) collision detect & react
   x = real(balls_xy(i))
   y = imag(balls_xy(i))
   vx = real(balls_v(i))
   vy = imag(balls_v(i))
   if x <= ball_r Then
     balls_xy(i) = ball_r + y * 1i
     balls_v(i) = vy * 1i - vx
   end if
   if x >= scw - ball_r Then
     balls_xy(i) = scw - ball_r + y * 1i
     balls_v(i) = vy * 1i - vx
   end if
   if y <= ball_r Then
     balls_xy(i) = x + ball_r * 1i
     balls_v(i) = vx - vy * 1i
   end if
   if y >= sch - ball_r Then
     balls_xy(i) = x + (sch - ball_r) * 1i
     balls_v(i) = vx - vy * 1i
   end if

  'ball to ball collision detect and react
   for j = i + 1 to max_balls
     
     vec_n = balls_xy(i) - balls_xy(j)
     if abs(vec_n) <= ball_d Then
       'col_str$ = "ball "&str$(i)&" colliding ball "&str$(j)
       'draw text col_str$ at 10,10
       'resolve collision of ball(i) with ball(j)
       'colission vector = normal vector
       'calculate normal vector of collision: _n 
       'normalize L=1 normal vector of collision
       'distance (vec_n_L) should be 2*ball_r
        vec_n_L = abs(vec_n)
        
       'separate balls penetration along the
       '"line of collision".
        
        midpt = (balls_xy(i) + balls_xy(j)) / 2

        factor = ball_r / vec_n_L
        balls_xy(i) = midpt + factor * (balls_xy(i) - balls_xy(j))
        balls_xy(j) = midpt + factor * (balls_xy(j) - balls_xy(i))

       '.. continue normalization..
        vec_nn = vec_n / vec_n_L
      
       'calculate normalized tangent vector to
       'normal vector
        vec_nn_x = real(vec_nn)
        vec_nn_y = imag(vec_nn)
        vec_tn_x = -vec_nn_y
        vec_tn_y = vec_nn_x
        vec_tn = vec_tn_x + vec_tn_y * 1i

       'resolve the velocity vectors, v1 and v2
       'into normal and tangential components 
       ' --> dot product
       ix = real(balls_v(i))
       iy = imag(balls_v(i))
       jx = real(balls_v(j))
       jy = imag(balls_v(j))
        v1_n = vec_nn_x * jx + vec_nn_y * jy
        v2_n = vec_nn_x * ix + vec_nn_y * iy
        v1_t = vec_tn_x * jx + vec_tn_y * jy
        v2_t = vec_tn_x * ix + vec_tn_y * iy
     
       'find the "new" tangential velocities 
       'after the collision (remain the same)
        v1_t_ac = v1_t
        v2_t_ac = v2_t
        
       'find the new normal velocities after
       'collision _ac
        im = balls_m(i)
        jm = balls_m(j)
        imjm = im + jm
        jmim = jm - im
        v1_n_ac = (v1_n * jmim + 2 * im * v2_n) / imjm
        v2_n_ac = (-v2_n * jmim + 2 * jm * v1_n) / imjm

       'convert the scalar normal and tangential 
       'velocities into vectors
        vec_v1_n_ac = v1_n_ac * vec_nn
        vec_v1_t_ac = v1_t_ac * vec_tn

        vec_v2_n_ac = v2_n_ac * vec_nn
        vec_v2_t_ac = v2_t_ac * vec_tn

       'final velocity vectors by adding the
       'normal and tangential components
        balls_v(j) = vec_v1_n_ac + vec_v1_t_ac
        balls_v(i) = vec_v2_n_ac + vec_v2_t_ac

     end if
   next j
   
next i

total_loops += 1
fill rect 0,0 to 280,40
draw text "Frames per Second "&str$(int(total_loops * 1000/timer())) AT 0,5

'graphics unlock

until 0

Henko
Posts: 814
Joined: Tue Apr 09, 2013 12:23 pm
My devices: iPhone,iPad
Windows
Location: Groningen, Netherlands
Flag: Netherlands

Re: 2D Elastic Collision Spheres

Post by Henko »

LOL, 160 fps on the iPhone 5s. I've got to slow it down to check the collisions.

Henko
Posts: 814
Joined: Tue Apr 09, 2013 12:23 pm
My devices: iPhone,iPad
Windows
Location: Groningen, Netherlands
Flag: Netherlands

Re: 2D Elastic Collision Spheres

Post by Henko »

Just an example of avoiding superfluous indexing:

Instead of the code

For i=1 to limit
.
. do a lot of calculations with balls(i,x) and likewise array elements
.
Next i

Use the code:

For i=1 to limit
b_i_x = balls(i,x). ( convert to single variable )
.
. do a lot of calculations with b_i_x and likewise converted single variables
.
balls(i,x)=b_i_x ( if b_i_x itself was modified too )
Next i

The gain in speed however will be small with respect to the other improvement mentioned by mr. K. ( he should know best, after all )

Operator
Posts: 138
Joined: Mon May 06, 2013 5:52 am

Re: 2D Elastic Collision Spheres

Post by Operator »

Just uploading marble.png,
"just rename it"
will come back later on...
Attachments
412619801.794688.png
412619801.794688.png (2.02 KiB) Viewed 3876 times

User avatar
Dutchman
Posts: 851
Joined: Mon May 06, 2013 9:21 am
My devices: iMac, iPad Air, iPhone
Location: Netherlands
Flag: Netherlands

Re: 2D Elastic Collision Spheres

Post by Dutchman »

Nice program. It is like an open fire, it keeps attracting your attention. Fascinating :o

Joel
Posts: 57
Joined: Fri Jan 15, 2016 1:36 pm
My devices: miniipad
Flag: Germany

dS>0...Everywhere!

Post by Joel »

To all of us who presumed, there was reversibility or determinism at least in our tiny niche...
But have a look for yourselves...and tap on the screen if/ when you feel like.
joel
N.B. My sincere apologies to the authors(Operator, Mr. K., et al.) of that wonderful program, that I have kinda ... abused...but I simply couldn't resist...

interesting article btw:
https://en.m.wikipedia.org/wiki/Reversible_computing

Code: Select all

REM 2D elastic collision with spheres v1.2
REM 1.1 avoiding double calculations : ) to speed a bit
REM 1.2 using sprites, 53-56 fps with 20 marbles
REM 2.0 using complex numbers
REM based on:
REM http://www.vobarian.com/collisions/2dcollisions2.pdf
REM http://blogs.love2d.org/content/circle-collisions
REM 
REM SB 3.4 / iPad mini 1.gen. / iOS 7.0.4 / Operator
REM mod by Mr.K.
REM abused by joel


GRAPHICS
GRAPHICS CLEAR 0,0,1
OPTION SPRITE POS CENTRAL
OPTION BASE 1
DRAW COLOR 1,1,1
DRAW FONT NAME "Chalkduster"

endd = 0
sch = SCREEN_HEIGHT()
scw = SCREEN_WIDTH()
init_speed = 2
 
max_balls = 21 '(n^2+n)/2 V n%2=0
DIM balls_xy(max_balls), balls_v(max_balls), balls_m(max_balls)
DIM marb$(max_balls)
ball_r = 15
ball_d = ball_r * 2
f$ = "marble.png"
IF FILE_EXISTS(f$) THEN 
  SPRITE "marble" LOAD f$
ELSE
  SPRITE "marble" BEGIN ball_d, ball_d
  FILL COLOR 1,1,0
  FILL CIRCLE ball_r, ball_r SIZE ball_r
  SPRITE "marble" END
END IF

FILL COLOR 0,0,1
setup_length=CEIL(SQR(2*max_balls+.25)-.5)
row_counter=0 ! column_counter=setup_length
'preload balls array x,y,vx,vy,mass and marbles (sprites)
FOR i = 1 TO max_balls
  row_counter+=1
  balls_xy(i)= (row_counter*(4/3*ball_d))-ball_d + (setup_length*(4/3*ball_d)+ball_d/3-(column_counter)*(ball_d+10))*1i
  'balls_xy(i) = ball_r + RND(scw - ball_d) + (ball_r + RND(sch - ball_d)) * 1i
  balls_v(i) = (-1 + 2*RNDC(2))*RND(init_speed)
  balls_m(i) = 1
  SPRITE "marble" COPY "marble"&i
  marb$(i) = "marble"&i
  SPRITE marb$(i) SHOW
  IF row_counter=column_counter THEN 
   row_counter=0
   column_counter -=1
  ENDIF 
NEXT i

DRAW FONT SIZE 50
t$ = "smart BASIC"
DRAW TEXT t$ AT scw - TEXT_WIDTH(t$),sch - TEXT_HEIGHT(t$)

DRAW FONT SIZE 20
TIMER RESET
total_loops = 0

DO
IF TOUCH_X(0)>0 THEN
 WHILE TOUCH_X(0) > 0 ! END WHILE 
 invert_speed
ENDIF
'graphics lock
'graphics clear 0,0,0

'draw balls
FOR i = 1 TO max_balls
  'draw balls
    'ab_v = abs(balls_v(i))/2
    'fill color ab_v,ab_v,ab_v
    'fill circle balls(i,x),balls(i,y) size ball_r

   'sprite marb$(i) alpha ab_v 'un mark but cost some fps!
   POS = balls_xy(i)
   IF FILE_EXISTS(f$) THEN 
    SPRITE marb$(i) AT REAL(POS),IMAG(POS) SCALE ball_r/15
   ELSE 
    SPRITE marb$(i) AT REAL(POS),IMAG(POS)
   ENDIF 
  'move balls
   balls_xy(i) += balls_v(i)

  'wall (screen margin) collision detect & react
   x = REAL(balls_xy(i))
   y = IMAG(balls_xy(i))
   vx = REAL(balls_v(i))
   vy = IMAG(balls_v(i))
   IF x <= ball_r THEN
     balls_xy(i) = ball_r + y * 1i
     balls_v(i) = vy * 1i - vx
   END IF
   IF x >= scw - ball_r THEN
     balls_xy(i) = scw - ball_r + y * 1i
     balls_v(i) = vy * 1i - vx
   END IF
   IF y <= ball_r THEN
     balls_xy(i) = x + ball_r * 1i
     balls_v(i) = vx - vy * 1i
   END IF
   IF y >= sch - ball_r THEN
     balls_xy(i) = x + (sch - ball_r) * 1i
     balls_v(i) = vx - vy * 1i
   END IF

  'ball to ball collision detect and react
   FOR j = i + 1 TO max_balls
     
     vec_n = balls_xy(i) - balls_xy(j)
     IF ABS(vec_n) <= ball_d THEN
       'col_str$ = "ball "&str$(i)&" colliding ball "&str$(j)
       'draw text col_str$ at 10,10
       'resolve collision of ball(i) with ball(j)
       'colission vector = normal vector
       'calculate normal vector of collision: _n 
       'normalize L=1 normal vector of collision
       'distance (vec_n_L) should be 2*ball_r
        vec_n_L = ABS(vec_n)
        
       'separate balls penetration along the
       '"line of collision".
        
        midpt = (balls_xy(i) + balls_xy(j)) / 2

        factor = ball_r / vec_n_L
        balls_xy(i) = midpt + factor * (balls_xy(i) - balls_xy(j))
        balls_xy(j) = midpt + factor * (balls_xy(j) - balls_xy(i))

       '.. continue normalization..
        vec_nn = vec_n / vec_n_L
      
       'calculate normalized tangent vector to
       'normal vector
        vec_nn_x = REAL(vec_nn)
        vec_nn_y = IMAG(vec_nn)
        vec_tn_x = -vec_nn_y
        vec_tn_y = vec_nn_x
        vec_tn = vec_tn_x + vec_tn_y * 1i

       'resolve the velocity vectors, v1 and v2
       'into normal and tangential components 
       ' --> dot product
       ix = REAL(balls_v(i))
       iy = IMAG(balls_v(i))
       jx = REAL(balls_v(j))
       jy = IMAG(balls_v(j))
        v1_n = vec_nn_x * jx + vec_nn_y * jy
        v2_n = vec_nn_x * ix + vec_nn_y * iy
        v1_t = vec_tn_x * jx + vec_tn_y * jy
        v2_t = vec_tn_x * ix + vec_tn_y * iy
     
       'find the "new" tangential velocities 
       'after the collision (remain the same)
        v1_t_ac = v1_t
        v2_t_ac = v2_t
        
       'find the new normal velocities after
       'collision _ac
        im = balls_m(i)
        jm = balls_m(j)
        imjm = im + jm
        jmim = jm - im
        v1_n_ac = (v1_n * jmim + 2 * im * v2_n) / imjm
        v2_n_ac = (-v2_n * jmim + 2 * jm * v1_n) / imjm

       'convert the scalar normal and tangential 
       'velocities into vectors
        vec_v1_n_ac = v1_n_ac * vec_nn
        vec_v1_t_ac = v1_t_ac * vec_tn

        vec_v2_n_ac = v2_n_ac * vec_nn
        vec_v2_t_ac = v2_t_ac * vec_tn

       'final velocity vectors by adding the
       'normal and tangential components
        balls_v(j) = vec_v1_n_ac + vec_v1_t_ac
        balls_v(i) = vec_v2_n_ac + vec_v2_t_ac

     END IF
   NEXT j
   
NEXT i

total_loops += 1
FILL RECT 0,0 TO 280,40
DRAW TEXT "Frames per Second "&STR$(INT(total_loops * 1000/TIMER())) AT 0,5

'graphics unlock

UNTIL 0

DEF invert_speed
FOR i=1 TO .max_balls
 .balls_v(i)=-1*REAL(.balls_v(i))-(IMAG(.balls_v(i))*1i)
NEXT i
END DEF

Post Reply