-
Notifications
You must be signed in to change notification settings - Fork 1
How the new card system works
This document will go over everything that changed between the old system that was in place for the cards in the game compared to the new system.
The following files are all changed/new compared to the old system
- play_card_button
- CardHandler
- CardManager
- obj_newDrawer (NEW)
- CardArea
- NewCardStruct (NEW)
- obj_NewCard (NEW)
- Buttons
- all_cards (NEW)
- Card - Room Creation Code
- Card_buttons
- TabTracker (NEW)
The most important change to understand how everything works now is with how cards are drawn in this new system. With the old system, cards were drawn very poorly; there were multiple sprites that had to get drawn, it relied on calculating position and size to find where to draw each part, and had issues with redundant variables that were used in-place of GameMaker's standard, included features.
The new system completely simplifies this. Now, all parts of a card are included in the sprite. This includes
- Card border
- Card name
- Card image
- Card background
Now the only thing the game needs to keep track of is which sprite a card needs. The original system would have done this with keeping track of art IDs in the card data json file, but another change with the new system makes that unnecessary. I've now changed it so that all sprites for a card are contained in a single sprite, called "all_cards." Each card is a single frame of the sprite (Move Pawn is frame 0, Move Knight is frame 1, etc.), and are in the same order as the cards are listed in the json file. The card data is parsed into an array from the json file, meaning each card already has an index value by default, and luckily for us these index values pair 1-to-1 with the frame each card's sprite is on.
Here is a mockup of what the sprites will look like when they're all finished:
However, because of this new system, two screens needed to be completely revamped: The card encyclopedia, and even more so, the actual gameplay screen
The first step to fixing these screens was to create a new card object from scratch, since trying to work with all of these changes from the old card object would've been a huge headache.
Here is all the code that is contained in the new card. This is what each line is for:
- image_speed: How fast the sprite animates. At 0, it doesn't animate at all.
- image_index: The frame of the sprite for the object. The default here is 40, which is the back of the card.
- belongs_to: Used to identify if a card belongs to the opponent or the player.
- description: Description of the card, parsed from the json; defaults to an empty string.
- type: What type of card it is, parsed from the json; defaults to an empty string.
- art_id: The old art_id system from the json, redundant and can be removed, but must also be removed from the json.
- effect: What the card does when played; defaults to undefined.
- interactable: Decides if the card can be clicked on or not; defaults to false.
The if-statement at the end makes sure that the sprite for the opponent's cards are set to the card back frame, so the player can't peek at them.
This script is the place where all the functions for the new card object are taken care of.
Firstly, the card_struct array is populated with the card data from the json. This is where we'll load the data from whenever we're creating a new instance of a card.
Next we'll look at the spawnCard function. The _card variable holds the data for the card in our json array at whatever index position is passed into the function, while the _inst variable is the new instance of the card being spawned. Once the new instance gets all of the data it needs, it gets pushed into the array for the player's hand, and the redraw_hand function is called.
The redraw_hand function replaces the old, strange system that was used to update the visuals when a card was drawn or played, located in the Step event of the CardHandler object. It also undoes the misconception that the player could only hold a certain number of cards in their hand at a time, which was programmed in for some reason, so it now allows for the player to hold as many cards as possible. The else case covers when the hand size is small enough that the cards wouldn't go off the screen, so it just places them at an equal distance of each other. The first case covers when the hand size is large enough that the cards would go off the screen, and moves the cards in a way so that they're neatly in a row and layered over each other.
Now that the new way cards are created and drawn is explained, let's go over how both the screens were updated to fit the new system.
The old card encyclopedia used a redundant card object that was designed ONLY for being displayed. Why do this when you already have a card object? It just makes the asset browser messy. The new page creates three instances of obj_newCard to display, and thanks to our interactable variable, we don't have to worry about any issues with reusing them here.
The next step was getting the buttons on the page updated to actually change the sprites on the card instances. When you first move to this screen, it's defaulted to viewing all of the cards, but there's also buttons at the top that allow you to view cards of a specific type, so that had to be take into consideration as well. The first thing I did was create the TabTracker object. This object's ONLY purpose is to verify which tab the user has selected, so the game knows how to properly change the sprites.
After that comes changing the forward and back buttons to view the cards. Because of the new image_index system, all you have to do is increase/decrease the "frame" the sprite is on by 3 to get the next set of 3 cards. However, obviously there's an issue when reaching the beginning/end of the cards because if you increase/decrease it past the minimum and maximum values you'll have an issue, so that had to be taken into account as well. The code below is for the "previous" button, and the code for the "next" button is basically the same, but the opposite. One difference with the next button is setting the instances to be invisible if you press the button and reach the end of whatever group of cards you're looking at. The previous button handles making them visible again.
This is the bulk of what had to be changed to adapt the new card system. This includes the passive card slots, the discard pile, the draw pile, the reset button, the play card button, and the player hands. We'll explain it in order of how the player would interact with the screen, where they would draw a card with the Drawer object, then the card would go into the player's hand with the CardHandler object, then a player would click on a card and the play_card_button would be set to whatever card was clicked, and then the player clicks the button and the card moves to whichever pile it should be placed on depending on what type of card it is.
The old "Drawer" object has been replaced with "obj_newDrawer," and the amount of code in both is like night and day. For example, the old Drawer object had 165 lines of code JUST to draw the visuals. The new Drawer is 4 lines long and does one thing: draws a random card.
The CardHandler has been updated to just keep track of 3 variables, as the other variables are all redundant. Thanks to our redraw_hand function from before, it doesn't need to worry about updating the visuals anymore.
The code in CardHandler to make sure the play card button aligns properly and gets the right card to be played works mostly the same as before, but is allowed to look neater because of the new way cards are implemented.
The delete_card_from_hand function that existed previously in the play_card_button object has been updated to properly delete the instance of the card being played, and then remove it from the player hand.
To explain how the play_card_button now functions, I first have to explain how the CardArea objects were changed. The CardArea has been changed to use the new "all_cards" sprite, so when a card is played and needs to be "moved" to one of those areas, it just does the same process of setting the index of the area to match the card that was played, depending on the area that needs to be updated, and defaults to the last frame of the sprite if it's empty.
Now we can see how the play_card_button works when interacted with. First it checks to see if the card needs to be played in one of the passive slots or the main discard pile, and then loops through all instances of the CardAreas until it finds the one that matches the case for the card being played. Then it runs the delete_card_from_hand function and makes the button invisible so it can't be accidentally clicked again while no card is selected (important tip, objects that are marked as "visible=false" in GameMaker can still be interacted with, which is why I added a check for visibility when the button is clicked).
The reset button now properly destroys all instances of cards in the player's hand.
The new card system is, in it's current state, now fully replacing the old card system. As of writing this, however, there are still features that need to be added
- Highlighting the card the player hover's over for ease of visibility
- Moving the card up if the player clicks on it so it's easier to see which card was selected before playing it
- Highlighting the new Drawer object when the player hover's over it
- Adding functionality to handle cases with the opponent, as right now some things only work with the player's hand
And then, of course, making the cards actually DO something when played still needs to be added. I already have an idea of how that will work, but will probably take even longer to do because there's a lot of cards, and considering the state of the code for the old card system, trying to parse the existing code for the actual chess gameplay AND making it fit with playing cards will be difficult.
Wiki
User Stories
Design
Requirements
Architecture
Considerations & Issues
Documentation
- How to Add a Card to the Game
- How the Music Controller & Script work
- Card Paging & Search System (CardManager)
- How to Spawn Cards in a Room
- How the Chessboard works
- How to Add a New Board Color
- How to use Alert System
- Chess Logic
- Cheat Mode
- Timer
- How the new card system works
- How the NEW Chessboard works