Computer Science Canada

Tutorial: Basic POOL and realistic collision

Author:  thoughtful [ Fri Jan 23, 2004 8:16 pm ]
Post subject:  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 Very Happy . 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 Razz ).

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.

code:

% 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

Author:  TheXploder [ Fri Jan 23, 2004 8:25 pm ]
Post subject: 

wow, amazing!! Very Happy
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...

Author:  thoughtful [ Fri Jan 23, 2004 8:29 pm ]
Post subject: 

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.

Author:  AsianSensation [ Fri Jan 23, 2004 8:31 pm ]
Post subject: 

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

Author:  Tony [ Fri Jan 23, 2004 8:58 pm ]
Post subject: 

awesome 8) I'm going to link to this from my old tutorial
+50Bits

Author:  Cervantes [ Fri Jan 23, 2004 9:06 pm ]
Post subject: 

wow thats amazing!! GREAT work!!!

Author:  Cervantes [ Sat Jan 24, 2004 1:32 pm ]
Post subject: 

hmmm.. I wonder if there's a way to use this kind of collision style in Slime Volleyball Smile

ballspx and ballspy is so much easier than ballangle and velocity and weight and all Confused

Author:  thoughtful [ Sat Jan 24, 2004 5:13 pm ]
Post subject: 

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

Author:  Cervantes [ Sat Jan 24, 2004 5:54 pm ]
Post subject: 

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.

Author:  Kuntzy [ Mon Jan 26, 2004 7:27 pm ]
Post subject: 

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. Crying or Very sad

Author:  jonos [ Mon Jan 26, 2004 7:54 pm ]
Post subject: 

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.

Author:  Tony [ Mon Jan 26, 2004 8:40 pm ]
Post subject: 

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 Confused

Author:  jonos [ Mon Jan 26, 2004 8:42 pm ]
Post subject: 

ok, should i take trig and physics in grade 11 and stuff like that or will i learn that in compsci 11 and 12

Author:  Tony [ Mon Jan 26, 2004 8:45 pm ]
Post subject: 

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 Laughing

Author:  Cervantes [ Tue Jan 27, 2004 11:18 am ]
Post subject: 

long live the if statements!! Smile

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 Smile

Author:  Tendulkar [ Wed Feb 04, 2004 4:23 pm ]
Post subject: 

this is great! excellent work thoughtful

Author:  gamer [ Thu Apr 08, 2004 2:39 pm ]
Post subject: 

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?

Author:  gamer [ Sat Apr 10, 2004 6:21 pm ]
Post subject: 

heloo??

thoughtful can ya reply?

or anyone else who knows please tell me, i reli gota understand
thnx

Author:  gamer [ Mon Apr 12, 2004 3:52 pm ]
Post subject: 

still no reply??? omg

Author:  Paul [ Mon Apr 12, 2004 3:55 pm ]
Post subject: 

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.

Author:  Tony [ Mon Apr 12, 2004 3:59 pm ]
Post subject: 

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.

Author:  gamer [ Mon Apr 12, 2004 4:14 pm ]
Post subject: 

thnx

Author:  evildaddy911 [ Sun Oct 16, 2011 1:35 pm ]
Post subject:  RE:Tutorial: Basic POOL and realistic collision

i dont have gr11 math till next semester, can you explain what you mean by vector components?

Author:  Raknarg [ Wed Oct 19, 2011 3:33 pm ]
Post subject:  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.

Author:  evildaddy911 [ Wed Oct 19, 2011 3:47 pm ]
Post subject:  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

Author:  Raknarg [ Wed Oct 19, 2011 3:53 pm ]
Post subject:  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.

Author:  evildaddy911 [ Thu Oct 20, 2011 3:29 pm ]
Post subject:  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:
Turing:

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 <= 10 or x >= maxx - 10 then
        xv := xv * (-1)
    end if
    if y >= maxy - 10 or y <= 10 then
        yv := yv * (-1)
    end if

    drawfilloval (x, y, 10, 10, black)
    drawfilloval (x - 2, y, 1, 2, brightgreen)
    drawfilloval (x + 2, y, 1, 2, brightgreen)
    drawline (x - 3, y - 4, x + 3, y - 4, brightred)
    delay (20)
end loop

it draws a smiley face ball bouncing off the walls, and every 10 seconds it randomly changes the x and y vectors

Author:  Raknarg [ Thu Oct 20, 2011 3:53 pm ]
Post subject:  RE:Tutorial: Basic POOL and realistic collision

That would work. You could even use angles:

Turing:

View.Set ("offscreenonly, graphics:700;700")

const xPos := 350
const yPos := 350
var x, y, b : int := 0 % variables for the Mouse.Where
var t : real % Theta, or the angle
var bltx, blty, bltvx, bltvy : real := 0 % the bullet positions, and the amount the x and y changes
var bltd : boolean := true % whether or not the bullet is live or dead

loop
    Mouse.Where (x, y, b)
    if x = xPos and 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


: