Add obstacles
This commit is contained in:
parent
27c835b8e5
commit
a2b5d45a52
11 changed files with 103 additions and 49 deletions
23
src/App.ts
23
src/App.ts
|
|
@ -37,18 +37,29 @@ export default new class App {
|
|||
|
||||
this.simulationStepsPerSecond = Config.simulationStepsPerSecond;
|
||||
this.updateSimulationInterval();
|
||||
|
||||
this.gui.on('antsCount', () => {
|
||||
this.resetRenderer();
|
||||
});
|
||||
|
||||
this.gui.on('worldSize', () => {
|
||||
this.resetRenderer();
|
||||
});
|
||||
|
||||
this.gui.on('simulationStepsPerSecond', () => {
|
||||
this.simulationStepsPerSecond = Config.simulationStepsPerSecond;
|
||||
this.updateSimulationInterval();
|
||||
});
|
||||
}
|
||||
|
||||
private resetRenderer() {
|
||||
this.renderer.reset();
|
||||
}
|
||||
|
||||
private updateSimulationInterval() {
|
||||
clearInterval(this.simInterval);
|
||||
|
||||
this.simInterval = setInterval(() => {
|
||||
if (Config.simulationStepsPerSecond !== this.simulationStepsPerSecond) {
|
||||
this.simulationStepsPerSecond = Config.simulationStepsPerSecond;
|
||||
this.updateSimulationInterval();
|
||||
return;
|
||||
}
|
||||
|
||||
this.simulationStep();
|
||||
|
||||
this.simStarted = true;
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ export default {
|
|||
antsCount: 64 ** 2,
|
||||
simulationStepsPerSecond: 60,
|
||||
scentThreshold: 0.01,
|
||||
scentFadeOutFactor: 0.998,
|
||||
scentBlurRadius: 0.2,
|
||||
scentFadeOutFactor: 0.999,
|
||||
scentBlurRadius: 0.1,
|
||||
scentMaxStorage: 1e6,
|
||||
scentPerMarker: 1000,
|
||||
antSpeed: 1,
|
||||
|
|
|
|||
17
src/GUI.ts
17
src/GUI.ts
|
|
@ -1,17 +1,26 @@
|
|||
import * as dat from 'dat.gui';
|
||||
import Config from "./Config";
|
||||
import EventEmitter from "events";
|
||||
|
||||
export default class GUI {
|
||||
export default class GUI extends EventEmitter {
|
||||
private gui: dat.GUI = new dat.GUI({
|
||||
width: 400
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const simFolder = this.gui.addFolder('Simulation');
|
||||
|
||||
simFolder.add(Config, 'worldSize', 256, 8096);
|
||||
simFolder.add(Config, 'antsCount', 1, 1e6);
|
||||
simFolder.add(Config, 'simulationStepsPerSecond', 1, 300);
|
||||
simFolder.add(Config, 'worldSize', 256, 8096).onChange(() => {
|
||||
this.emit('worldSize');
|
||||
});
|
||||
simFolder.add(Config, 'antsCount', 1, 1e6).onChange(() => {
|
||||
this.emit('antsCount');
|
||||
});
|
||||
simFolder.add(Config, 'simulationStepsPerSecond', 1, 300).onChange(() => {
|
||||
this.emit('simulationStepsPerSecond');
|
||||
});
|
||||
|
||||
const controlsFolder = this.gui.addFolder('Controls');
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export default class Renderer {
|
|||
type: THREE.FloatType,
|
||||
depthBuffer: false,
|
||||
magFilter: THREE.NearestFilter,
|
||||
minFilter: THREE.LinearFilter,
|
||||
minFilter: THREE.NearestFilter,
|
||||
}),
|
||||
worldBlurredRenderTarget: new THREE.WebGLRenderTarget(Config.worldSize, Config.worldSize, {
|
||||
format: THREE.RGBAFormat,
|
||||
|
|
@ -137,7 +137,7 @@ export default class Renderer {
|
|||
};
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
public reset() {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,23 @@
|
|||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#info {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-family: monospace;
|
||||
color: white;
|
||||
padding: 16px;
|
||||
text-shadow: 0 0 3px black;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="info">Controls:<br/>Q - draw home cells<br/>W - draw food cells<br/>E - draw obstacle<br/>Drag and scroll to move the camera</div>
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ export default class ScreenScene extends AbstractScene {
|
|||
new THREE.PlaneBufferGeometry(1, 1),
|
||||
new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
map: {value: this.renderer.resources.worldRenderTarget.texture},
|
||||
tDiscreteAnts: {value: this.renderer.resources.antsDiscreteRenderTarget.texture},
|
||||
map: {value: this.renderer.resources.worldRenderTarget.texture}
|
||||
},
|
||||
vertexShader: vertexShaderGround,
|
||||
fragmentShader: fragmentShaderGround,
|
||||
|
|
|
|||
|
|
@ -28,15 +28,25 @@ vec2 roundUvToCellCenter(vec2 uv) {
|
|||
}
|
||||
|
||||
bool tryGetFood(vec2 pos) {
|
||||
return texture(tWorld, roundUvToCellCenter(pos)).x == 1.;
|
||||
float value = texture(tWorld, roundUvToCellCenter(pos)).x;
|
||||
|
||||
return (int(value) & 1) == 1;
|
||||
}
|
||||
|
||||
bool tryDropFood(vec2 pos) {
|
||||
return texture(tWorld, roundUvToCellCenter(pos)).y == 1.;
|
||||
float value = texture(tWorld, roundUvToCellCenter(pos)).x;
|
||||
|
||||
return ((int(value) & 2) >> 1) == 1;
|
||||
}
|
||||
|
||||
bool isObstacle(vec2 pos) {
|
||||
float value = texture(tWorld, roundUvToCellCenter(pos)).x;
|
||||
|
||||
return ((int(value) & 4) >> 2) == 1;
|
||||
}
|
||||
|
||||
float smell(vec2 pos, float isCarrying) {
|
||||
vec2 value = texture(tWorld, pos).zw;
|
||||
vec2 value = texture(tWorld, pos).yz;
|
||||
|
||||
if (isCarrying > 0.5) {
|
||||
return value.y;
|
||||
|
|
@ -46,10 +56,13 @@ float smell(vec2 pos, float isCarrying) {
|
|||
}
|
||||
|
||||
vec2 applyOffsetToPos(vec2 pos, vec2 offsetDirectaion) {
|
||||
return vec2(
|
||||
clamp(pos.x + offsetDirectaion.x * cellSize, 0., 1.),
|
||||
clamp(pos.y + offsetDirectaion.y * cellSize, 0., 1.)
|
||||
);
|
||||
vec2 newPos = clamp(pos + offsetDirectaion * cellSize, 0., 1.);
|
||||
|
||||
if (!isObstacle(pos) && isObstacle(newPos)) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
return newPos;
|
||||
}
|
||||
|
||||
float getMaxScentStorage(vec2 antDataUv) {
|
||||
|
|
@ -67,6 +80,7 @@ void main() {
|
|||
float angle = lastState.z;
|
||||
float isCarrying = float(int(lastState.w) & 1);
|
||||
float storage = float(int(lastState.w) >> 1);
|
||||
bool wasObstacle = isObstacle(pos);
|
||||
|
||||
bool movementProcessed = false;
|
||||
|
||||
|
|
@ -162,7 +176,7 @@ void main() {
|
|||
vec2 offset = vec2(cos(angle), sin(angle));
|
||||
pos = applyOffsetToPos(pos, offset);
|
||||
|
||||
if (fract(pos.x) == 0. || fract(pos.y) == 0.) {
|
||||
if (fract(pos.x) == 0. || fract(pos.y) == 0. || (!wasObstacle && isObstacle(pos + offset * cellSize))) {
|
||||
angle += PI * (noise - 0.5);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,16 +13,20 @@ uniform float brushRadius;
|
|||
void main() {
|
||||
vec4 lastState = texture(tWorld, vUv);
|
||||
|
||||
float isFood = lastState.x;
|
||||
float isHome = lastState.y;
|
||||
int cellData = int(lastState.x);
|
||||
int isFood = cellData & 1;
|
||||
int isHome = (cellData & 2) >> 1;
|
||||
int isObstacle = (cellData & 4) >> 2;
|
||||
|
||||
if (distance(pointerPosition, vUv) < brushRadius / WORLD_SIZE) {
|
||||
if (drawMode == 1.) {
|
||||
isFood = 1.;
|
||||
isFood = 1;
|
||||
} else if (drawMode == 2.) {
|
||||
isHome = 1.;
|
||||
isHome = 1;
|
||||
} else if (drawMode == 3.) {
|
||||
isObstacle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
FragColor = vec4(isFood, isHome, lastState.zw);
|
||||
FragColor = vec4(float(isFood + (isHome << 1) + (isObstacle << 2)), lastState.yzw);
|
||||
}
|
||||
|
|
@ -6,15 +6,16 @@ in vec2 vUv;
|
|||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D map;
|
||||
uniform sampler2D tDiscreteAnts;
|
||||
|
||||
void main() {
|
||||
vec4 value = clamp(texture(map, vUv), 0., 1.);
|
||||
vec4 value = texture(map, vUv);
|
||||
|
||||
float isFood = value.r;
|
||||
float isHome = value.g;
|
||||
float toFood = value.b;
|
||||
float toHome = value.a;
|
||||
int cellData = int(value.x);
|
||||
int isFood = cellData & 1;
|
||||
int isHome = (cellData & 2) >> 1;
|
||||
int isObstacle = (cellData & 4) >> 2;
|
||||
float toFood = clamp(value.y, 0., 1.);
|
||||
float toHome = clamp(value.z, 0., 1.);
|
||||
|
||||
// The part below doen't seem right.
|
||||
// I could figure out a better way to make pheromone colors blend properly on white background :(
|
||||
|
|
@ -28,12 +29,12 @@ void main() {
|
|||
|
||||
vec3 color = mix(vec3(1, 1, 1), t, a * 0.7);
|
||||
|
||||
if (isFood == 1.) {
|
||||
if (isFood == 1) {
|
||||
color = vec3(1, 0.1, 0.1);
|
||||
}
|
||||
|
||||
if (isHome == 1.) {
|
||||
} else if (isHome == 1) {
|
||||
color = vec3(0.1, 0.1, 1);
|
||||
} else if (isObstacle == 1) {
|
||||
color = vec3(0.6, 0.6, 0.6);
|
||||
}
|
||||
|
||||
FragColor = vec4(color, 1);
|
||||
|
|
|
|||
|
|
@ -12,14 +12,16 @@ void main() {
|
|||
vec4 lastState = texture(tLastState, vUv);
|
||||
vec3 discreteAnts = texture(tDiscreteAnts, vUv).xyz;
|
||||
|
||||
float isFood = lastState.x;
|
||||
float isHome = lastState.y;
|
||||
float scentToHome = min(10., lastState.z + discreteAnts.x * 2.);
|
||||
float scentToFood = min(10., lastState.w + discreteAnts.y * 2.);
|
||||
int cellData = int(lastState.x);
|
||||
int isFood = cellData & 1;
|
||||
int isHome = (cellData & 2) >> 1;
|
||||
int isObstacle = (cellData & 4) >> 2;
|
||||
float scentToHome = lastState.y + discreteAnts.x * 10.;
|
||||
float scentToFood = lastState.z + discreteAnts.y * 10.;
|
||||
|
||||
if (discreteAnts.z == 1.) {
|
||||
isFood = 0.;
|
||||
isFood = 0;
|
||||
}
|
||||
|
||||
FragColor = vec4(isFood, isHome, scentToHome, scentToFood);
|
||||
FragColor = vec4(float(isFood + (isHome << 1) + (isObstacle << 2)), scentToHome, scentToFood, 0);
|
||||
}
|
||||
|
|
@ -16,13 +16,13 @@ void main() {
|
|||
vec4 s3 = texture(tWorld, vUv + vec2(-1, 1) * offset);
|
||||
vec4 s4 = texture(tWorld, vUv + vec2(1, -1) * offset);
|
||||
|
||||
float scentToHome = (s0.z + s1.z + s2.z + s3.z + s4.z) / 5. * SCENT_FADE_OUT_FACTOR;
|
||||
float scentToFood = (s0.w + s1.w + s2.w + s3.w + s4.w) / 5. * SCENT_FADE_OUT_FACTOR;
|
||||
float scentToHome = (s0.y + s1.y + s2.y + s3.y + s4.y) / 5. * SCENT_FADE_OUT_FACTOR;
|
||||
float scentToFood = (s0.z + s1.z + s2.z + s3.z + s4.z) / 5. * SCENT_FADE_OUT_FACTOR;
|
||||
|
||||
FragColor = vec4(
|
||||
s0.x,
|
||||
s0.y,
|
||||
scentToHome < SCENT_THRESHOLD ? 0. : scentToHome,
|
||||
scentToFood < SCENT_THRESHOLD ? 0. : scentToFood
|
||||
scentToFood < SCENT_THRESHOLD ? 0. : scentToFood,
|
||||
0
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue