Last active
September 17, 2022 13:23
-
-
Save cormullion/9c3676b8e456600c33011df03f978c42 to your computer and use it in GitHub Desktop.
julia bouncing balls
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is it possible to specify an arbitrary tile/partition dimension?