Skip to content

Instantly share code, notes, and snippets.

@cormullion
Last active September 17, 2022 13:22
Show Gist options
  • Save cormullion/a157d7ff1a876f6d3bf15c50ad407d49 to your computer and use it in GitHub Desktop.
Save cormullion/a157d7ff1a876f6d3bf15c50ad407d49 to your computer and use it in GitHub Desktop.
julia pool
using Luxor, Colors, Combinatorics, Random
mutable struct Ball
id::Int
position::Point
velocity::Point
color::Union{NTuple, Colorant, String}
ballradius::Float64
end
function backdropf(scene, framenumber)
background("grey20")
end
function collisioncheck!(balls;
tol = 0.01)
for ballpair in combinations(1:length(balls), 2)
balla, ballb = balls[ballpair[1]], balls[ballpair[2]]
if intersection2circles(balla.position, balla.ballradius, ballb.position, ballb.ballradius) > tol
collision = ballb.position - balla.position
d = distance(ballb.position, balla.position)
# Get the components of the velocity vectors which are parallel to the collision.
# The perpendicular component remains the same for both
collision = (collision / d)
aci = dotproduct(balla.velocity, collision)
bci = dotproduct(ballb.velocity, collision)
# new velocities using the 1-dimensional elastic collision equations
# masses are the same
acf = bci
bcf = aci
# replace the velocity components
balls[ballpair[1]].velocity += (acf - aci) * collision
balls[ballpair[2]].velocity += (bcf - bci) * collision
end
end
return balls
end
function update(scene, framenumber)
balls = scene.opts
for ball in balls
ball.position = ball.position += ball.velocity
# check bouncing off walls
if (ball.position.x <= (-scene.movie.width/2 + ball.ballradius))
ball.position = Point(-scene.movie.width/2 + ball.ballradius, ball.position.y)
ball.velocity = Point(-ball.velocity.x, ball.velocity.y)
end
if (ball.position.x >= (scene.movie.width/2 - ball.ballradius))
ball.position = Point(scene.movie.width/2 - ball.ballradius, ball.position.y)
ball.velocity = Point(-ball.velocity.x, ball.velocity.y)
end
if (ball.position.y <= (-scene.movie.height/2 + ball.ballradius))
ball.position = Point(ball.position.x, -scene.movie.width/2 + ball.ballradius)
ball.velocity = Point(ball.velocity.x, -ball.velocity.y)
end
if (ball.position.y >= (scene.movie.height/2 - ball.ballradius))
ball.position = Point(ball.position.x, scene.movie.width/2 - ball.ballradius)
ball.velocity = Point(ball.velocity.x, -ball.velocity.y)
end
sethue(ball.color)
circle(ball.position, ball.ballradius, :fill)
end
collisioncheck!(balls)
end
function main()
juliaballmovie = Movie(200, 200, "julia-billiard-pool")
numberofballs = 3
Random.seed!(42)
ballradius = 30
pts = [polar(100, θ) for θ in range(0, 2π, length = 1 + numberofballs)]
cols = [Luxor.julia_red, Luxor.julia_green, Luxor.julia_purple, Luxor.julia_blue]
balls = [Ball(i, pts[i], pts[i] * rand(-0.15:0.01:0.15), cols[mod1(i, 4)], ballradius) for i in 1:numberofballs]
animate(juliaballmovie, [
Scene(juliaballmovie, backdropf, 1:300),
Scene(juliaballmovie, update, optarg=balls, 1:300),
], creategif=true, pathname="/tmp/julia-billiard-pool.gif")
end
main()
@cormullion
Copy link
Author

cormullion commented Aug 16, 2017

julia-billiard-pool

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment