I don't know if raycasting would do the same thing, but I really liked how your enemy really felt like he ran the corner looking for you, didn't see you, paused a moment in confusion, then gave up and wandered away.
One cool option is also breadcrumbs! You spawn small invisible objects behind the player that disappear over time and you make the enemies go in that direction...
Hacky solution most of the time. Especially when u wanna add in different movement patterns. At most it should be used in combination w actual context steering behaviors (and pathfinding), not as the enemies' main form of navigation
Yes, a "last seen position" given to every enemy is a clever solution. When the enemy loses sight of the player, it should go towards a "last seen position" that it has, saved in its own script. When the enemy reaches this "last seen position", it has two possibilities: 1. Either from this new position it is able to see the player and will continue chasing them. Or 2. After getting to this new position, the player is still out of sight (they escaped), and the enemy returns to idle. It doesn't require a lot of memory, only a positon vector that needs to be assigned to an enemy when the player gets out of sight, and that is cleared if the enemy has line of sight on the player. At least that would be my solution to this problem.
@@pulsarhappy7514 Yeah, this is exactly the same thing I thought about. Breadcrumbs solution feels like enemies could still find the player although he already managed to get behind two obstacles what could by kind of annoying. It would feel you are fighting dogs which sniff their way to you. Also, these breadcrumbs should be visible only to enemies which had LOS when player was running away.
Nice idea. You could get some cool emergent behaviour too if you extended this to enemies. They could drop 'Alarm' bread crumbs, and then any other enemies that pass these will be drawn into the pursuit too.
very deceptively simple and performant way that's actually pretty realistic is for the enemy to move not towards the player, but towards the last spot they saw the player at. It's also cool because it introduces stealth elements where you CAN lose the enemy if you find a place to hide once line of sight is broken, but if they're following you closely they'll probably be able to see you after they reach the point. If you want to make it even better, you can make them go into a "search" state where they wander around randomly for a bit if they reach the point but still can't see you. If you want to get more complicated but make them even smarter, weight the random directions away from the direction they were just moving so they search an where you probably are and don't backtrack. Then put a timer on the search state so they go back to idle if they can't find you after a few seconds. That's how enemies in stealth games usually behave anyway.
This is definitely a great option, and if performance ever becomes an issue with my implementation, I’d likely move to something like this. But check out the clip at the 3 minute mark in the video - I think this is where my version shines, because Last Seen At wouldn’t work fully there
storing a “last known player direction” vector the enemy could follow for some small amount of time if they still do not have line-of-sight after they reach the last known player location could potentially approximate more complex pathing
@@NateVolker I think this depends on the map design. If there are lots of nooks and crannies to hide in, then @Challacade' s method might produce psychic-seeming AIs in some situations. In that case your idea to store last known direction with last known location could work well (or other heuristics, such as moving towards the tile which can see the most if player not sighted from last known location, etc). It seems that @Challacade' s probably takes into account their intended maps too.
@@NateVolker I think that's good because it makes it easier for the player to understand their thought process. They can see the enemy go in a straight line until they get sight of the player again, making it clear that evading sight is a reasonable option and they're not just using A* to track the player no matter what.
I'm so glad to finally be at a point where I can watch a short video like this and know exactly what I need to do to implement it into my game. This definitely beats having to watch 2 hr tutorials that have to explain each and every step.
how can i implement it to my game? i dont know the name of these things, the dots that you make when you move and stuff can you please help me find a good video about it
I was just watching a talk by Rami Ismail and he mentioned how you should fake smart AI instead of making actual smart AI. Although your set up so far seems more about pathfinding rather than making "smart" enemies, so you haven't dug deep into AI behavior yet. But it's something to consider. There was also a study done for one of the Halo games where players felt enemies with the same AI but dealt more damage were "smarter" even though the behavior was identical
I agree that hard coded behavior is easier to setup and easier to control, but I don't agree that it's the better solution in all cases and I believe with the ongoing advancement in AI it's only a matter of time for 'intelligent' enemies to replace hard coded behavior.
It wasn't that they dealt more damage, it was that they had more health. As a result they stayed alive longer for people to actually notice the behaviors the enemy AI had.
Something which might improve the performance is to calculate the line of sight by checking if the line intersects with any of the collision geometry inside the rectangle formed by the end-points of the line of sight. This way you don’t have to do a bunch of collision checkes iteratively over the line’s length, but instead check only once per line. Not sure how your collision is set up, but this might benefit the performance, especially if you have to recalculate line of sight for every tile for enemy pathfinding too
You would also want to only check LOS if the enemy or player moves and otherwise just reuse the existing calculation. This could also let you implement a lot of optimizations with pathfinding. For example, you could have the enemy "remember" where the player last was and take into account level geometry to make a guess if it should have LOS. Take an example where the player runs behind a wall, blocking LOS. You could then remember the position where they lost line of sight and try to move towards that, using a collider to move away from any walls, and assume that the enemy would not have LOS until it gets there. Then at the target point, recalculate line of sight. I'm positive there's a lot of issues with this though, as I thought about this for approximately 30 seconds.
Was going to say something similar to the breadcrumb idea, have the enemy store a sequence of last known player positions within it's detection radius, then have enemies pursue the latest position it still has LOS of. The breadcrumb is good because it only stores one copy of those positions though. One note about the breadcrumb idea is to only drop them if the player is within an enemy's detection radius to save performance. Another thing to consider maybe is having the enemy give up if it reaches the last position that was within it's detection radius and it still doesn't see the player. Then at that point it can choose a random direction to pursue based on the trajectory of the player's previous path. Say like within a 30 degree cone of the direction the enemy is already traveling. This way the enemy doesn't know where the player is, but it still goes in a pretty good guess of a direction.
Nice use of a bi-directional path finding ^_^, as you already have states for your enemies, it would be fun to see some "Elite" enemies order their minions around with "regroup" "swarm" "hold" "attack" actions etc. also would be fun to see if the slimes could coordinate a pincer attack or do a "wall tackle"
Something that could really add to the enemy system is different enemies pursuing the player in different ways. Maybe something small and dumb like the slime will just go at the player, but maybe those projectile launching guys from the cloud area back away from the player, and can even fly off the stage. a ranged enemy wouldnt want to go towards the player, it would want to be at a range. I think it could add some depth where different enemies instead circle, flank, or kinda bait the player instead of just going straight at them.
Be careful comparing lists against lists. It can get very performance heavy. Usually A* only checks one cell at the enemy position at a time. Then uses neighbour checks. You get neighbours by carrying the grid with you. It's a whole thing but imo well worth the performance increase.
A momentum-based pursuit approach (both linear and angular) would be interesting to try to make work. It has a little more persistence than stop-at-last-location, but it also allows you an opportunity to cleverly hide. Or, base some enemies on logic of “scent” instead of “sight”. Could be a fun mix.
That was a really fascinating video, I'm very interested in the way you tackled the enemy navigation/pathfinding to work in your game. It's a very good solution to the problem, and I especially like how you were able to use it to also create idle patrol movement too. Great game art as well btw, love your style!
Bro, take care of your game's performance, to LOS, use a raycast, and to let the enemy chase the player even when he loses the LOS, make the enemy go to the last position when player was sighted, or use a AStar algorithm to pathfinding the closest path beetwen player and enemy
@@notadev9000sounds a lot more expensive than Astar, as its especifically optimized for that task, which doesnt seem to be the case of his algo... let alone for the cases he actually wants to do anythint else than follow the player in a straight line (strafe around, zigzag, hit n run, flee, etc)
@@robertonome2448 Actually it depends how much enemies he wants to have, neither of these solutions would be great with a lot of enemies. Calculating A* with hundreds of enemies and you have a game with 10 FPS , especially if you have many obstacles. I think the best would be to create some flow field
Very cool! One possible solution: You could make the enemy go to the last known position of the player's position (Store the player last position before it goes out of sight)
I think the simpler solution is fine though, especially for simpler enemies as it makes them easier to get off your tail. For more difficult enemies the more complex solution might feel more warranted.
have you looked into context based steering? its a system im using in my game that can create very complex behaviors for ai when you combine it with state machines. in a nutshell the enemy casts rays around them, each ray has its own "interest" which is calculated based on the dot product of the rays angle to the target point you gave the ai. interest also gets set to 0 when the ray collides with an obstacle (or anything you want the ai to avoid), and then the chosen direction for the ai to move is calculated by multiplying each rays angle with its interest and then adding all those values together. this system is great as it automatically allows ai agents to make microadjustments to their chosen direction based on whats happening around them. when you have large groups of enemies they will automatically avoid clumping up and the way they move around and avoid eachother and obstacles looks very lifelike. you can also create behaviors like strafing around the player in a circle very easily with a little math. you should really look up context based steering
Increasing enemy AI is another way of having a harder difficulty without it feeling artificial. Just increasing attack power from enemy attacks can only do so much.
What if you make the enemy remember the place the player was when the line of sight was last maintained? If it's broken, you make that point the new location to reach for the enemy. If there is still no line of sight with the player when it gets there, it returns to idle state. This also gives a realistic chance for the player to outrun the enemies.
For me the easiest and simplest solution in code is to activate a conditional that if the enemy stops seeing the player (due to an obstacle) to calculate 2 paths in angles in reference to the player's last position, so continue walking along a stretch mechanically, and be able to see the player again and continue the chase.
3:19 my suggestion is to set a vector2 to the players pos every frame as long as they’re in LOS. Then if the play goes out of LOS the enemy goes to that vector2 where the player last was in LOS. This is just how I would do it and I hope I explained it well! I love your devlogs and look forward to them every time!
Really impressed here at the creativity in your solution to the problem. I wouldn't change it except for performance should that become an issue. Beauty of indie dev games is this type of uniqueness
The “last known position” works fine, maybe a lot easier too. You save the position where the LOS was lost and your mob will walk there. In the meantime, if the LOS became valid again, the mob ignores the last known position. This ensures that in corners the mob will “see” the player and acquire it as a target.
Maybe this has been mentioned already, but I would definitely check out DDA algorithm. I just added a modified version of it to my game for raycasting movement making sure things stay within tiles flagged as walls. Modified in a way to not check every single unit step on that line from it's origin point, ei your enemy. If you run into performance issues you could use this method provided you assume collisions are set to some tile, then handle other special cases some other way.
One interesting way to have a more "non-enemy relationship" type of AI is through a Utility System that decides what Behavior Tree to execute based on its modular list of Considerations. Although, this is far easier said than done. If it turns out uber sick, I kinda wanna make a video like yours. Your channel and devlog adventures are an inspiration!
I started following this channel a while ago because I love the devlog detail and style. Altho this game type isn't really my thing. You've won me over and I'm actually really hyped for this game. And cant wait to play it
Make the NPC chase a point that represents the player's last known location. Update that location every time the line of sight check to the player succeeds. If the enemy reaches the last known location and the line of sight check to the player fails, then the NPC gives up and goes back to idle. This way when the player runs around a corner, the enemy will go to that corner to look for the player. For the player to escape, they'd need to quickly get out of line of sight of that corner before the enemy reaches it. A more complex but more effective addition to this would be for the player's movement direction to be added to the last known location object. When the enemy reaches the last known location, it could continue moving in the player's last known direction. This would force the player to have to quickly go around multiple corners to avoid the enemy finding them. This is more realistic and somewhat on par with human behaviour.
Another idea would be to keep track of the position where LOS was last true, then have the enemy move to that position if LOS ever goes false. So if the player goes behind the wall enemy will go to the place where the player disappeared. From there, it might be able to regain LOS unless the player goes behind another obstacle, in which case, the enemy goes back to idle, essentially having “lost track” of the player. 😊
I think it's way easier just having a "last tile I saw the player" as a target, going there, then if there is no LOS from that tile to the player get "confused" and randomly search, or go back to the default position/last patrol point. It makes more sense from a real world perspective and is way better for performance (no need to recalculate an entire LOS grid).
I think you should add a cool-down to weapons, it forces the players to use a variety of weapons but it doesn’t completely get rid of any weapons and it can be used strategically in combat, I also think you should be able to equip a permanent ability to a weapon also adding to the strategic aspect of combat and allowing the player to in a way customise their favourite weapon
The cool-down would work where each weapon has a certain amount of uses and when the player maxes out the weapons uses it takes a certain amount of time to recharge depending on the weapon, it’ll force the player to use a variety of weapons and form a unique play style depending on which weapons they use the most.
Tried the demo, really nice I like a lot the style, it remembers me of Minish cap. Found a couple of things you may already know, anyway in the clouds map on those platforms that start moving when you are in their center, if you drop a weapon when the platform reaches the new position it just falls down and you lose it. In the first forest instead, I swam to the east and found an invisible wall in the river. You may just place some rocks there, right now it feels strange. Lastly a slime followed me inside the water making a strange effect. Hope this may help you. Good job anyway I hope the final release will be even more fun!
Psychic enemies that always know where you are is one solution. Another is that once it loses LoS, that it heads to the last place it saw you, and maybe search around that area for a bit (add a question mark above its head etc.) The drawback is that this might be a bit too easy to cheese, and is only fitting on the dumbest of monsters. A sneaky solution to which being to have your player have one or more ghost objects that lags behind them. When the enemy loses sight of the player, the monster can do a LoS check of these ghost objects, and you can program in an Investigation state, where it pauses in confusion, before moving towards where your ghost object was last. Giving the opportunity for the player to get away entirely.
Love the update. You should consider having the enemies talk/interact with eachother when idle. Making them feel a little more alive. Maybe use different symbols like ! 😊 and ❤s.
A simpler way would be 1) the monster can try to keep going the direction it WAS going 2) the monster can kind of randomly move about in a dumb "search" until such time it DOES have los with the player so effectively the monster can go into a third mode, a 'searching' mode (like with a ? above its head maybe) where it first tries to keep going forwards for a few seconds and then randomly searches. My other thought and addendum to this is to have a monster keep track of nearby collisions to itself in all 8 cardinal directions, and so when randomly searching it would never try to go that way (into a wall) but instead pick other paths. I am trying to do a very similar thing but in 3D with no navmesh so wish me luck. Im going to attempt to use the above strategies in 3D - should be interesting
Alternative AI player tracking thats maybe easier or simpler- if enemies lose LOS while chasing then store the last known coord of player pos and set that as the next target location for the AI, if it gets there and player is still not in LOS then either cancel chase or start some kind of "search" motion pattern where it does a circle or figure 8 or triangle that lasts for X seconds before returning to idle or patrol behavior.
An idea is that whenever the player leaves an enemies line of sight, the enemy will walk towards the players last location. Once it reaches the last location, if it finds the player again, it can continue chasing, but if the player isn't near their last location then go back to idle state.
I think I would give the enemy a searching state. when it first enters this state, it continues towards where it last saw you, then goes a short direction in your last known velocity. if it hasn't found you by this point, it wanders for a bit then reenters idle state. having your own los data on the player seems useful though.
A simpler solution with less processing for recalculating tile data I would say as the player is being pursue and by enemy they will periodically drop bread 🍞 crumbs. These are just invisible vector or specific tile. So say you turn a corner if you dropped a breadcrumb the enemy will look to the last breadcrumb go to that and then see if the enemy is within LOS. Breadcrumb is a awesome solution. The tricky part is what is too frequent and what is not frequent enough for dropping breadcrumb. You could adjust depending on the enemy like part of their intellectual stat.
Oh saw it was suggested lol A* path finding is another for obstacle avoidance. Doesn't resolve the turning the corner how can they still see me if the player successfully got away
I don't know if you hand draw your levels or generate them, but you can generate path nodes either way and just have the enemies follow the nearest path that they last saw you along until they get tired of chasing you, as in via a time limit to their agitation. Basically, LoS would be the key metric, but once that's lost they could follow path nodes closest to where they last saw you and scan their radius while the timer counts down, unless LoS is picked back up, and then the timer restarts. If you don't know how to generate path nodes, there's several videos showing various techniques for it, and there might still be one that explains Unreal's automatic path node generator.
Another good way to make enemies look for player when they lose sight of him, is going to the last position the player was at before they lost sight of him and then checking if the player is still visible, because the system you have rn is very good but might cause an issue that makes chasing never end, just a suggestion feel free to take it or leave it, I also started developing my own game not long ago so it's always fun to see how other people do things😁
I would've just made the player periodically drop breadcrumbs, and if the enemy loses sight, it goes to the most recent breadcrumb. Then if he doesn't find you from there, you lost him. Seems a lot simpler to me, and also has some personality.
I'd consider make a line of sight cone effect, and have the monster patrol in a area around where the player was last scene. This then can treat it in a aware, caution and danger state. Then put indicators such as a 1-10 and based on proxminity, movement within a certian range and other noise raise alert state. You can also give different monsters natural behaviors and routes, that would make sense for yheir organic function. Tbis is in some games monsters will feed on other monsters, to for instance incresse their health if low. Theyll seek out and devour weaker monsters to restore their health before attacking. Or try to put obstacles or traps for the player, to slow the plsyer down so they can find weaker prey or a means to heal
A lot of people have been suggesting to make the enemy move towards the last seen location of the player, but as you have said, with this system, if the player turns multiple corners, the enemy wouldn't be able to follow the player. So I thought of an extension of this system. It's actually probably wayyyy more performance intensive than your solution and probably more complicating, so it's totally pointless and useless, but I will share it anyways. Instead of the enemy simply going towards the last seen location of the player, it also creates a checkpoint at that location. The checkpoint itself performs LOS checks for the player, and when the player get's out of the checkpoint's sight, it creates another checkpoint at the next last seen location of the player. In this way, a trail of checkpoints are created for the enemy to follow. Idk how to explain some of the details I thought of, so I just made ChatGPT summarize the system: "-When an enemy has a direct line of sight to the player, it actively pursues them. -If the player goes out of sight, such as by turning a corner, the enemy marks the last seen location with an invisible checkpoint. -These checkpoints are not merely static markers; they actively perform line of sight checks to detect the player. -If the player goes out of the checkpoint's line of sight, it triggers the creation of a new checkpoint at this new location where the player was last visible. -This results in a sequence or trail of checkpoints. -The enemy follows this trail of checkpoints to track the player's movements. -This allows the enemy to continue the pursuit even when the player has made multiple turns or maneuvers that break the direct line of sight. Checkpoints are destroyed in three scenarios: -When the enemy reaches a checkpoint. -When the enemy resumes direct chase after spotting the player again. -When the enemy stops the chase altogether. -Enemies only follow checkpoints when they are in an active chase state, having seen the player themselves. -The enemy always follows the most recent checkpoint within its field of view. The system is designed to enable the enemy to pursue the player over a complex path with multiple turns and corners, not just to the last point where the player was seen" This is overall probably extremely performance intensive cuz of all the line of sight checks, and makes things way more complicated than it needs to be. But maybe this can help spark a new idea or something? What do you think? Edit: Also forgot to mention that the chase state is either determined by the amount of time it has spent chasing, or the overall distance between the player and the enemy. The checkpoints themselves don't play a role in it. The checkpoints are simply for following and tracking.
I'm making a game in Godot where I solve the same problem. In Godot it is relatively easy, because it has built in support for doing an A* search on a tile map. My enemies have an idle state where they are just patrolling a path. When they get a line of sight to the player, they start chasing, using the A* algorithm. If they lose line of sight while chasing for more than a second or so, they will use the A* algorithm to find back to their idle patrolling area, and then go back to patrolling. My entire enemy class is only 117 lines of code, but I still need to implement animation states and attack patterns and so on. I only have the basic Patrol - Chase - Return Home cycle done. The A* algorithm probably already has several implementations in Lua, which you can download and use. Otherwise it is not very difficult to implement it yourself.
Give the enemy a Vector4 variable called something like chasePoint. As long as the enemy has line of sight of the player update the chasePoint so the first 2 floats equals the players current position, and the last 2 floats equals the players current direction. Should the enemy lose sight of the player they can use the chasePoint to move to the players last position, then they can search for the player by moving in the last direction they saw the player go.
I didn't expect the tile grid active state method. I was expecting it to use a look behind, and simply move toward the players last known position, until it regains los. You method allows for potential good solutions, like the enemy taking a shortcut around a barrier, vs always the chasing line. *It could make for an interesting enemy to combine the 2 ideas, but inverted,* so it looks for the gap in data and chooses the _opposite_ side as where the player just left. Intentionally, this enemy would instead of opting for chasing around an object, prioritize cutting the player off at the other side. That would make for an easily exploitable enemy, but very different than standard enemies, and nasty in combo with regulars, as you run and gun gets cut off.
The problem with this solution is that if the distance of the player and the mob is small the player never lose the mob, I think that instead of tile tracking the mob could just "remember" the direction the player was going the last time it saw the player, so it will go to the last position and when get there start going to the last direction it know... if the player walk around a tree at some point the mob will lose it if the player keep walking around keeping the mob outside the line of sight. Another interesting idea is instead of walking straight from point A to Point B, using something like a beizer curve based in the average last n directions of the player... something like if the player if walking around something the when lose LOS try to keep walking around instead of start to walking straight
A solution for your issue a friend of mine did in college for his thesis was prebaking a few paths around the map whenever a level was loaded and used a raycast to check if the enemy was in line of sight with it's target, if the target was in los they'd gravitate to the closest node on the path and follow the path towards the closest node to the player till los was achieved. Had some minor issues but seemed quite performant. I'm paraphrasing obviously but it's interesting how you both came to similar solutions.
My solution for enemy losing LOS: * When the enemy looses LOS, store the last location the player was at * Have the the enemy move to that location, * If the enemy still can't regain LOS by the game by the time it get's there change to a searching state * The enemy moves around randomly trying to regain LOS * If the enemy can't regain LOS within some defined period of time they stop and go back to idling.
4:15 toggling the grid LOS can make a difference between smart enemies and dumb enemies. And because the slime is dumb, I think it would make more sense if it only has the regular LOS and would not check the grid at all. You can set a bool variable to disable the grid LOS for some enemies and I think it would feel a lot nicer if some enemies that don't look smart would only check the regular LOS and some will look smarter and check everything
I loved the methods you chose. As a beginner, I was able to convey some of it. I'm using unity and have no idea how I can transfer the tile technique. I would be very happy if you could say something enlightening.
The enemy could walk to the last tile in which line of sight was true. Once it reaches there, if the player is still in pursue range and LOS is true, it resumes pursuing, otherwise it goes back to idle. I think this approach may not always work as intended and is easily picked up by the player but performance wise, it might be a better option.
you can cutdown on the amount of line of sight checks to save on number of computations you can probably have some sort of look up table where you can quickly check if there is line of sight between the tile the player stands on and any other tiles instead of preforming the check for every tile.
Very cool AI logic. I have wondered how to code a roaming mode for my enemies. This tile logic looks like it will work really well. Thanks for the great visuals on how it is broken down. Does any of your current courses explain how to setup this particular AI logic?
If the enemy can see the player, store the player location in a "last seen at" variable, then regardless of line of sight, move toward the last seen location.
The enemys need to have an search delay. When they cant find any point anymore that is connected to the player the would have an little time delay before they get back to idle. This way it feels a little more dynamic and not like that all of them give up immediately. To spice things up, make the delay a little bit random in an specific range so that some enemys give up early , some make normal moves and some chase the player a little bit longer as normal. To spice this also up, it would be neat to add an little dark cloud over the head of an enemy that has an very high delay stat..... this way for the player it look like some of them are so pissed off that they chase you longer as anyone else.
I normally use floodfill from the destination position in a 2d grid. As soon as I reach the starting position via floodfill, I backtrack through the values to get the shortest path to the destination.
I do LOS with a raycast from the enemy to the player. Add a layer mask for obstacles and if hit.collider!=null it means there is an obstacle in between, so LOS=false, else, LOS=true.
That tile checking thing seems like it would become quite resource-intensive but it is a pretty good baseline. Raycasting works but is fairly simplistic and could be fine for basic enemies, or for handling combat movements. I'd say raycasting is the equivalent of giving enemies a d-pad and letting them "play" the game, but it wouldn't necessarily lend itself to searching for a player who went out of sight. Your tile system could be improved substantially by simply checking only locations where the player could be given his movement speed and the obstacles in that radius. The player can only travel maybe 5 tiles in one second, which means that unless the game has some kind of teleport or speed-boosting abilities, the player could only be within a 5 tile radius of the last known position, extending by 5 tiles for every second that passes by "last seen". Then, you can ignore all tiles which are obstacles to give the enemy a "most likely path", which they can investigate, then abandon if the player is not found within a certain time (the time they abandon should be randomized between a range to make it feel more dynamic). Even if the game does have speed boosting abilities or teleports, this information does not need to be conveyed to all enemies. Meaning that "dumber" enemies would give up pursuit more easily, but smarter ones may get info like "player used speed boost" which would then extend the searchable tiles for the duration of the boost. Not all enemies need to use the same logic or rules. More elite enemies could have improved player tracking, and search/hunt states where they linger in the area trying to find the player.
Another way to do the LoS around corners would be to have the enemy create a "dummy" of the player at their last seen location, and pathfind to that spot. It might be more efficient to do it that way, but I like your solution for it's adaptability
I guess i would just add some variable to the enemy that keeps track where it has last seen the player. If it reaches that point, it just raycast to the player and checks if it has a new line of sight. Just like anybody else would do - no magical "i know i have line of sight from that point" stuff. And it should be much more performant than throwing a whole lot of raycasts from a whole lot of positions.
you should make the enemies have a raycasting circle around them (that’s small) and if it detects an object/wall it will go the other direction depending on the situation, tree = right/left (random) wall = opposite direction of wall.
When the last steps are a confident "I know where you are" and "where you are going" and the existential "do I care where you are" which is why is the NPC even there Being kited away from where they were and what they were doing so the player can wrap back around to steal what they were guarding etc. Whatever they were doing or where they were idling having some pull so NPCs get less interested in a non-aggro player. Unless the player has loot they want and the game allows NPCs to tool and skill up versus being farmed without consequence That and how much logic can you add to individual NPC versus mobs without affecting performance but still keeping individuals in a mob somewhat intelligent enough to have their own tactics. That one NPC that goes around the corner the other way and a few of its mobbing fellows follow it because the player is already being chased by more than enough other NPCs to have their shit rocked. Flanking, cornering, cutting the player off because they know the player's speed and where the player could be/go, before getting confused and going idle again. Versus never stopping when the player had gone aggro on them personally or one of their clones. Or the other last considerations are still relating to farming.. how many NPCs are present, left, and can spawn/respawn so they there's far less interest in chasing a player when combat survivability is 0. Checking if there's too few or sufficient numbers for confidence then they'll chase/attack. If there's an NPC spawner and no other goals for them (such as resource/treasure pooling for their own purposes) then they can mob with abandon etc.
(PLZ DONT FEEL LAZY TO READ THIS LONG MESSAGE :P) For shooting enemies, instead of directly shooting projectiles right at the player (which can be easily dodged) it is better to give the enemy an angle range out of which it picks a random angle within the range to shoot at (so it will shoot close to the player, but not exactly ON the player) Then the range can be increased when the player is moving, so some random shots which hit the player will seem like they were actually predicted accurately but in a natural and non-mathematical way. This makes the enemy shooting a lot more natural and interesting. -Also, you can give each enemy random stats like speed, aggression, accuracy, IQ (for pathfinding) etc which makes each enemy more unique with its identity and behaviour. Hope the suggestions were helpful :)
Yeah, Just store the last sighted coordinates on the enemy instance. it goes to if it loses line of sight. It doesn’t require every tile doing a calculation and can scale for if there’s multiple players. The dev’s solution feels a bit over engineered, but it probably has its advantages.
You could have the player leave "breadcrumbs" with their current location always being the most recent bread crumb and have the enemies prioritize the most recent bread crumb within los
I'll admit it - I didn't know what a raycast was when I made this video.
Just watched this video and I'll admit - I was waiting to hear why you weren't doing that :P
still very informative!
i was about to say you literally made your own raycast
I don't know if raycasting would do the same thing, but I really liked how your enemy really felt like he ran the corner looking for you, didn't see you, paused a moment in confusion, then gave up and wandered away.
Lol I'm not great at this stuff but have used raycasts fairly often and I was curious if there was a reason you opted not to😂😂
One cool option is also breadcrumbs! You spawn small invisible objects behind the player that disappear over time and you make the enemies go in that direction...
just like in assassin's creed games....
Hacky solution most of the time. Especially when u wanna add in different movement patterns. At most it should be used in combination w actual context steering behaviors (and pathfinding), not as the enemies' main form of navigation
Yes, a "last seen position" given to every enemy is a clever solution.
When the enemy loses sight of the player, it should go towards a "last seen position" that it has, saved in its own script.
When the enemy reaches this "last seen position", it has two possibilities:
1. Either from this new position it is able to see the player and will continue chasing them.
Or
2. After getting to this new position, the player is still out of sight (they escaped), and the enemy returns to idle.
It doesn't require a lot of memory, only a positon vector that needs to be assigned to an enemy when the player gets out of sight, and that is cleared if the enemy has line of sight on the player.
At least that would be my solution to this problem.
@@pulsarhappy7514 Yeah, this is exactly the same thing I thought about. Breadcrumbs solution feels like enemies could still find the player although he already managed to get behind two obstacles what could by kind of annoying. It would feel you are fighting dogs which sniff their way to you. Also, these breadcrumbs should be visible only to enemies which had LOS when player was running away.
Nice idea. You could get some cool emergent behaviour too if you extended this to enemies. They could drop 'Alarm' bread crumbs, and then any other enemies that pass these will be drawn into the pursuit too.
very deceptively simple and performant way that's actually pretty realistic is for the enemy to move not towards the player, but towards the last spot they saw the player at. It's also cool because it introduces stealth elements where you CAN lose the enemy if you find a place to hide once line of sight is broken, but if they're following you closely they'll probably be able to see you after they reach the point.
If you want to make it even better, you can make them go into a "search" state where they wander around randomly for a bit if they reach the point but still can't see you. If you want to get more complicated but make them even smarter, weight the random directions away from the direction they were just moving so they search an where you probably are and don't backtrack. Then put a timer on the search state so they go back to idle if they can't find you after a few seconds. That's how enemies in stealth games usually behave anyway.
This sounds perfect. I’m saving this comment!
This is definitely a great option, and if performance ever becomes an issue with my implementation, I’d likely move to something like this. But check out the clip at the 3 minute mark in the video - I think this is where my version shines, because Last Seen At wouldn’t work fully there
storing a “last known player direction” vector the enemy could follow for some small amount of time if they still do not have line-of-sight after they reach the last known player location could potentially approximate more complex pathing
@@NateVolker I think this depends on the map design. If there are lots of nooks and crannies to hide in, then @Challacade' s method might produce psychic-seeming AIs in some situations. In that case your idea to store last known direction with last known location could work well (or other heuristics, such as moving towards the tile which can see the most if player not sighted from last known location, etc). It seems that @Challacade' s probably takes into account their intended maps too.
@@NateVolker I think that's good because it makes it easier for the player to understand their thought process. They can see the enemy go in a straight line until they get sight of the player again, making it clear that evading sight is a reasonable option and they're not just using A* to track the player no matter what.
I'm so glad to finally be at a point where I can watch a short video like this and know exactly what I need to do to implement it into my game. This definitely beats having to watch 2 hr tutorials that have to explain each and every step.
How long did it take you to get to this point?
how can i implement it to my game? i dont know the name of these things, the dots that you make when you move and stuff
can you please help me find a good video about it
I liked that it is more like a "pseudo"" code rather than actually showing the coding itself making it usable throughout different engines.
I was just watching a talk by Rami Ismail and he mentioned how you should fake smart AI instead of making actual smart AI. Although your set up so far seems more about pathfinding rather than making "smart" enemies, so you haven't dug deep into AI behavior yet. But it's something to consider. There was also a study done for one of the Halo games where players felt enemies with the same AI but dealt more damage were "smarter" even though the behavior was identical
I agree that hard coded behavior is easier to setup and easier to control, but I don't agree that it's the better solution in all cases and I believe with the ongoing advancement in AI it's only a matter of time for 'intelligent' enemies to replace hard coded behavior.
What talk is this?
@@_gamma. Konsoll 2021: Rami Ismail - 10 Empty Slides. The AI stuff is just one small section but the entire talk is very good
@@joestromo2592 Thank you, it was an excellent talk!
It wasn't that they dealt more damage, it was that they had more health. As a result they stayed alive longer for people to actually notice the behaviors the enemy AI had.
Something which might improve the performance is to calculate the line of sight by checking if the line intersects with any of the collision geometry inside the rectangle formed by the end-points of the line of sight. This way you don’t have to do a bunch of collision checkes iteratively over the line’s length, but instead check only once per line. Not sure how your collision is set up, but this might benefit the performance, especially if you have to recalculate line of sight for every tile for enemy pathfinding too
I completely agree; this would be a big performance improvement.
You would also want to only check LOS if the enemy or player moves and otherwise just reuse the existing calculation. This could also let you implement a lot of optimizations with pathfinding. For example, you could have the enemy "remember" where the player last was and take into account level geometry to make a guess if it should have LOS. Take an example where the player runs behind a wall, blocking LOS. You could then remember the position where they lost line of sight and try to move towards that, using a collider to move away from any walls, and assume that the enemy would not have LOS until it gets there. Then at the target point, recalculate line of sight. I'm positive there's a lot of issues with this though, as I thought about this for approximately 30 seconds.
Nice idea!
Was going to say something similar to the breadcrumb idea, have the enemy store a sequence of last known player positions within it's detection radius, then have enemies pursue the latest position it still has LOS of. The breadcrumb is good because it only stores one copy of those positions though.
One note about the breadcrumb idea is to only drop them if the player is within an enemy's detection radius to save performance.
Another thing to consider maybe is having the enemy give up if it reaches the last position that was within it's detection radius and it still doesn't see the player. Then at that point it can choose a random direction to pursue based on the trajectory of the player's previous path. Say like within a 30 degree cone of the direction the enemy is already traveling. This way the enemy doesn't know where the player is, but it still goes in a pretty good guess of a direction.
Great insight! Enemy AI is a surprisingly nuanced topic and it's great you got it to work well!
Nice use of a bi-directional path finding ^_^, as you already have states for your enemies, it would be fun to see some "Elite" enemies order their minions around with "regroup" "swarm" "hold" "attack" actions etc. also would be fun to see if the slimes could coordinate a pincer attack or do a "wall tackle"
Something that could really add to the enemy system is different enemies pursuing the player in different ways. Maybe something small and dumb like the slime will just go at the player, but maybe those projectile launching guys from the cloud area back away from the player, and can even fly off the stage. a ranged enemy wouldnt want to go towards the player, it would want to be at a range. I think it could add some depth where different enemies instead circle, flank, or kinda bait the player instead of just going straight at them.
Pretty solid solution. I thought about maybe pursuing the last known location, but after thinking about it, I could see that having issues in itself.
Be careful comparing lists against lists. It can get very performance heavy. Usually A* only checks one cell at the enemy position at a time. Then uses neighbour checks. You get neighbours by carrying the grid with you. It's a whole thing but imo well worth the performance increase.
Love the content! Always inspires me to work harder at game dev and making videos :)
I already really like the game!!!! Keep on the great work, man! Much respect .
A momentum-based pursuit approach (both linear and angular) would be interesting to try to make work. It has a little more persistence than stop-at-last-location, but it also allows you an opportunity to cleverly hide.
Or, base some enemies on logic of “scent” instead of “sight”. Could be a fun mix.
That was a really fascinating video, I'm very interested in the way you tackled the enemy navigation/pathfinding to work in your game. It's a very good solution to the problem, and I especially like how you were able to use it to also create idle patrol movement too. Great game art as well btw, love your style!
Bro, take care of your game's performance, to LOS, use a raycast, and to let the enemy chase the player even when he loses the LOS, make the enemy go to the last position when player was sighted, or use a AStar algorithm to pathfinding the closest path beetwen player and enemy
You just described what he's already doing. And using AStar would be more expensive because of the pathfinding.
@@notadev9000 I hope so, but since he didn't go into much detail about his implementation, I think it would be useful to say so
@@notadev9000sounds a lot more expensive than Astar, as its especifically optimized for that task, which doesnt seem to be the case of his algo... let alone for the cases he actually wants to do anythint else than follow the player in a straight line (strafe around, zigzag, hit n run, flee, etc)
@@robertonome2448 Actually it depends how much enemies he wants to have, neither of these solutions would be great with a lot of enemies. Calculating A* with hundreds of enemies and you have a game with 10 FPS , especially if you have many obstacles. I think the best would be to create some flow field
@@maervo4179 this clearly isnt a horde game...
You just earned a subscriber friend
Very cool!
One possible solution: You could make the enemy go to the last known position of the player's position (Store the player last position before it goes out of sight)
This option is simpler and less resource-intensive, but it couldn’t handle pathing like mine does at the 3min mark in the video
I think the simpler solution is fine though, especially for simpler enemies as it makes them easier to get off your tail. For more difficult enemies the more complex solution might feel more warranted.
Would reccomend checking out the A* pathfinding algorithm. I'll have to assume that the tiled LOS checking is kinda expensive.
have you looked into context based steering? its a system im using in my game that can create very complex behaviors for ai when you combine it with state machines. in a nutshell the enemy casts rays around them, each ray has its own "interest" which is calculated based on the dot product of the rays angle to the target point you gave the ai. interest also gets set to 0 when the ray collides with an obstacle (or anything you want the ai to avoid), and then the chosen direction for the ai to move is calculated by multiplying each rays angle with its interest and then adding all those values together. this system is great as it automatically allows ai agents to make microadjustments to their chosen direction based on whats happening around them. when you have large groups of enemies they will automatically avoid clumping up and the way they move around and avoid eachother and obstacles looks very lifelike. you can also create behaviors like strafing around the player in a circle very easily with a little math. you should really look up context based steering
Increasing enemy AI is another way of having a harder difficulty without it feeling artificial.
Just increasing attack power from enemy attacks can only do so much.
What if you make the enemy remember the place the player was when the line of sight was last maintained? If it's broken, you make that point the new location to reach for the enemy. If there is still no line of sight with the player when it gets there, it returns to idle state. This also gives a realistic chance for the player to outrun the enemies.
For me the easiest and simplest solution in code is to activate a conditional that if the enemy stops seeing the player (due to an obstacle) to calculate 2 paths in angles in reference to the player's last position, so continue walking along a stretch mechanically, and be able to see the player again and continue the chase.
3:19 my suggestion is to set a vector2 to the players pos every frame as long as they’re in LOS. Then if the play goes out of LOS the enemy goes to that vector2 where the player last was in LOS. This is just how I would do it and I hope I explained it well! I love your devlogs and look forward to them every time!
i love the pokemon mystery dungeon music at the start. also nice video, the games come a long way.
Really impressed here at the creativity in your solution to the problem. I wouldn't change it except for performance should that become an issue. Beauty of indie dev games is this type of uniqueness
you have an amazing knack for explaining things clearly and effectively! ️
Awesome devlog! This game is beautiful and looking great so far 😊
That's a very cool system! Since I make most of my games in Rust, I actually coded my own A* Pathfinding library and usually use that haha
Even the worst of the days become good days whenever I see that Challacade uploaded another video!
The “last known position” works fine, maybe a lot easier too. You save the position where the LOS was lost and your mob will walk there. In the meantime, if the LOS became valid again, the mob ignores the last known position. This ensures that in corners the mob will “see” the player and acquire it as a target.
Maybe this has been mentioned already, but I would definitely check out DDA algorithm. I just added a modified version of it to my game for raycasting movement making sure things stay within tiles flagged as walls. Modified in a way to not check every single unit step on that line from it's origin point, ei your enemy. If you run into performance issues you could use this method provided you assume collisions are set to some tile, then handle other special cases some other way.
One interesting way to have a more "non-enemy relationship" type of AI is through a Utility System that decides what Behavior Tree to execute based on its modular list of Considerations.
Although, this is far easier said than done. If it turns out uber sick, I kinda wanna make a video like yours. Your channel and devlog adventures are an inspiration!
It looks like smart movement! I might not be the only one who liked the aesthetic of the colored dots, did a great job explaining!
I spent at least 30 minutes deciding what colors to use, I also like how it looked!
I started following this channel a while ago because I love the devlog detail and style. Altho this game type isn't really my thing. You've won me over and I'm actually really hyped for this game. And cant wait to play it
Make the NPC chase a point that represents the player's last known location.
Update that location every time the line of sight check to the player succeeds.
If the enemy reaches the last known location and the line of sight check to the player fails, then the NPC gives up and goes back to idle.
This way when the player runs around a corner, the enemy will go to that corner to look for the player.
For the player to escape, they'd need to quickly get out of line of sight of that corner before the enemy reaches it.
A more complex but more effective addition to this would be for the player's movement direction to be added to the last known location object.
When the enemy reaches the last known location, it could continue moving in the player's last known direction.
This would force the player to have to quickly go around multiple corners to avoid the enemy finding them.
This is more realistic and somewhat on par with human behaviour.
Instantly subbed after hearing the song
Another idea would be to keep track of the position where LOS was last true, then have the enemy move to that position if LOS ever goes false. So if the player goes behind the wall enemy will go to the place where the player disappeared. From there, it might be able to regain LOS unless the player goes behind another obstacle, in which case, the enemy goes back to idle, essentially having “lost track” of the player. 😊
I think it's way easier just having a "last tile I saw the player" as a target, going there, then if there is no LOS from that tile to the player get "confused" and randomly search, or go back to the default position/last patrol point.
It makes more sense from a real world perspective and is way better for performance (no need to recalculate an entire LOS grid).
I think you should add a cool-down to weapons, it forces the players to use a variety of weapons but it doesn’t completely get rid of any weapons and it can be used strategically in combat, I also think you should be able to equip a permanent ability to a weapon also adding to the strategic aspect of combat and allowing the player to in a way customise their favourite weapon
The cool-down would work where each weapon has a certain amount of uses and when the player maxes out the weapons uses it takes a certain amount of time to recharge depending on the weapon, it’ll force the player to use a variety of weapons and form a unique play style depending on which weapons they use the most.
Love the visualizations. Keep it up!
The double LOS solution is actually really darn clever :o
Tried the demo, really nice I like a lot the style, it remembers me of Minish cap.
Found a couple of things you may already know, anyway in the clouds map on those platforms that start moving when you are in their center, if you drop a weapon when the platform reaches the new position it just falls down and you lose it. In the first forest instead, I swam to the east and found an invisible wall in the river. You may just place some rocks there, right now it feels strange. Lastly a slime followed me inside the water making a strange effect.
Hope this may help you.
Good job anyway I hope the final release will be even more fun!
Psychic enemies that always know where you are is one solution.
Another is that once it loses LoS, that it heads to the last place it saw you, and maybe search around that area for a bit (add a question mark above its head etc.)
The drawback is that this might be a bit too easy to cheese, and is only fitting on the dumbest of monsters.
A sneaky solution to which being to have your player have one or more ghost objects that lags behind them. When the enemy loses sight of the player, the monster can do a LoS check of these ghost objects, and you can program in an Investigation state, where it pauses in confusion, before moving towards where your ghost object was last. Giving the opportunity for the player to get away entirely.
Love the update. You should consider having the enemies talk/interact with eachother when idle. Making them feel a little more alive. Maybe use different symbols like ! 😊 and ❤s.
A simpler way would be
1) the monster can try to keep going the direction it WAS going
2) the monster can kind of randomly move about in a dumb "search" until such time it DOES have los with the player
so effectively the monster can go into a third mode, a 'searching' mode (like with a ? above its head maybe) where it first tries to keep going forwards for a few seconds and then randomly searches. My other thought and addendum to this is to have a monster keep track of nearby collisions to itself in all 8 cardinal directions, and so when randomly searching it would never try to go that way (into a wall) but instead pick other paths.
I am trying to do a very similar thing but in 3D with no navmesh so wish me luck. Im going to attempt to use the above strategies in 3D - should be interesting
Really dug this implimentation. Probably pretty similar to how I would have approached it myself!
Alternative AI player tracking thats maybe easier or simpler- if enemies lose LOS while chasing then store the last known coord of player pos and set that as the next target location for the AI, if it gets there and player is still not in LOS then either cancel chase or start some kind of "search" motion pattern where it does a circle or figure 8 or triangle that lasts for X seconds before returning to idle or patrol behavior.
Instead of iterative circulars towards the player you can use a ShapeCast. It’s designed for that purpose and optimized for it (much more efficient).
An idea is that whenever the player leaves an enemies line of sight, the enemy will walk towards the players last location. Once it reaches the last location, if it finds the player again, it can continue chasing, but if the player isn't near their last location then go back to idle state.
I think I would give the enemy a searching state. when it first enters this state, it continues towards where it last saw you, then goes a short direction in your last known velocity. if it hasn't found you by this point, it wanders for a bit then reenters idle state. having your own los data on the player seems useful though.
Congratulation, you invented navigation and sight perception!
These videos are so helpful for when I’m trying to problem solve. Legend 🤙
I really love the art direction of your game!
This is so cool, I love it.
Will keep this in mind if I ever become skilled enough to implement something like this.
Can't wait for this to come out
When it comes to Game design. Enemy behavior is probably, one of the hardest things to nail
A simpler solution with less processing for recalculating tile data I would say as the player is being pursue and by enemy they will periodically drop bread 🍞 crumbs.
These are just invisible vector or specific tile. So say you turn a corner if you dropped a breadcrumb the enemy will look to the last breadcrumb go to that and then see if the enemy is within LOS.
Breadcrumb is a awesome solution. The tricky part is what is too frequent and what is not frequent enough for dropping breadcrumb. You could adjust depending on the enemy like part of their intellectual stat.
Oh saw it was suggested lol A* path finding is another for obstacle avoidance. Doesn't resolve the turning the corner how can they still see me if the player successfully got away
I don't know if you hand draw your levels or generate them, but you can generate path nodes either way and just have the enemies follow the nearest path that they last saw you along until they get tired of chasing you, as in via a time limit to their agitation. Basically, LoS would be the key metric, but once that's lost they could follow path nodes closest to where they last saw you and scan their radius while the timer counts down, unless LoS is picked back up, and then the timer restarts. If you don't know how to generate path nodes, there's several videos showing various techniques for it, and there might still be one that explains Unreal's automatic path node generator.
Another good way to make enemies look for player when they lose sight of him, is going to the last position the player was at before they lost sight of him and then checking if the player is still visible, because the system you have rn is very good but might cause an issue that makes chasing never end, just a suggestion feel free to take it or leave it, I also started developing my own game not long ago so it's always fun to see how other people do things😁
I would've just made the player periodically drop breadcrumbs, and if the enemy loses sight, it goes to the most recent breadcrumb. Then if he doesn't find you from there, you lost him. Seems a lot simpler to me, and also has some personality.
All I see here is a genius at play. Amazing work dude, inspiring and motivational!! 😊
Thank you!!
I'd consider make a line of sight cone effect, and have the monster patrol in a area around where the player was last scene.
This then can treat it in a aware, caution and danger state.
Then put indicators such as a 1-10 and based on proxminity, movement within a certian range and other noise raise alert state.
You can also give different monsters natural behaviors and routes, that would make sense for yheir organic function.
Tbis is in some games monsters will feed on other monsters, to for instance incresse their health if low. Theyll seek out and devour weaker monsters to restore their health before attacking.
Or try to put obstacles or traps for the player, to slow the plsyer down so they can find weaker prey or a means to heal
A lot of people have been suggesting to make the enemy move towards the last seen location of the player, but as you have said, with this system, if the player turns multiple corners, the enemy wouldn't be able to follow the player.
So I thought of an extension of this system. It's actually probably wayyyy more performance intensive than your solution and probably more complicating, so it's totally pointless and useless, but I will share it anyways.
Instead of the enemy simply going towards the last seen location of the player, it also creates a checkpoint at that location. The checkpoint itself performs LOS checks for the player, and when the player get's out of the checkpoint's sight, it creates another checkpoint at the next last seen location of the player. In this way, a trail of checkpoints are created for the enemy to follow.
Idk how to explain some of the details I thought of, so I just made ChatGPT summarize the system:
"-When an enemy has a direct line of sight to the player, it actively pursues them.
-If the player goes out of sight, such as by turning a corner, the enemy marks the last seen location with an invisible checkpoint.
-These checkpoints are not merely static markers; they actively perform line of sight checks to detect the player.
-If the player goes out of the checkpoint's line of sight, it triggers the creation of a new checkpoint at this new location where the player was last visible.
-This results in a sequence or trail of checkpoints.
-The enemy follows this trail of checkpoints to track the player's movements.
-This allows the enemy to continue the pursuit even when the player has made multiple turns or maneuvers that break the direct line of sight.
Checkpoints are destroyed in three scenarios:
-When the enemy reaches a checkpoint.
-When the enemy resumes direct chase after spotting the player again.
-When the enemy stops the chase altogether.
-Enemies only follow checkpoints when they are in an active chase state, having seen the player themselves.
-The enemy always follows the most recent checkpoint within its field of view.
The system is designed to enable the enemy to pursue the player over a complex path with multiple turns and corners, not just to the last point where the player was seen"
This is overall probably extremely performance intensive cuz of all the line of sight checks, and makes things way more complicated than it needs to be. But maybe this can help spark a new idea or something? What do you think?
Edit: Also forgot to mention that the chase state is either determined by the amount of time it has spent chasing, or the overall distance between the player and the enemy. The checkpoints themselves don't play a role in it. The checkpoints are simply for following and tracking.
It was very interesting, this video was cool.
I think it would be great if the enemies would look left and right after they lose a player.
I'm making a game in Godot where I solve the same problem. In Godot it is relatively easy, because it has built in support for doing an A* search on a tile map. My enemies have an idle state where they are just patrolling a path. When they get a line of sight to the player, they start chasing, using the A* algorithm. If they lose line of sight while chasing for more than a second or so, they will use the A* algorithm to find back to their idle patrolling area, and then go back to patrolling. My entire enemy class is only 117 lines of code, but I still need to implement animation states and attack patterns and so on. I only have the basic Patrol - Chase - Return Home cycle done.
The A* algorithm probably already has several implementations in Lua, which you can download and use. Otherwise it is not very difficult to implement it yourself.
Give the enemy a Vector4 variable called something like chasePoint. As long as the enemy has line of sight of the player update the chasePoint so the first 2 floats equals the players current position, and the last 2 floats equals the players current direction. Should the enemy lose sight of the player they can use the chasePoint to move to the players last position, then they can search for the player by moving in the last direction they saw the player go.
I didn't expect the tile grid active state method. I was expecting it to use a look behind, and simply move toward the players last known position, until it regains los.
You method allows for potential good solutions, like the enemy taking a shortcut around a barrier, vs always the chasing line.
*It could make for an interesting enemy to combine the 2 ideas, but inverted,* so it looks for the gap in data and chooses the _opposite_ side as where the player just left. Intentionally, this enemy would instead of opting for chasing around an object, prioritize cutting the player off at the other side.
That would make for an easily exploitable enemy, but very different than standard enemies, and nasty in combo with regulars, as you run and gun gets cut off.
fantastic solution! I'm taking notes to use some of this on future projects :)
The problem with this solution is that if the distance of the player and the mob is small the player never lose the mob, I think that instead of tile tracking the mob could just "remember" the direction the player was going the last time it saw the player, so it will go to the last position and when get there start going to the last direction it know... if the player walk around a tree at some point the mob will lose it if the player keep walking around keeping the mob outside the line of sight.
Another interesting idea is instead of walking straight from point A to Point B, using something like a beizer curve based in the average last n directions of the player... something like if the player if walking around something the when lose LOS try to keep walking around instead of start to walking straight
There is some irony in our character being able to see through walls, while the enemies cannot
A solution for your issue a friend of mine did in college for his thesis was prebaking a few paths around the map whenever a level was loaded and used a raycast to check if the enemy was in line of sight with it's target, if the target was in los they'd gravitate to the closest node on the path and follow the path towards the closest node to the player till los was achieved. Had some minor issues but seemed quite performant. I'm paraphrasing obviously but it's interesting how you both came to similar solutions.
My solution for enemy losing LOS:
* When the enemy looses LOS, store the last location the player was at
* Have the the enemy move to that location,
* If the enemy still can't regain LOS by the game by the time it get's there change to a searching state
* The enemy moves around randomly trying to regain LOS
* If the enemy can't regain LOS within some defined period of time they stop and go back to idling.
4:15
toggling the grid LOS can make a difference between smart enemies and dumb enemies. And because the slime is dumb, I think it would make more sense if it only has the regular LOS and would not check the grid at all. You can set a bool variable to disable the grid LOS for some enemies and I think it would feel a lot nicer if some enemies that don't look smart would only check the regular LOS and some will look smarter and check everything
I loved the methods you chose. As a beginner, I was able to convey some of it. I'm using unity and have no idea how I can transfer the tile technique. I would be very happy if you could say something enlightening.
The enemy could walk to the last tile in which line of sight was true. Once it reaches there, if the player is still in pursue range and LOS is true, it resumes pursuing, otherwise it goes back to idle. I think this approach may not always work as intended and is easily picked up by the player but performance wise, it might be a better option.
you can cutdown on the amount of line of sight checks to save on number of computations you can probably have some sort of look up table where you can quickly check if there is line of sight between the tile the player stands on and any other tiles instead of preforming the check for every tile.
Very cool AI logic. I have wondered how to code a roaming mode for my enemies. This tile logic looks like it will work really well. Thanks for the great visuals on how it is broken down. Does any of your current courses explain how to setup this particular AI logic?
The courses don’t get that technical, they’re more beginner focused. I’d love to make more content detailing stuff like this!
@@Challacade Please do! :)
If the enemy can see the player, store the player location in a "last seen at" variable, then regardless of line of sight, move toward the last seen location.
The enemys need to have an search delay.
When they cant find any point anymore that is connected to the player the would have an little time delay before they get back to idle.
This way it feels a little more dynamic and not like that all of them give up immediately.
To spice things up, make the delay a little bit random in an specific range so that some enemys give up early , some make normal moves and some chase the player a little bit longer as normal.
To spice this also up, it would be neat to add an little dark cloud over the head of an enemy that has an very high delay stat..... this way for the player it look like some of them are so pissed off that they chase you longer as anyone else.
I normally use floodfill from the destination position in a 2d grid. As soon as I reach the starting position via floodfill, I backtrack through the values to get the shortest path to the destination.
If the player is suddenly not in los, the enemy will move to the last location of player in los
I do LOS with a raycast from the enemy to the player. Add a layer mask for obstacles and if hit.collider!=null it means there is an obstacle in between, so LOS=false, else, LOS=true.
This LOS system can be the foundation of a stealth mechanic
Very creative approach! I usually go for A* pathfinding or using a navmesh. I wonder how well this performs.
So you effectively made your own pathfinding, pretty cool
That tile checking thing seems like it would become quite resource-intensive but it is a pretty good baseline. Raycasting works but is fairly simplistic and could be fine for basic enemies, or for handling combat movements. I'd say raycasting is the equivalent of giving enemies a d-pad and letting them "play" the game, but it wouldn't necessarily lend itself to searching for a player who went out of sight.
Your tile system could be improved substantially by simply checking only locations where the player could be given his movement speed and the obstacles in that radius. The player can only travel maybe 5 tiles in one second, which means that unless the game has some kind of teleport or speed-boosting abilities, the player could only be within a 5 tile radius of the last known position, extending by 5 tiles for every second that passes by "last seen". Then, you can ignore all tiles which are obstacles to give the enemy a "most likely path", which they can investigate, then abandon if the player is not found within a certain time (the time they abandon should be randomized between a range to make it feel more dynamic).
Even if the game does have speed boosting abilities or teleports, this information does not need to be conveyed to all enemies. Meaning that "dumber" enemies would give up pursuit more easily, but smarter ones may get info like "player used speed boost" which would then extend the searchable tiles for the duration of the boost.
Not all enemies need to use the same logic or rules. More elite enemies could have improved player tracking, and search/hunt states where they linger in the area trying to find the player.
Another way to do the LoS around corners would be to have the enemy create a "dummy" of the player at their last seen location, and pathfind to that spot. It might be more efficient to do it that way, but I like your solution for it's adaptability
I guess i would just add some variable to the enemy that keeps track where it has last seen the player. If it reaches that point, it just raycast to the player and checks if it has a new line of sight. Just like anybody else would do - no magical "i know i have line of sight from that point" stuff. And it should be much more performant than throwing a whole lot of raycasts from a whole lot of positions.
you should make the enemies have a raycasting circle around them (that’s small) and if it detects an object/wall it will go the other direction depending on the situation, tree = right/left (random) wall = opposite direction of wall.
i had a simmilar thing except i made it so each enemy had some form of memory and remembered the last player position after loosing los
I always get so hyped whenever you upload
When the last steps are a confident "I know where you are" and "where you are going" and the existential "do I care where you are" which is why is the NPC even there
Being kited away from where they were and what they were doing so the player can wrap back around to steal what they were guarding etc. Whatever they were doing or where they were idling having some pull so NPCs get less interested in a non-aggro player. Unless the player has loot they want and the game allows NPCs to tool and skill up versus being farmed without consequence
That and how much logic can you add to individual NPC versus mobs without affecting performance but still keeping individuals in a mob somewhat intelligent enough to have their own tactics. That one NPC that goes around the corner the other way and a few of its mobbing fellows follow it because the player is already being chased by more than enough other NPCs to have their shit rocked. Flanking, cornering, cutting the player off because they know the player's speed and where the player could be/go, before getting confused and going idle again. Versus never stopping when the player had gone aggro on them personally or one of their clones.
Or the other last considerations are still relating to farming.. how many NPCs are present, left, and can spawn/respawn so they there's far less interest in chasing a player when combat survivability is 0. Checking if there's too few or sufficient numbers for confidence then they'll chase/attack. If there's an NPC spawner and no other goals for them (such as resource/treasure pooling for their own purposes) then they can mob with abandon etc.
(PLZ DONT FEEL LAZY TO READ THIS LONG MESSAGE :P)
For shooting enemies, instead of directly shooting projectiles right at the player (which can be easily dodged) it is better to give the enemy an angle range out of which it picks a random angle within the range to shoot at (so it will shoot close to the player, but not exactly ON the player)
Then the range can be increased when the player is moving, so some random shots which hit the player will seem like they were actually predicted accurately but in a natural and non-mathematical way. This makes the enemy shooting a lot more natural and interesting.
-Also, you can give each enemy random stats like speed, aggression, accuracy, IQ (for pathfinding) etc which makes each enemy more unique with its identity and behaviour.
Hope the suggestions were helpful :)
Wouldn't it be simpler if the enemy just follows the last line of sight to the player before losing sight?
Yeah, Just store the last sighted coordinates on the enemy instance. it goes to if it loses line of sight. It doesn’t require every tile doing a calculation and can scale for if there’s multiple players.
The dev’s solution feels a bit over engineered, but it probably has its advantages.
What the player really needs is a cardboard box to hide in. Works every time. 😎
This would make for a great stealth mission or something
You could have the player leave "breadcrumbs" with their current location always being the most recent bread crumb and have the enemies prioritize the most recent bread crumb within los
Dude that platinum (diamond or pearl) soundtrack