[Community Project] WIP Weather & Water Shader

Fish Avoidance

Hey everybody,

Since interest in project has picked up… a LOT, I’ve been getting a lot of messages relating to fish avoiding obstacles. I was never able to get quite working how I wanted it to. Let’s look at the code:


FVector AFlockFish::AvoidObstacle()
{
	FVector actorLocation = ->GetActorLocation();
	FVector forwardVector = (->GetActorForwardVector() * AvoidanceDistance) + actorLocation;

	FHitResult OutHitResult;
	FCollisionQueryParams Line(FName("Collision param"), true);
	bool const bHadBlockingHit = GetWorld()->LineTraceSingleByChannel(OutHitResult, actorLocation, forwardVector, COLLISION_TRACE, Line);
	FVector returnVector = FVector(0, 0, 0);
	float distanceToBound = distanceToBound = (->GetActorLocation() - OutHitResult.ImpactPoint).Size();
	if (bHadBlockingHit)
	{
		if (OutHitResult.ImpactPoint.Z > ->GetActorLocation().Z + FishInteractionSphere->GetScaledSphereRadius())
		{	
			returnVector.Z += (1 / (distanceToBound * (1 / AvoidForceMultiplier))) * -1;
		}
		else if (OutHitResult.ImpactPoint.Z < ->GetActorLocation().Z - FishInteractionSphere->GetScaledSphereRadius())
		{
			returnVector.Z += (1 / (distanceToBound * (1 / AvoidForceMultiplier))) * 1;
		}

		if (OutHitResult.ImpactPoint.X > ->GetActorLocation().X)
		{
			returnVector.X += (1 / (distanceToBound * (1 / AvoidForceMultiplier))) * -1;
		}
		else if (OutHitResult.ImpactPoint.X < ->GetActorLocation().X)
		{
			
			returnVector.X += (1 / (distanceToBound * (1 / AvoidForceMultiplier))) * 1;
		}

		if (OutHitResult.ImpactPoint.Y > ->GetActorLocation().Y)
		{
			returnVector.Y += (1 / (distanceToBound * (1 / AvoidForceMultiplier))) * -1;
		}
		else if (OutHitResult.ImpactPoint.Y < ->GetActorLocation().Y)
		{

			returnVector.Y  += (1 / (distanceToBound * (1 / AvoidForceMultiplier))) * 1;
		}

		returnVector.Normalize();
		FVector avoidance = returnVector * AvoidanceForce;
		return avoidance;
	}
	return FVector(0, 0, 0);
}

I think I was getting close to a solution, so I’ll write my thoughts out here and if anybody wants to give it a shot, or attempt another method then by all means please do it!

I basically set up a line trace on each AFlockFish that is created from the front of them, forward. I believe the distance they see in front of them is a modifiable value. When the line detects a collision, I attempt to add a vector to the fish’s current rotation.


	// Set Rotation 
	FVector targetRotation = (Fish->getSeekTarget() - Fish->GetActorLocation() + Fish->AvoidObstacle());
	FRotator leaderRotation = FRotationMatrix::MakeFromX(targetRotation).Rotator();
	leaderRotation = FMath::RInterpTo(Fish->GetActorRotation(), leaderRotation, delta, Fish->turnSpeed);
	Fish->setRotation(leaderRotation);

What should do is, when the fish detects an object in front of it, it should take into account the x,y, and z value differences between itself and the location of the hit, and the distance from the object. The fish will then flip all of the points of the hit location in relation to itself as its seeking target for the next tick. So say the fish is swimming downwards, it notices it’s about to hit a rock. The rock is -Z downwards from the fish, +X in relation to the fish, and -Y in relation to the fish or (+Xi, -Yi, -Zi) where i is the actual numeric value of the offset. means the fish will seek (-Xif, +Yif, +Zif) the next tick, where f is the force value determined by the distance to the object, and the modifiable AvoidForceMultiplier set by the user. What SHOULD achieve is a state where the fish will only lightly avoid obstacles in the distance, but veer strongly away from obstacles right in front of it.

Anyway there was the gist of how it was supposed to work. I can’t remember where I left off - I did have moderate success, but I was never able to get it fully working.

Hope one of you can figure it out :D,