Solitaire Week 1: New Project
So over the last couple of weeks I’ve been playing around with new project ideas. I had actually gotten stuck into a project and had planned on making a post about a week ago, but my motivations changed and reality said otherwise. One quick note for future me, I believe that while doing these moderately long, multi week type programming/gaming projects it may be necessary to take about a week off between projects. For one thing, taking a week off allows you to clear your head so that your next project gets a chance at being a “new thing” and not just an offshoot idea of the thing you’ve been focusing on. Secondly, if you’ve been really hammering the previous project to get it done, some time “off” allows you to take a little breather and get back on your feet.
Anyway, coming out of the last project I had it in my head that I wanted to make a Flappy Bird clone. I had a number of good reasons for thinking about this project. The base concept seemed simple enough, I could cross compile it to HTML and desktop just like the Breakout project, and it left enough room for some embellishments. The chief reason that I wanted to take the project on however was so that I could cross compile it to Android. I don’t think I’d be able to release it on the Google Play Store, as I think they’ve cracked down on Flappy Bird clones in recent years, but I could still cross compile it for Android, run it on the small pile of Android devices that I own, and learn that side of the LibGDX framework.
I worked on this Flappy Bird clone for about a week, and I actually got pretty far with it. I think I’d like to actually see it to completion sometime, ideally finishing it up before New Years. I had to download Android Studio to get access to the Android SDK, and once I had that on my local machine I uploaded it to my local file server, built it into my build container, and got the whole project compiling desktop, HTML, and Android binaries in my CI pipeline. Gameplay wise, I made an infinite world of pipes that the player has to navigate through by “jumping” his plane. A GIF of the gameplay after a week of work is below.
I’ve actually tested this on a couple different Android devices as well (you can tell the aspect ratio that I picked was more geared towards mobile) via the Google ADB toolset.
Getting something up and running on mobile (though not complete) was a lot of fun. However, after a week of work on this new project, I was feeling a little burnt out. I felt like I hadn’t given myself enough time between projects, and I was really looking for something “new” where I wasn’t quite using all of the tricks that I learned while making BreakoutGdx, but rather learning new tricks. Around this time, one evening, I was scrolling through OpenGameArt looking for interesting assets, and I ran across this asset pack of cards. These are just ordinary playing cards, but they sparked my interest and I began to wonder how I could use LibGDX to make a card game. I’m a pretty big Magic: The Gathering fan in my off time so I really enjoy anything related to deck building and strategy on a personal level, and it also seemed very different from BreakoutGDX altogether. I decided that evening that my next project should be a game of “Solitaire”, made with LibGDX. Solitaire isn’t exactly ground breaking, but I figured it was a good stepping stone target, and I was hoping that making a Solitaire game would give me an opportunity to learn a bit about making card games in software.
I started this exercise by writing down a definition of what a “card” was and what a game of Solitaire was. To assist with this, I played a number of games of Solitaire (via Google Solitaire) to help understand the game better. After a night of playing Solitaire and collecting my thoughts, I felt the first thing to do would be to write code for a Card object, write the definition of each type of card (in a playing card deck), and write code for a Deck object that contained a set of 52 playing cards. The crux of that came down to defining a CardType enum, which can be seen below.
As you can see, the chief property of a “Card” object is it’s CardType enum, and the CardType enum consists of a numerical value (1-13), a suit, and a color. Each card has a sprite definition that contains the information to get the sprite for the front face of the card, and it has a name as well (mostly for debugging). Since card backs are the same for all cards, the sprite for the card back is just held in the Card class itself. Upon making these objects I added some game boilerplate to bring the Scene2D framework into the fold, brought all of the cards in as “Actors”, and applied click and drag listeners to each card. In the below screenshot, each card had a click listener that would flip it face up/face down, and a drag listener that would move it around the screen.
Adding DragListeners took awhile to figure out, but once I had that working I had a realization for how to break down the game of Solitaire. My thinking is, in essence Solitaire can be broken down to the player moving cards between “Card Structures”. When a card is a member of a CardStructure it has specific functionality that it can perform in it’s attempt to make it’s way to other CardStructures. For example, if a card is in the “Deck” (typically held in the top left corner of the screen), those cards are always face down, and when clicked on they always exhibit the behaviour of turning face up, and moving to the pile of cards to the right of the deck. We can define similar rules for all other CardStructures in the game. I figured that I could model each of these CardStructures, build specific ways to add/remove cards from each type of CardStructure, and craft the “engine” so that when each card was added to a CardStructure I could apply the functionality to it that was specific to that type of CardStructure.
I decided that there were four CardStructures in the game: the deck, the stack, card heaps, and card columns. Each structure has specific requirements that a card needs to meet in order to be added to the structure, and once in the structure each structure applies specific functionality to it’s member cards. The week then largely turned into me defining each of these CardStructures and defining the functionality of transferring cards between them. I started with definining the deck and the stack.
Each card on the deck gets a TouchListener applied to it that says: when touched, remove yourself from the deck, add yourself to the stack, turn yourself face up, and apply a movement animation to move your sprite from deck to stack. When a card is removed from the deck, this TouchListener is removed. When a card is aded to the stack it gets assigned a DragListener that is tooled to say: when dragged, drag your sprite around the board. When the drag is released, check if you have collided with a valid column or heap object, and if so then remove yourself from the stack and add yourself to that heap or column. If you are not overlapping a valid heap or column, then return yourself to where you were when the drag started. Similarly (and far too complicated to explain in a short post) I implemeted the heaps and columns to the game. While doing this, I made sure that the game cross compiled to HTML5 and Android.
Finally, for the columns I made a special listener that gets applied to cards that are in the column but are not the last card in the column that allows for “multi card moves”.
This allows “groups” of cards to be moved from column to column, a vital functionality in Solitaire.
And that’s pretty much it for week 1. I haven’t given myself a concrete schedule or kanban board yet, but I hope that both this project and the FlappyBird project will be done by 1 January, 2022. More to come.