Hello,
I’m coming back to finally read and answer some old threads on our forum
I’m not sure if this thread was fully resolved, I see in the last post you ask how to determine what enemy is hit using the ray-cast.
Your code seems OK (except missing FindBehavior, see below) and in general following the “3D FPS Game” template code is the simplest approach. To be clear what happens there:
-
We have a TEnemy class, a descendant of TCastleBehavior ( Behaviors | Manual | Castle Game Engine ) . We add an instance of TEnemy to anything that can be hit by a ray.
-
Each time you press the key / mouse button to shoot, we make a “ray cast” to see whether the ray hits anything that has TEnemy attached.
In the example code, we check MainViewport.TransformUnderMouse. This is actually a simple way of doing a “ray cast” – CGE makes a ray cast to determine the MainViewport.TransformUnderMouse value.
I see in your code you do a “ray cast” using MainViewport.Items.WorldRay(...) which is also perfectly OK, this is a way to check arbitrary ray (from any position, along any direction).
Once you have a RayCollision, you can look at the first object hit. It will be a TCastleTransform instance. To be safe, you can actually chose first TCastleTransform instance on RayCollision that is not csTransient . Though for TCastleScene, choosing just the first TCastleTransform instance on RayCollision by RayCollision[0] will be equally good.
Once you have this, you should check whether the given transform has TEnemy behavior, using ExampleTransform.FindBehavior(TEnemy). This bit seems missing from the screenshot of your code in Doom RPG-like game and questions about it - #48 by sthox .
In total, to account for everything I wrote, I can define a function like this:
{ Extract enemy hit, given RayCollision instance as input.
RayCollision instance may be obtained by using
@link(TCastleViewport.MouseRayHit)
or calling SomeViewport.Items.WorldRay(...).
Returns nil if we didn't hit any enemy. }
function GetEnemyFromRayCollision(const RayCollision: TRayCollision): TEnemy;
var
I: Integer;
T, FirstTransform: TCastleTransform;
begin
FirstTransform := nil;
if RayCollision <> nil then
for I := 0 to MouseRayHit.Count - 1 do
begin
T := MouseRayHit[I].Item;
if not (csTransient in T.ComponentStyle) then
begin
FirstTransform := T;
break;
end;
end;
if FirstTransform <> nil then
Result := FirstTransform.FindBehavior(TEnemy)
else
Result := nil;
end;
And then in your code, you can do
if Event.IsMouseButton(...) then
begin
RayCollision := MainViewport.Items.WorldRay(...);
try
Enemy := GetEnemyFromRayCollision(RayCollision);
if Enemy <> nil then
begin
// act on Enemy being hit
end;
finally FreeAndNil(RayCollision) end;
end;
I am thinking how to make writing things like GetEnemyFromRayCollision unnecessary / simpler in future games 
Let me know if this helps, and / or if there are any remaining pending questions here.