playMaker

Author Topic: Raycast no hit as vector3  (Read 6451 times)

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2511
  • Mender of the past
    • Cleverous
Raycast no hit as vector3
« on: December 18, 2013, 10:33:45 PM »
How do I get the Raycast Action to give me the vector3 of its direction + distance.

Currently it's only giving me data on hits, but I want it to fill the hit info even if it misses so I'm getting a live feed of data that I can rely on actively rather than the raycast missing and it using historical data from old hits.

(doesn't make sense? I need the raycast data stored even if it hits nothing.)
Products by Cleverous
|| Vault Core : Database
|| Vault Inventory : Multiplayer Inventory
|| Vault Attributes : Character Stats
|| That Hurt! : Dmg Floaties
|| Quinn : 3D

dasbin

  • Junior Playmaker
  • **
  • Posts: 92
Re: Raycast no hit as vector3
« Reply #1 on: December 19, 2013, 12:27:03 AM »
I'm curious why you need to do this. Why not just test for a hit, and if there's no hit, just copy your input direction and distance to whatever result you need (because that *is* the result).

jeanfabre

  • Administrator
  • Hero Member
  • *****
  • Posts: 15500
  • Official Playmaker Support
Re: Raycast no hit as vector3
« Reply #2 on: December 19, 2013, 02:26:32 AM »
Hi,

 a bit lost here as well.

Do you want to save pool of results? like buffering raycasting info so that you can access them later or work on that bunch of infos?

bye,

 Jean

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2511
  • Mender of the past
    • Cleverous
Re: Raycast no hit as vector3
« Reply #3 on: December 19, 2013, 06:48:06 AM »
It's because of a weird setup I have for this AI system I'm working on, but I've found other places I could use this as well.

It's setup for a trapped agent, when he finds himself against a huge wall the raycast never doesn't hit so I use the didHit bool and test for false to trigger a change event since if it didnt hit then he found some clear area to go to. The hitPoint is used to throw together a vector that puts his destination into the clear area and its never simply 'forward', its using an animated float to move the ray around so direction is changing all the time.

It would be good to be able to just keep storing the data from the ray, rather than find out its false, then have to do a different set of vector calcs when the ray could just store the value I need in the same vector that the system is already using.

If I used the hitDistance to draw a line for graphics on a laser or something for example then unless there was a hit then the distance would be the last hit (wrong) unless I did a separate calc for when the ray misses.
Products by Cleverous
|| Vault Core : Database
|| Vault Inventory : Multiplayer Inventory
|| Vault Attributes : Character Stats
|| That Hurt! : Dmg Floaties
|| Quinn : 3D

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2511
  • Mender of the past
    • Cleverous
Re: Raycast no hit as vector3
« Reply #4 on: December 19, 2013, 09:13:43 AM »
I figured out how to do it (derp). Copied and modified the Raycast action. Will post up the results after I test it more.
Products by Cleverous
|| Vault Core : Database
|| Vault Inventory : Multiplayer Inventory
|| Vault Attributes : Character Stats
|| That Hurt! : Dmg Floaties
|| Quinn : 3D

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2511
  • Mender of the past
    • Cleverous
Re: Raycast no hit as vector3
« Reply #5 on: December 19, 2013, 05:35:54 PM »
Take a look at this action.

  • Choose a target object instead of a direction
  • No Hit Event
  • Store Distance On Miss
  • Debug for GameObject targetting (math I didn't originally understand! :) )

I'm completely stoked that its (apparently..) actually working, if someone would test it a bit and critique the code changes I'd appreciate it very much as I don't code and this was all basically done by my rummaging around the unity scripting reference for solutions. Kinda feels like a personal milestone in learning more code for me. I'm going to try to work with it tonight and look for more improvement ideas.

Took forever to figure out that FsmGameObjects are not GameObjects :P

Code: [Select]
// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.

using UnityEngine;
using System.Collections;

namespace HutongGames.PlayMaker.Actions
{
[ActionCategory(ActionCategory.Physics)]
[Tooltip("Casts a Ray against all Colliders in the scene. Use either a Game Object or Vector3 world position as the origin of the ray. Use GetRaycastInfo to get more detailed info.")]
public class Raycast2 : FsmStateAction
{
        //[ActionSection("Setup Raycast")]
 
[Tooltip("Start ray at game object position. \nOr use From Position parameter.")]
public FsmOwnerDefault fromGameObject;

[Tooltip("Start ray at a vector3 world position. \nOr use Game Object parameter.")]
public FsmVector3 fromPosition;

[Tooltip("A vector3 direction vector")]
public FsmVector3 direction;

[Tooltip("A Target Object for the direction. Overrides Direction if used.")]
public FsmGameObject endObject;

[Tooltip("Cast the ray in world or local space. Note if no Game Object is specfied, the direction is in world space.")]
public Space space;

[Tooltip("The length of the ray. Set to -1 for infinity.")]
public FsmFloat distance;

        [ActionSection("Result")]

[Tooltip("Event to send if the ray hits an object.")]
[UIHint(UIHint.Variable)]
public FsmEvent hitEvent;

[Tooltip("Event to send if the ray does not hit any object.")]
[UIHint(UIHint.Variable)]
public FsmEvent noHitEvent;

[Tooltip("Set a bool variable to true if hit something, otherwise false.")]
[UIHint(UIHint.Variable)]
public FsmBool storeDidHit;

[Tooltip("Store the game object hit in a variable.")]
[UIHint(UIHint.Variable)]
public FsmGameObject storeHitObject;

        [UIHint(UIHint.Variable)]
        [Tooltip("Get the world position of the ray hit point and store it in a variable.")]
        public FsmVector3 storeHitPoint;

        [UIHint(UIHint.Variable)]
        [Tooltip("Get the normal at the hit point and store it in a variable.")]
        public FsmVector3 storeHitNormal;

        [UIHint(UIHint.Variable)]
        [Tooltip("Get the distance along the ray to the hit point and store it in a variable.")]
        public FsmFloat storeHitDistance;

[Tooltip("If true the script will store hitDistance regardless of whether or not the ray hit something.")]
public FsmBool storeDistanceOnMiss;

        [ActionSection("Filter")]

        [Tooltip("Set how often to cast a ray. 0 = once, don't repeat; 1 = everyFrame; 2 = every other frame... \nSince raycasts can get expensive use the highest repeat interval you can get away with.")]
        public FsmInt repeatInterval;

        [UIHint(UIHint.Layer)]
        [Tooltip("Pick only from these layers.")]
        public FsmInt[] layerMask;

        [Tooltip("Invert the mask, so you pick from all layers except those defined above.")]
        public FsmBool invertMask;

[ActionSection("Debug")]

[Tooltip("The color to use for the debug line.")]
public FsmColor debugColor;

[Tooltip("Draw a debug line. Note: Check Gizmos in the Game View to see it in game.")]
public FsmBool debug;

int repeat;

public override void Reset()
{
fromGameObject = null;
fromPosition = new FsmVector3 { UseVariable = true };
direction = new FsmVector3 { UseVariable = true };
endObject = new FsmGameObject { UseVariable = true };
space = Space.Self;
distance = 100;
hitEvent = null;
noHitEvent = null;
storeDidHit = null;
storeHitObject = null;
    storeHitPoint = null;
    storeHitNormal = null;
    storeHitDistance = null;
storeDistanceOnMiss = true;
repeatInterval = 1;
layerMask = new FsmInt[0];
invertMask = false;
debugColor = Color.yellow;
debug = false;

}

public override void OnEnter()
{
DoRaycast();

if (repeatInterval.Value == 0)
{
Finish();
}
}

public override void OnUpdate()
{
repeat--;

if (repeat == 0)
{
DoRaycast();
}
}

void DoRaycast()
{
repeat = repeatInterval.Value;

if (distance.Value == 0)
{
return;
}

var goFr = Fsm.GetOwnerDefaultTarget(fromGameObject);
var originPos = goFr != null ? goFr.transform.position : fromPosition.Value;
var rayLength = Mathf.Infinity;
var goTo = endObject.Value;
var dirVector = direction.Value;
var next = true;

if (distance.Value > 0 )
{
rayLength = distance.Value;
}

if (goTo != null)
{
dirVector = goTo.transform.position - originPos;
next = false;
}

if (goFr != null && space == Space.Self && next)
{
dirVector = goFr.transform.TransformDirection(direction.Value);
}

RaycastHit hitInfo;
Physics.Raycast(originPos, dirVector, out hitInfo, rayLength, ActionHelpers.LayerArrayToLayerMask(layerMask, invertMask.Value));

Fsm.RaycastHitInfo = hitInfo;
var didHit = hitInfo.collider != null;
storeDidHit.Value = didHit;

if (didHit)
{
storeHitObject.Value = hitInfo.collider.collider.gameObject;
                storeHitPoint.Value = Fsm.RaycastHitInfo.point;
storeHitNormal.Value = Fsm.RaycastHitInfo.normal;
                storeHitDistance.Value = Fsm.RaycastHitInfo.distance;
Fsm.Event(hitEvent);
}

if (!didHit)
{
Fsm.Event(noHitEvent);
}

if (!didHit & storeDistanceOnMiss.Value)
{
storeHitDistance.Value = rayLength;
}

if (debug.Value && next)
{
var debugRayLength = Mathf.Min(rayLength, 1000);
Debug.DrawLine(originPos, originPos + dirVector * debugRayLength, debugColor.Value);
Debug.Log("Using Direction Based Debug");
}

if (debug.Value && !next)
{
var debugRayLength = Mathf.Min(rayLength, 1000);
var d = (goTo.transform.position - originPos).normalized * debugRayLength + originPos;
Debug.DrawLine(originPos, d, debugColor.Value);
Debug.Log("Using Object Based Debug");
}
}
}
}

Products by Cleverous
|| Vault Core : Database
|| Vault Inventory : Multiplayer Inventory
|| Vault Attributes : Character Stats
|| That Hurt! : Dmg Floaties
|| Quinn : 3D

dasbin

  • Junior Playmaker
  • **
  • Posts: 92
Re: Raycast no hit as vector3
« Reply #6 on: December 19, 2013, 05:48:51 PM »
I also made myself a "Raycast To Object" action for various reasons and find it useful, but check out Unity's Linecast functionality which is essentially an easier way of doing the same.

I still don't get why you're wanting to store a "miss" distance etc. Found your explanation quite confusing which might just be my fault. An Event for a miss can already be sent by 1) Setting an Event to call on a Hit, and 2) Adding a Finished transition to the state (so if the Hit event doesn't get called, the Finish will and you know it's a miss). The direction and distance of the missed ray will be exactly equal to your input direction and distance, which you must already have as variables somewhere. (The animated float you mentioned). It takes about five seconds to add a separate state and Set VectorXYZ action to set these on a raycast miss, right?
Anyway, if that five seconds bothers you more than writing your code above, well... good you on, I guess!
« Last Edit: December 19, 2013, 05:55:32 PM by dasbin »

Lane

  • Administrator
  • Hero Member
  • *****
  • Posts: 2511
  • Mender of the past
    • Cleverous
Re: Raycast no hit as vector3
« Reply #7 on: December 19, 2013, 07:26:49 PM »
Since I'm firing it every frame and not exiting the state then I don't use the transition events. I'm using the data from the raycast on every frame so it can't be inaccurate information, else the other FSM's using the data break down.

Do I absolutely need to do that? No, but I wouldn't get anywhere if I didn't experiment with the system design. Digging in and doing the code in this action taught me a whole lot about C#, scripting in Unity, FSM variables and such, so I see a lot of benefit to it. I like to be efficient, but I'll take an opportunity to 'waste time' and learn more because it's going to open more doors elsewhere.

I also like trying to find more interesting ways to design FSM's and the extra ray options helped me keep it all in one state.

I'll look into the Linecast stuff next, thanks for the tip!
Products by Cleverous
|| Vault Core : Database
|| Vault Inventory : Multiplayer Inventory
|| Vault Attributes : Character Stats
|| That Hurt! : Dmg Floaties
|| Quinn : 3D