Dev Log
Graphing Script - It's not exciting, but it needed to be made
A download link to my graphing asset is at the bottom of the post - if you want to try it out.
Game #2 will likely be centered around economics as well as climate (change). Deciding where to build a farm will likely be best done when looking at some climate data. Does it rain enough? Maybe too much? How hot does it get? Is the ground water polluted? Or looking at historical prices of commodities may help a player decide what type of business to pursue or how much they can afford to pay NPC employees. I don't want the game to be a data crunch fest, but data will be a part of the game. So naturally I'll be needing a way to visualize that data and graphs seem like a good way to do that. Pretty sure players don't want to read a list of float values.
Graph Maker
I'd seen Graph Maker on the Unity Asset store and bookmarked it many months back. The reviews are pretty decent and it is definitely capable of a lot of heavy lifting. I'm aware of at least one reasonably successful game that has made use of it. So it seemed worth the risk of a few bucks. Graph maker clearly has had hundreds of hours poured into it. It's polished and feature rich.
All those features have also caused it to be fairly complicated. Each graph has several nested prefab elements each with scripts attached. The documentation is also a bit rough. As a new user the number one thing I want to know how to do is send the graph a list or array of my data and have it graph it.That's it. One simple function. So where is it?
I spent a while clicking around trying to figure out where the data was stored (turns out to be in the series prefab/script). I opened the documentation and couldn't find clear directions of how to send my data to the graph via script. I opened the scripts in search of the list or function that would import my data... Couldn't find what I was looking for.
There is a neat reflection script that can be attached to gameObjects and looks like it could do some handy stuff, but I couldn't get it to do what I wanted. All in all the asset looked way bigger than what I needed. Do I need radial graphs? I don't think so...
The second thing I want to do is modify the appearance of the graph. The shear number of (nested) prefabs not to mention the number of settings in the main script it seemed like it was going to be a long battle to customize the looks of a graph.
So as I so often do, when I can't figure out an asset I start down the path of rolling my own asset. If you have more patience than I do, I know that Graph Maker is a good asset and will make pretty graphs for you.
Rolling My Own
The goal of rolling my own graphing asset was to make something simple, lightweight and easy to use. As of writing this post my graphing asset has 6 prefabs and three scripts (one of which is a custom inspector to allow graph updates in edit mode - another detects mouse hovering). The prefabs largely consist of gameObjects with just an image component. A few such as "tick marks" or "axis labels" have children with Text components, but nothing gets more complex than that. Sending data to the graph is done with 1 of 3 functions. Pretty simple.
In the end it's taken me way longer to roll my own graphing script then it would have taken to figure out Graph Maker. Is mine as pretty? No. Does mine do nice tweening animations? No. But I know how mine works and I know how to modify mine if I need to.
The feature list is short. It can switch between line (scatter) and bar graphs. The axes, points, connecting lines, and tick marks can all be tweaked in size and color.
Fonts, font size and font colors are all of course adjustable as well. Modification of the images was left out of the inspector/script and can be done with the prefabs. This was done for simplicity and the simple fact that changing images is less of a "tweak" than font size might be.
I still have one feature to figure out and that's auto-scaling. Currently the axes will auto scale and adjust to fit the data, but the values displayed on the axes does not. I'd like to figure out some basic auto scaling to keep things simple - sure I can manually adjust the values in the inspector (or by script if I expose the variables or add a new function), but that's hard to do when the game is published... I like to be involved the community, but manually adjusting each player's graphs is a bit much. I'll keep the linked package up to date if anyone has ideas of how to auto scale I'd love to hear them.
Edit: The auto scaling is now working.
Download (Free)
I may polish the asset a bit more and put it on the Unity Asset store, but that's a lot of work for not much of a return. Until then I'll happily handout a free download (box via goo.gl). Feel free to use it or modify it. Just don't flip it and sell it - don't steal my $12 in potential sales! If you do use it I'd love to hear about bugs or ways to improve it (but not bloat it).
Not until writing this post did I realize I named my asset the same as the one I'd purchased. Oops.
Environmental Simulation Part 1
When I settled on the current game design idea a central piece was an environment simulation that would effect player experiences and that player choices could in turn effect - creating a feedback cycle.
The goal wasn't (and still isn't) to create an environmental simulation that was "physically accurate." The goal was to create a simulation that was an abstraction of reality or at least had some of the key features seen day to day and year to year. I wanted the player to be able to alter the world around them in a way that reflects reality but that doesn't need to be 100% realistic.
Key Features:
- Day to day temperature swings
- Seasonal temperature swings
- Wind to transport moisture
- Water/Rain cycle
- CO2 effects
- Pollution accumulation and transport
- Runs off the main thread
Building Blocks
The first step in creating the simulation was to break up the environment into a series of blocks. Each box would have it's own set of environmental variables (temperature, humidity, ground water, wind, etc). These "climate blocks" would interact with it's neighbors to create localized weather and also to allow local variances such as terrain height and cloud density to impact the weather.
As the simulation developed and more complex interactions were add a few changes/additions to the climate blocks were needed. The first critical piece was the addition of an "atmosphere block" on top of each climate block. The atmosphere block is simulated air space above that often has a different temperature than the air on the ground/ocean. This allowed for up and down drafts that could help move clouds and cause an on or off shore wind depending on the season (more about this later). Without an onshore wind clouds and more importantly rain rarely make it to the land.
A second key addition was the classification of terrain types. At the time of writing this the simulation is only using three types of terrain ocean, grassland and mountains. This largely controls the "target" temperature of climate block and in the case of the ocean maintains a constant saturation of ground water. Oceans have moderate target temps with smaller seasonal and daily fluctuations. Grasslands have a higher target temp than the mountains but both have larger daily and seasonal fluctuations than the ocean.
Daily and Seasonal Temperatures
Seasonal sun intensity is controlled by an animation curve that is sinusoidal in shape. Max values occurring during the "summer" and of course minimum values occurring during the "winter." A second curve was used for daily fluctuations. The curves are currently identical... That may change in the future.
At first these curves were used and tuned to be a true energy flux with energy being added during the day and energy lost during the night. While more physically accurate and potentially allowing for more emergent weather, it also made it far more difficult to tune and balance. After significant testing and tuning this method was abandoned for a more controlled method.
Each terrain type has a median temperature that serves as a target temperature. There are also values for seasonal and daily fluctuations of that temperature. This means that median temperatures + seasonal flux + daily flux is roughly the high temp and likewise median temperature - seasonal flux - daily flux is roughly the low temp. Variance from this is caused by the connection of neighbors and other factors.
One of the other factors that adds some variability is the average height of the terrain. In the real world the higher the terrain the cooler the air. To reflect this each climate block samples the terrain height at multiple points and calculates an average height. From this the median temperature is adjusted slightly. This provides variation in the climate that (hopefully) lends itself to more interesting and emergent weather.
Wind
Wind in the simulation does not have a physical presence and is simply a Vector3 that stores the wind velocity. The wind for an individual climate block is calculated based on the temperatures of the neighboring climate blocks, including the upper atmosphere. The inclusion of the upper atmosphere allows up and down drafts which allows for onshore or offshore breezes (as mentioned above).
To calculate the wind the simulation calculates a temperature difference between the climate block and a neighbor and then multiplies that by a vector that goes from the climate block to the neighbor. Final direction (sign) of the wind is based on blowing from hot to cold.
The simulation sums all the winds due to neighbors to arrive at a (nearly) final wind value.
A prevailing wind is then added. This allows larger global winds to be added to create larger and different weather patterns. The strength of the prevailing wind is a tune-able variable. Current testing is with an in/out pattern that helps to blow clouds away from land in the summer.
After the prevailing wind is added the vector is normalized. There was some debate about normalizing the wind... In the end the choice was made to keep the normalization as this meant that clouds always would have some wind. It also prevents unrealistically large or small winds that become problematic when trying to transport clouds/moisture.
The final step is a check on the vertical component of the wind. Since the upper atmosphere is often at a very different temperature it can therefore be the dominant contribution to the wind. This is a problem due to only simulating two layers of atmosphere rather than more layers or the ideal of a continuous atmosphere. Effectively the vertical component is clamped to a range between -0.5 and 0.5. This helps to keep clouds generally moving horizontally.
Additional controls are needed to avoid the clouds going too high or going through the ground. The altitude of the clouds is mostly visual as the horizontal location determines where clouds can deliver rain. Because of the this a simple min and max altitude are set. Clouds check against these values and degrees of freedom are restricted in the rigidbody to prevent clouds from going outside the bounds. Checks on vertical velocity are also necessary to allow the clouds to move away from the limits.
In Part 2 I'll discuss the most difficult part (so far) of the simulation that being the Water and Rain Cycle. Or more specifically the balancing of that cycle.
The Inevitable : FTF PostMortem
Fracture the Flag is my first and only game. Not the only game that I've published. It's my only game, period.
I'm pretty damn proud of FTF. Sure I had dreams of selling 100k copies or 50k copies or even 10k copies. None of which happened, but the real goal was to learn, to build a (small) community and create a game that at least some people thought wasn't total garbage.
By that measure it has been a complete and total success.
While the code base is a mess of poorly written spaghetti code it mostly works. I learned how to better organize my code and how to create more efficient code. I discovered that multiplayer is great idea, but like so many before me, I also learned it's freaking hard to implement. What works well on two test machines on my desk is very different from two players that are on opposite sides of the Atlantic. I figured out a basic workflow from Blender to Unity. I stumbled through the process of creating basic editor extensions to make my game development a little easier. I also learned I had no idea how to set up the lighting in a scene and still don't.
I learned that there is plenty more to learn.
Managing the game and community surrounding the game after the initial Early Access release was stressful, but still more rewarding than I could have expected. I had no idea how buggy the game was. Not really. I had no idea how thoughtful and kind some people would be. So many people were constantly giving feedback and helping make the product better. My biggest lesson in taking a game from Greenlight to Early Access through to Full Release is simple:
Be open. Be honest. Be human.
Folks can smell from miles away a developer that just wants a quick paycheck. While not every interaction in the FTF Steam community was positive I found most can be turned that direction with a little humility and honest listening. Not every customer has a good idea or even a valid complaint, but most do. So I did my best to listen.
Case and point: Two friends each bought a copy of FTF hoping to play together. They quickly found several game breaking bugs that earlier players had simply ignored or hadn't noticed. These two players proceeded to rip FTF to shreds on Steam reviews - yes plural, they each wrote one. Both brutal and brutally honest. I didn't respond to the review, but when they posted in the forums I took the opportunity to start a conversation. After the exchange of several comments I had great feedback from the players and removed several sizable bugs from the code base. They dropped their negative reviews and decided not to ask for refunds. I never saw if they left positive reviews, but the huge negative reviews were gone. That's a huge win for a solo developer and worth every ounce of effort.
Let's talking pricing.
When I first had a vision for FTF I thought surely the game must be worth $10-12. I mean I've worked so hard on it! It's got multiplayer for crying out loud. As it got closer to the Early Access release date I got a bit gun-shy. I refocused on my main goals. Making money would be nice, but it wasn't the primary goal. So I cut the price. I cut it a lot. Down to $2.99 in the US market. This seemly had the effect of lowering expectations and doing so in a helpful way.
The early reviews were incredibly positive. Early on FTF has a 90+ percent positive rating - and not from people who got free keys. The game sold reasonably well in its first week with sales continuing to trickle in as the weeks passed.
I fixed bugs and added features before the full release. I added so much! So many good ideas came pouring in from the community. So I decided to raise the price. To the price of a latte in Aspen... All of $4.99. Sales slowed and expectations seemed to rise while the rating on Steam dropped to what it is now, 78%. Was it a mistake?
Then came release day.
Sales were modest but better than I hoped. The first day as a full release saw almost no exposure on Steam but was still the best sales day in the short history of FTF. More copies of FTF were sold in the those first three days then in the entire first week of Early Access. Not too shabby.
I hear people say you only get one release. Maybe that's true. But I think building a community and getting positive reviews helped to serve up more sales then FTF would have seen had it jumped straight in as a full release. I know I'm more likely to buy a game that has decent reviews and has been "out" for at least a little while. But who really knows, maybe I'm just seeing what I want to see.
7 months after the initial Early Access release FTF is essentially "finished." No, it doesn't have every possible feature. Yes, there are still bugs. And no, I didn't make enough to quit my day job - not even close. Sales are generally within the margin of error shown by Steam Spy but I have often seen the numbers dip too low (but I've never seen them go too high). I made enough to easily pay for a high-end mountain bike and new set of skis and boots. For a guy who's day job requires bikes and skis... Not a bad result.
My hourly wage? Probably didn't make it to minimum wage... No, let me rephrase that. I didn't make minimum wage.
You can see sales spike on the release day and then again during sales and of course the day FTF came out of Early Access.
So now the game is in the long tail. Sales have slowed as expected, but the trickle is still going. At least enough to buy my wife and I dinner out once a week.
So what would I do different?
No multiplayer. While I nearly dipped my toes into that pond again for game #2, a quick read of some FTF comments reminded me of the horrors of trying to sell a multiplayer game as a solo developer. This might be a lesson I have to learn more than once...
For game #2 I want to find an outlet for early builds beyond Early Access. Find a smaller market. Find a community interested in giving feedback and more willing to take risks on a title. Take the time to polish the game before heading to Steam.
As a solo developer I need my games to be more procedural. With FTF building a level took days and the way I built the level meant I often couldn't even make small changes without completely scrapping the level and starting over. Got a rock in the wrong spot? Combined the wrong meshes and can't get good occlusion culling? Too bad.
Game #2 needs to be a game I want to play. FTF started as memories of playing Crossbows and Catapults a kid. I loved that game. Then FTF started to morph. It turned into something totally different. Sometimes for good reasons and sometimes not. It's not even close to the game I first set out to make. As a result I tried to squeeze into an already defined genre and all the expectations that came with it. Slowly, with each added feature FTF became a game I wasn't really interested in. So, now I dream of the game that I simply want to keep working on. Wouldn't that be magical?
What's next?
Game #2 is next. I have a vision, but not a complete plan. I want to create something different. (Shocking I know). I am fascinated by how poorly we treat each other as humans and how poorly we treat our beautiful planet. I dream of a game that could explore those very real issues while still being fun and challenging. In my head the game is so hopelessly over scoped I worry I may never be able to finish it or if I do it will turn to total shit.
So ignoring common sense, step one is to create a game world that I want to spend more time in...
I know that's ass backwards for most folk, but a world that is pleasant and enjoyable to walk around it seems like the first step in learning to appreciate that world.
The page has just begun to be built, but you can see what there is to see about #2 here.
Older Posts
-
April 2024
- Apr 10, 2024 Ready for Steam Next Fest? - Polishing a Steam Page Apr 10, 2024
- Apr 1, 2024 Splitting Vertices - Hard Edges for Low Poly Procedural Generation Apr 1, 2024
-
November 2023
- Nov 18, 2023 Minute 5 to Minute 10 - Completing the Game Loop Nov 18, 2023
-
September 2023
- Sep 13, 2023 Visual Debugging with Gizmos Sep 13, 2023
-
July 2023
- Jul 4, 2023 Easy Mode - Unity's New Input System Jul 4, 2023
-
May 2023
- May 19, 2023 Level Builder - From Pixels to Playable Level May 19, 2023
-
April 2023
- Apr 11, 2023 Input Action in the Inspector - New Input System Apr 11, 2023
-
February 2023
- Feb 26, 2023 Tutorial Hell - Why You're There. How to Get Out. Feb 26, 2023
-
December 2022
- Dec 31, 2022 Upgrade System (Stats Part 2) Dec 31, 2022
-
November 2022
- Nov 10, 2022 Stats in Unity - The Way I Do it Nov 10, 2022
- Nov 5, 2022 State of UI in Unity - UI Toolkit Nov 5, 2022
-
August 2022
- Aug 17, 2022 Knowing When A Coroutine Finishes Aug 17, 2022
-
April 2022
- Apr 23, 2022 Unity Input Event Handlers - Or Adding Juice the Easy Way Apr 23, 2022
-
March 2022
- Mar 15, 2022 *Quitting a Job I Love Mar 15, 2022
-
February 2022
- Feb 8, 2022 Split Screen: New Input System & Cinemachine Feb 8, 2022
-
January 2022
- Jan 24, 2022 (Better) Object Pooling Jan 24, 2022
- Jan 19, 2022 Designing a New Game - My Process Jan 19, 2022
- Jan 16, 2022 Strategy Game Camera: Unity's New Input System Jan 16, 2022
-
December 2021
- Dec 16, 2021 Raycasting - It's mighty useful Dec 16, 2021
-
November 2021
- Nov 22, 2021 Cinemachine. If you’re not. You should. Nov 22, 2021
-
August 2021
- Aug 3, 2021 C# Extension Methods Aug 3, 2021
-
June 2021
- Jun 27, 2021 Changing Action Maps with Unity's "New" Input System Jun 27, 2021
-
May 2021
- May 28, 2021 Unity's New Input System May 28, 2021
- May 8, 2021 Bolt vs. C# - Thoughts with a dash of rant May 8, 2021
-
March 2021
- Mar 10, 2021 Coroutines - Unity & C# Mar 10, 2021
-
January 2021
- Jan 14, 2021 Where's My Lunch? - January Devlog Update Jan 14, 2021
-
December 2020
- Dec 27, 2020 C# Generics and Unity Dec 27, 2020
- Dec 7, 2020 Steam Workshop with Unity and Facepunch Steamworks Dec 7, 2020
-
November 2020
- Nov 27, 2020 Simple Level Save and Load System (Unity Editor) Nov 27, 2020
- Nov 9, 2020 Command Pattern - Encapsulation, Undo and Redo Nov 9, 2020
-
October 2020
- Oct 28, 2020 GJTS - Adding Steamworks API and Uploading Oct 28, 2020
- Oct 9, 2020 Game Jam... Now What? Oct 9, 2020
-
August 2020
- Aug 16, 2020 Strategy Pattern - Composition over Inheritance Aug 16, 2020
-
July 2020
- Jul 24, 2020 Observer Pattern - C# Events Jul 24, 2020
- Jul 15, 2020 Object Pooling Jul 15, 2020
- Jul 3, 2020 Cheat Codes with Unity and C# Jul 3, 2020
-
June 2020
- Jun 16, 2020 The State Pattern Jun 16, 2020
-
August 2019
- Aug 12, 2019 Easy UI Styles for Unity Aug 12, 2019
-
July 2019
- Jul 3, 2019 9th Grade Math to the Rescue Jul 3, 2019
-
June 2019
- Jun 12, 2019 Introducing My Next Game (Video DevLog) Jun 12, 2019
-
May 2019
- May 29, 2019 Programming Challenges May 29, 2019
-
March 2019
- Mar 2, 2019 Something New - Asking "What Can I Learn?" Mar 2, 2019
-
November 2018
- Nov 30, 2018 A Growing Channel and a New Tutorial Series Nov 30, 2018
-
October 2018
- Oct 11, 2018 Procedural Spaceship Generator Oct 11, 2018
-
July 2018
- Jul 11, 2018 Implementing SFX in Unity Jul 11, 2018
-
May 2018
- May 31, 2018 Prototyping Something New May 31, 2018
-
April 2018
- Apr 17, 2018 When to Shelve a Game Project? Apr 17, 2018
-
February 2018
- Feb 9, 2018 State of the Game - Episode 3 Feb 9, 2018
-
December 2017
- Dec 16, 2017 State of the Game - Episode 2 Dec 16, 2017
-
November 2017
- Nov 7, 2017 The Bump From A "Viral" Post Nov 7, 2017
-
October 2017
- Oct 30, 2017 NPC Job System Oct 30, 2017
-
September 2017
- Sep 1, 2017 Resources and Resource Systems Sep 1, 2017
-
August 2017
- Aug 3, 2017 State of the Game - Episode 1 Aug 3, 2017
-
June 2017
- Jun 20, 2017 Resources: Processing, Consumption and Inventory Jun 20, 2017
- Jun 15, 2017 Energy is Everything Jun 15, 2017
-
May 2017
- May 16, 2017 Graphing Script - It's not exciting, but it needed to be made May 16, 2017
- May 2, 2017 Tutorials: Low Poly Snow Shader May 2, 2017
-
April 2017
- Apr 28, 2017 Low Poly Snow Shader Apr 28, 2017
- Apr 21, 2017 Environmental Simulation Part 2 Apr 21, 2017
- Apr 11, 2017 Environmental Simulation Part 1 Apr 11, 2017
-
March 2017
- Mar 24, 2017 Building a Farming Game Loop and Troubles with Ground Water Mar 24, 2017
-
February 2017
- Feb 25, 2017 The Inevitable : FTF PostMortem Feb 25, 2017
-
December 2016
- Dec 7, 2016 Leaving Early Access Dec 7, 2016
-
November 2016
- Nov 28, 2016 Low Poly Renders Nov 28, 2016
- Nov 1, 2016 FTF: Testing New Features Nov 1, 2016
-
October 2016
- Oct 27, 2016 Watchtowers - Predictive Targeting Oct 27, 2016
- Oct 21, 2016 Click to Color Oct 21, 2016
- Oct 19, 2016 Unity Object Swapper Oct 19, 2016
-
September 2016
- Sep 18, 2016 Testing Single Player Combat Sep 18, 2016
-
May 2016
- May 25, 2016 Release Date and First Video Review May 25, 2016
-
March 2016
- Mar 26, 2016 Getting Greenlit on Steam Mar 26, 2016