Dark Bit Factory & Gravity

PROGRAMMING => Other languages => Yabasic => Topic started by: Clanky on February 10, 2007

Title: Pool
Post by: Clanky on February 10, 2007
Wow.. I just needa finish Green Boxcopter - then I have finished a game...
I will do this later, because'a I'm'a tryin' ta mak'a pool game'a.

Basic information:
  There are 15 balls (one black, 7 red, 7 yellow) with one white ball;
  I have the visuals of the table;
  I have set up a check system to see what each balls status is (current position, direction, etc.);
  Hopefully I can be taught how to make circlular collisions with defractions of the balls to the angle where the white ball has hit them.

I have the visuals - like normal I code the easy stuff. I just need to make it so the balls collide and rebound of of each other and stuff like that.
I won't be able to put the code up for awhile because I have it on the other - non internet connected computer.
When I get it on this computer, I will post it. But in the mean time, hopefully someone can give me a low down on making balls collide and rebound and stuff. And to make it so the balls go off on angles porportional to where they have been hit? Dig it??? (Hope so!)
Also, I am having real trouble with the white ball collisions... when I hit it (I have coded a little bit on breaking, with the power of the hit decreasing as it rolls, and decreasing more if it hits a wall), it is hitting the top of the table and turning right? Not suppose to happen as it hasn't hit a side wall yet?
Also, if someone would be kind enough to teach me how to make it so that you can more you 'cue' (I think that's the stick?) around in a circle, and to hit the ball of on an angle?

I will try and get the code up here as soon as I can... most probably tomorrow (hopefully)

Thanks.
Title: Re: Pool
Post by: Jim on February 10, 2007
Fryer put quite a bit of work into this problem a few years ago.  I don't think we were particularly satisfied with the results.  It's not too bad colliding one ball against another, but when you have a pack of balls it can be very difficult.

Post it up and we can all have a look.

Jim
Title: Re: Pool
Post by: Shockwave on February 10, 2007
If you can solve the problems of a game like this Clanky, I will personally give you a +50 Karma boost! Whatever happens, you'll learn a lot from it!! If you manage to impliment top and backspin and sidespin properly I'll boost your Karma by 100.

A great project. I can forsee problems of balls geting stuck inside each other etc... *shudders*
Title: Re: Pool
Post by: rdc on February 10, 2007
This might be of some help:

http://freespace.virgin.net/hugo.elias/models/m_snokr.htm

Title: Re: Pool
Post by: rain_storm on February 10, 2007
I would be delighted to help you on this one, in fact if you dont mind it being a team effort I would be happy to take on half the burden. I have already attempted a pool game not as far as putting backspin on the cue but got all the balls bouncing around correctly things went to pot for me when I thought it would be nice to make it 3D. Anyway I will type my old one out on the PC (its on my memory card atm) if you want a look at the code. I will post it here if you do.

Edit: Pool game attached at last. Graphics are a little modified from Clankys, It was the swept collision between the balls and the walls that held the whole show up, Sorry for the long wait. Thanks to everyone who had helped to make this happen.

Better late than never ;D
Title: Re: Pool
Post by: Jim on February 10, 2007
Nice link rdc - in snooker it can be simplified a bit because all the balls are the same size and you can just set both ball masses to 1 and ignore them.

Jim
Title: Re: Pool
Post by: Clanky on February 11, 2007
Ok, heres the visual side of the game... I had to make the power and shot code just for this demo - it only goes straight ahead. but, it isn't really calculated at all... it's only the visuals.

Thanx for everything guys.
And I agree, this will be heaps hard... and I did think about having spin and stuff - I will see if i can make it so you have a ball with the position of where the cue will hit the ball on a side panel.

Hopefully this can be a DBF Team Game.
Title: Re: Pool
Post by: Clanky on February 11, 2007
Thanx rcd... that page has really inspired me to make this game!
I did year 12 physics, so the momentum aspects of the collisions were a flash back *cries in happyness*... good Mr. Newton with his fundemental law for momentum - "after collision: both balls will have equal magnitude with opposite direction..." or something (and hopefully Mr. Newton's law)
I actually had two books complete on physics - with loads of information about collisions and momenta... but, there gone - bummer!!!
I guess this will be hard...
Title: Re: Pool
Post by: Stonemonkey on February 11, 2007
This was as far as I got with this, exe and source for b3d but it doesn't use b3d collisions or anything like that. I never quite worked out the right way of calculating the results of the sphere-sphere collisions but it works fairly well.

http://www.stonemonkie.pwp.blueyonder.co.uk/pool3d_3.zip
Title: Re: Pool
Post by: Shockwave on February 11, 2007
Holy shit Fryer! That's mentally good! Check your Karma.
Title: Re: Pool
Post by: Paul on February 11, 2007
I did a simple ball bounce code for a fire demo(haven't posted it because i haven't got any music to go with it). but it doesn't work to well, probably not well enough at all.  :(

the .exe is really nice and works perfectly but the sourcecode freezes







Title: Re: Pool
Post by: Stonemonkey on February 11, 2007
Sorry about that Paul. atm I don't have b3d installed so i'd probably been messing around with something at the time of working on it. I'll look out something that works.
Title: Re: Pool
Post by: Stonemonkey on February 11, 2007
installed b3d but can't work out why it's freezing atm but here's an earlier source, it doesn't have the pockets.
Title: Re: Pool
Post by: rain_storm on February 11, 2007
pool3d3 is amazing but I couldnt get pool3d2 to run its says error texture not found or something to that effect but the routines should prove invaluable looks like this little project has generated quite a bit of interest
Title: Re: Pool
Post by: Stonemonkey on February 11, 2007
Sorry again, I've added the texture to the above attachment.
Title: Re: Pool
Post by: rain_storm on February 11, 2007
its workin perfect now I love the shadows
Title: Re: Pool
Post by: Clanky on February 12, 2007
Very nice pool program Stonemonkey! Beautiful... just you can't sink the balls  :( lol


I've got a cue in my program now - copied Jim Shaw's rotation bit out of his Physics Sample. It rotates, but I need some help with creating an angle so the ball moves in the direction the cue is pointing.

Then, some help with making collisions... I tried using the information from the site rdc gave, but it seems YaBASIC doesn't allow normalise() or dotpoint() **or something**

I added really nice shadow effects to the balls today. This was really a nice addition because it gave it a 3D feel to the balls. I also added a spin factor... g2g - lightning comming!! eeee
Title: Re: Pool
Post by: Jim on February 12, 2007
Moving a ball in the direction of an arrow:
If a ball is going in direction 'angle' then if you say
Code: [Select]
xpos = xpos + cos(angle) * speed
ypos = ypos + sin(angle) * speed
that will move it the right way.  In yabasic, angles are in radians.
Code: [Select]
radians = degrees/180*3.14159
and
Code: [Select]
degrees = radians*3.14159/180

Normalising a vector:
If you want to make a vector have length 1 (that is, if you apply Pythagoras' Theorem to the x,y,z of the vector it comes out as 1) then you need to say
Code: [Select]
length = sqr(x*x + y*y + z*z) : rem Pythagoras
x = x / length
y = y / length
z = z / length

Vector dot product:
This calculates the amount of one vector that lies in the direction of another vector.  It's also useful for finding out the angle between two vectors.  If you have two vectors x1,y1,z1 and x2,y2,z2 then
Code: [Select]
dot = x1 * x2 + y1 * y2 + z1 * z2

If you're working in 2d (like in this pool game) just remove all the z terms from the last 2 equations, ie
Code: [Select]
length = sqr(x*x + y*y) : rem Pythagoras
x = x / length
y = y / length
Code: [Select]
dot = x1 * x2 + y1 * y2

Jim
Title: Re: Pool
Post by: rdc on February 12, 2007
Useful stuff, Jim.
Title: Re: Pool
Post by: Paul on February 12, 2007
the code is working for me now, wonder why it freezed instead of MAV'ing
Title: Re: Pool
Post by: Stonemonkey on February 12, 2007
A MAV is usually due to reading or writing to an address that you're not supposed to such as out of the range of an array or reading/writing fast pixels outside of the screen. I've not looked into this yet but the freeze is probably due to it getting stuck in some loop somewhere.
Title: Re: Pool
Post by: rain_storm on February 12, 2007
First I would suggest abandoning the traditional 2d movement of x+dirx / y+diry with a pool game it would be far more efficient imho to work with angles and momentum you can then obtain the dirx as cos(angle)*momentum and diry as sin(angle)*momentum you could of course keep things the way they are and obtain the angle by using the atan(adjacent,opposite) command but that would mean switching between one form to the other just to revert to the original form. better to just work in angles alone. if you post the code as it is now I would incorporate this feature. also I was thinking that when the setup routine is running that if you include a tiny amount of random displacement to the ball positions it would result in a totally unique break each time. the amount of displacement should be so small that it doesnt show up on a pixel basis but large enough to have a dramatic effect on the collisions. :)
Title: Re: Pool
Post by: Clanky on February 13, 2007
Thanx guys. I did do abit of the angle last night, got it working - with the exception of the spin and power... but I did it before I read these.
How could I make spin? I got it working before without having cue angles, but now it has cue angles it hits it funny.
I will see where I can get too...

@ Rain_Storm: How far have you got with your pool? Have you started writting it up yet?
@ Jim: Thanx for the codes, much appreciated.
Title: Re: Pool
Post by: Clanky on February 13, 2007
Here's the newest add... it has got Jim's help code, with Rain_Storm's too... but it is still hitting funny. I know why this is:
Code: [Select]
  if dirx=0 wx=wx+cos(dx)*((power/1.2)+(wbdirx/45))

**where**
'wx' is the white ball's X position;
'dx' is the angle hit;
'power' is the total power hit - decreases;
'wbdirx' is the spin.
**     **

Hope this can clear things up... I really want to finish this game. It's been a real knowledge booster. Thanks Guys!  :clap:
Title: Re: Pool
Post by: rain_storm on February 13, 2007
Im am workin on typin it but its takin awhile its over 200 lines but its just really what you already have but with collisions (balls and pockets are the same but one scores the other bounces) and thats about it. Alright heres how spin works
1) topspin - add cos(topspin_angle) to foward momentum if this value is negative its called backspin
    topspin will make a ball travel foward faster or slower but will have the opposite effect when the ball collides
    with something backspin slow before collision fast after topspin fast before slow after

2) sidespin does this for sideways momentum and will make the ball travel along a curve to the left or right but it is
    different when the ball collides with something it changes the angle of the bounce effect slightly

whilst traveling between collisions -
Code: [Select]
   dirx = cos(ball_ang)*foward_momentum + cos(ball_ang+pi/2)*side_momentum
   diry = sin(ball_ang)*foward_momentum + sin(ball_ang+pi/2)*side_momentum
   new_posx = posx + dirx
   new_posy = posy + diry

this should help you with the collisions with other balls and walls -
Code: [Select]
open window 640,512
window origin "cc"
degree = pi/180
doubpi = pi*2
halfpi = pi/2
kg = 1
m = 30
secs = 30
mins = 60*secs
mps = m/secs
rpm = doubpi/mins

