Playmaker Forum

PlayMaker Help & Tips => PlayMaker Help => Topic started by: curb47 on February 18, 2021, 04:08:06 AM

Title: Raycast logic mind-melt [SOLVED]
Post by: curb47 on February 18, 2021, 04:08:06 AM
Hello everyone,

I've got a situation with some logic that I can't work out, and my attempts always end up with the loop exceeding 1000 error...

I've got a Titan enemy, that is armed with 2 BFGs. When it fires the weapons the lasers are a continuous stream, like a hosepipe squirting water, not a pulse fire.

(https://i.postimg.cc/cHsWqWJ4/Raycast.jpg)

(https://i.postimg.cc/wTRSGMkQ/Raycast2.jpg)

When your player spaceship is hit by the raycast, it needs to send an event to drain your health for each frame you are in the path of the laser/raycast.

(https://i.postimg.cc/rpp6gJZK/didHit.jpg)

And when you leave the line of fire, the 'draining health' event stops.

(https://i.postimg.cc/fR2qWh5R/noHit.jpg)

The problem I'm having is sending the Hit Event from the raycast stops the raycast. I tried sending the Hit Event to another state with the same raycast on in, that then registers the No Hit Event instead, and when this is triggered it sends back to the first raycast state. This is where the exceeding 1000 error hits in.

I actually think it's because I have 2 raycasts, left gun and right gun, on both states and perhaps I should separate them into their own FSMs?

Any tips would be awesome, thank you.

J.
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 18, 2021, 04:50:59 AM
i've always found adding a wait of 0.1-0.2 had the same affect. Yes per frame will deal damage per frame but you won't hit the 1,000 requests that limit you.

even a wait of 0.05-0.005 may work, but it gets sketchy. I.E you WILL miss collisions.

and yes you should seperate right and left, THOUGH have them react to the same variable.

Edit: but on second thought, your player mesh can't possibly hit both raycasts simultaneously, so seperation isn't necessary.

Just try the slight delay. It should work while providing the same effect.   

Also hit event may not be necessary, if you you store a hit object variable (I.E player is tagged as player), when the ray hits compare tag to your player object and only send an event based on the compare tag event. STILL keep the slight wait delay at the end of the returning state.

This also helps in separating a player collision with say an asteroid collision. An asteroid tagged as asteroid may have a collision event on itself, making it explode when the raycast hits per frame ( it only explodes once) but the raycast still freed up to find the player (with a short wait).
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 18, 2021, 05:11:43 AM
Thanks RAVEN,

I've separated the raycasts to 2 different FSMs, and changed the hit detection to a tag switch, because I don't want the player's health to be drained if the lasers hit a passing asteroid or another enemy.

Now the logic gets stuck on the 2nd state (see picture) because the stored Hit Object doesn't refresh when the player leaves the line of fire.

In your suggestion, where do you add the Wait of 0.1-0.2? Do you mean untick any Every Frame boxes, set up a FINISHED-loop to Start, with the wait in there somewhere?

Thanks for your help.

(https://i.postimg.cc/0NjhRCgF/Newraycast.jpg)
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 18, 2021, 05:23:29 AM
once that action is complete add an empty action with wait of 'whatever' returning to the state that had the raycast. get me?
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 18, 2021, 05:24:48 AM
ALSO set game object , the variable you created with the tag to none (game object) with set game object in the same state as the wait.
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 18, 2021, 05:30:17 AM
ok, sorry, so the compare tag event spat out a game object, using that same object, set the game object to no object, subtract your damage, wait "whatever' return to the raycast event. This means that the game object ( now clear) is ready to be accepted agin by your raycast (be it an asteroid or a player). i think thats a better description

But now i'm looking at your screenshots, store hit object is right, store hit point ok if you have a particle on collision, in which case take the hit normal as well, to get your particle to fire at the right angle.

Then the compare tag, ONLY have the true event, then in the raycast event add a second compare for collide tag asteroid but this shouldn't need a wait, you destroy it, set tag to destroyed, raycast no longe rtriggers, also if the player object is destroyed then set on destruction a tag of destroyed so the raycast ignores it. Any compare tags should be set to every frame.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 18, 2021, 05:50:13 AM
Okay, I think I understand what you mean. I have one State with the raycast action & drawline etc on in and the raycast stores any (or none) hit objects, I could set that as an action sequence. Then at the end it spits out to a state that has a tag switch and wait (approx 0.1) on it, and if the tag switch is not player spaceship it loops back to the state with the raycast on it. If the tag switch is TRUE then it goes to a state that sends an event to activate the drain player health FSM, then back to the raycast state.

So essentially it's setting up a continuous loop around 2 or 3 states?

Thanks for your help, I can see the mist clearing.
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 18, 2021, 06:05:05 AM
Yep, you've got the hang of it, but you don't want it colliding with EVERYTHING, thats why we avoid "on hit event". on hit event collects data on ANY hit, to be more efficient, AND more accurate, limit what the raycast is looking for. So player is a tag, after your raycast add a compare tag action with player as the tag. Directly after that make another compare tag for asteroid, then after that make another one for planet. What happens after you get a hit from one of these tags is up to you.But things that take continuous damage will be a loop. Make it explode, make the ray end, make it take damage. But it will only respond to tags. Also l like i said, if your taking hit point data, you probably also want normal data. Hit point sets the position of a particle effect, normal essentially sets the rotation of an effect.

As far as a loop goes yes, but on the raycast compare tag, you can add a reaction to asteroids, player, enemy, any object that could be hit by that ray, you add them by compare tag "different tag" ( a seperate compare tag action, still on every frame) things that lose damage, give them a delay, things that explode instantly, don't need a delay, just change their tag to something the raycast isn't looking for and it will be ignored (exploded is what i have used in the past) once player reaches zero health get it to explode at the same time you tag it exploded, the rays will no longer detect it.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 18, 2021, 06:20:45 AM
Awesome! Thank you, that's great help.

I will set up your suggestion and get back to you.

Cheers.

J.
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 18, 2021, 06:28:31 AM
ANOTHER thing ive found is raycast from your player object may collide with the collider itself, in which case make a child cube (use the the visual form to make it sit JUST past your main collider, then remove ALL data (mesh renderer etc, leaving an empty game object, name it whatever you want.), make it REALLY small, then physically move it past your main player collider, THEN any raycasts, don't set as your main mesh, set as from the cube whatever you named it. The ray point you have created (which exists out of your main collider, unity physics is very complicated, more complicated than common sense would dictate, but when your talking physics objects, the aforementioned might be helpful. otherwise, your on your way), won't have anything to collide with. I may have rambled, but you're getting there, this may act as a reference when you're dealing with physics.

Glad i could help. bed time. signing out :)

feel free to post more, i'll try and answer anything else tomorrow, but you may find another user to answer beforehand.
either way. good luck
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 19, 2021, 01:34:15 AM
Hi RAVEN,

Well, it's another one of those days... up at 5am to tackle this before work.

I've gone through your workflow, and I am missing something. It's still melting my mind.

(https://i.postimg.cc/nc3sJS1H/Raycast-Loop2.jpg)

In regard to you other point about setting up raycasts to avoid colliding with meshes, I think I have it set up right. The image below shows the main object with collider (sphere), and the empty game objects L1 and L2 are the raycast start points:

(https://i.postimg.cc/wMZj1Z4J/titan.jpg)

(https://i.postimg.cc/rpMFRSjh/raycast-Point.jpg)

I will go through your previous posts again...
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 19, 2021, 02:04:50 AM
Hi again,

So, I've gone through it again and this is what I've ended up with...

(https://i.postimg.cc/XqRs7KFL/New-State1.jpg)

(https://i.postimg.cc/2SDf0hJn/New-State2.jpg)

(https://i.postimg.cc/5t9WV1f0/New-State3.jpg)
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 19, 2021, 03:53:14 AM
ok so looking at your screen shots, i think you have over thought the process. Why is player health not a global, that any fsm can subtract from. You are sending events to another fsm when a single fsm could just subtract from a global int/float.
as far as your colliders go, yes, you have done it right. The main sphere cannot possibly collide with a raycast. so its all good.

Now you've posted screenshots of an fsm i would think would work, what are you experiencing that isn't what you intended?
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 19, 2021, 04:22:49 AM
one other thing, you have 'set layer' on every one of these on frame calls. Set layer should only be called once, every game i have made always starts with an 'instantiate' object, ALL other objects are disabled. The instantiate object loads everything you NEED into the level, and sets things like layers, sound volume, creates prefabs, activates game objects already instantiated etc. What i'm suggesting may take A LOT more explanation. If so, let me know.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 19, 2021, 04:36:06 AM
Hi RAVEN,

I'm avoiding using global ints and floats. My understanding is that they're quite demanding. I guess, if the global variable isn't being updated constantly, it's not so demanding?

It would make it a million times easier if i could just use a global.

The issue I'm having with the raycast now is... how do i explain this...

When the Titan starts firing, and misses you, the Raycast & Draw Line are good - full length lasers, but when you 'cross the beam' it detects the hit and sends the event, but the Draw Line doesn't stop at your spaceship, it stays full length.

Another result I had was the Draw Line detached from the Titan and just sat there stationary, until you cross back into the raycast, when it would be destroyed and re-drawn as a new laser from the Titan.

I've played around with Destroy on Exit, and various other bits n bobs, but I can't get it right.

Title: Re: Raycast logic mind-melt
Post by: curb47 on February 19, 2021, 04:44:21 AM
Yes, I have a pooler system set up, prefabs etc. I didn't think about 'pre-fabing' and pooling the Draw Line, it makes sense.

I could then, after the raycast, spawn a Draw Line and set the start/end?
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 19, 2021, 05:00:52 AM
Globals are your best friend, Find actions are what is bad (find closest is inefficient because it needs to send a raycast to ALL objects to find the closest, find child (or is it get child, dunno.) is inefficient because it has to search ALL child objects to find the child you want. If you give a direct target from a tag, or a global variable it's the most direct path to the object you are referencing.

Use globals.

with your problem, try adding the line draw to the damage event, DON'T add the raycast. It should still take the last point it was given and continue drawing the line. Otherwise, seperate the draw line from the damage fsm completely. i.e have an fsm that ONLY controls the line draw, based on hit (again add tag compare to this fsm)
Title: Re: Raycast logic mind-melt
Post by: RAVEN001 on February 19, 2021, 06:19:08 AM
do you have a testing device? i.e you are talking a lot about efficiency so your deployment is mobile? Testing in the editor DOES NOT indicate how it will work on a mobile device. Build and test on a device regularly. Camera distance, shaders, shadows, load times, there  are a lot of of reasons to test on a device, i'd recommend at least a 1080 screen device, cos lets face it 2k display is now the standard, 4k is primo and 8k is samsungs new standard. My point is, editor plays DON'T represent how the game will actually play on a device.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 23, 2021, 02:19:54 AM

with your problem, try adding the line draw to the damage event, DON'T add the raycast. It should still take the last point it was given and continue drawing the line. Otherwise, seperate the draw line from the damage fsm completely. i.e have an fsm that ONLY controls the line draw, based on hit (again add tag compare to this fsm)

The but I need the raycast to be continuous because that defines the hit point/end point of the draw line. If there's no raycast, the line doesn't move as the Titan rotates to find the player spaceship. Know what I mean?

The draw line needs the 'every frame' updated position of the raycast hit point.

If I were to turn the Titan laser fire into a pulse fire weapon I can do that, no problem, that's how I've done the player spaceship lasers, but I'm trying to add variation to my enemies, and having the continuous 'hosepipe' laser is really what I'm after.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 23, 2021, 02:20:36 AM
I'm really struggling with this. It's kinda doing my head in.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 23, 2021, 03:14:22 AM
Maybe I actually need to have 2 raycasts on separate FSMs for each laser? One to drive the Draw Line, with no events or anything, and one to handle the hit detection which can trigger damage etc.

I'm under the impression that raycast is expensive, so maybe it's not the best solution, but I can't think of any other way.
Title: Re: Raycast logic mind-melt
Post by: djaydino on February 23, 2021, 07:19:43 AM
Hi.
You could maybe store the object hit and use a 'Fsm Game Object Compare (Tag)' on a 'damage handler' fsm.
and/or user 'Store Did Hit' and use a 'Fsm Bool Test' on the 'damage handler' fsm.

on the 'damage handler' fsm you can set a delay :

State 1 check raycast fsm (Fsm Game Object Compare (Tag)/Fsm Bool Test)
State 2 Do damage
State 3 Delay (for example wait 0.1)
Go back to state 1
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 23, 2021, 08:51:41 AM
Hello,

Thanks, I'm at work right now so will need to re-address this later, or tomorrow morning.
Title: Re: Raycast logic mind-melt
Post by: curb47 on February 24, 2021, 04:15:53 AM
Hi,

So, this is what I've ended up with, and it works pretty well...

(https://i.postimg.cc/SsMNSX0W/laser2.jpg)

The global event 'Fire' is activated when the Titan is in range of the player.

1. Spawn Laser, spawns a pooled Prefab of the Laser which has the Draw Line action, and two child objects for the Start & End of the Draw Line.

2. Main Raycast spits out the raycast, and sets the position (every frame) of the End object in the laser/Draw Line prefab. It also stores any hit objects and has a Game Object Tag Switch, one for the player and one for other enemies. If nothing is Hit after a Wait of 3, it goes to FINISHED which sends an event to stop firing lasers/De-spawn the pooled Laser/Draw Line prefab and start the Titan hunting again.

If the player is hit by the raycast, it goes to the hitPlayer event which zips through the Subtract Player Health state which simply sends a global event to the player spaceship to reduce health by 1 (int), and then on to Aux Raycast. I did not want to use a global variable for Health because I've worked really hard at completely stripping my game of global variables.

3. Aux Raycast is a copy of Main Raycast, but with no Tag Switch for the player spaceship and is mainly used to continue driving the Draw Line laser prefab. It has a Wait of 0.3 then FINISHED.

4. Clear Hit Object sets the hit object variable stored in Main Raycast to Null, so it doesn't instantly send the hitPlayer event.

The result is pretty much perfect. If the player is hit by the laser, it takes 1 off Health, and an additional 1 off Health for every Wait 0.3 the player is in the path of the laser. It's cool, because there are loads of other enemies doing different things, and sometimes it's not a case of simply flying out of the path of the lasers, so things get quite hectic and exciting!

I'll mark the thread as SOLVED. I've done plenty of game testing and it seems really solid.

Thanks.