Last active
February 6, 2022 15:25
-
-
Save mroavi/d10cd90b1d895e0f00e14774b5f01537 to your computer and use it in GitHub Desktop.
A simple particle system animation in Julia.
This file contains 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 Plots, Distributions | |
theme(:juno) # sets theme and resets all attributes of the Plots package | |
gr( | |
xlims=[-10,10], | |
ylims=[-10,10], | |
aspect_ratio=:equal, | |
framestyle=:grid, | |
fillalpha=0.3, | |
leg=false, | |
size=(1200,800), | |
thickness_scaling = 1.5, | |
linealpha=0.5, | |
markerstrokewidth=0, | |
markersize=10, | |
markeralpha=0.8, | |
); plot() | |
import Base.+, Base.-, Base.*, Base./ | |
mutable struct PVector | |
x::Float64 | |
y::Float64 | |
end | |
+(v1::PVector, v2::PVector) = PVector(v1.x + v2.x, v1.y + v2.y) | |
-(v1::PVector, v2::PVector) = PVector(v1.x - v2.x, v1.y - v2.y) | |
-(v::PVector) = PVector(-v.x, -v.y) | |
*(v::PVector, n::Float64) = PVector(n * v.x, n * v.y) | |
*(n::Float64, v::PVector) = v * n | |
/(v::PVector, n::Float64) = PVector(v.x/n, v.y/n) | |
mag(v::PVector) = sqrt(v.x^2 + v.y^2) | |
normalize(v::PVector) = (mag(v) != 0 ) ? PVector(v.x/mag(v), v.y/mag(v)) : PVector(0,0) | |
limit(v::PVector, n) = (mag(v) > n) ? normalize(v) * n : v | |
mutable struct Particle | |
pos::PVector | |
vel::PVector | |
acc::PVector | |
mass::Float64 | |
lifespan::Float64 | |
function Particle(pos, vel, acc, mass, lifespan=1) | |
new(pos, vel, acc, mass, lifespan) | |
end | |
end | |
function Particle(p::Particle) | |
Particle(p.pos, p.vel, p.acc, p.mass, p.lifespan) | |
end | |
function rescale(x, start1, stop1, start2, stop2) | |
start2 + (((x - start1)*(stop2 - start2))/(stop1-start1)) | |
end | |
isDead(p::Particle) = (p.pos.y < -10) ? true : false | |
function update(p::Particle) | |
p.vel = p.vel + p.acc | |
p.pos = p.pos + p.vel | |
p.acc = PVector(0,0) # clear acceleration | |
p.lifespan -= 0.05 | |
return Particle(p.pos, p.vel, p.acc, p.mass, p.lifespan) | |
end | |
function disp(particles::Array{Particle}) | |
plot(ylims=(-10,10)) # fixes unwanted padding | |
for p in particles | |
scatter!([p.pos.x], [p.pos.y], | |
m=:circle, | |
markersize=p.mass*20, | |
markeralpha=rescale(p.pos.y, 10, -10, 1, 0), | |
c = floor(Int64, p.mass*100) | |
) | |
end | |
end | |
function applyForce(p::Particle, f::PVector) | |
ret = Particle(p) | |
ret.acc = ret.acc + f/p.mass # Newton's 2nd law of motion | |
return ret | |
end | |
function newParticle() | |
pos = PVector(0, 5) | |
vel = PVector(rand(Uniform(-0.2, 0.2)), rand(Uniform(0, 0.7))) | |
acc = PVector(0,0) | |
mass = rand(Uniform(0.4, 0.6)) | |
return Particle(pos, vel, PVector(0, 0), mass) | |
end | |
particles = Array{Particle}(undef, 0) # initialize particles | |
anim = @animate for _ in 1:100 | |
push!(particles, newParticle()) | |
push!(particles, newParticle()) | |
for i in length(particles):-1:1 | |
gravity = PVector(0, -0.03) | |
particles[i] = applyForce(particles[i], gravity) | |
particles[i] = update(particles[i]) | |
if isDead(particles[i]) | |
deleteat!(particles, i) # delete dead particle | |
push!(particles, newParticle()) # create a new particle | |
end | |
end | |
disp(particles) | |
end | |
gif(anim, joinpath(@__DIR__, "4.1.gif"), fps = 15) |
@PlasmaThias Not really sure what you mean there but I advise you to take a look at this video: https://youtu.be/TQ_WZU5s_VA. They explain where these equations come from.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi!
Just I don't understand those two lines:
p.vel = p.vel + p.acc
p.pos = p.pos + p.vel
Why do you sum two different entities. I mean why not, there is no unit when coding and it doesn't have to be physically true.
But you're using the second law of motion:
ret.acc = ret.acc + f/p.mass # Newton's 2nd law of motion
So I'm a bit confuse.