diff --git a/examples/fireworks/fireworks.v b/examples/fireworks/fireworks.v new file mode 100644 index 0000000000..411fda6658 --- /dev/null +++ b/examples/fireworks/fireworks.v @@ -0,0 +1,70 @@ +import objects +import gg +import gx +import rand + +struct App { +mut: + gg &gg.Context = 0 + rockets []objects.Rocket + frames [][]objects.Rocket + // i thought about using a fixed fifo queue for the frames but the array + // seemed to work fine, if you'd like a challenge try implementing it with the queue :) +} + +fn on_frame(mut app App) { + app.gg.begin() + + // drawing previous frames + for mut frame in app.frames { + for mut rocket in frame { + if !rocket.exploded { + rocket.color.a = byte(f32_max(rocket.color.a - 8, 0)) + rocket.draw(mut app.gg) + } + } + } + + // chance of firing new rocket + if rand.intn(30) == 0 { + app.rockets << objects.new_rocket() + } + // simulating rockets + app.rockets = app.rockets.filter(!it.dead) + + for mut rocket in app.rockets { + rocket.tick(mut app.gg) + } + + // adding frame + mut frame := app.rockets.clone() + + for mut rocket in frame { + rocket.particles = [] + } + + app.frames << frame + + // trimming out frames + if app.frames.len > 30 { + app.frames.delete(0) + } + + app.gg.end() +} + +fn main() { + mut app := &App{} + + app.gg = gg.new_context( + width: objects.width + height: objects.height + window_title: 'Fireworks!' + bg_color: gx.black + use_ortho: true + user_data: app + frame_fn: on_frame + ) + + app.gg.run() +} diff --git a/examples/fireworks/modules/objects/color.v b/examples/fireworks/modules/objects/color.v new file mode 100644 index 0000000000..6761f26a88 --- /dev/null +++ b/examples/fireworks/modules/objects/color.v @@ -0,0 +1,12 @@ +module objects + +import gx +import rand + +pub fn random_color() gx.Color { + return gx.Color{ + r: byte(rand.int_in_range(0, 256)) + g: byte(rand.int_in_range(0, 256)) + b: byte(rand.int_in_range(0, 256)) + } +} diff --git a/examples/fireworks/modules/objects/constants.v b/examples/fireworks/modules/objects/constants.v new file mode 100644 index 0000000000..8160c57dea --- /dev/null +++ b/examples/fireworks/modules/objects/constants.v @@ -0,0 +1,12 @@ +module objects + +const ( + width = 800 + height = 800 + gravity = Vector{0, -0.03} + age_rate = 1 + offspring_count = 100 + rocket_radius = 5 + particle_radius = 2.5 + drag = 0.98 +) diff --git a/examples/fireworks/modules/objects/particle.v b/examples/fireworks/modules/objects/particle.v new file mode 100644 index 0000000000..32fb82d8ad --- /dev/null +++ b/examples/fireworks/modules/objects/particle.v @@ -0,0 +1,35 @@ +module objects + +import gg +import gx + +pub struct Particle { +pub mut: + color gx.Color + pos Vector + vel Vector + accel Vector + lifespan f32 = 255 +} + +pub fn (particle Particle) draw(mut ctx gg.Context) { + ctx.draw_circle(particle.pos.x, height - particle.pos.y, particle_radius, particle.color) +} + +pub fn (mut particle Particle) tick(mut rocket Rocket, mut ctx gg.Context) { + particle.lifespan -= age_rate + particle.color.a = byte(particle.lifespan) + + if particle.lifespan <= 0 { + rocket.dead = true + return + } + + particle.accel += gravity + particle.vel += particle.accel + particle.vel = particle.vel.mult(drag) + particle.pos += particle.vel + particle.draw(mut ctx) + + particle.accel = {} +} diff --git a/examples/fireworks/modules/objects/rocket.v b/examples/fireworks/modules/objects/rocket.v new file mode 100644 index 0000000000..5257bc45d4 --- /dev/null +++ b/examples/fireworks/modules/objects/rocket.v @@ -0,0 +1,68 @@ +module objects + +import gg +import gx +import rand + +pub struct Rocket { +pub mut: + color gx.Color + pos Vector + vel Vector + accel Vector + exploded bool + particles []Particle + dead bool +} + +pub fn (rocket Rocket) draw(mut ctx gg.Context) { + ctx.draw_circle(rocket.pos.x, height - rocket.pos.y, rocket_radius, rocket.color) +} + +pub fn (mut rocket Rocket) explode() { + rocket.exploded = true + + for _ in 0 .. offspring_count { + rocket.spawn_particle() + } +} + +pub fn (mut rocket Rocket) tick(mut ctx gg.Context) { + if !rocket.exploded { + if rocket.vel.y <= 1 { + rocket.explode() + } + + rocket.accel += gravity + rocket.vel += rocket.accel + rocket.pos += rocket.vel + rocket.draw(mut ctx) + + rocket.accel = {} + } + + for mut particle in rocket.particles { + particle.tick(mut rocket, mut ctx) + } +} + +pub fn new_rocket() Rocket { + return Rocket{ + color: random_color() + pos: { + x: rand.f32_in_range(50, width - 50) + } + vel: { + x: rand.f32_in_range(-1.5, 1.5) + y: rand.f32_in_range(5, 7) + } + } +} + +pub fn (mut rocket Rocket) spawn_particle() { + rocket.particles << Particle{ + color: rocket.color + pos: rocket.pos + accel: random_vector_in_circle().mult(2) + } +} diff --git a/examples/fireworks/modules/objects/vector.v b/examples/fireworks/modules/objects/vector.v new file mode 100644 index 0000000000..cfcd764740 --- /dev/null +++ b/examples/fireworks/modules/objects/vector.v @@ -0,0 +1,28 @@ +module objects + +import math +import rand + +pub struct Vector { +pub mut: + x f32 + y f32 +} + +pub fn (a Vector) + (b Vector) Vector { + return Vector{a.x + b.x, a.y + b.y} +} + +pub fn (vector Vector) mult(scalar f32) Vector { + return Vector{vector.x * scalar, vector.y * scalar} +} + +pub fn random_vector_in_circle() Vector { + theta := rand.f32n(2 * math.pi) + y := rand.f32() + + return { + x: f32(y * math.sin(theta)) + y: f32(y * math.cos(theta)) + } +}