Rewrite ant behavior as priority stack with suppressors
This commit is contained in:
parent
8bf718bbbe
commit
a7aeb064b3
1 changed files with 136 additions and 153 deletions
|
|
@ -89,8 +89,6 @@ void main() {
|
||||||
float pathIntDx = lastExtState.b;
|
float pathIntDx = lastExtState.b;
|
||||||
float pathIntDy = lastExtState.a;
|
float pathIntDy = lastExtState.a;
|
||||||
|
|
||||||
bool movementProcessed = false;
|
|
||||||
|
|
||||||
// calculate this ant's index from its UV position in the texture
|
// calculate this ant's index from its UV position in the texture
|
||||||
ivec2 texSize = textureSize(tLastState, 0);
|
ivec2 texSize = textureSize(tLastState, 0);
|
||||||
int antIndex = int(vUv.y * float(texSize.y)) * texSize.x + int(vUv.x * float(texSize.x));
|
int antIndex = int(vUv.y * float(texSize.y)) * texSize.x + int(vUv.x * float(texSize.x));
|
||||||
|
|
@ -163,177 +161,162 @@ void main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFalling) {
|
if (!isFalling) {
|
||||||
|
bool acted = false;
|
||||||
|
|
||||||
if (isCarrying == 0.) {
|
// ---- PRIORITY 1: DEPOSIT ----
|
||||||
if (noise < 0.33) {
|
if (!acted && isCarrying == 1.) {
|
||||||
vec2 offset = vec2(cos(angle), sin(angle)) * sampleDistance;
|
|
||||||
vec2 point = applyOffsetToPos(pos, offset);
|
|
||||||
|
|
||||||
if (tryGetFood(point)) {
|
|
||||||
movementProcessed = true;
|
|
||||||
}
|
|
||||||
} else if (noise < 0.66) {
|
|
||||||
float newAngle = angle - ANT_ROTATION_ANGLE;
|
|
||||||
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
||||||
vec2 point = applyOffsetToPos(pos, offset);
|
|
||||||
|
|
||||||
if (tryGetFood(point)) {
|
|
||||||
movementProcessed = true;
|
|
||||||
angle = newAngle;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
float newAngle = angle + ANT_ROTATION_ANGLE;
|
|
||||||
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
||||||
vec2 point = applyOffsetToPos(pos, offset);
|
|
||||||
|
|
||||||
if (tryGetFood(point)) {
|
|
||||||
movementProcessed = true;
|
|
||||||
angle = newAngle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (isCarrying == 1.) {
|
|
||||||
if (noise < 0.33) {
|
|
||||||
vec2 offset = vec2(cos(angle), sin(angle)) * sampleDistance;
|
|
||||||
vec2 point = applyOffsetToPos(pos, offset);
|
|
||||||
|
|
||||||
if (tryDropFood(point)) {
|
|
||||||
movementProcessed = true;
|
|
||||||
}
|
|
||||||
} else if (noise < 0.66) {
|
|
||||||
float newAngle = angle - ANT_ROTATION_ANGLE;
|
|
||||||
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
||||||
vec2 point = applyOffsetToPos(pos, offset);
|
|
||||||
|
|
||||||
if (tryDropFood(point)) {
|
|
||||||
movementProcessed = true;
|
|
||||||
angle = newAngle;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
float newAngle = angle + ANT_ROTATION_ANGLE;
|
|
||||||
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
||||||
vec2 point = applyOffsetToPos(pos, offset);
|
|
||||||
|
|
||||||
if (tryDropFood(point)) {
|
|
||||||
movementProcessed = true;
|
|
||||||
angle = newAngle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!movementProcessed) {
|
|
||||||
#if VIEW_MODE_SIDE
|
|
||||||
// vertical bias for digging behavior
|
|
||||||
if (isCarrying == 1. && int(cargoMaterialId) != MAT_FOOD) {
|
|
||||||
// carrying powder: bias upward toward surface
|
|
||||||
float upwardBias = PI * 0.5; // straight up
|
|
||||||
float angleDiff = upwardBias - angle;
|
|
||||||
// normalize to [-PI, PI]
|
|
||||||
angleDiff = mod(angleDiff + PI, 2.0 * PI) - PI;
|
|
||||||
// gentle steering toward up (blend 30% toward upward)
|
|
||||||
angle += angleDiff * 0.3;
|
|
||||||
} else if (isCarrying == 0.) {
|
|
||||||
// not carrying: check if surrounded by diggable material
|
|
||||||
// if so, prefer downward movement
|
|
||||||
float cellMatId = texture(tWorld, roundUvToCellCenter(pos)).x;
|
float cellMatId = texture(tWorld, roundUvToCellCenter(pos)).x;
|
||||||
vec4 props = texelFetch(uMaterialProps, ivec2(int(cellMatId), 0), 0);
|
|
||||||
|
|
||||||
// check cell below for diggable material
|
// carrying food and at home -> drop food
|
||||||
vec2 belowUv = roundUvToCellCenter(pos - vec2(0., cellSize));
|
if (int(cargoMaterialId) == MAT_FOOD && tryDropFood(pos)) {
|
||||||
float belowDigMat = texture(tWorld, belowUv).x;
|
isCarrying = 0.;
|
||||||
vec4 belowProps = texelFetch(uMaterialProps, ivec2(int(belowDigMat), 0), 0);
|
cargoMaterialId = 0.;
|
||||||
|
angle += PI;
|
||||||
|
storage = getMaxScentStorage(vUv);
|
||||||
|
acted = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (belowProps.r == BEHAVIOR_POWDER && belowProps.b <= ANT_CARRY_STRENGTH) {
|
// carrying powder and on surface (air cell, solid below) -> deposit
|
||||||
// diggable material below — bias downward
|
if (!acted && int(cargoMaterialId) != MAT_FOOD) {
|
||||||
float downwardBias = -PI * 0.5; // straight down
|
if (int(cellMatId) == MAT_AIR) {
|
||||||
float angleDiff = downwardBias - angle;
|
vec2 belowPos = pos - vec2(0., cellSize);
|
||||||
|
float belowMatId = texture(tWorld, roundUvToCellCenter(belowPos)).x;
|
||||||
|
vec2 abovePos = pos + vec2(0., cellSize);
|
||||||
|
float aboveMatId = texture(tWorld, roundUvToCellCenter(abovePos)).x;
|
||||||
|
if ((int(belowMatId) != MAT_AIR || belowPos.y <= 0.)
|
||||||
|
&& int(aboveMatId) == MAT_AIR) {
|
||||||
|
isCarrying = 0.;
|
||||||
|
// keep cargoMaterialId set so discretize reads it this frame
|
||||||
|
angle += PI;
|
||||||
|
storage = getMaxScentStorage(vUv);
|
||||||
|
acted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- PRIORITY 2: NAVIGATE (carrying) ----
|
||||||
|
if (!acted && isCarrying == 1.) {
|
||||||
|
if (int(cargoMaterialId) == MAT_FOOD) {
|
||||||
|
// follow toHome pheromone
|
||||||
|
float sAhead = smell(applyOffsetToPos(pos, vec2(cos(angle), sin(angle)) * sampleDistance), 1.);
|
||||||
|
float sLeft = smell(applyOffsetToPos(pos, vec2(cos(angle - ANT_ROTATION_ANGLE), sin(angle - ANT_ROTATION_ANGLE)) * sampleDistance), 1.);
|
||||||
|
float sRight = smell(applyOffsetToPos(pos, vec2(cos(angle + ANT_ROTATION_ANGLE), sin(angle + ANT_ROTATION_ANGLE)) * sampleDistance), 1.);
|
||||||
|
|
||||||
|
if (sLeft > sAhead && sLeft > sRight) {
|
||||||
|
angle -= ANT_ROTATION_ANGLE;
|
||||||
|
} else if (sRight > sAhead && sRight > sLeft) {
|
||||||
|
angle += ANT_ROTATION_ANGLE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// carrying powder: bias upward toward surface
|
||||||
|
#if VIEW_MODE_SIDE
|
||||||
|
float upwardBias = PI * 0.5;
|
||||||
|
float angleDiff = upwardBias - angle;
|
||||||
angleDiff = mod(angleDiff + PI, 2.0 * PI) - PI;
|
angleDiff = mod(angleDiff + PI, 2.0 * PI) - PI;
|
||||||
// gentle steering toward down (20% blend)
|
angle += angleDiff * 0.3;
|
||||||
angle += angleDiff * 0.2;
|
#endif
|
||||||
|
}
|
||||||
|
// add wander noise to carrying ants too
|
||||||
|
float noise2 = rand(vUv * 1000. + fract(uTime / 1000.) + 0.2);
|
||||||
|
if (noise2 > 0.5) {
|
||||||
|
angle += ANT_ROTATION_ANGLE;
|
||||||
|
} else {
|
||||||
|
angle -= ANT_ROTATION_ANGLE;
|
||||||
|
}
|
||||||
|
acted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- PRIORITY 3: FORAGE (not carrying, food scent detected) ----
|
||||||
|
if (!acted && isCarrying == 0.) {
|
||||||
|
float sAhead = smell(applyOffsetToPos(pos, vec2(cos(angle), sin(angle)) * sampleDistance), 0.);
|
||||||
|
float sLeft = smell(applyOffsetToPos(pos, vec2(cos(angle - ANT_ROTATION_ANGLE), sin(angle - ANT_ROTATION_ANGLE)) * sampleDistance), 0.);
|
||||||
|
float sRight = smell(applyOffsetToPos(pos, vec2(cos(angle + ANT_ROTATION_ANGLE), sin(angle + ANT_ROTATION_ANGLE)) * sampleDistance), 0.);
|
||||||
|
|
||||||
|
float maxSmell = max(sAhead, max(sLeft, sRight));
|
||||||
|
|
||||||
|
if (maxSmell > SCENT_THRESHOLD) {
|
||||||
|
if (sLeft > sAhead && sLeft > sRight) {
|
||||||
|
angle -= ANT_ROTATION_ANGLE;
|
||||||
|
} else if (sRight > sAhead && sRight > sLeft) {
|
||||||
|
angle += ANT_ROTATION_ANGLE;
|
||||||
|
}
|
||||||
|
acted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- PRIORITY 4: DIG (not carrying, diggable material nearby below surface) ----
|
||||||
|
#if VIEW_MODE_SIDE
|
||||||
|
if (!acted && isCarrying == 0.) {
|
||||||
|
vec2 belowUv = roundUvToCellCenter(pos - vec2(0., cellSize));
|
||||||
|
float belowMat2 = texture(tWorld, belowUv).x;
|
||||||
|
vec4 belowProps2 = texelFetch(uMaterialProps, ivec2(int(belowMat2), 0), 0);
|
||||||
|
|
||||||
|
// suppress digging if on the surface (air above) — don't dig topsoil into sky
|
||||||
|
vec2 aboveUv = roundUvToCellCenter(pos + vec2(0., cellSize));
|
||||||
|
float aboveMat2 = texture(tWorld, aboveUv).x;
|
||||||
|
bool onSurfaceTop = (int(aboveMat2) == MAT_AIR);
|
||||||
|
|
||||||
|
if (!onSurfaceTop
|
||||||
|
&& belowProps2.r == BEHAVIOR_POWDER
|
||||||
|
&& belowProps2.b <= ANT_CARRY_STRENGTH) {
|
||||||
|
// bias angle toward ~40 degrees below horizontal (angle of repose)
|
||||||
|
float targetAngle = (cos(angle) >= 0.)
|
||||||
|
? -0.7 // ~-40 degrees (right and down)
|
||||||
|
: -(PI - 0.7); // ~-(180-40) degrees (left and down)
|
||||||
|
float angleDiff2 = targetAngle - angle;
|
||||||
|
angleDiff2 = mod(angleDiff2 + PI, 2.0 * PI) - PI;
|
||||||
|
angle += angleDiff2 * 0.2;
|
||||||
|
acted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float noise2 = rand(vUv * 1000. + fract(uTime / 1000.) + 0.2);
|
// ---- PRIORITY 5: WANDER (fallback) ----
|
||||||
|
if (!acted) {
|
||||||
float sampleAhead = smell(applyOffsetToPos(pos, vec2(cos(angle), sin(angle)) * sampleDistance), isCarrying);
|
if (noise < 0.33) {
|
||||||
float sampleLeft = smell(applyOffsetToPos(pos, vec2(cos(angle - ANT_ROTATION_ANGLE), sin(angle - ANT_ROTATION_ANGLE)) * sampleDistance), isCarrying);
|
angle += ANT_ROTATION_ANGLE;
|
||||||
float sampleRight = smell(applyOffsetToPos(pos, vec2(cos(angle + ANT_ROTATION_ANGLE), sin(angle + ANT_ROTATION_ANGLE)) * sampleDistance), isCarrying);
|
} else if (noise < 0.66) {
|
||||||
|
angle -= ANT_ROTATION_ANGLE;
|
||||||
if (sampleAhead > sampleLeft && sampleAhead > sampleRight) {
|
}
|
||||||
// don't change direction
|
float noise2 = rand(vUv * 1000. + fract(uTime / 1000.) + 0.2);
|
||||||
} else if (sampleLeft > sampleAhead && sampleLeft > sampleRight) {
|
if (noise2 > 0.5) {
|
||||||
angle -= ANT_ROTATION_ANGLE; // steer left
|
angle += ANT_ROTATION_ANGLE * 2.;
|
||||||
} else if (sampleRight > sampleAhead && sampleRight > sampleLeft) {
|
} else {
|
||||||
angle += ANT_ROTATION_ANGLE; // steer right
|
angle -= ANT_ROTATION_ANGLE * 2.;
|
||||||
} else if (noise < 0.33) {
|
}
|
||||||
angle += ANT_ROTATION_ANGLE; // no smell detected, do random movement
|
|
||||||
} else if (noise < 0.66) {
|
|
||||||
angle -= ANT_ROTATION_ANGLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noise2 > 0.5) {
|
// ---- MOVEMENT APPLICATION ----
|
||||||
angle += ANT_ROTATION_ANGLE * 2.;
|
vec2 offset = vec2(cos(angle), sin(angle));
|
||||||
} else {
|
pos = applyOffsetToPos(pos, offset);
|
||||||
angle -= ANT_ROTATION_ANGLE * 2.;
|
|
||||||
|
if (fract(pos.x) == 0. || fract(pos.y) == 0. || (!wasObstacle && isObstacle(pos + offset * cellSize))) {
|
||||||
|
angle += PI * (noise - 0.5);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
vec2 offset = vec2(cos(angle), sin(angle));
|
// ---- PICKUP ----
|
||||||
pos = applyOffsetToPos(pos, offset);
|
if (isCarrying == 0.) {
|
||||||
|
float cellMatId = texture(tWorld, roundUvToCellCenter(pos)).x;
|
||||||
|
int cellMatInt = int(cellMatId);
|
||||||
|
|
||||||
if (fract(pos.x) == 0. || fract(pos.y) == 0. || (!wasObstacle && isObstacle(pos + offset * cellSize))) {
|
if (cellMatInt == MAT_FOOD) {
|
||||||
angle += PI * (noise - 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCarrying == 0.) {
|
|
||||||
float cellMatId = texture(tWorld, roundUvToCellCenter(pos)).x;
|
|
||||||
int cellMatInt = int(cellMatId);
|
|
||||||
|
|
||||||
if (cellMatInt == MAT_FOOD) {
|
|
||||||
// food pickup (existing foraging behavior)
|
|
||||||
isCarrying = 1.;
|
|
||||||
cargoMaterialId = cellMatId;
|
|
||||||
angle += PI;
|
|
||||||
storage = getMaxScentStorage(vUv);
|
|
||||||
} else if (cellMatInt != MAT_AIR && cellMatInt != MAT_HOME) {
|
|
||||||
// check if diggable powder material
|
|
||||||
vec4 props = texelFetch(uMaterialProps, ivec2(cellMatInt, 0), 0);
|
|
||||||
float behavior = props.r;
|
|
||||||
float hardness = props.b;
|
|
||||||
if (behavior == BEHAVIOR_POWDER && hardness <= ANT_CARRY_STRENGTH) {
|
|
||||||
isCarrying = 1.;
|
isCarrying = 1.;
|
||||||
cargoMaterialId = cellMatId;
|
cargoMaterialId = cellMatId;
|
||||||
angle += PI;
|
angle += PI;
|
||||||
storage = getMaxScentStorage(vUv);
|
storage = getMaxScentStorage(vUv);
|
||||||
|
} else if (cellMatInt != MAT_AIR && cellMatInt != MAT_HOME) {
|
||||||
|
vec4 props = texelFetch(uMaterialProps, ivec2(cellMatInt, 0), 0);
|
||||||
|
float behavior = props.r;
|
||||||
|
float hardness = props.b;
|
||||||
|
if (behavior == BEHAVIOR_POWDER && hardness <= ANT_CARRY_STRENGTH) {
|
||||||
|
isCarrying = 1.;
|
||||||
|
cargoMaterialId = cellMatId;
|
||||||
|
angle += PI;
|
||||||
|
storage = getMaxScentStorage(vUv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tryDropFood(pos)) {
|
|
||||||
storage = getMaxScentStorage(vUv);
|
|
||||||
|
|
||||||
if (isCarrying == 1.) {
|
|
||||||
isCarrying = 0.;
|
|
||||||
cargoMaterialId = 0.;
|
|
||||||
angle += PI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// deposit carried powder material when standing on air with solid ground below
|
|
||||||
if (isCarrying == 1. && int(cargoMaterialId) != MAT_FOOD) {
|
|
||||||
float cellMatId = texture(tWorld, roundUvToCellCenter(pos)).x;
|
|
||||||
if (int(cellMatId) == MAT_AIR) {
|
|
||||||
vec2 belowPos = pos - vec2(0., cellSize);
|
|
||||||
float belowMatId = texture(tWorld, roundUvToCellCenter(belowPos)).x;
|
|
||||||
if (int(belowMatId) != MAT_AIR || belowPos.y <= 0.) {
|
|
||||||
isCarrying = 0.;
|
|
||||||
// keep cargoMaterialId set so discretize can read it this frame
|
|
||||||
angle += PI;
|
|
||||||
storage = getMaxScentStorage(vUv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end !isFalling
|
} // end !isFalling
|
||||||
|
|
||||||
FragColor = vec4(
|
FragColor = vec4(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue