
-----------------------------------
thoughtful
Fri Jan 23, 2004 8:16 pm

Tutorial: Basic POOL and realistic collision
-----------------------------------
Okay here is my long promised tutorial

I have seen a lot of reference to poor tonys tutorial, which has some bugs. That turotial was meant to be a base information, he said in his post that he did not spend all the time figuring all the trig out. So give him a break  :D . BTW my tutorial was inspired by somewhat same principle and then i added some stuff.

The tutorial is not just on collision but it actually provieds a base package for n e pool game, with a lot of room to expand. I actually took out a old version of my ISP and had to delete some stuff to make it so it doesnt give the whole solution. The collision algorithm is very good, but it might have some problem, such as the balls sticking together, now that i want u to figure on your own (my ISP has an advanced version of the same algorith with no problems  :P ).

Also you can change the values of the constants to increase ball size, decay, highest speed, lowest speed or number of balls e.t.c.

And also i will like to thank tony and catalyst who at the start helped me understand how the realistic collision works.


% by Abdullah Ramay a.k.a Thoughtful
% some variables may not be used in this tutorial becuase this is taken from my game that i am making for my ISP
%click on the white ball and drag to take a shot
var white_x : real% positions
var white_y : real
var white_xsp : real%velocities
var white_ysp : real
var x, y, but : int
var sunk_x, sunk_y : int
const totalballs := 3  %change this to change number of balls
var balls_x : array 1 .. totalballs of real%positions
var balls_y : array 1 .. totalballs of real
var balls_xsp : array 1 .. totalballs of real%velocities
var balls_ysp : array 1 .. totalballs of real
var balls_check : array 1 .. totalballs of int
var font : int := Font.New ("verdana:5:bold")
var font2 : int := Font.New ("verdana:5")
var distance : real
var xsp_temp1, ysp_temp1, xsp_temp2, ysp_temp2 : real
var movedist1, movedist2, collangle, mass, a1, a2, nX, nY, optimisedP : real
const decay := 75 %inversely poportional to stopping, bigger decay= longer moving ball
const lowbar := 50
const ballradius := 8 %radius of the ball, try 18 for monster ball ;=)
const lowestspeed := .01%lowest possible speed
const highestspeed := 10 %highest possible speed
const ballcollidedistance := ballradius * 2 %how far does the ball has to be before it collides
const pocketcollidedistance := 20

var cuecolor : int := white
setscreen ("title:Thoughtful's Pool")
setscreen ("offscreenonly")
View.Set ("graphics:600;350")
sunk_x := 20
sunk_y := 20
mass := 1
for i : 1 .. totalballs %initialises starting positions 
    balls_x (i) := Rand.Int (20 + lowbar, (maxx - 20)) + Rand.Real
    balls_y (i) := Rand.Int (20, (maxy - 20)) + Rand.Real
    balls_xsp (i) := 0
    balls_ysp (i) := 0
    balls_check (i) := 1
end for
% ignore these , jus some initial setup values
white_x := (maxx div 2)
white_y := (maxy div 2) + (lowbar / 2)
white_xsp := 0
white_ysp := 0
proc drawfield %draws the field
    drawfillbox (0, 0, maxx, maxy, brown)
    drawfillbox (10, 10 + lowbar, maxx - 10, maxy - 10, white)
    drawfillbox (20, 20 + lowbar, maxx - 20, maxy - 20, green)

end drawfield
%collision of white ball to balls
proc white_collide
    for i : 1 .. totalballs
        distance := ((balls_x (i) - white_x) * (balls_x (i) - white_x) + (balls_y (i) - white_y) * (balls_y (i) - white_y)) ** 0.5
        if distance < ballcollidedistance then
            % this the part which controls the ball to ball collision
                    /******************************************************************************************
                    * the collision part is below                                                             *
                    ******************************************************************************************/

            collangle := arctand ((balls_y (i) - white_y) / ((balls_x (i) - white_x))) %get angle
            

            nX := cosd (collangle) %x vector
            nY := sind (collangle) %y vector

            a2 := balls_xsp (i) * nX + balls_ysp (i) * nY%figure out reultant velcoities
            a1 := white_xsp * nX + white_ysp * nY  %resultants

            optimisedP := (2.0 * (a1 - a2)) / (mass + mass) %you can have different masses, i am using same masses for all balls

            balls_xsp (i) := balls_xsp (i) + (optimisedP * mass * nX) %finally initialises the x and y velocoities to the balls
            balls_ysp (i) := balls_ysp (i) + (optimisedP * mass * nY)
            white_xsp := white_xsp - (optimisedP * mass * nX)
            white_ysp := white_ysp - (optimisedP * mass * nY)
                /******************************************************************************************
                * the collision part ends                                                             *
                ******************************************************************************************/
      





        end if
    end for
