Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust_particles/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
7 changes: 3 additions & 4 deletions rust_particles/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
[package]
name = "rust_particles"
version = "0.1.0"
edition = "2018"
version = "0.2.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
piston = "0.53.0"
piston_window = "0.120.0"
speedy2d = "1.8.0"
rand = "0.8.4"
117 changes: 82 additions & 35 deletions rust_particles/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,99 @@
extern crate piston_window;
use piston_window::*;
use rand::Rng;
use speedy2d::color::Color;
use speedy2d::dimen::Vec2;
use speedy2d::window::{MouseButton, WindowHandler, WindowHelper, WindowStartupInfo};
use speedy2d::{Graphics2D, Window};

mod particle;

pub const WIDTH: u32 = 400;
pub const HEIGHT: u32 = 400;

fn main() {
let mut p: Vec<particle::Particle> = Vec::new();
let mut counter = 0;
let mut rng = rand::thread_rng();

p.push(particle::Particle::new(
vec![200., 200.],
vec![rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)],
vec![0.0, 0.1],
HEIGHT,
WIDTH,
));

let mut window: PistonWindow = WindowSettings::new("Particle System", [WIDTH, HEIGHT])
.exit_on_esc(true)
.build()
.unwrap();
// The animation loop for the window
while let Some(e) = window.next() {
window.draw_2d(&e, |c, g, _device| {
clear([0.0, 0.0, 0.0, 1.0], g);
for i in 0..p.len() {
ellipse(color::alpha(p[i].lifetime), p[i].show(), c.transform, g);
p[i].update();
}
});
counter = counter + 1;
if counter % 10 == 0 {
p.push(particle::Particle::new(
vec![200., 200.],
let window = Window::new_centered("Particle System", (WIDTH, HEIGHT)).unwrap();

window.run_loop(MyWindowHandler {
p: Vec::new(),
counter: 0,
color: [1., 0., 0., 1.],
mouse_pos: vec![0., 0.],
start_pos: vec![(WIDTH / 2) as f32, (HEIGHT / 2) as f32],
});
}

struct MyWindowHandler {
p: Vec<particle::Particle>,
counter: u32,
color: [f32; 4],
mouse_pos: Vec<f32>,
start_pos: Vec<f32>,
}

impl WindowHandler for MyWindowHandler {
fn on_start(&mut self, helper: &mut WindowHelper, _info: WindowStartupInfo) {
helper.set_resizable(false); // We don't handle resize yet.
}

fn on_draw(&mut self, helper: &mut WindowHelper, graphics: &mut Graphics2D) {
let mut rng = rand::thread_rng();
if self.counter % 10 == 0 {
self.p.push(particle::Particle::new(
self.start_pos.clone(),
vec![rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0)],
vec![0.0, 0.1],
HEIGHT,
WIDTH,
self.color,
));
self.counter = 0;
}
graphics.clear_screen(Color::BLACK);
for part in &mut self.p {
graphics.draw_circle(part.particle_pos(), part.size, part.particle_color());
part.update();
}
self.counter += 1;
self.p.retain(|x| !x.finished());

helper.request_redraw();
}

fn on_mouse_move(&mut self, _helper: &mut WindowHelper, position: Vec2) {
self.mouse_pos[0] = position.x;
self.mouse_pos[1] = position.y;
}

fn on_mouse_button_down(
&mut self,
helper: &mut WindowHelper<()>,
button: speedy2d::window::MouseButton,
) {
if button == MouseButton::Left {
self.start_pos = self.mouse_pos.clone();
}
helper.request_redraw();
}

fn on_keyboard_char(&mut self, helper: &mut WindowHelper<()>, unicode_codepoint: char) {
let new_color: [f32; 4];

if unicode_codepoint == 'r' {
new_color = [1., 0., 0., 1.]
} else if unicode_codepoint == 'g' {
new_color = [0., 1., 0., 1.]
} else if unicode_codepoint == 'b' {
new_color = [0., 0., 1., 1.]
} else {
new_color = [0., 0., 0., 0.]
}
for i in (0..(p.len() - 1)).rev() {
if p[i].clone().finished() {
p.remove(i);
}

self.color = new_color;
for i in &mut self.p {
i.colour[0] = new_color[0]; // fix this to be RUSTY
i.colour[1] = new_color[1];
i.colour[2] = new_color[2];
}

helper.request_redraw();
}
}
70 changes: 37 additions & 33 deletions rust_particles/src/particle.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,50 @@
#[derive(Clone)]
use speedy2d::{dimen::Vec2, color::Color};
pub struct Particle {
pub pos: Vec<f64>,
pub vel: Vec<f64>,
pub acc: Vec<f64>,
size: f64,
pub pos: Vec<f32>,
pub vel: Vec<f32>,
pub acc: Vec<f32>,
pub size: f32,
pub lifetime: f32,
pub colour: [f32; 4],
max_speed: f64,
max_acc: f64,
height: f64,
width: f64,
max_speed: f32,
max_acc: f32,
height: u32,
width: u32,
}

impl Particle {
pub fn new(pos: Vec<f64>, vel: Vec<f64>, acc: Vec<f64>, height: u32, width: u32) -> Particle {
return Particle {
pos: pos,
vel: vel,
acc: acc,
pub fn new(pos: Vec<f32>, vel: Vec<f32>, acc: Vec<f32>, height: u32, width: u32, colour: [f32; 4]) -> Particle {
Particle {
pos,
vel,
acc,
lifetime: 1.0,
size: 10.,
colour: [1.0, 0.0, 0.0, 1.0],
size: 5.,
colour,
max_speed: 10.0,
max_acc: 0.5,
height: height as f64,
width: width as f64,
};
height,
width,
}
}

pub fn update(&mut self) {
self.pos[0] = self.pos[0] + self.vel[0];
self.vel[0] = self.vel[0] + self.acc[0];
self.pos[1] = self.pos[1] + self.vel[1];
self.vel[1] = self.vel[1] + self.acc[1];
self.pos[0] += self.vel[0];
self.vel[0] += self.acc[0];
self.pos[1] += self.vel[1];
self.vel[1] += self.acc[1];
self.check_limits();
self.edges();
self.lifetime = self.lifetime - 0.01;
self.colour = [1.0, 0.0, 0.0, self.lifetime];
self.lifetime -= 0.01;
self.colour[3] = self.lifetime;
}

pub fn particle_pos(&self) -> Vec2 {
Vec2::new(self.pos[0], self.pos[1])
}

pub fn show(&self) -> [f64; 4] {
return [self.pos[0], self.pos[1], self.size, self.size];
pub fn particle_color(&self) -> Color {
Color::from_rgba(self.colour[0], self.colour[1], self.colour[2], self.colour[3])
}

fn check_limits(&mut self) {
Expand All @@ -59,15 +63,15 @@ impl Particle {
}

fn edges(&mut self) {
if self.pos[1] >= self.height || self.pos[1] <= 0.0 {
self.vel[1] = self.vel[1] * -1.0;
if self.pos[1] >= self.height as f32 || self.pos[1] <= 0.0 {
self.vel[1] *= -1.0;
}
if self.pos[0] >= self.width || self.pos[0] <= 0.0 {
self.vel[0] = self.vel[0] * -1.0;
if self.pos[0] >= self.width as f32 || self.pos[0] <= 0.0 {
self.vel[0] *= -1.0;
}
}

pub fn finished(self) -> bool {
return self.lifetime <= 0.;
pub fn finished(&self) -> bool {
self.lifetime <= 0.
}
}