So here’s a fun little project I’m working on–Python Tactics (very tentative title). In short, it’s a turn-based tactics game that I’m developing in Python using Maya as an engine.
Near the beginning of my internship at EA Tiburon, I knew that I would be working on various tools and scripts that would be written in Python and C#. At that time, I hadn’t written any Python for about a month or two, and I hadn’t used C# for a few years, so I wanted to start a little side project to help me get back into it. I thought maybe I could make chess or something grid-based, but I wasn’t sure what yet. A couple of days later, I randomly wondered if it was possible to use animated images (.gif’s or image sequences or something) in Maya’s GUI. That thought along with the grid idea lead me to decide on making a tactics game. I briefly thought about making the whole game in Maya’s GUI (displaying the game board, the characters, the animations, etc.), but then I thought it would be neat if I could use 3D models in the viewport in addition to using some GUI windows as the actual user interface.
At the same time, I was thinking how cool it would be if Maya, this robust tool for creating 3D models, could also be used as an engine to run a game. I always thought it was a bummer that artists created their assets in one program, where they may look and work perfectly, but then had to import them into an engine which might display and treat the assets differently than the program they were created in, requiring the artists to go back and fix the assets. I observed that this often led to artists not ever wanting to touch the engine because 1) they would often observe something was wrong, meaning they had to do more work and 2) they didn’t how why something was wrong because the engine wasn’t a program they were required to be familiar with. This obviously led to frustration. Who can blame them? It’s an awful feeling when you think you’re done with something only to find out that you’re not, especially when you don’t know how to actually finish your work. What if the 3D creation tool and the engine were one and the same? What if the artists could use all of their creation tools in the engine? They would already know how to fix things, and their assets would look and work exactly as expected–what you’d see is what you’d get! Cool stuff.
I had been using mostly Python at the time, so I decided to start writing in that and then port it over to C# later. My hope was this would give me some good practice in both languages as well as practice in writing code that was as language independent as possible.
So that’s where the idea came from–essentially just a combination of “Huh, I wonder if you can do this,” and “Hey, wouldn’t this be cool?”
Structuring the Code
One thing I wanted to practice was dividing and structuring my code into different, appropriate groups. Mainly, I wanted to get some more practice effectively using classes and inheritance. The concepts were not at all new to me, but I had never really used classes together before, especially those that inherited from one another, and when I had, it was never really anything extensive. The first thing that immediately came to mind was characters. No wait! Entities… Yes… *wrings hands together* Entities would be perfect for this kind of thing. I came up with two types of entities–characters and obstacles. For both characters and obstacles, I would need to know where in 3D space (and on the grid) these would be. I would also need the ability to move both characters and obstacles. These attributes and functions would go in the Entity class, and both the Character and Obstacle classes would inherit from Entity. Each of those classes–Character and Obstacle–were broken down into more classes and those classes into yet more classes. In order to avoid becoming unnecessarily wordy, I’ll just use a diagram:
Classes lower in the diagram inherit from the higher ones they’re connected to.
So that’s the meat of my starting material. All of those classes are in an Entities module. I have a few other modules. EventController controls handling selections/mouse actions, starting the game, and controlling turns. GUIBuilder takes care of setting up, displaying, and editing the two GUI windows as the game goes on. TheGrid contains a GridSpaceVert class that holds information about a vertex, a GridSpace class that holds information about an individual square on the grid, and the TheGrid class that can create the game board/grid (comprised of many GridSpace instances), can clear the board, can resize the board, and can get/set information about the grid’s spaces and any entities on those spaces. Finally, I have a CubeBattle module that I’m using to import everything, create instances, and put the whole thing in motion.
These classes, while well organized (I think), are probably nowhere near done. However, so far I’ve been able to appropriately group every new piece of code I’ve thought of into one of the modules, so I’m pretty pleased with that. So far…
Problems and Obstacles I’ve Encountered
The first real obstacle I ran into was trying to get things to happen when I made a new selection. I knew that I needed, for example, the soldier cube to move to the space I clicked on. I knew how to move it, that was a simple matter of setting its position to the center of the square I clicked on, but how could I move it when I clicked on that square? I did quite a lot of research on the topic. For a while I thought that I would have to get into some C++(?) in order to anything event-based. I also found some information on Maya’s dragger context command and thought I might be able to use that. Thankfully, I eventually found my Holy Grail: script jobs. Script jobs run when certain events are triggered in Maya, and one just so happens to run whenever a new selection is made. Perfect! This was exactly what I needed! Whenever a new selection was made, I could run code based on what that selection was. In this case, I could detect if a square was selected in the character’s range, and, if it was during the character’s movement phase, move the geometry to that square.
I ran into a few more problems related to this (turning the script jobs off, using more than one script job for different tasks, etc.), but I eventually worked them all out. The next big problem was getting the Mario sprite in the GUI window to animate. The first thing I tried was simply setting the GUI’s image as a .gif. Unfortunately (but not surprisingly), this did not work. I also tried using a video as the GUI image’s source, but that too did not work (again not surprising). My next thought was that I would have to have different images and change the GUI image’s source over time, but how would I do that? I looked through the script jobs to see if there was one that could help me, but didn’t see one that could. They all run when an event is triggered, not simply over time in the background (or so I thought). I then tried mucking with moving the timeline and having that control the GUI image’s animation. I soon learned that I was unable to run code while the timeline was playing. Too bad… That would have been nice when the time came to implement 3D character animations. Oh well… I kept looking and looking, and I couldn’t find any answers or even helpful information. Finally, one day, I was looking back through the script jobs, and I noticed there was an “idle” event. I looked into it a bit and realized that this was exactly what I needed! When Maya wasn’t performing any other tasks, it was idle (duh :P), and it would call an idle event script job! With this, I was able to keep track of time, and switch the GUI image’s source to the next image in the sequence over time. Problem solved (b^_^)b
As you can see in the video, the game already runs at a basic level. Characters have turns in which they can move and attack, they can die, and the game can end. I’m in the process of deciding what exactly I want to implement next. I’m still not sure, but I do have some things I want to implement eventually (in no particular order):
- 3D characters and animations
- different elevations on the board
- a more robust GUI (which would be anything at this point :P)
- special attacks/moves for different character classes
- more character classes
- support for an infinite number of entities on the board (I think I already have this, but I haven’t really tested it yet)
So that’s where I am so far. I’ll keep updating as I get more done 😀