rem initialise balls -
balls = 4
radius = 30
dim posx(balls), posy(balls), posz(balls)
dim dirx(balls), diry(balls), dirz(balls)
dim rotx(balls), roty(balls), rotz(balls)
dim r(balls), g(balls), b(balls)
for b = 0 to balls
  repeat

    rem randomise ball location -
    posx(b) = ran(200) - ran(200)
    posy(b) = ran(200) - ran(200)
    posz(b) = ran(200) - ran(200)

    rem ensure initial positions are clear of other balls -
    h = radius*3
    for a = 0 to balls
      if (a <> b) then

        rem check if location is already occupied -
        adj = posx(b) - posx(a)
        opp = posy(b) - posy(a)
        hyp = sqrt(adj*adj + opp*opp)
        if (hyp < h) h = hyp
      fi
    next
  until (h>radius*2)

  rem initialise other properties -
  dirx(b) = ran(mps)*5 : rem only positive values are allowed
  diry(b) = ran(mps)*5 : rem only positive values are allowed
  dirz(b) = ran(mps)*5 : rem only positive values are allowed
  rotx(b) = ran(doubpi)
  roty(b) = ran(doubpi)
  rotz(b) = ran(doubpi)
  r(b) = ran(100)+ran(100)+ran(55) : rem balanced random colours
  g(b) = ran(100)+ran(100)+ran(55) : rem balanced random colours
  b(b) = ran(100)+ran(100)+ran(55) : rem balanced random colours
next
diry(0) = diry(0)*3

rem draw fake phong shaded balls -
sub pcircle(a,b,c) x = a+c/3 : y = b+c/3 : f = pi/8
  for e = 0 to doubpi step f
    gtriangle x,y to a+cos(e)*c,b+sin(e)*c to a+cos(e+f)*c,b+sin(e+f)*c
  next
end sub

repeat
  setdispbuf draw
  draw = 1 - draw
  setdrawbuf draw
  clear window

  rem draw balls
  for b = 0 to balls
    red = r(b)
    grn = g(b)
    blu = b(b)
    setrgb 1, red, grn, blu
    setrgb 2, red/10, grn/10, blu/10
    setrgb 3, red/10, grn/10, blu/10
    pcircle(posx(b),posy(b),radius)
    setrgb 1, red*2, grn*2, blu*2
    fill circle posx(b)+radius/3,posy(b)+radius/3,3
  next

  rem collision detection
  for b = 0 to balls

    rem update current ball position -
    posx(b) = posx(b) + cos(rotz(b))*diry(b)
    posy(b) = posy(b) + sin(rotz(b))*diry(b)

    rem check new position against other balls
    for a = 0 to balls
      if (a <> b) then

        rem calculate the distance between both balls
        adj = posx(b) - posx(a)
        opp = posy(b) - posy(a)
        hyp = sqrt(adj*adj + opp*opp)

        rem check if both balls overlap -
        if (hyp < radius*2) then

          rem find out how much they are overlapping by -
          penetration = (radius*2) - hyp

          rem rewind the current ball to the point of collision -
          posx(b) = posx(b) - cos(rotz(b))*penetration
          posy(b) = posy(b) - sin(rotz(b))*penetration

          rem calculate new trajectories for the both balls -
          rotz(b) = atan(-adj, opp) + halfpi
          rotz(a) = atan(-adj, opp) - halfpi

          rem energy is transferred between both balls and
          rem each ball will lose energy as a result -
          dx = dirx(b)/4 + dirx(a)/4 : rem relative velocity x
          dy = diry(b)/4 + diry(a)/4 : rem relative velocity y
          dx = dx*0.8 : rem coefficient of restitution
          dy = dy*0.8 : rem coefficient of restitution
          dirx(a) = dirx(a)/2 + dx
          diry(a) = diry(a)/2 + dy
          dirx(b) = dirx(b)/2 + dx
          diry(b) = diry(b)/2 + dy
        else
          dirx(b) = dirx(b)*0.9999 : rem coefficient of friction
          diry(b) = diry(b)*0.9999 : rem coefficient of friction
        fi
      fi
    next

    rem ensure that current ball doesn't leave the screen -
    if    (posx(b) < -320+radius) then
      rotz(b) = pi - rotz(b)
      posx(b) = -320 + radius
    elsif (posx(b) >  320-radius) then
      rotz(b) = pi - rotz(b)
      posx(b) =  320 - radius
    fi
    if    (posy(b) < -256+radius) then
      rotz(b) = -rotz(b)
      posy(b) = -256 + radius
    elsif (posy(b) >  256-radius) then
      rotz(b) = -rotz(b)
      posy(b) =  256 - radius
    fi
  next
until (1 = 0)
Title: Re: Pool
Post by: Clanky on February 13, 2007
Thanks, I will take this into account.
Title: Re: Pool
Post by: rain_storm on February 13, 2007
I will include the angular movement and collisions in the last version of pool you posted tomarrow and will put it on the forum its far too late now ;)
Title: Re: Pool
Post by: rain_storm on February 13, 2007
Guese what I'm takin the day off today I should've been sleepin last night but I just couldn't help it and threw this together its fairly bug free and commented too
###############################
# Comments that look like this are important #
###############################

enjoy
Title: Re: Pool
Post by: Jim on February 13, 2007
That's a lot of progress for one night!  K++!

The collisions look pretty inelastic at the moment - is it possible to reduce the total enery at the time of the collision?  That would model real life where some kinetic energy is lost as sound and heat, and might make it look a little more realistic.

How well does it handle smashing a pack?  How well does it handle a very fast cue ball hitting (or not!) a stationary ball?

Jim
Title: Re: Pool
Post by: rain_storm on February 13, 2007
Aha well spotted you're exactly right the balls are alot harder than the code above implies since I set the coefficient of restitution to around 0.8 when it should be above 0.9 for balls that hard but this is because all the balls momentum is randomised so there is far more energy on the table at the moment then there would be from the break with all balls stationary also I have set the coefficient of restitution for the bunkers stlightly lower 0.78 i think to reflect the softer surface, the coefficient of friction is 0.999 preatty smooth slowdown and the coefficient for angular momentum is 0.99 so balls will stay spinnin for quite a bit these values must be played with to suit a static layout with only the cue ball having momentum and I have left notes in the code of how to play with them and what ranges are good.
From my own observations the maximum speed you can get away with before collisions begin to suffer is about 10 meters per second since the screen is updated 100 times per second, one meter is also 100 this means that at 1*mps a ball will travel one pixel each frame so at 10*mps a ball will move exactly one radius (radius = 10) each frame I have included a feature that forbids overlapping balls by rewinding the moving ball to the point of collision but if the ball moves more than one radius that feature may move the ball to the opposite side of the other ball and generate incorrect collisions also the bunkers are a bounding box with the balls inside it there is the possibility that a ball may get stuck outside those bounds and start vibrating. this is also stated in the code but again well spotted as this is an important part in a pool game the physics have got to be right in fact the only thing you can really cheat is the balls mass which is the same for all balls so it can be assumed to be one and ignored. phew that was a long post
Title: Re: Pool
Post by: Jim on February 13, 2007
Quote
if the ball moves more than one radius that feature may move the ball to the opposite side of the other ball
If you limit it to < half a ball radius that can't happen.

Jim
Title: Re: Pool
Post by: rain_storm on February 13, 2007
thats gonna have to be the road to take
I've noticed a bug in the way I was rewinding the moving ball back to the point of collision thats messin things up in the pack.
At the destination point ball A is overlapping ball B. so we rewind ball A to the point of collision, but at this point in time ball A's new position overlaps ball C, collisions are not detected between ball A and ball C. by right we should collide with ball C, ignore ball A and let that be that. but we are in the middle of a for next loop so it will also require a goto statement to break out of it. but what if there are two balls occupying a part of that new space. Its gonna be a real problem if at any point an overlap is missed and two ball become glued together. The best solution I can think of is to simply detect collisions in one loop then find the closest of those in another loop. complex or what?
Title: Re: Pool
Post by: Jim on February 13, 2007
:)  I'm pretty sure there are some good articles on the web about this.
Title: Re: Pool
Post by: JumpMan on February 14, 2007
I have this code I downloaded a while back when I was still using Blitzbasic. It  may not be exactly what you are looking for but, maybe it is helpfull to somebody.
Code: [Select]
;------------------------------------------
;2D COLLISION DEMO CODE
;------------------------------------------
; By Joseph 'Phish' Humfrey
; This type of collision response isn't
; just useful for pool and billiard style
; games, and in fact, I didn't write it for
; that reason at all. I wrote it because I
; needed to have collision for the space
; ships in my game 'Unity'. When their
; shields are up, they use this relatively
; simple method. It can be used for almost
; anything - player character bouncing off
; enemies in a platform game, to space
; ship collision, to a game which does
; actually involve balls. The basic
; algorithm which I used would work for
; both 2d and 3d, so if you would like to
; see it, email me at phish@aelius.com
;------------------------------------------
; The actual code which works out what
; happens after a collision is in the
; UpdateCirclePhysics() function.
;------------------------------------------
; Enjoy!
;------------------------------------------
;------------------------------------------

Graphics 800, 600, 16, 2
SetBuffer BackBuffer()
SeedRnd MilliSecs()



;------------------------------------------
; MAIN DATA TYPE
;------------------------------------------
; This exact type isn't supposed to be used
; Instead, you should use some of the fields
; in your own type, or just use this one
; for reference, to see what each field does
Type circle
Field x#, y#;position
Field dx#, dy#;x and y speeds

Field radius#;radius of circle
Field mass#;mass of circle
End Type
;------------------------------------------
;------------------------------------------






;------------------------------------------
; SET UP BALLS INTO A POOL STYLE ARRANGEMENT
; FOR DEMO
;------------------------------------------
.Setup
ballTriangleSize=5
For xloop = ballTriangleSize To 1 Step -1
For yloop = 1 To xloop
c.circle = New circle
c\x = (5-xloop)*27 + 200
c\y = yloop*31-(xloop*31)/2.0 + 300
c\dx=0
c\dy=0
c\radius = 15
c\mass = 50
Next
Next

;Cue ball (smaller so you know which it is :)
cue.circle = New circle
cue\x = 800
cue\y = 300 +20
cue\dx = -20
cue\dy = Rnd(4)-2
cue\radius = 14
cue\mass = 50
;------------------------------------------
;------------------------------------------







;------------------------------------------
;MAIN LOOP
;------------------------------------------
; This is the main While..Wend game loop
While Not KeyDown(1)

Cls

UpdateCirclePhysics()
RenderCircles()

;------------
; Reset button
Text 10, 10, "Press a mouse button to reset."
Text 10, 25, "Press Esc to exit."
If GetMouse() Then
For c.circle = Each circle
Delete c
Next
Goto setup
End If
;------------

Flip

Wend
;------------------------------------------
;------------------------------------------
End









;------------------------------------------
Function UpdateCirclePhysics()
;------------------------------------------
; This is the main physics function for the
; circles. It contains the very basic
; movement physics as well as the collision
; response code.
;------------------------------------------