end white_collide

%collision of balls to balls
proc balls_collide
    for i : 1 .. totalballs
        for k : i .. totalballs

            if k not= i then
                distance := (((balls_x (i) - balls_x (k)) * (balls_x (i) - balls_x (k))) + ((balls_y (i) - balls_y (k)) * (balls_y (i) - balls_y (k)))) ** 0.5
                if distance < ballcollidedistance then
                    
                    collangle := arctand ((balls_y (k) - balls_y (i)) / ((balls_x (k) - balls_x (i))))
                   

                    nX := cosd (collangle)
                    nY := sind (collangle)

                    a1 := balls_xsp (i) * nX + balls_ysp (i) * nY
                    a2 := balls_xsp (k) * nX + balls_ysp (k) * nY

                    optimisedP := (2.0 * (a1 - a2)) / (mass + mass)

                    balls_xsp (i) := balls_xsp (i) - (optimisedP * mass * nX)
                    balls_ysp (i) := balls_ysp (i) - (optimisedP * mass * nY)
                    balls_xsp (k) := balls_xsp (k) + (optimisedP * mass * nX)
                    balls_ysp (k) := balls_ysp (k) + (optimisedP * mass * nY)
                    % moves the balls forward a step so they dont get stuck with each other( but the balls will still stick)
                    balls_x (i) += balls_xsp (i)
                    balls_y (i) += balls_ysp (i)
                    balls_x (k) += balls_xsp (k)
                    balls_y (k) += balls_ysp (k)
                    

                end if
            end if

        end for
    end for
end balls_collide

% controls the motion& collision with the side bars, also decays the speed so it slows
proc balls_mov
    for i : 1 .. totalballs
    
        if balls_check (i) not= 0 then
            balls_x (i) += balls_xsp (i)
            balls_y (i) += balls_ysp (i)
            if balls_x (i) < (20 + ballradius) then
                balls_x (i) := 20 + ballradius
                balls_xsp (i) := - (balls_xsp (i))
            end if
            if balls_x (i) > (maxx - (20 + ballradius)) then
                balls_x (i) := maxx - (20 + ballradius)
                balls_xsp (i) := - (balls_xsp (i))
            end if
            if balls_y (i) < (20 + ballradius) + lowbar then
                balls_y (i) := (20 + ballradius) + lowbar
                balls_ysp (i) := - (balls_ysp (i))
            end if
            if balls_y (i) > (maxy - (20 + ballradius)) then
                balls_y (i) := maxy - (20 + ballradius)
                balls_ysp (i) := - (balls_ysp (i))
            end if


            if balls_xsp (i) > 0 then
                balls_xsp (i) := balls_xsp (i) - (balls_xsp (i) / decay)
            end if
            if balls_ysp (i) > 0 then
                balls_ysp (i) := balls_ysp (i) - (balls_ysp (i) / decay)
            end if
            if balls_xsp (i) < 0 then
                balls_xsp (i) := balls_xsp (i) + (- (balls_xsp (i) / decay))
            end if
            if balls_ysp (i) < 0 then
                balls_ysp (i) := balls_ysp (i) + (- (balls_ysp (i) / decay))
            end if

            if balls_ysp (i) > - (lowestspeed) and balls_ysp (i) < (lowestspeed) then
                balls_ysp (i) := 0
            end if

            if balls_xsp (i) > - (lowestspeed) and balls_xsp (i) < (lowestspeed) then
                balls_xsp (i) := 0
            end if
        end if
    end for


    for i : 1 .. totalballs %draws the balls

        drawfilloval (round (balls_x (i)), round (balls_y (i)), ballradius, ballradius, i)
        drawfilloval (round (balls_x (i)), round (balls_y (i)), ballradius - 4, ballradius - 4, white)

        drawoval (round (balls_x (i)), round (balls_y (i)), ballradius, ballradius, black)
        Font.Draw (intstr (i), round (balls_x (i)) - 2, round (balls_y (i)) - 2, font, 7)

    end for


    

