BWA V2.0 Deep Dive
GD.Print("Hello World");
Yesterday, I released Better Weeping Angels Version 2.0. This will likely be my last update to the project unless something major breaks. I want to take the time to go over in depth the changes I made and how I envision the project being used by others. This devlog is going to go into great detail about the code and game development systems as well as how other developers can use it in their own projects so proceed with caution.
To start off, I am going to do a quick recap on how the last system worked as to better emphasize the improvements that the new system has made. In Version 1.0 the Weeping Angel (for simplicity I will refer to it as the monster from now on.) traveled towards the player using a NavigationRegion3D Node and a NavigationAgent3D Node. The player was set as the target each physics frame to update movement in real time. In order to control if the monster was allowed to move or not I used a combination of Raycast3D Nodes and a VisibleOnScreenNotifier3D Node. The latter can simply be hooked up to a Boolean controlled by a signal triggered when the node is visible or not on screen. This Node works for this simple tech demo and it saved me a lot of time creating a ShapeCast3D system to detect if the monster was in the camera frame but I imagine it would be better to create a more refined system for an official game. This can be seen when the atmosphere is enabled in the demo the monster will occasionally stop moving even when the player cannot see it because of the fog. This could be fixed with an additional Raycast controlling range.
As long as the monster is not on screen or doesn't have line of sight of the player it is allowed to move along its path. As shown in the previous devlog, three Raycasts are used for line of sight: One on each side of the monster and one in the middle. This could be expanded for more precision but three was the minimum for this particular systems so I kept it that way to optimize performance. By using the two raycasts on the sides of the enemy it is able to stop just barely visible to the player giving the effect of the monster waiting around the corners. It also ensures that the monster is completely idle before the player can see it removing the annoying quirk of most modern weeping angels being caught moving when the camera is flipped quickly enough. The overstare behavior is initiated when the monster can only see the player with one Raycast. This starts a five second timer that once completed rechecks line of sight. If the conditions are met the monster builds an invisible wall. The wall is created by finding the nearest collisions directly in front and behind it when it is facing the player. The wall is angled towards the player. After the wall is built the NavigationRegion3D rebakes the NavigationMesh to include the new wall and the monster is teleports to its last saved location along its path. This position is determined by saving every position along the path that is 1.0 meter or greater than the last saved position starting from the monsters spawn. The idea for this was to build an invisible wall that can not be crossed by the monster but causes no collision and moving the monster back direction it came to force it to repath to behind the player. It did work under controlled circumstances but was easily broken which lead me to redesign the system for V2.0. The main issue with this system I will illustrate with a diagram pictured below:

In the instance that the monster, indicated by the circle, sees the player, indicated by the star, at position A and then while maintaining line of sight moves to position B the monster will enter overstare and teleport to the last position along its path (Last position is indicated by the red X and the path is indicated by the red line). This position is still in the players line of sight and therefore the overstare behavior fails. Version 1.0 also had many issues with the order in which Navigation was decided leading to a bunch of patch job solutions that felt bad. Now, with this understanding of V1.0 lets dive into how V2.0 works.
For Version 2.0 I opted to create a state machine to control how the enemy behaves. I have included three states: Stalking, Staring, and Repositioning. The monster starts in stalking mode in which it targets the player and paths towards them every frame. If at any point the player is determined in sight either by sightline or screen visibility notifications it will enter the starting stage where it stops moving. If the player is only visible by one of the three sightlines it starts a timer. If however this sightline changes the timer is stopped. This prevents a bug with the old version that allowed instant overstare behavior if the monster moved past and obstacle with the correct timing. When the timer ends if a single line of sight is still maintained overstare behavior is entered. The wall is created the same as it was in the last version but instead of teleporting to the last saved position, using a mathematical formula the monster targets a new location with its NavigationAgent3D. The way that the target position is picked is by calculating the global vector of the side Raycast that isn't making contact with the player and its target and extending it past the monster by a random number from 2.0m to 3.0m. Since this system calculates a new spot locally from the monster it doesn't have the problem of failing if the player moves. I also allowed the monster to reposition even if the player has one sightline so even if the player starts to follow the monster it can still get away around the corner without being seen. The pathing walls are deleted whenever the monster reenters the staring phase.
My goal with using a state machine is to make the system much more friendly for other developers to understand as well as add on to. Ideally adding new states and behaviors should slot into the existing states allowing for even more complex monster behavior. I have a link to the GitHub repo where all the project files are listed on the release page. I want this to be a free public resource for developers to take inspiration from or use to improve the indie horror genre's quality.
Thank you to anybody taking the time to read this and take interest in this project. It was very frustrating at times but overall I had a blast working on it. Hopefully there will much more to come in the future but until then:
GetTree().Quit();
Get Better Weeping Angels
Better Weeping Angels
Status | Released |
Author | Yellowguy08 |
Genre | Survival |
Tags | demo, Horror, No AI, showcase, techdemo, weepingangel |
Languages | English |
More posts
- BWA V2.0 Devlog Postponed2 days ago
- Launch of Itch.io and Better Weeping Angels.8 days ago
Leave a comment
Log in with itch.io to leave a comment.