For c.circle = Each circle

;update positions
c\x=c\x+c\dx
c\y=c\y+c\dy

;gradually slow down
c\dx=c\dx*0.991
c\dy=c\dy*0.991

;------------------------------------------
;COLLISION CHECKING
;------------------------------------------
; Check each circle in the loop against
; every other (c against c2)
For c2.circle = Each circle

collisionDistance# = c\radius+c2\radius
actualDistance# = Sqr((c2\x-c\x)^2+(c2\y-c\y)^2)

;Collided or not?
If actualDistance<collisionDistance Then

collNormalAngle#=ATan2(c2\y-c\y, c2\x-c\x)

;Position exactly touching, no intersection
moveDist1#=(collisionDistance-actualDistance)*(c2\mass/Float((c\mass+c2\mass)))
moveDist2#=(collisionDistance-actualDistance)*(c\mass/Float((c\mass+c2\mass)))
c\x=c\x + moveDist1*Cos(collNormalAngle+180)
c\y=c\y + moveDist1*Sin(collNormalAngle+180)
c2\x=c2\x + moveDist2*Cos(collNormalAngle)
c2\y=c2\y + moveDist2*Sin(collNormalAngle)


;------------------------------------------
;COLLISION RESPONSE
;------------------------------------------
;n = vector connecting the centers of the circles.
;we are finding the components of the normalised vector n
nX#=Cos(collNormalAngle)
nY#=Sin(collNormalAngle)

;now find the length of the components of each movement vectors
;along n, by using dot product.
a1# = c\dx*nX  +  c\dy*nY
a2# = c2\dx*nX +  c2\dy*nY

;optimisedP = 2(a1 - a2)
;             ----------
;              m1 + m2
optimisedP# = (2.0 * (a1-a2)) / (c\mass + c2\mass)

;now find out the resultant vectors
;r1 = c1\v - optimisedP * mass2 * n
c\dx = c\dx - (optimisedP*c2\mass*nX)
c\dy = c\dy - (optimisedP*c2\mass*nY)

;r2 = c2\v - optimisedP * mass1 * n
c2\dx = c2\dx + (optimisedP*c\mass*nX)
c2\dy = c2\dy + (optimisedP*c\mass*nY)

End If

Next
;------------------------------------------
;------------------------------------------


;Simple Bouncing off walls.
If c\x<c\radius Then
c\x=c\radius
c\dx=c\dx*-0.9
End If
If c\x>GraphicsWidth()-c\radius Then
c\x=GraphicsWidth()-c\radius
c\dx=c\dx*-0.9
End If
If c\y<c\radius Then
c\y=c\radius
c\dy=c\dy*-0.9
End If
If c\y>GraphicsHeight()-c\radius Then
c\y=GraphicsHeight()-c\radius
c\dy=c\dy*-0.9
End If

Next

End Function





;------------------------------------------
Function RenderCircles()
;------------------------------------------
; Simple function draws all the circles
; on the screen.
;------------------------------------------

For c.circle = Each circle
If c\radius=15 Then Color 200, 50, 50 Else Color 255, 255, 255
Oval c\x-c\radius, c\y-c\radius, c\radius*2, c\radius*2
Next

End Function
;------------------------------------------
;------------------------------------------
Title: Re: Pool
Post by: Clanky on February 14, 2007
I've done some great graphics for this game now...
I had a look at your collisions Rain, but it was too complex for my simple mind - great though!

I have done all the rules, and have pause & restart options. All I need now is the collisions and to fix the spin (can't get it to work even with your codes Rain?... don't know whats going on there) and it's finished.

For the spin, I have said (along the line of):
Code: [Select]
side_momentum = (power + spin_x)
forward_momentum = (power + spin_y)
I did this because the side spin will be affected by the x-spin value, and the forward the y-spin value??? Correct?
I can get back spin, but not top or either side spin?
I also need to find a way to make it so when the white ball hits something else - wall(s) or ball(s) - it changes it's spin... if I read correctly in one of your post's Rain?

Great help you guys... this is the most inspiring game out I have tried to make!!!

Oh... and to Stonemonkey: I showed a friend your pool clone program and he was impressed! I think that maybe, if you would like - maybe look at completing it with rules and stuff... because that would be a great game!!!
Title: Re: Pool
Post by: rain_storm on February 14, 2007
hypotenuse as you know must be less than 2*radius for a collision to occur after that you can use adj and opp to determine the angle of the line of action. the trajectories will change according to this angle its the angle of the line between both center points. Its easier to use atan because this will return the tan of that angle. so the value in line_of_action isnt the true line of action but rather a line perpendicular to it, this is in effect a wall angled correctly that both balls simply bounce away from. once we have that angle we either add or subtract 90 degrees (pi/2) for each ball

Code: [Select]
adj = ballx(a) - ballx(b) : rem (distance between centters along x axis)
opp = bally(a) - bally(b) : rem (distance along y axis)
hyp = sqrt(adj*adj + opp*opp) : rem (true distance between points)
if (hyp < radius*2) then
   line_of_action = atan(-adj, opp)
   trajectory(a) = line_of_action + pi/2 : rem new angle for ball a
   trajectory(b) = line_of_action - pi/2 : rem new angle for ball b
fi
this will send the both balls heading off in the correct direction. Once you got it you will see that circle to circle collisions are far more easy and much faster than box to box collisions ;D
Title: Re: Pool
Post by: rain_storm on February 15, 2007
Sorry Clanky, I misread what you were asking.

   "side_momentum = (power + spin_x)
    forward_momentum = (power + spin_y)"

(side_momentum = (power + spin_x) <- is spin_x the current rotation value or the increment? You need to find the increment its the rate of rotation that is effecting side momentum not the current angle. should be more like this)

    side_momentum = cos(spin_x_increment)    <-    no power added here power effects foward momentum
    forward_momentum = power + cos(spin_y_increment)
    (if cos isnt workin try sin its the same principal though)

"I did this because the side spin will be affected by the x-spin value, and the forward the y-spin value??? Correct?
I can get back spin, but not top or either side spin?
I also need to find a way to make it so when the white ball hits something else - wall(s) or ball(s) - it changes it's spin... if I read correctly in one of your post's Rain?"

now you have backspin workin thats a sign that you are on the right road with foward momentum. sidespin should be one of the last things you add in you need to get the collisions running perfectly or else you will not be able to observe how sidespin is effecting things. it should only have a slight effect on the balls motion until the ball hits something then sidespin becomes really noticeable as the ball shoots off in a direction you would not have expected it should be a lot easier once the collisions are up and runnin
Title: Re: Pool
Post by: Clanky on February 15, 2007
K, that makes it abit clearier... i will try the collisions again, and wait till i get that working - then try the spins haha!
Can't wait for this sucker to be complete!!! YAYz

Thanks for your help 'again' Rain... been a pleasure working on this with you.
Title: Re: Pool
Post by: rain_storm on February 15, 2007
You're gonna get a ton of karma when its done I'll see to that
Title: Re: Pool
Post by: Clanky on February 17, 2007
Ok, here's the problem...

My old computer which I used to make the pool game can't burn CD's, and my new computer doesn't have a floppy disc drive... and, to top that off, my brothers' MP3 is stuffing up - like normal - so I am not able to put it up here Rain... gawd annoying things like this get too me real bad!

I have no way in knowing when I can get it up here for you Rain if you want to fix it, so I guess I will have to keep trying... bare with me.  :telloff:
Title: Re: Pool
Post by: rain_storm on February 17, 2007
damn thats a kick in the stones do you know how to install a flappy drive you would be able to slot the floppy drive in the other pc the only thing is that floppy cables can go in the wrong way around unlike all other cables in a modern pc it would take about five minutes tops if you get the cable the right way around first time and if its the wrong way it wont break your pc at all
Title: Re: Pool
Post by: Clanky on February 17, 2007
Ok, finally got it working... had to use 'my' old cord instead of my brothers.

It just needs the collisions added and I'm sure it's all working properly with rules and stuff.
Title: Re: Pool
Post by: rain_storm on February 17, 2007
I'll put in the collisions a.s.a.p  ;) I cant wait til this is a finished game  :D Its looking ace at the moment Clanky this is gonna be brill
Title: Re: Pool
Post by: Clanky on February 17, 2007
Just realised... there are some rules missing... and I also need to fix the spin stuff. So, when you finish and post it - I will edit it so it has the other missing rules and spin (hopefully I can code the spin).

Thanks for this Rain.
I'll give you karma!
Title: Re: Pool
Post by: rain_storm on February 17, 2007
You deserve k+ too man like the pause and stuff hope to have the collisions up and runnin by tomarrow then we can tackle the finishing touches
Title: Re: Pool
Post by: rain_storm on February 17, 2007
Man this is proving to be a challenge for me I am not use to workin in someone elses code but I always loved a challenge :D I may have to rework some parts but where ever I make a change I will try to have my adjustments runnin alongside you own code and not effect things for your code. that will help me and make it so that things are not messed up elsewhere so if you see something being done twice but with different variables thats why
Title: Re: Pool
Post by: Clanky on February 18, 2007
Haha, I see your point!
Good luck with this... glad you took over to finish it because it was just sitting on my computer without collisions...

Thanks again Rain.  :buddies:
Title: Re: Pool
Post by: Stonemonkey on February 18, 2007
I've been looking into these collisions again, not with the intentions of being used in this project but feel free to use anything if you want (although it's still not working).

For this I've made some assumptions so please tell me if anything at all here is wrong.

1. The velocities of the balls along the tangent to the collision normal do not change.

2. The speed and direction of the combined centre of mass of both balls is the same before and after the collision

3. The speed at which the balls travel away from each other after the collision is equal to the speed at which they travelled towards each other before the collision.

I'm pretty certain about 1 and 2 but not so sure about 3.

from that, I've come up with this test in blitz.

Code: [Select]
Graphics 800,600,32,2

x1#=300:y1#=300
vx1#=40:vy1#=20
x2#=310:y2#=295
vx2#=-20:vy2#=40

Repeat

;read start position of ball1 from mouse coords
vx1#=300.0-MouseX()
vy1#=300.0-MouseY()

;get the collision normal and tangent
nx#=x2-x1
ny#=y2-y1
l#=1.0/Sqr(nx*nx+ny*ny)
nx#=nx*l
ny#=ny*l
tx#=ny
ty#=-nx

;get the tangent component of each balls vector
vp1#=vx1*tx+vy1*ty
vp2#=vx2*tx+vy2*ty

;write the tangent component into variables for the result
rx1#=vp1*tx
ry1#=vp1*ty
rx2#=vp2*tx
ry2#=vp2*ty

;find the centre of gravity of both balls combined
;the direction and speed of the centre of gravity should be constant before and after the collision
cx#=((vx1)+(vx2))*.5
cy#=((vy1)+(vy2))*.5

;get the initial distance apart
;they should be travelling apart After the collision at the same rate they travelled towards each other before
rad#=Sqr(((vx1)-(vx2))^2.0+((vy1)-(vy2))^2.0)*.5