end balls_mov
proc whiteball_mov %controls the moving of the white ball

    white_x += white_xsp
    white_y += white_ysp
    Mouse.Where (x, y, but)
    
    % bouncing of the wall
    if white_x < (20 + ballradius) then
        white_x := 20 + ballradius
        white_xsp := - (white_xsp)
    end if
    if white_x > (maxx - (20 + ballradius)) then
        white_x := maxx - (20 + ballradius)
        white_xsp := - (white_xsp)
    end if
    if white_y < (20 + ballradius) + lowbar then
        white_y := (20 + ballradius) + lowbar
        white_ysp := - (white_ysp)
    end if
    if white_y > (maxy - (20 + ballradius)) then
        white_y := maxy - (20 + ballradius)
        white_ysp := - (white_ysp)
    end if

    % decays the ball
    if white_xsp > 0 then
        white_xsp := white_xsp - (white_xsp / decay)
    end if
    if white_ysp > 0 then
        white_ysp := white_ysp - (white_ysp / decay)
    end if
    if white_xsp < 0 then
        white_xsp := white_xsp + (- (white_xsp / decay))
    end if
    if white_ysp < 0 then
        white_ysp := white_ysp + (- (white_ysp / decay))
    end if
    % makes the ball stop
    if white_ysp > - (lowestspeed) and white_ysp < (lowestspeed) then
        white_ysp := 0
    end if

    if white_xsp > - (lowestspeed) and white_xsp < (lowestspeed) then
        white_xsp := 0
    end if
  

    drawfilloval (round (white_x), round (white_y), ballradius, ballradius, white)
    drawoval (round (white_x), round (white_y), ballradius, ballradius, black)
 

end whiteball_mov
proc poolcue
    if (x > white_x - 5) and x < (white_x + ballradius) and (y > white_y - ballradius) and y < (white_y + ballradius) and but = 1 then
        white_xsp := 0
        white_ysp := 0
        loop
            drawfield
            Mouse.Where (x, y, but) %gets
            exit when but = 0
            drawfilloval (round (white_x), round (white_y), ballradius, ballradius, white)
            drawoval (round (white_x), round (white_y), ballradius, ballradius, black)
            balls_mov
            
            Draw.Line (round (white_x), round (white_y), x, y, cuecolor)
        


            delay (10)% take this away if the game runs too slowly, my computer is a 2.6 Ghz so doesnt amtters to me :)
            View.Update
            cls
        end loop
        
        white_xsp := (white_x - x) / 15 % gets the power from cue for the shot
        white_ysp := (white_y - y) / 15
        if white_xsp > highestspeed then % sees if the power is according to the highest speed e.t.c
            white_xsp := highestspeed
        elsif white_xsp < -highestspeed then
            white_xsp := -highestspeed
        end if
        if white_ysp > highestspeed then
            white_ysp := highestspeed
        elsif white_ysp < -highestspeed then
            white_ysp := -highestspeed
        end if
    end if
end poolcue
% main loop, i always like procedure, very easy to add rules and stuff to the game, my final isp just uses a single procedure for all rules
loop
    drawfield
   
    white_collide
    balls_collide
    whiteball_mov
    balls_mov
    if but = 1 then
        poolcue
    end if
    View.Update
    cls
end loop


i hope u liked it, if you did let me know by replying

-----------------------------------
TheXploder
Fri Jan 23, 2004 8:25 pm


-----------------------------------
wow, amazing!! :D
I think it speeds up a bit too fast, and slows almost abruptly, I think it should roll a bit more. But hey +10 bits good job, maybe some mods can give you more, hint, hint,  :wink: ,  :wink:...

-----------------------------------
thoughtful
Fri Jan 23, 2004 8:29 pm


-----------------------------------
thanks a lot, though as i said  i left some error in their..otherwise it wont be any fun..all the guys would have the same pool game...so you can improve this and put in rules e.t.c, the version i made actually jsut had a procedure for everything and was very easy to add/ remove stuff(specially rules for 8-ball,9-ball,e.t.c).

The slowing down and speed you can adjust with the constants.

-----------------------------------
AsianSensation
Fri Jan 23, 2004 8:31 pm


