It’s an exciting day today. I bring to you the first edition of “Learning Together”. I came up with the idea during a car ride this weekend to get ice cream. I was so burned out with Unity3D and Playmaker. There’s tons of resources out there, but they didn’t quite do what I wanted. I spent hours browsing the forums of Hutong (a great resource) to finally get this wonderfully complex (It’s actually quite simple) state machine up and running. So here’s the video and some explanation to follow. Let’s get started.
My Personal Philosophy on Programming
This is very important as it sets the expectations of people who are coming aboard the learning series. I come from the C++ and later C# Object Oriented programming world. So classes are built to contain their worldly information and that’s it. In game design each object is like a “class”. It is responsible for it’s own world and not much else. The Game Manager runs the world. The Player deals with themselves and each object is it’s own entity.
Simplicity is key. There’s an art to keeping things simple. It’s like this lost concept in a world of growing complexity. I worked really hard this weekend to get to an elegant and simple solution. One that’s both easy to read and understand as well as easy to maintain. As a one person team, I can’t afford the time to upkeep an overly complex system of tools. I’m sure there’s a lot of 1-4 person Indie shops out there running into the same issues.
Like a lightswitch in the real world, interactive objects should just hang out waiting to be interacted with in order to do their job. The Playmaker NoExit tutorial did this backwards. Their door switch cast a “Mouse Pick Event” that needed a “Mouse Over” state, then another state to wait for input and check for a “Mouse Off” event. Then a third return state that would set the mouse cursor back to default and go to wait. This made 3 extra steps that are just not needed.
While it works, their design is a lot of work. For a single switch it’s fine, but add in several thousand objects all scanning to see if they’ve been interacted with is just a drag and full of lag. Further it’s a lot of repetitive work to set up. Each object would need 3-4 additional states just to check if they’ve been “picked”. A huge
The flying Spaghetti monster State machine! This is actually the last step in a 3 part State Machine. Or FSM as Hutong calls it. Having three working parts may seem like a lot, but each piece does an important singular role and they all work together in harmony. I feel this is a very simple and elegant solution that should not affect the performance of the game all that much. Win-Win situation here.
Note: All the FSM elements will be explained in the video. Honestly, it’s a lot.
As a long time programmer, global variables are a scary prospect. Anything can, and possibly will go wrong. ADHD moment: As of this writing, I’m thinking the “player object” shouldn’t be global even if it’s used everywhere. Having a “read only” global would be a great feature.
Despite the dirty feeling, I’m still sparingly using globals. The simple reason is it simplifies the communication between the various FSM and it can keep track of important items like the state of the mouse. Is it locked or is it free roaming? Though with playmaker changing a variable is a very deliberate process.
The first major component and one I started with was the Mouse Lock and Unlock component. It operates on a very simple premise: to allow the users to scan the environment with the mouse. It also paves the path towards centralizing the inventory manager and other commands.
I’m using Opsive’s “Third Person Controller”, but it’s compatibility with “Inventory Pro” is wonky. Since Devdog is focusing on “Rucksack” they’ve dropped the Inventory Pro support to barely existent. No big deal. There’s Playmaker and the Source code to the rescue.
For some reason, since Opsive updated their TPC recently, the “Lock Input” feature of Inventory Pro stopped. So opening Inventory with “i” no longer locks input and unlocks the mouse. So this is a backup solution once complete.
Mouse Over Manager
This is the major workhorse of the whole project. It’s also a very elegant solution.
The Wait State only waits for a “Mouse Pick” object to change. It further only cares about a few layers. It then checks the global variable if the cursor is locked or not.
If the cursor is locked, then this checks all available tags. If the cursor is unlocked (room scan/GUI mode) then it has a short list of mouse cursors to use. This keeps everything short and sweet.
Finally it uses an intermediary local event to send out a global event. This part is a touch messy. I did it for readability and to keep things readable. Each component is strictly responsible for one action. This way the code comes out clean.
I know, you’ve already seen this one. Well here it is again with explanation. This guy does all the work of changing the mouse cursor to the proper ones. Each state listens for a global event and does a bool test for “cursorLocked”. Here’s where things get beautiful. Only one global variable is needed!
The “Allow Input” is from Opsive’s Playmaker integration. It works really well. If the cursorLocked bool is true, then the cursor is locked and input is allowed. If the cursorLocked is False, the cursor is “free roam” and the input is locked. Pure genius. So it’s the “end state”. There’s no need for a “FINISHED” event because each State listens to a global event and will activate upon receipt. This keeps the controller tight and organized. I could add in 20 more mouse pointers and the work is now minimal. Just add in a few Global Events, update the mouse manager and I’m done.
A real lot of work went into this solution. Why? Because the mouse cursor is your eyes into the game world. It tells a subtle little story that “something can happen to this object”. Or “This guy is an enemy”. “You can talk to this girl”. In the real world, you recognize object because they’ve been taught to you. Everything can be interacted with. But in a game world, we need that extra sensory perception because not everything is as intuitive. Not every item has life or function. So we need to tell you what does. This is an important part of User Interface design and a very important consideration early on in the game design process.
Immortal Realm Design Steps
- It started with an idea. A basic concept for a game. I wanted it to be a Dungeon Crawl.
- I took Ben Tristem’s “RPG Core Combat” course on Udemy and got inspired. The town became an idea to be a central location to “come up for air” after each dungeon.
- Everything was scrapped. Yes, all the work above was wiped out.
- I turned to Gaia and the various landscape tools to generate initial Island.
- I formed the land to create a place for the two towns to exist and thrive.
- Then I was futzing with Gaia on my laptop and it generated an even more incredible island that is the world today.
- Everything was scrapped and the new island was born.
- Then I warily tried Playmaker.
- Nothing was scrapped. I love Playmaker’s ability.
- I opted to go third person instead of top down.
- Now I’m working on getting Inventory Manager, Playmaker and Third Person Controller to work nice together. They mostly do, but there’s issues.
- I am here ->>>> Getting the Third Person controller to work with Invetory manager so I/You can equip weapons and attack. The demo scenes already have the character fully decked out with weapons and armor. But I cannot possibly add in 300+ weapons and armor outfits to the character. So there needs to be a Mount point system. Ootii has this and a really good Third Person controller with great tech support and pretty tight Inventory Pro integration. But it’s expensive. I factored in almost $200 for all the needed components. Ugh.
- TPC or Ootii can be used in Super Panda 2. So I’m not at a loss with whatever direction I go.
- Behavior Designer is next. Ugh.