;calculate where on the circle edge (radius from centre of gravity) the line is for v1
dot#=tx*(rx1-cx)+ty*(ry1-cy)
dis#=-Sqr(rad*rad-dot*dot)-(nx*(rx1-cx)+ny*(ry1-cy))
rx1#=rx1+nx*dis
ry1#=ry1+ny*dis

;and same for v2
dot#=tx*(rx2-cx)+ty*(ry2-cy)
dis#=Sqr(rad*rad-dot*dot)-(nx*(rx2-cx)+ny*(ry2-cy))
rx2#=rx2+nx*dis
ry2#=ry2+ny*dis

;draw test
Color $ff,$ff,$ff
Line x1,y1,x1-vx1,y1-vy1
Line x2,y2,x2-vx2,y2-vy2
Text 50,50,"total v before:"+(Sqr(vx1^2+vy1^2)+Sqr(vx2^2+vy2^2))

Color 0,0,$ff
Line x1,y1,x1+rx1,y1+ry1
Line x2,y2,x2+rx2,y2+ry2
Text 50,70,"total v after:"+(Sqr(rx1^2+ry1^2)+Sqr(rx2^2+ry2^2))

Flip
Cls
Until KeyDown(1)
End

But the sum of the velocities before and after the collision vary quite a lot and I have no idea what else to try as this all fits with the assumptions I've made.
Title: Re: Pool
Post by: rain_storm on February 18, 2007
3 is true but its true of the speed at which they are traveling relative to each other not the table so if ball one moves at 1 meter per second and ball two is not moving both balls will end up traveling at 1/2 meter per second after collision. This will be useful thanks for including it here Stonemonkey. This is a really tough game to get right even though its just a game based on collisions.
Title: Re: Pool
Post by: Stonemonkey on February 18, 2007
For 3. I mean (ignoring any other forces) if they are 1m apart 1 second before the collision then they will be 1m apart 1 second after the collision.

