How to raycast using a mouse to hit an object?

Hi LY coders :-), i want to know how to raycast in lumberyard c++ using mouse left click…Thanks in Advance

Hi @akashgamedev

One of the easiest ways to do this is with Flowgraph using the Input:MouseButtonInfo and Input:MouseRayCast nodes like in this image:

The XML For this is here if you want to copy/paste it into your own Flowgraph:

 <Graph Description="" Group="">
<Nodes>
<Node Id="1" Class="Input:MouseRayCast" pos="-50,-190,0" flags="1">
<Inputs RayType="0" EntitiesToIgnore="0" IgnoreBackfaces="0"/>
</Node>
<Node Id="2" Class="Input:MouseButtonInfo" pos="-340,-190,0" flags="1">
<Inputs MouseButton="1" MouseWheel="0"/>
</Node>
<Node Id="3" Class="Game:Start" pos="-530,-190,0" flags="1">
<Inputs InGame="1" InEditor="1"/>
</Node>
<Node Id="4" Class="Input:MouseCursor" pos="-340,-280,0" flags="1">
<Inputs />
</Node>
<Node Id="5" Name="Show the mouse cursor" Class="_comment" pos="-340,-300,0" flags="1"/>
<Node Id="6" Name="Listen for mouse button events" Class="_comment" pos="-340,-220,0" flags="1"/>
</Nodes>
<Edges>
<Edge nodeIn="1" nodeOut="2" portIn="Enable" portOut="MousePressed" enabled="1"/>
<Edge nodeIn="1" nodeOut="2" portIn="Disable" portOut="MouseReleased" enabled="1"/>
<Edge nodeIn="2" nodeOut="3" portIn="Enable" portOut="output" enabled="1"/>
<Edge nodeIn="4" nodeOut="3" portIn="Show" portOut="output" enabled="1"/>
</Edges>
</Graph>

If you want to do this in C++ it looks like this:

	// derive your class from IInputEventListener and add yourself as an input listener to capture mouse events
bool OnInputEvent( const SInputEvent& event) override
{
if(event.keyId = eKI_MousePosition)
{
m_mouseX = event.screenPosition.x;
m_mouseY = event.screenPosition.y;
}
}
void PerformRayCast()
{
// invert the mouse y for the raycast
float invMouseY = static_cast<float>(gEnv->pRenderer->GetHeight()) - m_mouseY;
// get the direction of our raycast
Vec3 start(0,0,0);
gEnv->pRenderer->UnProjectFromScreen(m_mouseX, invMouseY, 0, &start.x, &start.y, &start.z);
Vec3 end(0,0,0);
gEnv->pRenderer->UnProjectFromScreen(m_mouseX, invMouseY, 1, &end.x, &end.y, &end.z);
Vec3 direction = end - start;
direction.Normalize();
// set up our raycast options - you can choose what entities to ignore and much more, but this // example just returns the first object hit const unsigned int flags = rwi_stop_at_pierceable | rwi_colltype_any | rwi_ignore_back_faces;
const entity_query_flags entityTypes = ent_all;
const int maxHits = 1;
ray_hit hit;
if (gEnv->pPhysicalWorld->RayWorldIntersection(start, direction * gEnv->p3DEngine->GetMaxViewDistance(), entityTypes, flags, &hit, maxHits))
{
// this is the hit position and normal Vec3 hitPosition = hit.pt;
Vec3 hitNormal = hit.n;
// did we hit an entity?
IEntity *pEntity = nullptr;
if(hit.pCollider)
{
pEntity = gEnv->pEntitySystem->GetEntityFromPhysics(hit.pCollider);
// do something with the hit entity
}
}
}

The above code is basically what the CFlowMouseRayCast class does in FlowMouseInfo.cpp though I stripped out the Flowgraph specific stuff.

You can also use access the RayWorldIntersection function in Lua. Let me know if you’d like an example of that.

Thank you petrocket this could be very useful and yes am using c++ not by flowgraph… :slight_smile:

Hello petrocket Please write an example RayWorldIntersection function in Lua.