-----------------------------------
very very nice. This is a great program. It also has that kinda of polished look to it. Here, have some bits, you deserve it.

+50 bits

-----------------------------------
Tony
Fri Jan 23, 2004 8:58 pm


-----------------------------------
awesome 8) I'm going to link to this from my old tutorial
+50Bits

-----------------------------------
Cervantes
Fri Jan 23, 2004 9:06 pm


-----------------------------------
wow thats amazing!!  GREAT work!!!

-----------------------------------
Cervantes
Sat Jan 24, 2004 1:32 pm


-----------------------------------
hmmm.. I wonder if there's a way to use this kind of collision style in Slime Volleyball :)

ballspx and ballspy is so much easier than ballangle and velocity and weight and all :?

-----------------------------------
thoughtful
Sat Jan 24, 2004 5:13 pm


-----------------------------------
yes..you can, jsut use a decay for the y speed, so tht it goes downwards if you thinking off a side view volley ball.

If its top view ti should be rpetty simple

-----------------------------------
Cervantes
Sat Jan 24, 2004 5:54 pm


-----------------------------------
hhmmm.. I shall try to impliment that...

I'm almost done making a game like the space game that turing comes with.. will post it here in a bit.

-----------------------------------
Kuntzy
Mon Jan 26, 2004 7:27 pm


-----------------------------------
Great tutorial! +bits, it helped me out a lot, I get your code, only when I run the pool oi made base off of yours, my veloities seem to ammplify when balls collide with eachother. :cry:

-----------------------------------
jonos
Mon Jan 26, 2004 7:54 pm


-----------------------------------
where do all you guys learn this. do you get the basics from compsci class then just learn it on your own. im trying to learn on my own cause my compsci grade 10 class was useless, but ahhhhhhh it takes so long.

-----------------------------------
Tony
Mon Jan 26, 2004 8:40 pm


-----------------------------------
yeah, preaty much. Just pick up syntax from compsci class and pick a challange for yourself. You'll learn a great deal while trying to achieve it.

btw - pool involves trig and physics, so that might be a bit above gr10 level :?

-----------------------------------
jonos
Mon Jan 26, 2004 8:42 pm


-----------------------------------
ok, should i take trig and physics in grade 11 and stuff like that or will i learn that in compsci 11 and 12

-----------------------------------
Tony
Mon Jan 26, 2004 8:45 pm


-----------------------------------
you learn trig in grade10/11 math. And you should defenatly take physics 11 if you're into making games. You dont learn that in CS... heck, you dont learn anything in CS. Just "if" statements :lol:

-----------------------------------
Cervantes
Tue Jan 27, 2004 11:18 am


-----------------------------------
long live the if statements!! :)

we learn trig (or start learning it) in gr 10 math, (im only in gr 10 now, and have math next semester)

you also learn some physics in gr10 science, but not enough to do much in turing... for compsci it just helps you understand the physics in other ppls games :)

-----------------------------------
Tendulkar
Wed Feb 04, 2004 4:23 pm


-----------------------------------
this is great! excellent work thoughtful

-----------------------------------
gamer
Thu Apr 08, 2004 2:39 pm


-----------------------------------
helo thoughtful btw GREAT JOB on this pool program, u see im kind of new to program so my question is, do you think u can explain to me how the collision part of the program works?? i understand the fact that u applied trig but how exactly did you do it?

-----------------------------------
gamer
Sat Apr 10, 2004 6:21 pm


-----------------------------------
heloo??

thoughtful can ya reply?

or anyone else who knows please tell me, i reli gota understand 
thnx

-----------------------------------
gamer
Mon Apr 12, 2004 3:52 pm


-----------------------------------
still no reply??? omg

-----------------------------------
Paul
Mon Apr 12, 2004 3:55 pm


-----------------------------------
Thoughtful is not on Compsci very often, and don't triple post lol, Asian Sensation would be angry at you. Im sure whenever he gets on, he'll try and reply. You could always send him a PM.

-----------------------------------
Tony
Mon Apr 12, 2004 3:59 pm


-----------------------------------
you find the angle
you break it up into vector components (x and y)
you find total energy transfer from the collision
you use vector components as ratios to redestribute the energy after collision.

-----------------------------------
gamer
Mon Apr 12, 2004 4:14 pm


-----------------------------------
thnx