EDIT:
My calculations even though not working properly have a very surprising result, if the balls are placed and given velocity vectors in such a way that separate them instead of colliding them, the collision calculations seem to be able to handle that and the calculated vectors are the same as the initial vectors.
Title: Re: Pool
Post by: Clanky on February 19, 2007
I thought there was friction applied to the balls through the table? This would make 3 not true for this game?
But, I don't know haha lol
Title: Re: Pool
Post by: Stonemonkey on February 19, 2007
Heh, there should be but I'm wanting to work out the collision calcs without worrying about any other forces like that for now.
Title: Re: Pool
Post by: rain_storm on February 19, 2007
Not necessary to include friction at the moment of impact because the force of the collisions is so great that it will overshadow all other forces acting on the balls at the moment of impact at least. friction can easily be applied after collisions in a separate process
Title: Re: Pool
Post by: Clanky on February 19, 2007
Ok! Sounds like a plan!  :inspired:
Looks like your  :stirrer: something really good up Rain... all the best
Title: Re: Pool
Post by: rain_storm on February 19, 2007
Hey guys I have come accross the perfect algorithm (https://www.gamasutra.com/php-bin/login.php?from=http://www.gamasutra.com/features/20020118/vandenhuevel_01.htm) ( you have to register an account) that addresses all of the short comings that my own collisions fail to incorporate. But there is one thing that I cant figure out. I need to calculate the angle between two vectors by using the dot product and I am not familiar with the process involved. This is the best I can come up with ...

Code: [Select]
  dot_product = (cosine_a*cosine_b + sine_a*sine_b)

  angle = acos(dot_product)
  if (cos(angle > 0) then
    rem both balls are heading towards each other
  fi

is that right? I cant get the angle returned to tell me if the balls are heading towards each other. this algorithm is far superior in that balls can travel at any speed and this is the only part that I cant understand. all the rest makes perfect sense to me. also this algorithm will always strike the nearest ball at the correct place and time something my own collisions can only achieve through trial and error (and a lot of rewinding)
Title: Re: Pool
Post by: Stonemonkey on February 19, 2007
Looks ok but you don't need to change to the angle and back again and i think it should be < 0

dot_product = (cosine_a*cosine_b + sine_a*sine_b)
if (dot_product < 0) then
    rem both balls are heading towards each other
  fi
Title: Re: Pool
Post by: rdc on February 19, 2007
Her is a good explanation of a dot product:

http://freespace.virgin.net/hugo.elias/routines/r_dot.htm

Title: Re: Pool
Post by: rain_storm on February 19, 2007
Thanks rdc thats gettin bookmarked really clear and shows how to do it in 3D as well  :D
Title: Re: Pool
Post by: Clanky on February 20, 2007
Sounds like this project just got a kick in the butt!
Hope all is going well Rain, I'm looking forward to seeing this project complete, your name has 30+ karma written on it haha
 :updance: :2funny:
Title: Re: Pool
Post by: rain_storm on February 20, 2007
Hope it works out like it should and nothin goes against us, I have also been lookin into A.I. routine based on calculating distance and the angle between white ball, colour ball and pocket but I think that kind of thing may be too hard to get workin, but who knows at this stage. thank god there has been a lot of help with this game. Big thanks guys :cheers:
Title: Re: Pool
Post by: Clanky on February 20, 2007
AI as in, opponent AI - so you can choose 1 or 2 player?
Well, if that's it, that would be an awesome addition!!!
Cheers
Title: Re: Pool
Post by: Stonemonkey on February 20, 2007
I'm not totally certain but I think I've solved it for the way i've been working on the collisions.

The maths is the same as what I'd come up with before except I'm using it on the square root of the vectors now.

Freebasic code:
Title: Re: Pool
Post by: Jim on February 20, 2007
Time to plug it in to the yabasic code and see what it looks like!  But the conservation of momentum makes it look hopeful.

Jim
Title: Re: Pool
Post by: Stonemonkey on February 21, 2007
I'm having some problems with it like that, but seems ok if I go back to the method of just transferring the velocities along the normal but with the square root of the velocity vectors.

EDIT:
my mistake, works pretty well after all.
Title: Re: Pool
Post by: Stonemonkey on February 21, 2007
I've just been thinking about thi rainstorm:

Code: [Select]
dot_product = (cosine_a*cosine_b + sine_a*sine_b)

  angle = acos(dot_product)
  if (cos(angle < 0) then
    rem both balls are heading towards each other
  fi

and it's not quite right, both balls could be traveling in the same direction but at different speeds and still collide so it doesn't quite work out. What you have to do is find the speed of 1 ball relative to the other and then do the dot product with that and the vector between the 2 balls

dot_product=(cosine_b-cosine_a)*(ball_b_x-ball_a_x)+(sine_b-sine_a)*(ball_b_y-ball_a_y)

Title: Re: Pool
Post by: rain_storm on February 21, 2007
Thanks stonemonkey but I already spotted that I am now working out how to collide balls so that both can be considered in motion (not by moving them one at a time which was the old way I did it) the trick is to translate one of the balls vector against the others vector so that the other ball can be considered stationary (but its motion is still being considered as a subtraction to the moving balls vector) still workin that part out but this is what I have so far for the collisions (only one moving atm) speed of travel is irrelevant and collisions are still accurate : )

controls - move balls vector with up/down/left/right (both controllers)
the red balls are the destinations the unfilled circle is ball a's vector minus ball b's vector

Code: [Select]
sub distance(px,py, x1,y1, x2,y2)
  local dx,dy,clip_line
  dx = x2 - x1
  dy = y2 - y1
  clip_line = ((px-x1)*dx + (py-y1)*dy) / (dx*dx + dy*dy)
  closest_point_x = (x1 + clip_line*dx)
  closest_point_y = (y1 + clip_line*dy)
  dx = px - closest_point_x
  dy = py - closest_point_y
  return sqrt(dx*dx + dy*dy)
end sub
sub rnd(range)
  rnd$ = time$
  length = len(rnd$)
  local rnd$(length)
  static rnd, seed
  for l = 1 to length
    if (mid$(rnd$,l,1) = "-") then
      rnd$ = left$(rnd$,l-1) + " " + right$(rnd$,length-l)
    else
      rnd$ = left$(rnd$,l-1) + str$(9-val(mid$(rnd$,l,1))) + right$(rnd$,length-l)
    fi
  next l
  seed = ran(rnd)
  if (seed < 1) seed = range + 1
  random = token(rnd$, rnd$())
  for r = 1 to random rnd = val(rnd$(r)) + rnd next
  rnd = ran(rnd) / ran(seed)
  return range*frac(rnd)
end sub

open window 640, 512
window origin "cc"

ball_radius = 30
sum_radii = ball_radius + ball_radius
balls = 1
dim posx(balls), posy(balls)
dim momx(balls), momy(balls)
dim rotx(balls), roty(balls), rotz(balls)
dim newx(balls), newy(balls)

label start
  for a = 0 to balls
0   x = rnd(200) - rnd(200)
    y = rnd(200) - rnd(200)
    for b = 0 to a
    if (a <> b) then
      adjacent = posx(b) - x
      opposite = posy(b) - y
      distance = sqrt(adjacent*adjacent + opposite*opposite)
      if (distance <= sum_radii) goto 0
    fi
    next b
    posx(a) = x
    posy(a) = y
  next a
  wait 0.1

label loop
  setdispbuf draw
  draw = 1 - draw
  setdrawbuf draw
  clear window

  for a = 0 to balls
    setrgb 1, 000, 000, 255
    fill circle posx(a), posy(a), ball_radius
    setrgb 1, 255, 000, 000
    fill circle newx(a), newy(a), ball_radius
    setrgb 1, 255, 255, 000
    line posx(a), posy(a) to newx(a), newy(a)
  next a

  for a = 0 to balls
    posx_a = posx(a)
    posy_a = posy(a)
    momy_a = momy(a)
    rotz_a = rotz(a)
    dirx_a = cos(rotz_a)*momy_a
    diry_a = sin(rotz_a)*momy_a
    newx_a = posx_a + dirx_a
    newy_a = posy_a + diry_a
    travel = sqrt(dirx_a*dirx_a + diry_a*diry_a)
    hyp = travel
    for b = 0 to balls
    if (a <> b) then
      posx_b = posx(b)
      posy_b = posy(b)

'     find the distance and check if  a collision is possible
      adjacent = posx_b - posx_a
      opposite = posy_b - posy_a
      distance = sqrt(adjacent*adjacent + opposite*opposite)
      if (travel < distance-sum_radii) goto 1

'     check if the balls are heading towards each other
      dot_product = dirx_a*adjacent + diry_a*opposite
      if (dot_product <= 0) goto 1

'     find the closest point along vector to the center of ball
      closest = distance(posx_b,posy_b,posx_a,posy_a,newx_a,newy_a)
      if (closest > sum_radii) goto 1
      nx = closest_point_x
      ny = closest_point_y

'     find the point at which both surfaces just begin to touch
      contact = sqrt(sum_radii*sum_radii - closest*closest)
      minx_a = nx - cos(rotz_a)*contact
      miny_a = ny - sin(rotz_a)*contact

'     check that this is closer than any other collisions
      mx = minx_a - posx_a
      my = miny_a - posy_a
      min_dist = sqrt(mx*mx + my*my)
      if (min_dist < hyp) then
        newx_a = minx_a
        newy_a = miny_a
        hyp = min_dist
      fi
    fi
1   next b
    newx(a) = newx_a
    newy(a) = newy_a
  next a

  newx_a = newx(0) - (newx(1) - posx(1))
  newy_a = newy(0) - (newy(1) - posy(1))
  circle newx_a, newy_a, ball_radius

' controls
  p = peek("port1")
  if    (and(p,   16) <> 0) then momy(0) = momy(0) + 1
  elsif (and(p,   32) <> 0) then rotz(0) = rotz(0) + pi/360
  elsif (and(p,   64) <> 0) then momy(0) = momy(0) - 1
  elsif (and(p,  128) <> 0) then rotz(0) = rotz(0) - pi/360
  elsif (and(p,65535) <> 0) then goto start
  fi
  p = peek("port2")
  if    (and(p,   16) <> 0) then momy(balls) = momy(balls) + 1
  elsif (and(p,   32) <> 0) then rotz(balls) = rotz(balls) + pi/360
  elsif (and(p,   64) <> 0) then momy(balls) = momy(balls) - 1
  elsif (and(p,  128) <> 0) then rotz(balls) = rotz(balls) - pi/360
  elsif (and(p,65535) <> 0) then goto start
  fi
  goto loop

Edit :
 Position the red balls so that they overlap and you can see that the unfilled circle will also overlap the other ball
Title: Re: Pool
Post by: rain_storm on February 21, 2007
here is a better example nearly have these collisions perfected just that I have to remove the final overlap between both balls. I still dont know why this is happening the distance should have been corrected to bring both balls up to the position where the touch for the first time. Nearly there though ; )

Code: [Select]

sub distance(px,py, x1,y1, x2,y2)
  local dx,dy,clip_line
  dx = x2 - x1
  dy = y2 - y1
  clip_line = ((px-x1)*dx + (py-y1)*dy) / (dx*dx + dy*dy)
  closest_point_x = (x1 + clip_line*dx)
  closest_point_y = (y1 + clip_line*dy)
  dx = px - closest_point_x
  dy = py - closest_point_y
  return sqrt(dx*dx + dy*dy)
end sub
sub rnd(range)
  rnd$ = time$
  length = len(rnd$)
  local rnd$(length)
  static rnd, seed
  for l = 1 to length
    if (mid$(rnd$,l,1) = "-") then
      rnd$ = left$(rnd$,l-1) + " " + right$(rnd$,length-l)
    else
      rnd$ = left$(rnd$,l-1) + str$(9-val(mid$(rnd$,l,1))) + right$(rnd$,length-l)
    fi
  next l
  seed = ran(rnd)
  if (seed < 1) seed = range + 1
  random = token(rnd$, rnd$())
  for r = 1 to random rnd = val(rnd$(r)) + rnd next
  rnd = ran(rnd) / ran(seed)
  return range*frac(rnd)
end sub

open window 640, 512
window origin "cc"

ball_radius = 30
sum_radii = ball_radius + ball_radius
balls = 1
dim posx(balls), posy(balls)
dim momx(balls), momy(balls)
dim rotx(balls), roty(balls), rotz(balls)
dim newx(balls), newy(balls)

label start
  for a = 0 to balls
0   x = rnd(200) - rnd(200)
    y = rnd(200) - rnd(200)
    for b = 0 to a
    if (a <> b) then
      adjacent = posx(b) - x
      opposite = posy(b) - y
      distance = sqrt(adjacent*adjacent + opposite*opposite)
      if (distance <= sum_radii) goto 0
    fi
    next b
    posx(a) = x
    posy(a) = y
  next a
  wait 0.1

label loop
  setdispbuf draw
  draw = 1 - draw
  setdrawbuf draw
  clear window

  for a = 0 to balls
    setrgb 1, 000, 000, 255
    fill circle posx(a), posy(a), ball_radius
    setrgb 1, 255, 000, 000
    fill circle newx(a), newy(a), ball_radius
    setrgb 1, 255, 255, 000
    line posx(a), posy(a) to newx(a), newy(a)
  next a

  for a = 0 to balls
    posx_a = posx(a)
    posy_a = posy(a)
    momy_a = momy(a)
    rotz_a = rotz(a)
    dirxa = cos(rotz_a)*momy_a
    dirya = sin(rotz_a)*momy_a
    newxa = posx_a + dirxa
    newya = posy_a + dirya
    travela = sqrt(dirxa*dirxa + dirya*dirya)
    hyp = travela
    for b = 0 to balls
    if (a <> b) then
      posx_b = posx(b)
      posy_b = posy(b)

      momy_b = momy(b)
      rotz_b = rotz(b)
      dirx_b = cos(rotz_b)*momy_b
      diry_b = sin(rotz_b)*momy_b
      dirx_a = dirxa - dirx_b
      diry_a = dirya - diry_b
      newx_a = posx_a + dirx_a
      newy_a = posy_a + diry_a
      travel_a = sqrt(dirx_a*dirx_a + diry_a*diry_a)

'     find the distance and check if  a collision is possible
      adjacent = posx_b - posx_a
      opposite = posy_b - posy_a
      distance = sqrt(adjacent*adjacent + opposite*opposite)
      if (travel_a < distance-sum_radii) goto 1

'     check if the balls are heading towards each other
      dot_product = dirx_a*adjacent + diry_a*opposite
      if (dot_product <= 0) goto 1

'     find the closest point along vector to the center of ball
      closest = distance(posx_b,posy_b,posx_a,posy_a,newx_a,newy_a)
      if (closest > sum_radii) goto 1
      nx = closest_point_x
      ny = closest_point_y

'     find the point at which both surfaces just begin to touch
      contact = sqrt(sum_radii*sum_radii - closest*closest)
      minx_a = nx - cos(rotz_a)*contact
      miny_a = ny - sin(rotz_a)*contact

'     check that this is closer than any other collisions
      mx = minx_a - posx_a
      my = miny_a - posy_a
      min_dist = sqrt(mx*mx + my*my)
      if (min_dist < hyp) then
        dist = min_dist/travel_a
        newxa = posx_a + cos(rotz_a)*momy_a*dist
        newya = posy_a + sin(rotz_a)*momy_a*dist
        hyp = min_dist
      fi
    fi
1   next b
    newx(a) = newxa
    newy(a) = newya
  next a

  newx_a = newx(0) - (newx(1) - posx(1))
  newy_a = newy(0) - (newy(1) - posy(1))
  circle newx_a, newy_a, ball_radius

' controls
  p = peek("port1")
  if    (and(p,   16) <> 0) then momy(0) = momy(0) + 1
  elsif (and(p,   32) <> 0) then rotz(0) = rotz(0) + pi/360
  elsif (and(p,   64) <> 0) then momy(0) = momy(0) - 1
  elsif (and(p,  128) <> 0) then rotz(0) = rotz(0) - pi/360
  elsif (and(p,65535) <> 0) then goto start
  fi
  p = peek("port2")
  if    (and(p,   16) <> 0) then momy(balls) = momy(balls) + 1
  elsif (and(p,   32) <> 0) then rotz(balls) = rotz(balls) + pi/360
  elsif (and(p,   64) <> 0) then momy(balls) = momy(balls) - 1
  elsif (and(p,  128) <> 0) then rotz(balls) = rotz(balls) - pi/360
  elsif (and(p,65535) <> 0) then goto start
  fi
  goto loop


Title: Re: Pool
Post by: rain_storm on March 06, 2007
I have to abandon the above technique there is a glitch in my interpretation of the algorithm and I simply cannot root it out and it has taken up too much time (I got other proggys on the go including 20 secs compo). It's a major bummer because my own technique will require that the balls all be moved by an amount that is less than the radius where as the above could handle anything (if it were done right) I really can't get it workin so there is no other option left >:(
I feel disappointed but its the best choice, at least things will be moving foward instead of hitting the same brick wall time and again. I think I was a bit too ambitious and the new technique was very much over my head :whack: at least I can understand my own solution if things get buggy
Title: Re: Pool
Post by: Shockwave on March 06, 2007
I felt a bit like that when I was converting Battlezone to Yabasic sometimes, but I have a feeling that you will crack this problem sooner or later. Remember that it's not always possible to get it right first time, you'll find a way.
Title: Re: Pool
Post by: GrahamK on March 06, 2007
I've written a full pool game, and you are certanly going about it in the correct way for collision.

Part of the secret to this (and sorry if someone else has talked about it, I've not been through the full thread), is down to slicing the time up.
one way is to break the calculation into very small time spans, recalculate the ball positions, collision check then repeat, this means the balls move in very small steps (so you end up with movements which would be less than the radius). This can then be optimised, because it's only important for the collision part. So, if you can calculate how long it would take for the first collision to take place, you can jump that many slices and continue from there.


While you are working on your 20second intro, I'll see if I can dig out some code/links for you. Afraid it won't be in yabasic, but I can see what I can come up with if it helps.
Title: Re: Pool
Post by: rain_storm on March 06, 2007
Are the vectors shortened for all moving balls? Such that only one collision happens at a time unless two collisions occur simultaeniously? Also are collisions with the bunkers treated in the same fashion. This is an interesting approach and cleans up the whole bussiness of a ball being overlapped by another ball just because it happened to be too close to the collision (like in the pack) I dont mind that the code isn't Yabasic as long as it is in some form basic I should be able to makeuse of it?
Title: Re: Pool
Post by: GrahamK on March 06, 2007
yeah, generally consider all collisions as the same, ball-ball and ball-sides.
If something is moving at 10 units per second, you would just consider it as 1 unit per 10th so everything would be divided by 10. It may need a smaller step but you have to balance that against how many calculations you perform. The smaller the step, the less chance of simultanious collisions (which is the perfect situation).

If you do happen to have multiple collisions, I did something like this.
1) Loop through balls finding first collision,
2) resolve that collision
3) go back and loop through the balls from the beginning again.
It can get a bit deadlooped there, which you can usually check for (and for example, ignore something that's already been resolved once).

If you get it working well with these timesteps, you can put in the optimization, which is along the lines of
1) Loop through each ball
2) see if it's possible for this to collide with edges (speed vector line/ edge line intersection), add collision point / distance to a list of collisions
3) compare with all other balls (speed vector line / speed vector line intersection), add collision point / distance to a list of collisions
4) distance between current position and collision position indicates how long it would take for that collision to take place
5) repeat for each ball
6) List of collisions should show which one is first, and therefore how long the step needs to be (instead of the fixed time above)
7) resolve this first collision, and go back to 1 (although this can be optimized to say only recalculate the balls effected in the collision)
This is obviously using lines for simplicity, but it's not too much work to make it a little more fuzzy to include the ball radius.