Hi @Rafael,

Here
is a basic implementation of the same general idea in Lua. Not quite the exact same, but similar. In this case, there are three scripts: Two on your main character and one on an object being hit by a raycast (say an enemy AI). The scripts are very bare bones, but they should get
you started:

Script #1 character_raycast

5192-character-raycast.txt (992 Bytes)character-raycast.txt

Script #2 raycast_controller

5193-raycast-controller.txt (1.87 KB)raycast-controller.txt

Script #3 raycast_ai

5194-raycast-ai.txt (445 Bytes)raycast-ai.txt

Keep in mind that the mouse input in script #1 was not a default and was configured - refer here for more info:

http://docs.aws.amazon.com/lumberyard/latest/developerguide/controllers-azframework-input.html

And that the first two scripts will only work as written if they are both on the same entity due to the GamplayNotificationId, but this can be easily changed.

Let me know if this helps you out!

If you are interested in doing this in c++, I have a step by step tutorial on achieving this along with visual debug line.

Raycasting with Lumberyard in C++

If you have any questions, feel free to ask.

Tried out the Lua script linked above and it gives errors about GameplayNotificationId and points to lines in all three scripts where this is used.
Any ideas how to fix it for newer version of LY?

You’ll better use StarterGame scripts for as an example about how something works in lua or how to use some feature in lua.

I think they always works for actual version of engine.

For an instance try to open 1.16.0.0\dev\StarterGame\Scripts\AI\AIController.lua

then press ctrl+f type “RayCast” and you’ll find some info about how they doing RayCast in this version of engine

For everyone who got problems with unprojecting mousecoordinates and raycast in Lumberyard 1.18. I found a workaround by using the old CryUnproject with the new AZ:Camera. You should turn the AZ:Module into a CryhookModule. For the debug line follow horvay´s tutorial. Feel free to ask any Questions.


	void raycast(float distance, int colisionFlags){
AZ::Vector2 cursorPos = AZ::Vector2::CreateZero();
UiCursorBus::BroadcastResult(cursorPos, &UiCursorBus::Events::GetUiCursorPosition);
float fov, nearClip, farClip;
Camera::CameraRequestBus::BroadcastResult(fov, &Camera::CameraComponentRequests::GetFovRadians);
Camera::CameraRequestBus::BroadcastResult(nearClip, &Camera::CameraComponentRequests::GetNearClipDistance);
Camera::CameraRequestBus::BroadcastResult(farClip, &Camera::CameraComponentRequests::GetFarClipDistance);
auto &cam = GetISystem()->GetViewCamera();
float invMouseY = static_cast<float>(gEnv->pRenderer->GetHeight()) - cursorPos.GetY();
//Compare AZ:Camera FOV with CryCameraFOV -> Set Right FOV in Cry for Unproject
if (cam.GetFov() != fov)
cam.SetFrustum(gEnv->pRenderer->GetWidth(), gEnv->pRenderer->GetHeight(), fov, nearClip, farClip);
// CryVectores for Unproject
Vec3 startCry, endCry, directionCry;
cam.Unproject(Vec3(cursorPos.GetX(), invMouseY, 0.0f), startCry); gEnv->pSystem->GetViewCamera().Unproject(Vec3(cursorPos.GetX(), invMouseY, 1.0f), endCry);
directionCry = endCry - startCry;
directionCry = directionCry.GetNormalizedSafe();
//CryVec -> AZ VEC
AZ::Vector3 start(startCry.x, startCry.y, startCry.z);
AZ::Vector3 direction(directionCry.x, directionCry.y, directionCry.z);
//AZ Raycast
AzFramework::PhysicsSystemRequests::RayCastConfiguration config;
config.m_origin = start;
config.m_direction = direction;
config.m_maxHits = 1;
config.m_maxDistance = distance;
AzFramework::PhysicsSystemRequests::RayCastResult result;
EBUS_EVENT_RESULT(result, AzFramework::PhysicsSystemRequestBus, RayCast, config);
//work here with the result
}