Multiplayer Mess, UI Undertaking, Deadline Dread and Coding Composure (week 7)

JAN. 13 – JAN. 23

This was a long week (10 days apparently!). On our weekly Monday meeting, Jan. 16, we decided on a milestone for me. Until the next meeting, I would make the game “playable”. That meant the multiplayer synching had to work. I needed to implement UI, and update it. Playing cards should only be possible if they can legally be played. Turn order had to be implemented, and the different phases of the turn be programmed. Cards you play should have an impact on the player’s resources.
I was confident to reach all of these goals. Maybe I was too confident.

Multiplayer

I was already neck-deep into the multiplayer aspect before the meeting, and since the game is pointless without it, I kept working at it before anything else. At this point let me explain the term Equivision.

In our game, akin to the way Hearthstone did it, each player sees the game from the same camera.

In-Development art is best art
Both players see this with their side at the bottom.

The player is at the bottom of the screen, the opponent at the top. On one hand, the players see something different – they don’t look at the same table from opposing ends like you would in a physical game. You can see this fact in the shape of the board, it is not symmetrical. On the other hand, the players have the same point of view. There is one camera in the unity scene and both players are looking through the camera. However they see their own resources and Board-Cards on their side of the field and the opponent’s on their side. This is what I refer to as Equivision.
Part of the Equivision aspect -code wise- is that I refer to the two players as “host” or “guest”. The cardgame is always one-on-one so I can make use of that. Every action that a player takes tells the server the either “host” or “guest” as an argument, and the game handles it based on that.

Implementing Equivision, along with the other multiplayer aspects, took a lot of time from me. I had never made a multiplayer game before, not even a local one, so I came into this project with a lot of things to learn. I definitely underestimated this aspect of the programming!
To best explain how I implemented Equivision, and other multiplayer aspects, I should explain the main components of it. The most important Scripts for this are ServerAuthority, ClientController and PlayerController as well as ResourceContainer.

ServerAuthority is the script that handles the turn-order. In its Update function, it rotates through the two players’ phases and sets relevant variables. It is server-only and therefore does not exist on the client, which is why I needed this many scripts to communicate between the hosting and the remote client. Surely there had to be a better way to solve this, but I had already given up on writing pretty code. The ServerAuthority script does hold each player’s deck, but it does not hold their resources (Profit&Budget&Public Opinion), nor does it hold the “currentPhase” variable. The reason for this is the aforementioned, that the guest client cannot access the ServerAuthority script to ask for the values. These are instead held by the ResourceContainer.

ResourceContainer is exactly what the name implies – a container. It contains only variables and Set&Get methods, it does not execute any actions on its own.

ClientController contains all of the [ClientRpc] functions. ClientRpc functions are called from the host client and executed on both clients. I use this for everything part of the Equivision. In fact only for that. It updates the UI to display the current resources, it assigns newly drawn cards to the players’ hands, and it places cards on the board on the correct positions.

PlayerController is attached to the Player Prefab. It is therefore set to local player authority, which means that only the person who owns this player can call functions in this script. PlayerController contains all [Command] functions. Command functions are the counterpart to the ClientRpc functions, they are called by a client, and executed only on the host client. The Script handles most of the gamelogic, those parts which require the player to take action. It contains the functions that check whether a card can be played, and resolves playing them. It also contains the function that reacts to the player pressing the “next phase” button.

User Interface

At the same time, I was working on the UI. I plonked the mockup assets I took from Andreas’ files on a Canvas and set it to scale with screensize. There is really not much else to say about it, but I didn’t have the final assets yet, so I had to come back to it later anyways.

Matchmaking

The worst part of week 7 was attempting to make an automatic matchmaking scene. The Unity-provided UI for this were absolutely disgusting OnGUI generated buttons and I wanted the matchmaking to happen automatically anyways, instead of asking the player to click through a bunch of menus. Here is an impression of the work I put into it.

Note the “V4” name of the script, and the roughly 3.5 billion open tabs.

And after a total of around 10 hours, I had no working result. I hoped to get back to it in the next week, but I doubted I could spend even more time on it. After around 9 hours I was at the point where it worked as I wanted, but only if the hosting client is the Unity editor. I decided to stop trying to fix it about an hour later, and re-implemented the ugly Unity UI.

I cannot leave this in for the deliverable. I cannot make anyone look at this.

The worst thing about it is that the UI is pixelsize, and does not scale with screensize. This means that on a modern phone, you literally could not tap the buttons without equipping finger hands.

Required peripheral for QR

Funny Programming Fails
Number 2 will blow your mind!!

This is how tired me thinks encapsulation works:

how tired me thinks encapsulation works
These functions look like other Scripts need to call them. I better make them private!

I DO have a tendency for long names:

I really don’t like abbreviations.

This is how I comment my code after a long session:

I need someone to talk to…

When I try to code, IF is written in capitals:

New line, so you gotta write a capital letter.

Ups and downs

While fiddling with the “Check if you can play the card” implementation I finally learned how to use delegates! I had seen them before, and they appeared to be extremely useful, but they also seemed very complicated at the time. However thanks to this video, I understood them within 10 minutes. And my mind was blown. Thankfully, someone re-enacted what was happening during that moment, so I can share it with you here.

Accurate depiction of me, watching the video.
Accurate depiction of me, watching the video.

But then, disaster struck. Delegates could not be used with networking Commands or ClientRpcs.

Accurate depiction of me, realising it.

Ultimately, I had to funnel it through 4 different scripts (sound familiar) instead. But in the end it worked out, so all was well!

Home Stretch

All of the multiplayer stuff I needed was done. The UI was rigged up and synched. Cards could only be played if there were free slots for them, and if the player had the resources, and the resources were affected by the cards. All I had left to do was implement the turn order. It was already past midnight of monday, my deadline, and I my code started to look bad.

I wrote code for about 90 minutes straight without compiling and testing inbetween and in what seems like nothing short of a miracle to me, the code worked as intended, instantly! (I forgot to assign a reference but that doesn’t count!)

john carmack
The less famous id Co-founder.

I made builds for PC and Android and loaded them on the testing devices and checked if they worked. Then I collapsed into bed  – tired, but satisfied.

Aftermath

I had reached all of my critical goals, and did some extra bits, but unfortunately not as much as I had hoped to, due to the matchmaking fiasko.

The fruits of my hard work were the reactions of my team members. They had fun playing around with the bugs I had left in, enough that we made one of them a feature! During the meeting I found that there was yet a bit more for me to do than I was aware of before, but I was still confident that I could implement a lot of features. The main workload now was implementing each and every card effect, and I hoped I could implement at least most of them.

Multiplayer and Intermediate Presentation (Week 6)

Jan. 6 – Jan. 13

Multiplayer

Now that I started really working on the App, it was time to look into how I could implement multiplayer. On Sunday I started researching different ways of how I could do multiplayer in Unity. The best options were Photon and Unity’s own networking services. I eventually decided to use Unity’s service, because it seemed easy to implement and Unity provided a matchmaking service for up to 20 concurrent users, which would be enough for our prototype phase. I spent the rest of the day working with the Unity tutorial on Networking. Annoyingly, the tutorial didn’t go as far as I needed it to. I didn’t explain the Unity Services part of multiplayer networking, which is necessary to take the game from LAN-only to internet multiplayer. So I had to play around with that for a while to get it work, and bother some of my friends to test if I could match them until I could get it to work. I met with Markus the day after to ask for his opinion on my approach, and he didn’t have any objections, so I went ahead with it. Also I tested the tutorial game on android, to verify that networking works the same, as Unity claimed.

Motivation

Motivating myself was always rather difficult for me at the start of a new project, and there was really not trick to it. I had been training my willpower, and slowly but surely I could motivate myself better.

This is the trick. There is no trick.
It’s silly but he’s right.

Progress

After doing a lot of research and setting up some of the basics for multiplayer, I started implementing bits of the interactive parts of the game. Until the end of the week I made responsible scripts and classes for drawing cards from the deck and adding them to the hand, dragging cards from the hand to play them, placing structures on the board and some more.

 

Intermediate Presentation

Our intermediate presentation was on January 11, so on our weekly meeting on Monday 9, we started working on the presentation. We outlined what we wanted to talk about in a googledoc presentation file. Sarah then took that and made the slides in some other program to make them look good. Everyone told her what they wanted on their slides, but I really had no idea what to talk about, however Sarah solved that very gracefully:

01100010 01101001 01101110 01100001 01110010 01111001 00100000 01101001 01110011 00100000 01101101 01111001 00100000 01110011 01100101 01100011 01101111 01101110 01100100 00100000 01101100 01100001 01101110 01100111 01110101 01100001 01100111 01100101
Luckily no one fell asleep on this slide, until Dimitry asked a coding question…

The presentation went very well in my opinion, the Profs commented on some things like the huge scope we were planning for, but we had a good answer for everything (we had already cut down the scope a huge amount for the prototype).

 

Programming (Week 5)

DEC. 30 – Jan. 6

Monkey see …

I started this week by looking at the game files for the game that is our main inspiration – Hearthstone. The only relevant files that were not encrypted were the XML files. I had hoped to find the main files for cards, but it seemed as if those were wither not saved as XML, or split between so many files that I could not puzzle them together. I did however find out that they don’t have different elements for the different properties of the cards, but instead differ between them with different values for the “field” attribute.

… Monkey do.

I thought about changing my XML to the way Hearthstone did it, but decided against it, because i saw no reason to do it. I did however spend some more time on changing the names of the attributes of each card, to better reflect, and more clearly explain their function.

I got the core XML functionalities running to the point where I could load cards from the XML document and display the values on a card-mockup.

xml loading

The importance of examples

During our meeting on Monday we found out that we had different concepts of one of our Resources, “Profit”. Some of us understood it as an accumulation of the player’s income, and the others as cash-flow. This explained why we had such different ideas of how it would be used. After I explained to the others how I imagined Profit as cashflow to work, we decided on using that.

I learned that whenever you talk about a game mechanic like this, you should make some kind of example, perhaps do a few turns of mock-play to see if everyone is on the same page.

Programming continues

For this project I decided to write every class in their own Script, like Card and CardSlot for clarity and neatness.

During programming I often noticed things that we hadn’t talked about before. I was wondering whether this was fine, or whether we should have planned ahead more. One of these things was showing buffs or debuffs on certain cards, for example if you were to use an event card that increases profit of a structure, that change has to be somehow shown on the card.

I also get to make small gameplay decisions all the time.
For example, I decided that the chance for a card that is randomly inserted into a deck would be a tiny bit (like 0.000001%) higher to be inserted at the top than anywhere else. This is due to the way probabilities are calculated in programming. I could have chosen any location to be this tiny bit higher, but the top position was the most fun imo.

One of my favourite things in programming are named and optional attributes. They allow you to keep method calls short if you do not need all parameters.