Archive 17/01/2023.

Move npc head to track player movement

GodMan

So I have a class for my NPC, and I have some code to manually track the players movement by making the npc slightly rotate his head. So it’s a little rough but I might be using the wrong event type. It seems like the players position is never updated.

void AIMelee::LookAtPlayer(StringHash eventType, VariantMap& eventData)
{
	head = node_->GetChild("head", true);
	Node* player = scene_->GetChild("Player", true);

	Vector3 worldPos = head->GetWorldPosition();
	Vector3 headWorldTarget = head->GetWorldPosition() + worldPos *  Vector3(player->GetWorldPosition().x_, player->GetWorldPosition().y_, 0.5f);
	head->LookAt(headWorldTarget, Vector3::RIGHT);

	// debug lines
	DebugRenderer *dbgRenderer = scene_->GetComponent<DebugRenderer>();
	dbgRenderer->AddLine(headWorldTarget, head->GetWorldPosition(), Color::YELLOW);
}

The event is:
SubscribeToEvent(E_POSTUPDATE, URHO3D_HANDLER(AIMelee, LookAtPlayer));

SirNate0

The head target should just be the players world position. Or possibly the players world position +0.5f in the Z direction. Don’t multiply that by the head’s world position.

Also, I’ll assume it’s because of how your skeleton is set up, but if not - why are you using RIGHT for the up direction in LookAt?

GodMan

@SirNate0 Apologies for the late reply. I amended the code to this:

	head = node_->GetChild("head", true);
	Node* player = scene_->GetChild("Player", true);

	Vector3 worldPos = player->GetWorldPosition();
	Vector3 headWorldTarget = worldPos;
	head->LookAt(headWorldTarget, Vector3::RIGHT);

It does seem to work much better now. I need to limit the heads pitch, because if I don’t I get strange behavior. Also the Y-Axis is up for this skeleton not Z-Axis.

GodMan

So I came up with this code, but it does not seem to work once the npc is facing another direction. Once the npc moves from it’s default spawn orientation. It gives a pretty close solutions, but does not seem to adjust for the new npc direction changes. His head rotates strangely. Maybe someone can spot something.

	head = node_->GetChild("head", true);
	Node* player = scene_->GetChild("Player", true);

	Vector3 worldPos = player->GetWorldPosition();
	Quaternion rot = player->GetWorldRotation();
	Vector3 headWorldTarget = rot * worldPos;

	Vector3 lookDir = (headWorldTarget - head->GetWorldPosition()).Normalized();
	Quaternion headDir;
	headDir.FromLookRotation(lookDir);

	Vector3 headWorldTarget2 = head->GetWorldPosition() + headDir * Vector3(0, 0, -1);
	head->LookAt(headWorldTarget2, Vector3::RIGHT);