Godot 3.0: 2D Visibility with Ray-casting

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello in this tutorial I'm going to show you how to use ray casting in Godot 3.0 to implement visibility we're going to make an automated turret that will shoot at you but only if you can see you so here's your situation you have your player and you have these turrets that when they detect the player are going to try to shoot them and so you can see if I enter the circular detection area of the turret it will see me and start shooting at me and this is all fine this is just being done with area enter and area exit so it knows whether it can see me or not the problem is that even if I'm up here on the other side of the wall the turret is still shooting at me and I want to make sure that the turret can't shoot at me if it can't see me so I need this turret to have some sort of limit to its visibility before we go too far let's take a look at how the code is organized right now this is the player script it is just detecting the four directional keys and moving the player in whatever direction is indicated we're not going to change anything about the players movement to do the visibility now the turret the turret has got a couple things going on so it has a detect radius variable that's how big that visibility circle is the bullet sorry the turret has a is a kinematic body but it has an area 2d attached to it with a collision shape and that area 2d is called visibility that's the thing that you saw in yellow and we're setting its detect radius in the script so that you can set it in your inspector here and then in the ready function we will take the shape and set its rate create a circle shape and set its radius and then we also have a fire rate and the bullet scene so that it can do the shooting and it'll just instance a bullet every X number of seconds or X number of times per second this is the color this is that pale yellow that I was using to do the outline of the visibility circle and then we have a variable to store our target and can shoot is for the fire rate so what's going on is we have our body entered and body exited when the area detects a body entering if we already have a target we ignore it because we already have a target but if we don't then we make that body the target and then I'm using modulate to just dim the dim the sprite and make it red when it sees a target so that we have a visual confirmation when the visibility are sorry when the visibility body exited signal happens then if the body that exited was the target then our target gets set to null and we go back to dim we don't have a target anymore and then in our physics process we are just updating if we have a target we rotate to point at the target and if can shoot lets us we shoot shoot spawns a bullet and sets the bullet off on its way and lastly we have the update being called here in the physics process so that we can do our draw function which is which is drawing a circle to show that detect radius so that's what we're seeing here when we enter the player is set as the target bullets are spawned and when we exit the target is null so it doesn't have anything to shoot at now if you want to download this starting project I'll link it in the description below so you can start out at the same point that I do for moving forward and making the visibility work so to start with we want to get rid of this if we have a target we're not just going to turn and point at it and shoot we're going to get rid of that instead we're going to try to aim and we're gonna see if we can hit it so this is where our visibility is gonna come into play is we're gonna check to see if we can hit something and so the first thing we need to do is we need to test array towards our target and in order to visualize this we're also going to add some some visualizations so I'm gonna go up here and add a variable called hit pause that's going to be the position of where our raycast hit so that we can draw it on the screen and so in our aim function we're going to get the space state this is the get the world 2d direct space state and this when you use it inside a physics process is a snapshot of the physics state during this frame so where every physics body is and what it's doing and you can access a lot of things about the physics of the world using this object and so we're gonna cast array so our ray is going to use the space state and the command is intersect ray and what this method takes as its arguments are a starting point so that's going to be our position an ending point that's the target position and these by the way are in global coordinates so these are not relative to the turret these are going to be global and then the third argument is a list of objects to exclude well we want to exclude ourself we don't want the array to hit ourselves or it wouldn't travel any distance at all and then finally you have a fourth parameter and that is collision masks that you can use to say what things should I hit and what things should I avoid well the turret itself has a collision mask that's set to detect the environment layer and the player layer and it doesn't see any of the other physics layers well that's perfect for us so rather than create a new mask we're just gonna use the parent bodies mask okay and we can actually put this on the next line if you want to make it a little more readable so we're gonna cast array from the position from from our turret towards the targets position which is going to be the center of the target remember we're gonna ignore ourself and we're also going to only count the objects that are in the collision mask which are going to be the walls and the player and now result is either going to be null or have something in it so if we got a result then we hit something so if our ray hits something it might have been the player it might have been a wall so let's set our hit pause to the result dot position and this result object has a lot of different properties in it one of them is the position of the thing we hit if result if the result Collider has the name player well then we should shoot at it right this is where we should set our rotation and point it at the player so we want to go from the targets position to our position angle and we want to say if can shoot then we'll call shoot to the target position target dot position and so that's what we were doing before right if we're allowed to shoot then we call shoot but the reason that we stored this right here this hit pause variable because so that we can also visualize what's going on with our race so we can make sure that things are working right so if we go over to our draw method where we're drawing our circle we're also going to draw a line at the along the raycast to the hit position where it hit so we can see where that ray intersects the wall or whatever it ran into so we're going to say if there's a target we want to draw this line so we're going to do two things we're going to draw a circle and that circle is going to be at the hit position now draw a circle and all these draw all these draw up functions actually are in relative coordinates they're relative to the parent body so this is going to be relative to the turret so we need to do some little some calculations to take the hit pause and subtract the position of the turret we also need to cancel out the rotation of the turret because it might be rotated we'll set the radius which doesn't have to be that big and then we'll set the color now I'm actually going to go up here and I'm just gonna define this up here laser color because I have I think already saved yeah there we go I'm just going to use this which is a kind of pale ish red color that we can use this is like our our aiming laser on our turrets gun so we draw the circle we're also going to draw a line and for drawing the line we need to do pretty much the same thing we need to start at the turret so we'll put it at 0 0 that means again relative to the turret that's where we're gonna go and then we're going to take hit pause - position and we're gonna rotate it again to cancel out the rotation and we'll put that in the same laser color and there we go so now we have if we have a target we'll be drawing that line towards it and marking the spot where we hit oh and one other thing we'll do is instead of making the turret light up red win it when the body enters the circle we only want to do it if it can actually see it so if you can actually see it will set the color to red all right so let's run it and see what happens so here's our player when we enter shooting us as it did before but now you can see that ray and where it's and where it's hitting the player now if I'm out here and I go up here now the arrays being casted and we can see where it's hitting the wall before it's able to reach the player so it cannot and shouldn't light up and shoot now that all works pretty well but there is one small problem which you'll notice if you go over here near a corner let's say I hug the wall here you can see as I get down here this still counts as the turret not being able to see me but of course the turret is trying to shoot array only at the center of the player so it's shooting towards this position and it can't see that position but it can't see all of this part of the player so if you can see all this part of the player it ought to still be shooting at them so we need to actually improve this a bit by casting more than one ray what we actually want to do is cast Ray's towards the four corners of the player and if any of them contact the player then we should still be able to shoot towards them so I'm going to start by the aim getting the targets extense and this is so I can tell where their corners of the target are so we're going to get its collision shaped 2d node and we're going to check its shape extents now if we just do that the problem is going to be that we are right at the very very corners of the collision shape which are going to be against the wall and so our Ray shape could all right say our raycast could still hit the corner of the wall so what we want to do is actually back that out a little bit from the from the corners so I'm just going to subtract about five pixels from each corner just a very small amount but we're just a little bit inside the collision shape now so now we have those extents now we have now we have to list the four corners so I'm going to call them northwest-southeast and so on so the northwest corner is the target is the target position minus the target extents that's the northwest corner the southeast corner is the target position plus the target extents right because that's down into the right now the Northeast is up and to the right so we need to take the target position and we need to add a vector with the target extents X and a negative of the target extents Y and then finally for the southwest we need to do the opposite of that so the target position plus a vector two of the negative target extents X and the positive of the tar extend that way and then we have our four corners that we need to shoot at so we'll just do a loop in here four paws in and we'll just go Northwest northeast southeast southwest order doesn't really matter for these and then each time we do that we're going to cast array so our place we're shooting at is now the pause whatever pause we're on in the loop and then if there's a result then we want to do the same thing we did before but if we're going to visualize all of this then I want hit pause to actually be a list I wanted to be an array of positions so we're gonna set that to a blank array an empty array and then when we do hit something we're going to append it hit pause dot append the result position and then we still shoot towards the player if we hit it that way if we didn't hit the player we will have a list of the positions that we did hit on the wall and we can see where these are going this is again just so that we can visualize so down in our draw section instead of just doing one we're gonna say for hit in hit pause and we're gonna draw the line in the circle using those coordinates alright now let's see what happens when we run it I'm going to go up here to the wall and I made a typo with vector2 all right now if we go up here there you can see the four rays getting cast towards the player and that way now when I'm here I'm shooting but the problem is now of course I'm shooting I'm not shooting at the Ray position I'm still shooting at the center of the player so we want to shoot at the place that we saw so we'll add that we want to shoot at the position that we saw the Ray hit and now if we get over here on the corner you can see we're shooting oh just along that gap and still hitting the player in the corner sometimes alright so that isn't bad but the problem is that that we have is out here in the open area we're gonna wind up shooting at the corner of the player because that's the first one it sees so it starts shooting at that one and that looks a little weird why is Italy shooting at one edge of the player right over here it's always shooting at that one or if we're down here it's only going to be shooting at one of the corners so we can fix that by adding in our lifts it's list of positions we can also put the target position in here that which is again the center of the sprite so now it'll shoot at five and so now we're going to have five rays shooting towards the player fives not that many more and now what we want to do is since we since we checked the center position first right we check the center position first then our result is going to be at that position and we'll shoot if we want to speed things up a little bit or be a little bit more efficient than what we can do is say if we did find a one that worked then we can break out we don't need to check the other remaining we don't need to check the other remaining corners if we already found one that works and started shooting right there's no point in doing that after we've already shot so that means that when we're here we're gonna cast one ray and that's all we need when we're up here we may have to cast more than one when we're at a obscured position we may need to cast more than one but once we've found one that works we just keep using that one and now when we're inside in a clear area it still looks like it used to that we're shooting straight towards the player so now you have some really nice functional turrets and you can add a bunch of them to the map and get a lot of Duggal situations where the player can't find a place to hide and might even be getting attacked by multiple turrets at the same time and you can make for a much more challenging experience if that's what you're going for of course there are many more applications of this that you could use instead of the turrets firing bullets that Ray itself could be the weapon of the of the turret shooting its laser towards you you can vary it a little bit give it a little bit of randomness to have it you know sometimes shoot to the sides you can even do ricochets if you want so if you have something like if you have something like this situation here the Ray comes out and hits the wall you you cast a second ray from here at the reflected angle in this direction and then you see what that hits and you can put that in a loop and do that as many times as you want there are lots of possibilities so I hope this video was useful to you if you like this kind of content please let me know in the in the comments below and I'll try and make more happy here requests if you haven't subscribed please do so you'll see the next videos and I'll see you next time you
Info
Channel: KidsCanCode
Views: 52,392
Rating: undefined out of 5
Keywords: programming, coding, tutorial, lesson, gamedev, game development, godot, godot engine
Id: lNADi7kTDJ4
Channel Id: undefined
Length: 22min 21sec (1341 seconds)
Published: Sat Mar 10 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.