-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve blood placement on Riot Damage #79575
Improve blood placement on Riot Damage #79575
Conversation
Remove my redundant (and probably broken) bounds checking Blood streaks don't start on furniture Blood streaks avoid furniture like walls. Remove some duplicated code and use conditionals for handling wall and floor streak behavior. Streaks can terminate early and the chance goes up the longer the streak is. Floor streaks can meander on the ground and the chance to meander goes up the longer the streak is.
Stay DRY by removing duplicated code. Ternary operator used instead to create conditional behavior.
Implement blood spawning into pools that start at a point and crawl co-ords outwards. Move blood streaks to their own function.
Fix Streaks not generating (Again). Fix Blood pools not generating properly. Slightly the probability of blood pools spawning adjacent blood. Blood streaks can skip tiles, the chance is increased the longer the streak is
Switch the flag calls to ignore vehicles. Increase comment documentation Slight change to behavior roll conditions Streaks don't start on tiles that aren't valid for them Increase amount of blood places overall
Very nice! Each streak looks like it's telling a story |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty! Although i'm not sure why the screenshots have so few wall streaks.. Bad luck? Wall streaks naturally less common because there are much fewer walls than floors? idk. Probably not a big deal.
Code looks good in that it does what it claims to do, but I did leave some highly opinionated comments. Please feel free to ignore.
Still pretty newish to C++ so all feedback, useful tips, and sage advice welcome
I strongly considered trying to create a function that could check for multiple flags at once, to avoid multiple function calls from the same condition. But it didn't seem like such an easy thing to do, and I didn't want to do it unless otherwise asked to.
Don't worry about multiple function calls. As the saying goes, "premature optimization is the root of all evil".
Don't take this literally of course, but an extra function call is blazingly fast and not something to worry about. Code that wants optimization is that which is called a lot - be it on every turn, or for every item, or on every turn for every item, or each time mouse is moved etc. And compiler would probably optimize things even without you doing anything here.
This generator is called ~20 times total per overmap. Even if you had 100-long blood streaks, each checking 50 different flags on every step - that would result in 100000 (1e5) checks. With modern gigaherz processors, all of those checks would be done under a millisecond. You can do those checks every frame at 120fps and still be fine.
Code readability/maintainability is usually much more important than raw speed
Could the chance of blood spawning be tuned down? It feels quite odd seeing so much blood in so many places. |
Co-authored-by: moxian <[email protected]>
Thank you for taking the time to leave such a detailed review. I appreciate your advice and wisdom. I've gone ahead and applied the suggestions from the review. At the time, I completely spaced that enums were a thing. Definitely the better way to go for code readability. I originally had the brute force way but tried to collapse it down with the ternary operator to be fancy and optimize things. I can see how that behavior makes it much harder to read what's going on though. I think using the enum in combination with the more brute force method produces the most readable and least smelly code so I'll go with that. |
Sorry my C# was showing
I think you're right it might be a bit much. I have been ping-ponging back in forth between 1 in 100 and 2 in 100. But I think the value sits somewhere in between. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C++ code LGTM, although I'm still confused about the lack of wall streaks in screenshots. (But I can easily buy that we are simply being unlucky there)
Looking at it I did actually break the code recently by inverting a condition accidently. And in my recent commit I also apparently broke the behavior roll when trying to decrease the amount of blood spawning. Which further reduces the placement of wall streaks. Fixing these two issues we got wall streaks back. My bad. |
Summary
Features "Improve blood placement on Riot Damage"
Purpose of change
Currently blood is just placed in single tiles randomly. Which is was fine for as a starting point. But not so great for the long term. Placing them randomly just tends to make the maps feel a bit noisy, and it doesn't quite sell the intended experience of being in a riot devasted city.
Current behavior:
![image](https://private-user-images.githubusercontent.com/8084840/410765103-3753c7f4-2fc2-4d54-a024-7a73316ece6a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNTkyNjMsIm5iZiI6MTczOTI1ODk2MywicGF0aCI6Ii84MDg0ODQwLzQxMDc2NTEwMy0zNzUzYzdmNC0yZmMyLTRkNTQtYTAyNC03YTczMzE2ZWNlNmEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTFUMDcyOTIzWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9N2RmYjU5OWVlNzVlZGEwMTFmYWY4ZjFlZjM3ZDdlYjU4MzIwNzYyZDJlMjBjMTg3MjlkYWYxNWNkMDI2MDVkZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.AbAbK6vxCayLYw05YZIt26HhPTrmPpK9eFNiHdcOP9g)
Describe the solution
Implement a system of rules to give blood placement greater rationale and reduce noise in the maps.
After passing the initial check to begin placing a blood field the game will now randomly select between 1 or 3 possible behaviors: It has a 20% chance to place only a field by itself, a 40% to begin a streak of blood, and a 40% chance to begin a pool of blood.
Placing a single field behaves exactly as before.
Streaks
Streaks of blood randomly pick a direction to move and a length to be. After that it determines if it's a wall streak or a floor streak.
Wall streaks stick to the walls only and are intended to represent blood splattered on the surface of walls.
Floor streaks stick to floors as best as they can. They avoid obstacles like walls, furniture, doors, and windows. They are intended to give the impression of individuals trudging through buildings leaving a trail of blood. Given enough space floor streaks will meander to the side so they are rarely perfectly straight. Instead favoring a slight curve.
All streaks can terminate early and some will occasionally skip a tile to break up the line a bit.
Blood pools
Blood pools set the initial tile as blood and then attempt to expand to that start point's adjacent tiles. The First generation has the highest likelihood of placing blood fields. It will then attempt a second generation by trying the adjacent tiles of all tiles from the first generation. At a reduced chance of placing blood fields.
The result is a usually a blob like puddle that works quite well.
Revised Behavior:
![image](https://private-user-images.githubusercontent.com/8084840/410765530-b3f32838-1706-44df-8970-6c0a199c0152.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNTkyNjMsIm5iZiI6MTczOTI1ODk2MywicGF0aCI6Ii84MDg0ODQwLzQxMDc2NTUzMC1iM2YzMjgzOC0xNzA2LTQ0ZGYtODk3MC02YzBhMTk5YzAxNTIucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTFUMDcyOTIzWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTNjMDU4MDk3OWFiMjQyZmU4MWNmMWJlMGI1NjJlMTgzYjk4Nzk2MmQ4NjVlMDNlOWNmMGNjZTAyZjZmZDliYiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.XR7JOZfsxVjOIiPOAFYKJfd5udYVKVZnxUaNNJB5MN4)
![image](https://private-user-images.githubusercontent.com/8084840/410765686-d94db9ca-688d-4472-baf8-f386f0749286.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNTkyNjMsIm5iZiI6MTczOTI1ODk2MywicGF0aCI6Ii84MDg0ODQwLzQxMDc2NTY4Ni1kOTRkYjljYS02ODhkLTQ0NzItYmFmOC1mMzg2ZjA3NDkyODYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTFUMDcyOTIzWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OGZiZmFlNDNkOWM0Mzk3NjVkOTBmOTY2M2ZjNmNlODI5ZWMyODc0ZWQ4ZTFlMTg5YzU2ZjEzODY4OGE3OWM2NiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.kWU1Ydn-U-C8Do6dRaf8KS-qLVocpfECG8M-Ykjsr1A)
![image](https://private-user-images.githubusercontent.com/8084840/410765994-96456eda-54ae-4c6d-b99c-cb59ffb21d87.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkyNTkyNjMsIm5iZiI6MTczOTI1ODk2MywicGF0aCI6Ii84MDg0ODQwLzQxMDc2NTk5NC05NjQ1NmVkYS01NGFlLTRjNmQtYjk5Yy1jYjU5ZmZiMjFkODcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTFUMDcyOTIzWiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ODU0NDU2MWQ1MzJjZGVkMTI4MDM3MDU4Y2M4MGZkYTgyMDA0YmQ0OGE5NmJiNzdhZjRjZDg3NTkyODhmZDRiNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.muK7KfGSVCxPzUm4F67L8hWeZa-drfyfzbrVtMDrsdk)
Describe alternatives you've considered
I considered making a more robust system for the blood pools. One that allows a configurable amount of generations. But since blood pools and trails already tend to combine on their own. I feel any more than two generations will turn a blood puddle into a blood sea.
I initially had the wall and floor streak code a lot more separated. But I ended up repeating the code since most of it is the same. So I settled for one function that conditional changes it's behavior slightly if it's a wall streak or a floor streak.
I strongly considered trying to create a function that could check for multiple flags at once, to avoid multiple function calls from the same condition. But it didn't seem like such an easy thing to do, and I didn't want to do it unless otherwise asked to.
I really wanted to use less magic numbers and just move the design levers to class level variables. But I held off because I didn't really see any other design levers being defined on the class. And I don't yet know what parts need to be configurable for JSON anyway.
Testing
Loaded up and reset the world many times. Looking at many structures in the cities while pushing and pulling the levers until I got something I liked. I jumped around a lot of buildings and cities and nothing's broken yet.
Additional context
Still pretty newish to C++ so all feedback, useful tips, and sage advice welcome. I probably did some really stupid stuff without realizing.