Title: Re: Pool
Post by: rain_storm on March 06, 2007
Thanks GrahamK thats sounds solid i think I will do the loop once to detect collisions and just determine which happens first. then once the loop completes start a new loop to update all positions
Well this is what I have to work with, my own solution where only one ball moves at a time movement is limited to less than radius but momentum is conserved and trajectories look good. I will include you're suggestions asap. And thanks for the help really good idea and well explained  :cheers:

Code: [Select]
open window 640, 512
window origin "cc"

holes = 5
dim hx(holes), hy(holes)
data -280,-140, 000,-140, 280,-140
data -280, 140, 000, 140, 280, 140
for a = 0 to holes read hx(a), hy(a) next

colrs = 3
dim red(colrs), grn(colrs), blu(colrs)
data 255,255,255, 255,255,000, 255,000,000, 100,100,100
for a = 0 to colrs read red(a), grn(a), blu(a) next

fric = 0.999
damp = 0.990
bump = 0.900
radi = 10
hradi = radi*1.5
sum_radi = (radi+radi)^2
sum_hradi = hradi^2
minx = -270
miny = -130
maxx =  270
maxy =  130

label setup
  balls = 15
  redim posx(balls), posy(balls)
  redim dirx(balls), diry(balls)
  redim colr(balls)

  for a = 0 to balls
    colr(a) = mod(a,2)+1
    dirx(a) = ran(5) - ran(5)
    diry(a) = ran(5) - ran(5)
00  posx(a) = ran(200) - ran(200)
    posy(a) = ran(100) - ran(100)
    for b = 0 to a
      if (a <> b) then
        adj = posx(b) - posx(a)
        opp = posy(b) - posy(a)
        hyp = adj^2 + opp^2
        if (hyp < sum_radi) goto 00
      fi
    next
  next
  colr(0) = 0
  colr(balls) = 3
  motionless = 0

label main
  setdispbuf draw
  draw = 1 - draw
  setdrawbuf draw
  clear window
  if (and(peek("port1"),16384) <> 0) goto setup

  setrgb 1, 000, 100, 000
  fill box minx-radi, miny-radi to maxx+radi, maxy+radi
  setrgb 1, 255,255,255
  for a = 0 to holes circle hx(a), hy(a), hradi next
  for a = 0 to balls
    for b = 1.0 to 0.1 step -0.1
      setrgb 1, red(colr(a))*(1-b), grn(colr(a))*(1-b), blu(colr(a))*(1-b)
      fill circle posx(a), posy(a), radi*b
    next
  next

  if (motionless = balls) goto setup
  motionless = 0
  for a = 0 to balls
    if (dirx(a)^2 + diry(a)^2 > 0.00001) then
      dxa = dirx(a)*fric
      dya = diry(a)*fric
      pxa = posx(a)
      pya = posy(a)
      for b = a+1 to balls
        adj = posx(b) - pxa
        opp = posy(b) - pya
        dist = adj^2 + opp^2
        if (dist < sum_radi) then
          dist = sqrt(dist)
          nx = adj / dist
          ny = opp / dist

          cx = (pxa+posx(b))/2
          cy = (pya+posy(b))/2
          pxa = cx - nx*radi
          pya = cy - ny*radi
          posx(b) = cx + nx*radi
          posy(b) = cy + ny*radi

          product = ((dirx(b)-dxa)*nx + (diry(b)-dya)*ny) * damp
          sx = nx * product
          sy = ny * product
          dxa = dxa + sx
          dya = dya + sy
          dirx(b) = dirx(b) - sx
          diry(b) = diry(b) - sy
        fi
      next

      pxa = pxa + dxa
      pya = pya + dya
      if    (pxa < minx) then
        pxa =  minx
        dxa = -dxa*bump
        dya =  dya*bump
      elsif (pxa > maxx) then
        pxa =  maxx
        dxa = -dxa*bump
        dya =  dya*bump
      fi
      if    (pya < miny) then
        pya = miny
        dxa =  dxa*bump
        dya = -dya*bump
      elsif (pya > maxy) then
        pya =  maxy
        dxa =  dxa*bump
        dya = -dya*bump
      fi

      posx(a) = pxa
      posy(a) = pya
      dirx(a) = dxa
      diry(a) = dya

      for b = 0 to holes
        adj = pxa - hx(b)
        opp = pya - hy(b)
        if (adj^2 + opp^2 < sum_hradi) then
          for c = a to balls-1
            posx(c) = posx(c+1)
            posy(c) = posy(c+1)
            dirx(c) = dirx(c+1)
            diry(c) = diry(c+1)
            colr(c) = colr(c+1)
          next
          balls = balls - 1
        fi
      next
    else motionless = motionless + 1
    fi
  next
  goto main


Title: Re: Pool
Post by: GrahamK on March 06, 2007
Glad I can be of some help.

I've done a bit of code, I may be able to post it tomorrow.
Title: Re: Pool
Post by: Tetra on March 07, 2007
I've made a picture to aid what Graham had to say.

Heres my interpritation.
The red ball has moved a certain amount (say 100 units) from frame 1 to frame 2. a certain amount of time has aslo passed between frame 1 and frame 2 ( t1 + t2  say 0.1s). At somepoint between frame 1 and frame 2 the red ball has hit the black ball.

So in the calculation, you loop through from frame 1 to frame 2 by 1 unit at a time until you find the point the red ball touches the black ball. That means, it takes a total time of t1 before the ball hits the black ball. the remaining time is t2 and thats how long the black ball has to travel before being in the correct place at frame 2,

Heres the pic to go with the text. Its not very accurate, but it shows the principal of what should happen :)
Title: Re: Pool
Post by: GrahamK on March 07, 2007
Yep, that's about it.

I've managed to get some code working which shows collision response etc. I'll post it later on (In Cobra I'm afraid, but reasonably readable... I'm biased tho ;) )

