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 pathIntDy = lastExtState.a;
|
||||
|
||||
bool movementProcessed = false;
|
||||
|
||||
// calculate this ant's index from its UV position in the texture
|
||||
ivec2 texSize = textureSize(tLastState, 0);
|
||||
int antIndex = int(vUv.y * float(texSize.y)) * texSize.x + int(vUv.x * float(texSize.x));
|
||||
|
|
@ -163,114 +161,125 @@ void main() {
|
|||
}
|
||||
|
||||
if (!isFalling) {
|
||||
bool acted = false;
|
||||
|
||||
if (isCarrying == 0.) {
|
||||
if (noise < 0.33) {
|
||||
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
|
||||
// ---- PRIORITY 1: DEPOSIT ----
|
||||
if (!acted && isCarrying == 1.) {
|
||||
float cellMatId = texture(tWorld, roundUvToCellCenter(pos)).x;
|
||||
vec4 props = texelFetch(uMaterialProps, ivec2(int(cellMatId), 0), 0);
|
||||
|
||||
// check cell below for diggable material
|
||||
vec2 belowUv = roundUvToCellCenter(pos - vec2(0., cellSize));
|
||||
float belowDigMat = texture(tWorld, belowUv).x;
|
||||
vec4 belowProps = texelFetch(uMaterialProps, ivec2(int(belowDigMat), 0), 0);
|
||||
// carrying food and at home -> drop food
|
||||
if (int(cargoMaterialId) == MAT_FOOD && tryDropFood(pos)) {
|
||||
isCarrying = 0.;
|
||||
cargoMaterialId = 0.;
|
||||
angle += PI;
|
||||
storage = getMaxScentStorage(vUv);
|
||||
acted = true;
|
||||
}
|
||||
|
||||
if (belowProps.r == BEHAVIOR_POWDER && belowProps.b <= ANT_CARRY_STRENGTH) {
|
||||
// diggable material below — bias downward
|
||||
float downwardBias = -PI * 0.5; // straight down
|
||||
float angleDiff = downwardBias - angle;
|
||||
// carrying powder and on surface (air cell, solid below) -> deposit
|
||||
if (!acted && int(cargoMaterialId) != MAT_FOOD) {
|
||||
if (int(cellMatId) == MAT_AIR) {
|
||||
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;
|
||||
// gentle steering toward down (20% blend)
|
||||
angle += angleDiff * 0.2;
|
||||
angle += angleDiff * 0.3;
|
||||
#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
|
||||
|
||||
float noise2 = rand(vUv * 1000. + fract(uTime / 1000.) + 0.2);
|
||||
|
||||
float sampleAhead = smell(applyOffsetToPos(pos, vec2(cos(angle), sin(angle)) * sampleDistance), isCarrying);
|
||||
float sampleLeft = smell(applyOffsetToPos(pos, vec2(cos(angle - ANT_ROTATION_ANGLE), sin(angle - ANT_ROTATION_ANGLE)) * sampleDistance), isCarrying);
|
||||
float sampleRight = smell(applyOffsetToPos(pos, vec2(cos(angle + ANT_ROTATION_ANGLE), sin(angle + ANT_ROTATION_ANGLE)) * sampleDistance), isCarrying);
|
||||
|
||||
if (sampleAhead > sampleLeft && sampleAhead > sampleRight) {
|
||||
// don't change direction
|
||||
} else if (sampleLeft > sampleAhead && sampleLeft > sampleRight) {
|
||||
angle -= ANT_ROTATION_ANGLE; // steer left
|
||||
} else if (sampleRight > sampleAhead && sampleRight > sampleLeft) {
|
||||
angle += ANT_ROTATION_ANGLE; // steer right
|
||||
} else if (noise < 0.33) {
|
||||
angle += ANT_ROTATION_ANGLE; // no smell detected, do random movement
|
||||
// ---- PRIORITY 5: WANDER (fallback) ----
|
||||
if (!acted) {
|
||||
if (noise < 0.33) {
|
||||
angle += ANT_ROTATION_ANGLE;
|
||||
} else if (noise < 0.66) {
|
||||
angle -= ANT_ROTATION_ANGLE;
|
||||
}
|
||||
|
||||
float noise2 = rand(vUv * 1000. + fract(uTime / 1000.) + 0.2);
|
||||
if (noise2 > 0.5) {
|
||||
angle += ANT_ROTATION_ANGLE * 2.;
|
||||
} else {
|
||||
|
|
@ -278,6 +287,7 @@ void main() {
|
|||
}
|
||||
}
|
||||
|
||||
// ---- MOVEMENT APPLICATION ----
|
||||
vec2 offset = vec2(cos(angle), sin(angle));
|
||||
pos = applyOffsetToPos(pos, offset);
|
||||
|
||||
|
|
@ -285,18 +295,17 @@ void main() {
|
|||
angle += PI * (noise - 0.5);
|
||||
}
|
||||
|
||||
// ---- PICKUP ----
|
||||
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;
|
||||
|
|
@ -308,32 +317,6 @@ void main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
FragColor = vec4(
|
||||
|
|
|
|||
Loading…
Reference in a new issue