-----------------------------------
evildaddy911
Sun Oct 16, 2011 1:35 pm

RE:Tutorial: Basic POOL and realistic collision
-----------------------------------
i dont have gr11 math till next semester, can you explain what you mean by vector components?

-----------------------------------
Raknarg
Wed Oct 19, 2011 3:33 pm

RE:Tutorial: Basic POOL and realistic collision
-----------------------------------
It's actually physics... lets say you have a line. This line goes up by 3 and across by 4. Those woule be the x and y vector components: The change in x and the change in y.

Correect me if I'm wrong.

-----------------------------------
evildaddy911
Wed Oct 19, 2011 3:47 pm

RE:Tutorial: Basic POOL and realistic collision
-----------------------------------
so its like finding slope, but not actually finding the slope, cuz slope is change in y divided by change in x, but you dont do the dividing

-----------------------------------
Raknarg
Wed Oct 19, 2011 3:53 pm

RE:Tutorial: Basic POOL and realistic collision
-----------------------------------
Its basically trigonometry. Usually when you're working with vectors, you are given a bunch of distances with directions (ex. 35m[E25oS], or 25 meters, East 25 degrees to the South) and from that you calculate the overall displacement and the overall angle (compared from your starting point to your finishing point).

Of course, this is a really bad explaination. You should look it up:
http://zonalandeducation.com/mstm/physics/mechanics/vectors/introduction/introductionVectors.html
That seems promising.

-----------------------------------
evildaddy911
Thu Oct 20, 2011 3:29 pm

Re: Tutorial: Basic POOL and realistic collision
-----------------------------------
okay, so the vectors are really just horizontal/vertical distances.... and i puzzled out a quick screensaver-like program...
im not sure what you mean by displacement, but i think i could figure out the angle... 
anyways, voila:

var x, y, xv, yv : int
var change_time : int := 10000
var last_change : int := -change_time
x := Rand.Int (10, maxx - 10)
y := Rand.Int (10, maxy - 10)
xv := Rand.Int ((-5), 5)
yv := Rand.Int ((-5), 5)
loop
    var now := Time.Elapsed
    if now - last_change >= change_time then
        xv := Rand.Int ((-5), 5)
        yv := Rand.Int ((-5), 5)
        last_change := now
    end if
    drawfilloval (x, y, 10, 10, white)
    x := xv + x
    y := y + yv
    if x = maxx - 10 then
        xv := xv * (-1)
    end if
    if y >= maxy - 10 or y  yPos then
        t := 270
    elsif x < xPos and y = yPos then
        t := 0
    elsif x = xPos and y < yPos then
        t := 90
    elsif x > xPos and y = yPos then
        t := 180
    elsif x = xPos and y = yPos then
        t := 0
    elsif x > xPos then
        t := arctand ((y - yPos) / (x - xPos)) + 180
    else
        t := arctand ((y - yPos) / (x - xPos))
    end if
    % This thing here calculates your angle. It'll make sense if you've ever done vectors before. It uses the function tan-1. The ones before it are for mathematical correctness; you cannot divide anything by zero.
   
    if b = 1 and bltd = true then % Only shoots when the bullet is dead and the button is clicked.
        bltd := false
        bltx := xPos - (40 * cosd (t)) % setting the position of the bullet
        blty := yPos - (40 * sind (t)) % same
        bltvx := -5 * cosd (t) % setting the change in x
        bltvy := -5 * sind (t) % setting the change in y
    end if
    
    Draw.FillOval (xPos, yPos, 20, 20, blue)
    Draw.ThickLine (xPos, yPos, xPos - round (40 * cosd (t)), yPos - round (40 * sind (t)), 4, 7) % This is important for drawing shapes according to an angle. You add onto the original postion. In the case of x, its the radius * cos(angle). For y it's radius * sin (angle)
    if bltd = false then
        Draw.FillOval (round (bltx), round (blty), 4, 4, brightred)
        Draw.FillOval (round (bltx), round (blty), 2, 2, 7)
        bltx += bltvx % Changes the bullet x position relative to the change in x
        blty += bltvy % Changes the bullet y position relative to the change in y
        if bltx > maxx or bltx < 0 or blty > maxy or blty < 0 then % If the bullet hits the edge, it dies
            bltd := true
        end if
    end if
    View.Update
    cls
end loop