Title: Re: Pool
Post by: JumpMan on March 07, 2007
here is a pool game with source in c and ogl. Maybe it can help.
another pool game (http://planetjahn.de/apool/download.php)

Title: Re: Pool
Post by: GrahamK on March 08, 2007
ok, here you go... Not as well commented as I'd hoped, but I'll try and answer any questions.
I've included an exe and the source here (http://www.squeakyduck.co.uk/downloads/pooldemo.zip) as this won't compile under the demo of cobra.

It's not perfect, as there are a few niggles in the collision response (no comments about sticky balls!), but I hope it helps.
Only thing which isn't described, is that Cobra has a command LineIntersectPt, which takes two lines (4 coordinates) and tells you if they intersect, and where. The other helpful command is pointdistance, which just returns the distance between two points. Other than that, most of the rest should convert reasonably simply.

Main bits of handy code are in Iteration, and ballballcollision.

Code: [Select]
program
  uses pure2d,keyset                                   
 
const
    rad=10
    preserve=0.9 // amount of energy preserved after collision
 
type aball=record
    x,y:real
    dx,dy:real
    col:integer
endtype

type intersect=record
    b1,b2:^aball
    wall:integer
    x,y:real   
    count:integer=255
endtype
 
procedure ReDrawScreen
var
    ball:^aball
    coll:^intersect
begin
    ////writelog('Redraw')
    Rectc(100,50,700,550,ToRGBA(255,255,255),FALSE)
    Rectc(100+rad,50+rad,700-rad,550-rad,ToRGBA(100,100,100),FALSE)

    loop ball through balls
        ellipse(ball.x,ball.y,rad,rad,ball.col,false)   
    endloop

    loop ball through balls
        Line(ball.x,ball.y,ball.x+ball.dx,ball.y+ball.dy,ToRGBA(0,255,255))   
    endloop
       
    loop coll through collisions
        Rect(coll.x-4,coll.y-4,9,9,ToRGBA(0,coll.count,0),FALSE)
        coll.count = coll.count-1
        if coll.count<0 then free(coll)
    endloop

end


procedure Init
var
    ball:^aball
begin
        ball = newitem(balls)
        ball.x = Rand(120,680)
        ball.y = Rand(70,530)
        ball.dx = Rnd(-50,50)
        ball.dy = Rnd(-50,50)
        ball.col = ToRGBA(255,255,255)
end

procedure CreateBalls(count:integer=10)
var
    ball,b2:^aball
    ok : boolean
    x,y:real
begin
    while count >0
        ok = false
        while not ok
            x = Rand(120,680)
            y = Rand(70,530)
                   
            ok = true
            // keep balls apart no overlap
            loop b2 through balls
                if sqrt((b2.x-x)*(b2.x-x)+(b2.y-y)*(b2.y-y)) < 50 then ok = false                         
            endloop
        wend
           
            ball = newitem(balls)
            ball.col = ToRGBA(255,0,0)
            ball.x=x
            ball.y=y

            ball.dx = Rnd(-10,10)
            ball.dy = Rnd(-10,10)
           
           
        dec(count)
    wend

end

procedure BallWallCollision(b:^aball,wall:integer,cx,cy:real,tstep:real=0.1)
var
    cdist,tdist,prop:real
    dx,dy:real
begin
    // walls are easy as they act purely mirrors, and don't react to the impact
    // should really do sphere to plane collision, but too lazy in this version
    ////writelog('Collision: in ('+b.dx+','+b.dy+')')
   
    // first work out how far into the move the collision occured, needed to calc new position
    tdist = Sqrt((b.dx*b.dx)+(b.dy*b.dy))*tstep
    dx = cx-b.x
    dy = cy-b.y
    cdist = Sqrt((dx*dx)+(dy*dy))
    if tdist = cdist then
        prop = 0
    else
        prop = 1-(cdist/tdist)
    endif
   
    if (wall <2) then // horizontal walls
        b.dy=-(b.dy*preserve)       
    else         
        b.dx=-(b.dx*preserve)
    endif     
    //writelog('Collision: tdist ('+tdist+') cdist('+cdist+') prop('+(prop)+')')
    // reposition ball at collision point, then move it out by amount Left after the collision
    b.x = cx + (b.dx * prop)
    b.y = cy + (b.dy * prop)
end

procedure BallBallCollision(b1,b2:^aball,substep:real)
var
    b1sx,b1sy,b2sx,b2sy,mb1,mb2,mt:real // speeds
    vel1,vel2:real
    mv,vm,mt2,ep,fac:real;
    b1tob2vx,b1tob2vy:real // vector between balls
    b1uvectorX,b1uvectory:real // normal speed vector
    cosine,mvcosine:real
begin

      // calculate ball/ball collision
      // Move balls to collision positions,
          b1.x = b1.x+(b1.dx*substep)
          b1.y = b1.y+(b1.dy*substep) 
                           
          b2.x = b2.x+(b2.dx*substep)
          b2.y = b2.y+(b2.dy*substep)         
      //calculate the new speeds for both
     
      b1SX = b1.dx
  b1Sy =b1.dy

    b2SX = b2.dx
  b2Sy = b2.dy
     
      vel1 = Sqrt((b1sx*b1sx)+(b1sy*b1sy))
      vel2 = Sqrt((b2sx*b2sx)+(b2sy*b2sy))
                                 
      mb1=vel1
  mb2=vel2
  mt = mb1+mb2
     
      //   subtract second ball speed from first
b1sx = b1sx - b2sx
b1sy = b1sy - b2sy

    // calculate magnitude
mv = Sqrt((b1sx*b1sx)+(b1sy*b1sy))
    if mv = 0 then mv = 0.00001 // trap for div 0 case

// calculate vector between balls
b1tob2vX = b2.x - b1.x
b1tob2vy = b2.y - b1.y
   
    //normalise vector between balls
vm = Sqrt((b1tob2vx*b1tob2vx)+(b1tob2vy*b1tob2vy))
    if vm = 0 then vm = 0.00001
     
b1tob2vX = b1tob2vx / vm
b1tob2vy = b1tob2vy / vm
   
    // create a normal of the speed vector
b1uvectorX = b1sx / mv
b1uvectory = b1sy / mv
   
    // create dot product
cosine = (b1uvectorx*b1tob2vx)+(b1uvectory*b1tob2vy)
mvcosine = cosine * mv
   
    //multiply interball vector
b1tob2vx=b1tob2vx*mv
b1tob2vy=b1tob2vy*mv

    //subtract from speed vector
b1sx = b1sx - b1tob2vx
b1sy = b1sy - b1tob2vy

    //add ball 2's speed back to 1
b1sx = b1sx + b2sx
b1sy = b1sy + b2sy
 
    //and add new speed to ball 2's
b2sx = b2sx + b1tob2vx
b2sy = b2sy + b1tob2vy
   
    vel1 = Sqrt((b1sx*b1sx)+(b1sy*b1sy))
Vel2 = Sqrt((b2sx*b2sx)+(b2sy*b2sy))
mt2 = vel1 + vel2
   
    If mt2 <> mt Then
//rescale momentum to correct rounding errors
ep=preserve // amount of energy preserved
fac = ((mt*ep)/mt2)
fac = fac * fac

    b1sx = b1sx * fac
b1sy = b1sy * fac
b2sx = b2sx * fac
b2sy = b2sy * fac
   
    // now reset internal vectors
b1.dx = b1sx
    b1.dy = b1sy
    b2.dx = b2sx
    b2.dy = b2sy
   

end

procedure Iteration(timestep:real=0.1)
var
    b1,b2:^aball       
    x1,x2,y1,y2,dx,dy:real
    x1c,x2c,y1c,y2c,dxc,dyc:real
    ix,iy:real
    coll:boolean
    ccount:integer 
    substep:real
begin
    b1 = firstitem(balls)
    ////writelog('In Collision: ('+b1.dx+','+b1.dy+')')
   


    loop b1 through balls
                                       
   
      if ((b1.dx*b1.dx)+(b1.dy*b1.dy)) < 0.0001 then
            b1.dx = 0
            b1.dy = 0
      endif
     
       
      if (b1.dx<>0) or (b1.dy<>0) then
        // only process moving balls     
        x1 = b1.x
        y1 = b1.y   
        dx = (b1.dx*timestep)
        dy = (b1.dy*timestep) 
        x2 = b1.x+dx
        y2 = b1.y+dy
                                       
        cleartype(b2)
        ccount= 0       
        // check against walls (cheat.. move walls in by radius, takes care of fuzz automatically 
        coll=LineIntersectPt(x1,y1,x2,y2,100+rad,50+rad,700-rad,50+rad,ix,iy)
        if coll then
            addintersect(b1,b2,ix,iy,0)
            ballwallcollision(b1,0,ix,iy,timestep)
            inc(ccount)
        else
          coll=LineIntersectPt(x1,y1,x2,y2,100+rad,550-rad,700-rad,550-rad,ix,iy)
          if coll then
              addintersect(b1,b2,ix,iy,1)
              ballwallcollision(b1,1,ix,iy,timestep)
              inc(ccount)
          else
            coll=LineIntersectPt(x1,y1,x2,y2,100+rad,50+rad,100+rad,550-rad,ix,iy)
            if coll then
                addintersect(b1,b2,ix,iy,2)
                ballwallcollision(b1,2,ix,iy,timestep)
                inc(ccount)
            else
              coll=LineIntersectPt(x1,y1,x2,y2,700-rad,50+rad,700-rad,550-rad,ix,iy)
              if coll then
                  addintersect(b1,b2,ix,iy,3)
                  ballwallcollision(b1,3,ix,iy,timestep)
                  inc(ccount)
              endif
            endif
          endif
        endif
       
        if ccount = 0 then // no wall collisions, so we'll step through the other balls looking for collision

            loop b2 through balls
                if not (b1 = b2) then // don't check collisions with yourself silly!
                    x1c = b2.x
                    y1c = b2.y
                    dxc = (b2.dx*timestep)
                    dyc = (b2.dy*timestep) 
                   
                    coll = false
                   
                    // perform a simple 'swept sphere' type calculation (there is better maths, but it should work)
                    // number of iterations is up to you, the more you do the better the accuracy (I'm doing 30)
                    substep = 0
                    while (substep <= timestep) and (not coll)
                        //if distance between two centers is < 2 x Radius, they've collided.
                        if PointDistance(x1+(dx*substep),y1+(dy*substep),x1c+(dxc*substep),y1c+(dyc*substep)) < (rad*2) then
                            coll=true
                            ix = ((x1+(dx*substep)) + (x1c+(dxc*substep)))/2   
                            iy = ((y1+(dy*substep)) + (y1c+(dyc*substep)))/2   
                        else
                            substep = substep + (timestep/30)
                        endif                                           
                    wend
                   
                    if coll then
                        addintersect(b1,b2,ix,iy,3)
                        BallBallCollision(B1,b2,substep)                         
                    endif
                   
                endif
            endloop 
                 
       
       
        endif
       

        if ccount = 0 then // collision reaction covers movement in case of collisions   
            b1.x = b1.x+(b1.dx*timestep)
            b1.y = b1.y+(b1.dy*timestep)
        else
            ////writelog('Collision: out2 ('+b1.dx+','+b1.dy+')')
        endif

     endif
     
    endloop



end

procedure AddIntersect(b1,b2:^aball,x,y:real,wall:integer)
var
    coll:^intersect
begin
    coll = newitem(collisions)
    coll.b1 = b1
    coll.b2 = b2
    coll.wall = wall
    coll.x = x     
    coll.y = y
end

var
    balls : list of aball
    collisions: list of intersect
    ball:^aball
 
begin
  OpenScreen(800,600,32,FALSE,5)     
 
  Randomize
             
  init
  createballs(10)
 
  while (not keydown(vk_escape)) and (not ExitRequested)
    cls
    Iteration(0.05)
    redrawscreen
    flip
  wend
 
  closescreen
end

Title: Re: Pool
Post by: rain_storm on March 08, 2007
Thanks GrahamK I will give it a look through, Well here is the current state of the collisions there doesn't seem to be any bugs in here still keepin the balls speed under 1 radius per frame but to tell you the truth I dont think it needs to be any faster than this. At full speed the pack breaks preatty well and scatters them all around the table.

controls
left/right = aim
down = increase power
up = reduce power
X = shoot

Code: [Select]
open window 640, 512
window origin "cc"

holes = 5
dim hx(holes), hy(holes)
data -280,-140, 000,-140, 280,-140
data -280, 140, 000, 140, 280, 140
for a = 0 to holes read hx(a), hy(a) next

colrs = 3
dim red(colrs), grn(colrs), blu(colrs)
data 255,255,255, 255,255,000, 255,000,000, 100,100,100
for a = 0 to colrs read red(a), grn(a), blu(a) next

fric = 0.998
damp = 0.991
bump = 0.950
radi = 12
hradi = radi*1.5
sum_radi = (radi+radi)^2
sum_hradi = hradi^2
minx = -270
miny = -130
maxx =  270
maxy =  130

label setup
  balls = 15
  redim posx(balls), posy(balls)
  redim dirx(balls), diry(balls)
  redim colr(balls)
  restore setup_balls
  for a = 0 to balls
    colr(a) = mod(a,2)+1
    dirx(a) = 0
    diry(a) = 0
    read posx(a), posy(a)
  next
  dirx(0) = ran(10)
  colr(0) = 0
  colr(balls) = 3
  motionless = balls+1

label main
  setdispbuf draw
  draw = 1 - draw
  setdrawbuf draw
  clear window
  setrgb 1, 000, 100, 000
  fill box minx-radi, miny-radi to maxx+radi, maxy+radi
  setrgb 1, 255,255,255
  for a = 0 to holes circle hx(a), hy(a), hradi next
  for a = 0 to balls
    for b = 1.0 to 0.1 step -0.1
      setrgb 1, red(colr(a))*(1-b), grn(colr(a))*(1-b), blu(colr(a))*(1-b)
      fill circle posx(a), posy(a), radi*b
    next
  next
  if (motionless > balls) then
    ctrl(peek("port1"))
  else
    force = 0
    angle = 0
    motionless = 0
    collisions()
  fi
  goto main

sub ctrl(c)
  if    (and(c, 32) <> 0) then
    angle = angle + pi / 4096
  elsif (and(c,128) <> 0) then
    angle = angle - pi / 4096
  fi
  if    (and(c, 16) <> 0) then
    force = force - 0.01
    if (force < 0) force = 0
  elsif (and(c, 64) <> 0) then
    force = force + 0.01
    if (force > radi) force = radi
  fi

  if (and(c,16384) <> 0) then
    dirx(0) = cos(angle)*force
    diry(0) = sin(angle)*force
    motionless = 1
  else
    x = posx(0)
    y = posy(0)
    cs = cos(angle)*force
    sn = sin(angle)*force
    ct = cos(angle+pi/2)
    tn = sin(angle+pi/2)
    x1 = x - cs*10
    y1 = y - sn*10
    x2 = x1 - cos(angle)*200
    y2 = y1 - sin(angle)*200
    setrgb 1, 255, 255, 255
    line x,y to x+cs*30,y+sn*30
    setrgb 1, 255, 220, 180
    fill triangle x1+ct*2,y1+tn*2 to x2+ct*5,y2+tn*5 to x2-ct*5,y2-tn*5
    fill triangle x1+ct*2,y1+tn*2 to x1-ct*2,y1-tn*2 to x2-ct*5,y2-tn*5
  fi
end sub

sub collisions()
  for a = 0 to balls
    if (dirx(a)^2 + diry(a)^2 > 0.0001) then
      dxa = dirx(a)*fric
      dya = diry(a)*fric
      pxa = posx(a)
      pya = posy(a)
      for b = 0 to balls
        if (a <> b) then
          adj = posx(b) - pxa
          opp = posy(b) - pya
          dist = adj^2 + opp^2
          if (dist < sum_radi) then
            dist = sqrt(dist)
            nx = adj / dist
            ny = opp / dist

            cx = (pxa+posx(b))/2
            cy = (pya+posy(b))/2
            pxa = cx - nx*radi
            pya = cy - ny*radi
            posx(b) = cx + nx*radi
            posy(b) = cy + ny*radi

            product = ((dirx(b)-dxa)*nx + (diry(b)-dya)*ny) * damp
            sx = nx * product
            sy = ny * product
            dxa = dxa + sx
            dya = dya + sy
            dirx(b) = dirx(b) - sx
            diry(b) = diry(b) - sy
          fi
        fi
      next

      pxa = pxa + dxa
      pya = pya + dya
      if    (pxa < minx) then
        pxa =  minx
        dxa = -dxa*bump
        dya =  dya*bump
      elsif (pxa > maxx) then
        pxa =  maxx
        dxa = -dxa*bump
        dya =  dya*bump
      fi
      if    (pya < miny) then
        pya = miny
        dxa =  dxa*bump
        dya = -dya*bump
      elsif (pya > maxy) then
        pya =  maxy
        dxa =  dxa*bump
        dya = -dya*bump
      fi

      posx(a) = pxa
      posy(a) = pya
      dirx(a) = dxa
      diry(a) = dya

      for b = 0 to holes
        adj = pxa - hx(b)
        opp = pya - hy(b)
        if (adj^2 + opp^2 < sum_hradi) then
          col = colr(a)
          for c = a to balls-1
            posx(c) = posx(c+1)
            posy(c) = posy(c+1)
            dirx(c) = dirx(c+1)
            diry(c) = diry(c+1)
            colr(c) = colr(c+1)
          next
          posx(balls) = pxa
          posy(balls) = pya
          dirx(balls) = dxa
          diry(balls) = dya
          colr(balls) = col
          balls = balls - 1
        fi
      next
    else motionless = motionless + 1
    fi
  next
end sub

label setup_balls
data -140,000
data  100,000, 120,010, 140,-20, 120,-10, 140,020
data  160,-30, 160,010, 160,030, 180,000, 160,-10
data  180,-40, 180,-20, 180,040, 180,020, 140,000

Title: Re: Pool
Post by: Clanky on March 09, 2007
Very Nice rain!!!  :updance:
Is that the final, or just a visual collision simulation?
Title: Re: Pool
Post by: rain_storm on March 09, 2007
its the collisions only it needs rules better graphics etc. but the mechanics are up and runnin and we are one step closer btw Hows College ?
Title: Re: Pool
Post by: Clanky on March 09, 2007
Uni is great! haha. hadn't had too many hard assignments, and my group are flying with our Innovation and Design assignment (we're making a rope bag for water skiing and abseiling and other rope sports haha!)

