Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

We implemented MetaDeck in Java, using primarily swing components for the front end. We used a standard client-server message protocol, and had a standard MVC architecture on the client side. The model contained all the data that was persistent in the game state, meaning that the different players' clients should have models that are eventually consistent with one another. The view contained the state that was specific to one client, such as the cards that player is currently selecting. Only that player can see the state contained in the view; it does not propagate to their other players' clients. The controller contains all the input listeners, and processes them, changing the model and view appropriately. On the server side, there is a lock for each stack of cards, ensuring that two clients cannot try to move the same cards at the same time. The server also contains its own model, which is necessary since new clients must be able to request the full game state from the server.

First, we describe the model. The model is essentially the same on the client side and the server side. In short, the model contains all the information needed for an observer to be able to kibitz. It is represented as a TableModel, along with a set of PlayerModels. The TableModel contains information about what is on the table, and the PlayerModel contains information about the players sitting at the table and the contents of their hands. The TableModel contains a list of CardStacks, which represent physical stacks of cards on the playing table. CardStacks are objects containing a list of Cards, as well as their x,y position on the table, and whether they are flipped up or down. Each Card represents a physical playing card, with a unique ID, as well as a number value and a suit value, or a joker value. The PlayerModel contains a unique player name/identifier, as well as a list of Cards. Overall, we tried to keep the model as straightforward and simple as possible.

Second, we describe the view. The view contains state about what the client is currently selecting, both for the table and for the hand. The view contains a TableSelection, which is a list of StackFragments. A StackFragment represents the top so many cards of a stack, possibly up to the whole stack. This restricts the allowed selection for the player, so for example, it is impossible for the player to select the second card in a stack without selecting the first card also. The view also contains a HandSelection, which is a set of cards in the player's hand. The HandSelection represents the cards that are visually positioned slightly above the other cards in the player's hand, so that the player can make any arbitrary selection from his hand. The view also contains the implementation of the painting. All of the necessary images are preloaded from image files are stored in memory. The painting is drawn in the standard swing hierarchical manner. The table painting is done in its own component, and each hand is painted in its own component. The chat and to-be-implemented scoreboard are painted in their own components.

Third, we describe the controller. The controller handles the interactions. The controller listens for mouse actions and mouse motion, and filters the events into their respective swing components. When the controller needs to change the model, it calls the appropriate functions in the model, and afterwards will update the view appropriately. Realistically though, the mouse will probably be moving across the screen all the time, and so the view will need to be continuously updated to make sure the usability affordances are accurate.

Finally, we describe the features and their implementations.

A very important notion is how users use the interface to manipulate stacks of cards. A user can drag a selected stack of cards in the standard manner, and while dragging, green circle affordances will show up on each stack, and they will give feedback when the dragged stack crosses over the other stack.

There are many ways to select a stack. While the mouse is hovering over stacks, we dynamically update the affordances on the stack to show what stack fragment will be selected if the user decides to click. We also show the size of the stacks, as well as the size of the stack fragment about to be selected, and the size of the dragged component. We try to draw the sizes slightly merged into the stack itself, to make it obvious which stack the number corresponds to. However, this sometimes decreases visibility of this data.

Some implementation issues we have not had time to iron out yet.

For example, we always draw a stack the same way, and currently, our table size isn't very big, so it's possible that the cards will overflow out of the table. Our solution in this case is to contract the stack depth to make it stay within the bounds of the component, but we have not implemented this yet.

Also, most of our click listeners are on mouse presses instead of mouse clicks, so we have some issues with not being able to differentiate between a mouse press that was meant to just be a click, and a mouse press that was meant to just be a mouse press. This restricts the amount of options we have as events we can listen for, and decreases the usability. For example, in some occasions when we want to click on a stack fragment to select it, it will register as a mouse press and start dragging that stack fragment first. In the common use case, where the user wants to move the selected stack immediately, this is fine, but it can be frustrating at times for a user that just wants to select a stack fragment for whatever reason.

We have not had the time to make any fancy graphics, or anything involving animation, so some cool ideas we have of improving visibility have not been implemented. For example, we want to have an animation for shuffling to alert users that a stack has just been shuffled, but cannot think of an easy way to make such an animation.