This is my first experiment using pico-8, a basic water simulation that hopefully is simple enough to be used in other projects.
The two main things used to make this simulation is;
1) A vertical force applied to each point on the water surface, positive if the point is below "sea level" and negative if it is above the same point.
2) Diffusion of each point relating to its neighbours, which looks like this;
local diff = dampm * ( pt(i+1) + pt(i-1) +pt(i+2) + pt(i-2) +pt(i+3) + pt(i-3) +pt(i+4) + pt(i-4) ) * (-8*points[i]) points[i] -= diff*damp*dt
Where dt is time since the last frame, diff & damp are value multipliers and pt(n) being a function that returns the values from the points array, making sure none of them encounter any index errors.
Like I said, this is my first attempt at using pico-8, so if I've made any really silly mistakes, please do let me know as it's the only way I'll ever learn!
Super fun! I really like having the cannon as another way to interact with the water.
I made a couple of changes to the water dynamics to make it feel ... sloshier, I guess? I basically wanted to make it easier to have large traveling waves. The scale of waves vs. boat is maybe not so realistic now, though.
Also, this would probably feel better with wrap-around boundaries than the reflecting ones currently present.
luchak, I love some of these changes you've made and I'm looking forward to going through your code to see how you managed to achieve this effect :D
I've made a few updates since I last posted, notably you can no longer break the game so easily and now we have reflections!
Nice update! The sounds are a lot of fun and I really like the giant octopus.
My code basically just implements the 1D wave equation. This is, uh ... very approximate for ocean waves, but it does allow for the formation of big traveling waves, which is what I wanted. Implementation notes, in case they help:
- The code uses semi-implicit Euler integration, which basically means that it updates position and velocity in separate loops, rather than allocating a temp position array and doing them in the same loop. This leads to slightly more stable behavior.
- There are two kinds of damping. One is simple velocity damping (scale velocities by some constant slightly less than 1 each time step) and the other is a simple smoothing filter on positions, where I directly move each point a little closer to the straight line between its neighbors. (Although this is buggy -- I'm not allocating a temp position array for this, so the code smears position information in an asymmetric and slightly weird way.)
- With a 3-point Laplacian stencil (0.5, -1, 0.5) you can only transmit information one cell per timestep, no matter what dt is. This not only feels slow, it can lead to really weird behavior when dt is big! So I do two different things to increase wave propagation speed: one is to use a 5-point Laplacian (see constants in code), and the other is to run multiple simulation timesteps per frame.
- The boundaries reflect right now because water levels outside the simulation boundary are fixed to a constant. To make wrap-around boundaries, you'd need to copy position and velocity values just inside the left boundary to just outside the right boundary (and values from just inside on the right to just outside on the left) after each substep. Absorbing boundaries are yet another possibility, but they can be kind of annoying, plus for my goals they'd be no fun. (It's hard to have really big waves when they just move offscreen and disappear!)
[Please log in to post a comment]