Staying on campus is a ball! Haha!

Yea, nice. Do you think you'll use the graphics I used?
Title: Re: Pool
Post by: Shockwave on March 09, 2007
The collisions look like they work really well, I liked the graphics that you had before, I hope you use them in the finished version. The only things that I would suggest are that the balls are too dark, they take forever to slow down, also aiming and adjusting the power should be faster. These are just minor tweaks though, you've accomplished a lot here. It might be one of the toughest projects you'll do for quite a long time too!
Title: Re: Pool
Post by: rain_storm on March 09, 2007
Yes Clanky the graphics that you developed are going in there but I wanted to get the rules etc in there first. But I think I will work on this first since both of you guys noticed it (which is a very good indicator that the time is right to address it)
Thanks for pointing out the controls and slow down Shocky I had blinded myself to this as I was building it this became unnoticeable but now that you mention it it does take forever for the balls to stop.
Title: Re: Pool
Post by: Tetra on March 09, 2007
Seems to be coming along very nicely, looking forward to see the final prod :)

Pool games are great  :updance:
Title: Re: Pool
Post by: Way.net on September 10, 2009
Just following the spiders earlier and came across this interesting thread. :)

Did a final version ever get released as would love to see it O0
Title: Re: Pool
Post by: rain_storm on September 10, 2009
Never did finish this but I will have another go at it. I would like to see this completed myself
Title: Re: Pool
Post by: rain_storm on September 22, 2009
Update, this is the current game engine. Ball spin is not gonna be included because these routines require straight lines. Collisions are time based and I've used swept routines for everything so ball speed is not constrained.

Well that's the theory anyways in practise it still has some minor glitches in the ball / wall collisions. This is as good as its gonna get cause I wrote that routine over a year ago and it was only loosely commented, I have no idea how it works any more.

The graphics are modified from Clankys design but I made the balls and holes larger the reason being that larger balls seem to reduce issues with the the wall collisions.

I just have to merge some game logic which Clanky has already done some work on. Rules and what not.
Title: Re: Pool
Post by: Shockwave on September 22, 2009
Excellent engine Rain Storm, I find the controls strange, when I pull the cue back and then hit X the cue flies forward and the cue ball just seems to creep forward, maybe I am missing a trick here?
Title: Re: Pool
Post by: rain_storm on September 23, 2009
if you tap X it works best, the distance the cue is to striking the white ball when you release determines the power of the shot. I wanna use a timer eventually cause pulling back the cue just doesnt feel right. But it is good for debugging.
Title: Re: Pool
Post by: Clanky on September 23, 2009
Awesome RS! That looks so sweet.

The collisions are great.. although it seems as though the balls have the tendency to speed up if they bounce and bounce.


Just a few bugs;
When you sink the white ball - it is placed in the 'sunken balls area'. You can still shoot however.. collisions are calculated within the 'sunken balls area' as well.
Scenario: Once you have sunken a ball, sink the white ball. This will place the white ball in the area outside the table. You will still be able too shoot.. aim at the balls which have already been sunken.. these balls will collide and move around.
The cue is 'stuck' on the white ball after you shoot.. maybe the cue could disappear until you want to shoot again.

I'm still playing it : ) soo cooool.
Title: Re: Pool
Post by: bikemadness on October 10, 2009
Whew!
I could only juggle two balls, when trying my hand at this.
And I almost dropped them, when coming up with the maths
to get this basic pinball!

Code: [Select]
open window 640,512
ang1=pi/180
ang2=180/pi
ra=30
ball=6
dim dirs(ball),xs(ball),ys(ball),ssp(ball)
dim hitang(ball),hit(ball),reang(ball)
for a=1 to ball
dirs(a)=0
read xs(a),ys(a)
ssp(a)=0
next a
dirm=30
xm=500
ym=100
msp=8
repeat
setdispbuf vm
vm=1-vm
setdrawbuf vm
clear window
  setrgb 1,200,200,0
  fill rectangle 0,0 to 640,512
  for a=1 to ball
  setrgb 1,0,256,0
fill circle xs(a),ys(a),ra
  setrgb 1,0,0,0
  circle xs(a),ys(a),ra
hitang(a)=atan(xs(a)-xm,ym-ys(a))*ang2+180
hit(a)=(abs(xs(a)-xm)^2+abs(ys(a)-ym)^2)^0.5
reang(a)=((dirs(a)+180)-dirm)*2+dirm-180
if hit(a)<ra*2 dirm=reang(a)
dirs(a)=hitang(a)-90
line xs(a),ys(a) to xs(a)+cos(dirs(a)*ang1)*ra,ys(a)+sin(dirs(a)*ang1)*ra
  next a
xm=xm+cos(dirm*ang1)*msp
ym=ym+sin(dirm*ang1)*msp
  setrgb 1,250,120,0
fill circle xm,ym,ra
  setrgb 1,0,0,0
  circle xm,ym,ra
if xm<0+ra dirm=270-dirm+270
if xm>640-ra dirm=90-dirm+90
if ym<0+ra dirm=-dirm
if ym>510-ra dirm=180-dirm+180
if dirm>360 dirm=dirm-360
if dirm<0 dirm=dirm+360
until (1=0)
data 252,126,396,126,468,252,396,378,252,378,180,252
Title: Re: Pool
Post by: rain_storm on October 11, 2009
Wow thats remarkably tight code and those collisions work very well.

Code: [Select]
abs(xs(a)-xm)^2
^taken from the pythagoras theorum is that faster (in yabasic) than the way its done below
Code: [Select]
(xs(a)-xm)*(xs(a)-xm)

also this code uses atan to reflect the movement vector about the normal of the collision plane
Code: [Select]
hitang(a)=atan(xs(a)-xm,ym-ys(a))*ang2+180
...
reang(a)=((dirs(a)+180)-dirm)*2+dirm-180
...
dirm=reang(a)
dirs(a)=hitang(a)-90
...
xm=xm+cos(dirm*ang1)*msp
ym=ym+sin(dirm*ang1)*msp
dirs is the surface normal and dirm = collision plane? Anyway its much tighter than the way I have done this
Code: [Select]
  ed = 1.0 // energy disapated (lost)
  ...
  D = 1 / sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
  ax = (x2-x1) * D
  ay = (y2-y1) * D
  va1 = dirX(A)*ax + dirY(A)*ay
  vb1 =-dirX(A)*ay + dirY(A)*ax
  va2 = dirX(B)*ax + dirY(B)*ay
  vb2 =-dirX(B)*ay + dirY(B)*ax
  vaP1 = va1 + (1+ed)*(va2-va1) / (1+mass(A)/mass(B))
  vaP2 = va2 + (1+ed)*(va1-va2) / (1+mass(B)/mass(A))
  vecX(A) = vaP1*ax - vb1*ay
  vecY(A) = vaP1*ay + vb1*ax
  vecX(B) = vaP2*ax - vb2*ay
  vecY(B) = vaP2*ay + vb2*ax
Title: Re: Pool
Post by: bikemadness on October 12, 2009
Thanks.
I really had to dig deep to remember the maths you see in the code - and the way it's used - from high school (it's been a while!) and with no reference material.
Title: $
Post by: rain_storm on October 12, 2009
http://www.youtube.com/watch?v=CdpR3hU5bAI

^The 3D pool game written for yabasic, most of you will recognise it from youtube. Well here is the source code for that program...

http://canarddechien.blogspot.com/

Problem is it doesn't run, keeps giving parse errors. I've been reading through it to see how it works, but without the ability to edit and run it's not easy to see the inner workings.

Does anyone recognise this syntax cos it doesn't make any sense to me...
Code: [Select]
if ctnz< nzc="nzc+1" xoff="FOV*ctnx/ctnz"
strings are not "$" termated variable names, also are those supposed to be c like comparisons or is this source code simply erronious.
Title: Re: Pool
Post by: Jim on October 12, 2009
It looks like most of the quotes shouldn't be there at all.

Jim
Title: Re: Pool
Post by: Clyde on October 14, 2009
also the speech marks might be brackets ( ... ) that have got jumbled with formatting. if they are at all needed.
Title: Re: Pool
Post by: rain_storm on October 14, 2009
on a lighter note this game is finished check my first post for the attachment. it turned out to be >38kb. Better late than never. Hope you dont mind the changes I made to your graphics Clanky, I tried to keep them very close to what you had in mind.

Back to the youtube pool. The source code is badly corrupted it is impossible to restore it with so much of the text missing.

Code: [Select]
pad="peek(">0 then :rem R

should be something more like

Code: [Select]
pad=peek("port1")
if pad>0 then :rem Read controller only if input <> 0

with more than half of the code already corrupt in a similar fashion to this. I asked him to reupload a working copy to his blog over on youtube just wait and see what comes of it.
Title: Re: Pool
Post by: rain_storm on November 08, 2009
ps2Yabasic 3D Pool has been corrected by its author Canard De Chien
http://textsnip.com/a87d35
AWESOME