Skip to content

Instantly share code, notes, and snippets.

@dev001hajipro
Last active June 28, 2017 07:42
Show Gist options
  • Save dev001hajipro/0c1b43a1c8b9aa5edd5f44a0abb5ec8e to your computer and use it in GitHub Desktop.
Save dev001hajipro/0c1b43a1c8b9aa5edd5f44a0abb5ec8e to your computer and use it in GitHub Desktop.
flowfield with OpenSive3D
#include <Siv3D.hpp>
#define _USE_MATH_DEFINES
#include <math.h>
// p5.js helper functions for OpenSiv3D
namespace p5h {
template <typename T>
inline T map(T n, T start1, T stop1, T start2, T stop2) noexcept {
return ((n - start1) / (stop1 - start1)) * (stop2 - start2) + start2;
}
inline void limit(Vec2& v, double a) noexcept {
double b = v.lengthSq();
if (b > a*a) {
v /= sqrt((float)b);
}
v *= a;
}
inline double heading(Vec2& v) noexcept {
return atan2(v.y, v.x);
}
template <typename T>
inline auto radians(T d) noexcept {
return 2 * M_PI / 360 * d; // 2*PI=360 degrees.
}
template <typename T>
inline auto constrain(T n, T low, T high) noexcept {
return max(min(n, high), low);
}
}
using namespace std;
struct FlowField
{
std::vector<std::vector<Vec2>> field;
int32_t resolution = 10;
int32_t cols;
int32_t rows;
double zoff = 0.0; // perlin noize offset.
FlowField()
{
cols = Window::Width() / resolution;
rows = Window::Height() / resolution;
field.resize(cols);
initFieldNoize3();
}
void initFieldNoize3() {
PerlinNoise noise(1234); // seed = 1234
double xoff = 0.0;
for (int x = 0; x < cols; x++) {
field[x] = std::vector<Vec2>(rows);
double yoff = 0.0;
for (int y = 0; y < rows; y++) {
double n = noise.noise(xoff, yoff, zoff) + 1;
//_RPTN(_CRT_WARN, "n= %f\n", n);
double theta = p5h::map(n*0.5, 0.0, 1.0, 0.0, M_PI * 2);
field[x][y].x = cos(theta);
field[x][y].y = sin(theta);
yoff += 0.05;
}
xoff += 0.05;
}
zoff += 0.02;
}
Vec2 lookup(Vec2& src)
{
int x = p5h::constrain((int)src.x / resolution, 0, cols - 1);
int y = p5h::constrain((int)src.y / resolution, 0, rows - 1);
return field[x][y];
}
void display() {
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
Line(x* resolution, y* resolution,
x* resolution + field[x][y].x * resolution,
y* resolution + field[x][y].y * resolution).draw(Palette::Lightpink);
}
}
}
};
struct Vehicle {
int mass = 1;
int r = 5;
double maxspeed = 4.0;
double maxforce = 0.1;
Vec2 position;
Vec2 velocity;
Vec2 acceleration;
Vehicle():
position(Vec2(Random(0, Window::Width()), Random(0, Window::Height()))),
velocity(Vec2::Zero()),
acceleration(Vec2(Random(-1, 1), Random(-1, 1))) {
}
void applyForce(Vec2 force) {
Vec2 a = force / mass;
acceleration += a;
}
void follow(FlowField& flowField) {
Vec2 desired = flowField.lookup(position);
desired *= maxspeed;
Vec2 steer = desired - velocity;
p5h::limit(steer, maxforce);
applyForce(steer);
}
void update() {
velocity += acceleration;
position += velocity;
acceleration *= 0.0;
if (position.x < 0) {
position.x = Window::Width();
} else if (position.x > Window::Width()) {
position.x = 0;
}
if (position.y < 0) {
position.y = Window::Height();
} else if (position.y > Window::Height()) {
position.y = 0;
}
}
void display(const Texture& t) {
auto theta = p5h::heading(velocity) + M_PI / 2;
t.resize(30).rotate(theta).draw(position);
}
};
void Main()
{
Range(1, 13);
Window::Resize(1280, 720);
Graphics::SetBackground(Color(20, 20, 20));
const Font font(20);
const Texture texture3(Emoji(L"🗻"), TextureDesc::Unmipped);
FlowField ff;
std::vector<Vehicle> vs(1000);
while (System::Update())
{
ff.initFieldNoize3();
ff.display();
for (auto& v : vs) {
v.follow(ff);
v.update();
v.display(texture3);
}
font(L"OpenSiv3D!").drawAt(80, 20, Palette::Black);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment