Kings Of Pool

Most of my time at Uken Games was spent working on Kings Of Pool an online competitive mobile pool game built in Unity. The team I was working on was relatively small and this gave me a lot of freedom as well as responsibility when contributing to the project. I got to be a part of every aspect of the project from planning and design to implementation and maintenance.  I really grew as a developer through my time on this project. Being able to own features through design all the way to release was a great experience.

I got to own quite a few features while on the project, the most interesting were the following few:

Medals:

Medals were created to award the player for interesting or cool shots during the game. If the player potted a ball with a bank shot or a combo shot etc, a small medal would appear on the screen for a brief moment to acknowledge the players accomplishment. You can see similar systems in the Call Of Duty Series and Rocket League. The medal system was one of the most fun features to implement because I got to work with a lot of gameplay code in many areas. The core system was a process that was passed in shot data after each shot and analyzed certain circumstances to see if 1 or more medals were to be awarded. This included checking things like distance from the cue ball to the target ball, which ball was hit first in a chain and many other situations. For example in the case of a combo shot the code looked similar to this

private bool WasCombo(int ballNumber){
    List<Collisions> targetBallCollisions = GetBallCollisions(ballNumber, this.collisions);

    return targetBallCollisions[0].ball!= CueBall;
}

The only parameter the function took was an int representing the number of the potted ball. The function would then get the list of collisions for that ball. From there the function would check whether the first collision with a ball was not with the cue ball. After that the ball can do whatever it wants as long as it gets potted it counted as a combo shot. This was a pretty loose definition of a combo shot but it would be trivial to check whether or not the next collision was with a pocket to make the definition more strict.

This system was able to process a shot quickly and award multiple medals if a shot warranted it. Since the system was just doing boolean checks on a list of collision data there wasn’t any real issues with performance.

The player was also able to check which medals they had been awarded in the game. We had already planned on being able to show the medals after the game and have a history of all medals a player had on their profile so creating and showing this window was trivial.

The last part to this feature was the medals history page, as mentioned above. This required storing the medals in the players profile in the database. One tricky part to the history is we wanted the player to be able to show off specific medals so the players profile also needed a section to store which medals they had selected to be shown most prominently on their profile.

All the medals implemented:

Quick Shooter, “Shoot quickly and sink a ball”
Sniper, “Sink a long distance shot with no contact”
Deuce, “Sink 2 balls in a row on a single turn”
Triple, “Sink 3 balls in a row on a single turn”
4-in-a-row, “Sink 4 balls in a row on a single turn”
5-in-a-row, “Sink 5 balls in a row on a single turn”
6 pack, “Sink 6 balls in a row on a single turn”
Lucky 7, “Sink 7 balls in a row on a single turn”
Perfect Game, “Sink 8 balls in a row on a single turn”
Gentlemen’s Streak, “Win by sinking your balls in numerical order”
Bank Shot, “Sink a ball using the rail”
Bouncer, “Sink a ball using multiple rails”
Nice Break, “Sink 2 balls off the break”
Great Break, “Sink 3 balls off the break”
Breakin’ it Down, “Sink 4 or more balls off the break”
Quicky, “Win a game in 2 or 3 turns”
Combo Shot, “Sink a ball without hitting it with the cue ball”
2 in 1, “Sink 2 balls in a single shot”
3 in 1, “Sink 3 balls in a single shot”
4 in 1, “Sink 4 or more balls in a single shot”
Squeaky Clean, “Win a game without scratching or fouling”
The Hard Way, “Ignore using Ball In Hand and sink a ball”
Generosity, “Sink an opponent’s ball alongside yours”
Unlucky, “Miss 3 shots in a row”
Pool DJ, “Scratch 3 or more times in a match”

Game Rules:

On Kings of Pool we had a script called GameManager.cs and it controlled the entire flow of the game. Changing turns, recording shot data, sending RPC’s between players and a numerous amount of other tasks were done in the game manager. This was a monolithic script that I had the pleasure of owning for my time on the Kings of Pool team starting with the Game Rules Refactor and extension.

The refactoring and extending of the Game Rules is probably the system that I am most proud of because it was the first system that I got to own from architecture to release and was the task I believe to be instrumental in my gaining more responsibility on the team. The goal was simple, it was to add new game rules to the game. Up until this point, the game only had the standard billiard rules. The first problem I faced when implementing the system was figuring out a way to separate the hard coded rules from the game manager. After some time I settled on using the Strategy Pattern.  So I created a Game Rules interface for all the rules and it looked like this:

//This isn't a complete interface but it give the basic
// idea of what its purpose is
public abstract class GameRulesInterface{
    public abstract bool Guidelines();
    public abstract bool Win();
    public abstract bool Lose();
    public abstract bool Foul();
    public abstract bool Scratch();
    public abstract bool GameOver();
    public abstract bool CallPockets();
    public abstract bool SwitchPlayers();
}

// Usage:
// Don't need to figure out if it is a foul
// just check if it is
if(gameRules.foul()){
    //Process Foul 
}

This ended up working really well. It allowed us to create multiple rule sets, for things like Call 8 Ball Rules, Call All Pockets Rules and an All In Rule set where you must win 2 games in a row to take all of your opponents money. What I loved about this approach was it allowed us to simplify the game manager greatly. Instead of having conditions based on game type to determine if the shot was a foul the game manager would just consult the game rules, greatly reducing the logic contained in the game manager.

Calling the bottom right pocket

 

Badges:

Badges are the achievements system within Kings Of Pool that allows players to keep track of their progress on certain tasks. They were also tiered achievements so once one tier was done the next would begin. Since I had already created the medals history page creating the achievements systems was pretty easy. I added achievements to the player profile, created achievements on the back end and created a system to progress an achievement when players completed certain tasks.

The silver Badges are in the second tier, and they can go up to a possible diamond tier for 4 tiers in total

 

All Badges implemented:

Streaker, “Earn Shot Streak Medals”
Multi-Ball Shooter, “Earn Multi-Shot Medals”
Master Railer, “Earn 5000 Rail Shots”
Combo Shooter, “Earn 5 Combo Shots”
Breaking Through “Earn 500 Break Medals”
Mr Clean, “Earn Squeaky Clean Medals”
Total Coin Winnings, “Win Cash”
All I Do Is Win, “Win games”
Winning Streak, “Win games in a row”

Carousel:

We already had a carousel in the game to display the stages but before this it was hard coded in many ways. The size of the carousel was hard coded, the position of the elements in the carousel were hard coded, and the elements within the carousel were also hard coded and couldn’t be changed without an app update. So the goal of this task was to create a new carousel from scratch. A carousel that could be updated on the back end and whenever it was refreshed would get the new updated data and display it in a nice smooth carousel.  This required multiple changes to multiple parts of the code base. I started by writing a Carousel Item that would be created from data stored on the back end. This would allow the client side to query the server side for all active stages. Doing this gave us the ability to turn off or on a stage at any time and have it disappear or appear on a carousel refresh.  Next, I created the carousel in a basic MVC pattern. At this time in the project the team was moving toward an MVC structure for the entire project and this was one of the first times a feature was being implemented under these new guidelines. The view extended the UGUI ScrollRect because I wanted to tap into some of the functions it had. The model was just a storage for basic information like the number of items in the carousel and which item was the current item to be focused. Finally, the Controller initiated construction of the model and the carousel items, and then passed it to the view for rendering.  The core update function for the movement of the carousel was simple but worked well:

// This code relies on the horizontal scrolling of the UGUI ScrollRect
void Update() {
     if(lerp && velocity <= velocityCuttOff) {
         // If the Carousel is slow enough snapping begins
         velocity = Vector2.zero;
         xTarget = content.position.x - controller.GetDistanceToTargetItem();

         Vector3 target = new Vector3(xTarget, content.position.y, content.position.z);

         if(Mathf.Approximately(content.position.x, xTarget)) {
            // If the Content is close enough to the position it stops snapping
            lerp = false;
         }

         content.position = Vector3.Lerp(content.position, target, Time.deltaTime * SnapSpeed);
     } else if(velocity > velocityCutOff) {
         // This just updates the target for when the carousel is going to stop
         // ScrollRect handles the scrolling
         controller.SetTargetToClosestItem();
     }
 }

// This is part of the carousel items controller. The carousel items were also part of their own sub MVC structure
// This would be called as the title suggests whenever the position of the carousel item was changed
 public void OnPositionChange(){

     // On a position change we find the number of item widths between the object and the center
     float numItemWidths = (Mathf.Abs(this.transform.position.x - this.carouselController.transform.position.x) / this.gameObject.GetComponent<RectTransform>().rect.width);

     // we use 1 - the items widths times the offset to have it
     // decrease in size and clamp it between 0.5 and 1
     this.model.scale = Mathf.Clamp(1 - (numItemWidths * this.scrollSizeOffset), minScale, maxScale);

     // same logic for the scale but now the maximum value has changed
     float rgbvalue = Mathf.Clamp(1 - (numItemWidths * this.scrollColorOffset), minRGBValue, maxRGBValue);
     this.model.color = new Color(rgbvalue, rgbvalue, rgbvalue, 1f);

     this.view.Render(this.model);
 }

In the end all of it came together to produce a carousel that I am pretty proud of:

Ranks:

I want to talk about ranks a bit here because this was the feature that I fought for at every meeting and eventually was given the time to design. There were a few goals I had when designing this system; a players rank needed to be immediately visible, easily understood, and meaningful. This meant 3 important things to me. First, the rank would be displayed on the players profile and rank changes would be visible after each game. This meant your rank followed you throughout your time within the game and you would want it to be good because it was constantly visible and right next to your profile picture. I believe this helped it become part of your identity within Kings Of Pool. Second, the ranks should be numerical numbers from 25 to 1, even though the real evaluation was based on Microsoft’s TrueSkill ranking system. I didn’t want to have leagues only our players would understand or to require our players to have an understanding of precious medals to know where they stood. #1 is the best and everything follows from that. It is easy to understand what a rank means and you can quickly understand a players relative skill level from it.  Finally, there would be seasonal rewards tied to your rank. There would be cues, cash, icons, badges and all sorts of rewards based on your placing in the current professional season. This gives the player a reason beyond pride to care about their rank and with good rewards makes ranks a well rounded and meaningful addition to the game.

I was very excited to have the first feature I designed added to the game shortly before leaving Uken

 

Team Processes:

One of the things I was happy to have been a part of at Uken was changes to a lot of the processes for the development team on the Kings Of Pool team. The pool team had a few problems that I wanted to try my best to address. The first was a lack of code reviews, which was eventually solved by the team lead creating a more robust process. The second was pillars of knowledge within the team where people only really understood sections of the project that they personally had worked on. Finally, the team lacked any collaborative architecture design. I really wanted to try and address the last two in whatever ways I could. So when I was tasked with creating the carousel I tried something different. I created an architecture document and scheduled a meeting to present my ideas to the rest of the team. It ended up going very well and the team lead really enjoyed it. Eventually the team lead created a more robust process for everyone to have input on system designs and share knowledge with one another. I was only at Uken for a bit of time under this new system but I found it made a huge difference in the team. Everyone seemed to have a better grasp of the state of the project and what everyone else was working on.

Daily Goals:

Daily Goals was the first system I implemented under the new development process. It was a simple task but required a lot of collaboration with the rest of the team to get all the UI and Server side changes made. The new processes helped make this much easier than it would have without it. The goals of the system were to create daily goals for the player to finish each day. A player could have 3 active daily goals as well as 3 goals in the bank. Every day the player would have 3 goals given to them to complete, but if they already had 3 active goals the new goals would go into the bank for a maximum of 3 bank goals. If the bank was full no new goals were added. I handled the client side of this system, incrementing progress, saving progress and sending it to the server and most of the UI. In the end it looked like this!

Multiple Ante Ups:

One of the last features I made before leaving was extending the Ante Up feature to allow players to ante up multiple times for a varying maximum based on the stage. This was a super easy feature to implement since the ability to ante up was already in the game. I simply needed to change the restrictions on how often it could be done to match the stages maximum and change the UI to handle showing the current state of the pot.

You can see the small pips at the top of the window show how many times the bet has been increased. You can also see some of the animations and views that display relevant information and control the flow of the interaction.

Conclusions:

If you made it this far, thanks! I really like talking about the work I’ve done and the challenges I’ve faced to get the desired results. I left Uken in May 2016. I faced a lot of new challenges at Uken and learned a lot from the experiences. The people I worked with were fantastic and taught me how to be a better game developer. I left to pursue more core gaming opportunities and have been enjoying the challenges that come with the pursuit. I look forward to what Uken does in the future!

Thanks for reading!