MC2 – Updates – April 7th to April 13th

What I did this week:

1. Fixed various bugs with the end of round point tally in Brawl mode and added the leader crown. Not too sure about the emissive properties of the material, but that’s tweakable:

2. Added a LEADER callout at the beginning of each round. This is only in brawl for now, but I may add it to Soccer and Recycling at some point. The intent is to make it more attractive for competitors to gang up on those who are ahead, without giving these players what I perceive to be unfair disadvantages (see Towerfall’s reduction of arrows for leading players and addition of shields for trailing players):

3. Added a podium state to the match. I really like how Rocket League does its podium. So I did something quite similar. I included the ability to move in place and also included game mode relevant stats. Some of these stats are not tracked correctly yet, but it’s on the TODO list. I will be supporting Ribbons, which will further gamify things. This feature doesn’t work at all at the moment, but these will be tracking complex stats, and most likely relative to the other players as well (imagine if blue killed yellow many times more than the rest of the players, the blue player may get the “yellow death” ribbon, or something along these lines):

4. Changed the look of the Brawl arena slightly to make it sharper (left is old, right is new). Functionality remains the same:

5. Made important fixes to damage system and charge system. Also, rebalanced sphere attributes (for the balillionth time! :D) Won’t disclose details here.

6. Started working on a new mode! Codename… “disc“. What’s that red thing in the middle, I hear you ask? That’s the “disc”. What about the floor with tiles? That may play a part in the game mode… Wait and see!

7. Spent some money on a local online marketing consulting company. I will be collaborating with these people in the near future to try and increase online exposure for in Principle Inc and MC2.

8. Prepared for the 2018/04/14 Trade Show in a local town nearby. Will be promoting in Principle Games and in Principle Learning as well. Will report back on how it went in a separate post.

Pretty busy week, all things considered! Cheers.

– Mike

MC2 – The Story – Soccer with at least 3 balls

Early March 2018… It was time for me to create a new mode. Brawl is cool and all, but I wanted to try my hand at a proper sport. And since I’ve been playing Rocket League more than I should recently… might as well go with Soccer (or as it’s properly called, Football, but I don’t want to get into that argument now!)

1. ART

So I began by creating an arena. For those who have played Rocket League extensively, you will know that it feels like the goals have some kind of “attraction” force when the ball is right on the edge of going in. It may very well not be the case that this force exists, but at least it feels like it does. I decided that I would have the opposite instead, without cheating physics. So I created a small slope in front of each goal that would naturally push the ball away from the goal. Well, my initial implementation of this idea was really bad. The slope was quite steep, so it was really difficult to score, it turns out. After quite a bit of playtesting I opted to lower the slope substantially, so it now has a very small angle. Here is the most recent design of the Soccer arena:

And here’s how it looks like in game:

Quick note: the colours on the ground are spot lights i put in the four semi-cardinal points (NE, NW, SW, SE).

OK, so the lower slope created an interesting dynamic, where the ball can linger near the goal for quite a long time, which leads to emotional situations. It seems OK for now, but the mode needs a lot more testing to confirm this.

2. DESIGN

MC2 supports 2, 3, and 4 players. For 2 and 4 it would be easy. I would simply have 2 teams. For 4 players I decided that the warm colours (Red and Yellow) would be the “Hot Team”, whereas the cold colours (Green and Blue) would be the “Cool Team”. But 3 players was complex… So I decided to try a crazy thing. I’m going to make one of the players be the ball, for a period of time. This player’s goal is to avoid being scored in either goal.

Quite a bit of testing went into the 3 player version of Soccer with my own kids. I’m not going to break the lid wide open on all of the design quirks for now, so you guys will have to try this mode yourselves!

Another thing that’s very important to me in design is the “quirk“. In simple terms, what does a game of mine do that others don’t? Well, it’s possible for players to throw themselves into either goal, just as if they were a ball too. However, I’ve made this relatively easy and cheap thing to do somewhat unrewarding. Scoring oneself into a goal is worth 1 point, and leads to a 5 second timeout, whereas scoring the ball is worth 3 points, and leads to a 2 second window where all players can throw themselves into either goal to score extra points. I’m curious to see this playtested more in future to see how people like this mechanic.

Here “ENCORE! +4” indicates that Yellow scored the ball for 3 point, plus himself (+1 point), for a total of 4.

3. CODE

There would be a lot to say here. I expected this mode to largely use the same concepts as Brawl, and to some extent this is true, however, all sorts of extra complications appeared. From the issue of the 3 player-ball hybrid, to the timer, to overtime as a concept, to displaying the scores and the time, to figuring out which goal the ball was hit into, or the player for that matter. I’m not going to go into details, because it would be information overload, however, what I will say is that this mode forced me to essentially rewrite my GameManager singleton. This now has a massive switch(gameType){} in it that allows me to manage how each mode behaves independently.

In short, making Soccer was a lot more work than I had originally anticipated, and it was a bit of a nightmare to QA as well, considering all of the possibilities and combinations! Hopefully it’s going to be fun though.

– Mike

MC2 – Technical – Now we see me… Before we couldn’t

With the damage system in place, one thing that became apparent was that the spheres players controlled would become difficult to see over time.

1. Starting situation of a match:

2. Yellow takes some damage, it becomes harder to see:

3. Yellow is completely destroyed, it’s now technically almost invisible:

4. And even worse, its shadow has disappeared, so the yellow player cannot even figure out where the sphere will land!

OK, I had to fix this. Most of the shaders here are taking advantage of PBR (Physically Based Rendering), so I have all of the pretty lights, shadows and the Z buffer all nicely managed by the Unity Standard Shader. It would be a problem if I added some other material to the sphere that transparent yet fully visible. Don’t get me wrong, it’s possible, but I didn’t necessarily want to invest too much time into this. So I came up with a cheap solution, both in terms of effort invested and performance. Before I reveal what it is, here’s how the solution looks like…

1. This is when the spheres have taken no damage:

2. This is how the shadows look like when the spheres are intact:

3. This is how the spheres look like when they are damaged:

4. And they are visible when they are completely destroyed! And they have a handy shadow too:

How do you think I accomplished this? Take a moment to develop a theory BEFORE you read on. Feel free to let me know what you think I did in the comments, I’m curious! 😀

So here how I did this:

That’s right, two 2D planes, or, more precisely, two quads!

1. The first quad has a transparent PBR material on it with a circle-like texture on it. The important thing about it is that it must be constantly looking at the camera, so it appears to the players to be correctly rotated all the time. It is also important that this quad cast no shadows. It doesn’t need to receive them either.

2. The second quad is the horizontal one. This also needs to maintain a rotation constantly. It needs to always point up. It has the same material as the other quad, but its render settings are set to Shadows only. So it’s invisible to the players, but it always casts that round shadow.

Of course this is possible because MC2 has spheres as characters and a perfectly vertically oriented directional light for gameplay reasons (the shadow is exactly under the player), but this was a pretty neat trick and I’m generally happy with the result, as none of the playtesters were able to spot the tickery.

And here is ALL of the code that makes this trickery possible:

Just two lines:

coreQuadRenderer.transform.LookAt(
  GameManager.singleton.camManager.transform
);
coreShadowQuadRenderer.transform.rotation =
  Quaternion.LookRotation(Vector3.up);
);

So to recap:
4 polygons (2 triangles)
1 material (1 extra draw call)
2 lines of code in Update()

I think this was a cheap and fun solution to make! And it seems to work. Hope this comes handy for someone else in future.

– Mike

MC2 – Technical – Sometimes I make silly mistakes…

I just started implementing stat tracking in MC2. I don’t mean user data tracking, or anything nefarious like that, I simply mean in game stats, like how many kills a player has scored, how many jumps, and so on. One of the stats is damage taken and damage caused. I named these floats damageAgainst and damageFor, respectively.

As I was testing the stat tracking I noticed something that made no sense. When two spheres collided, the damageFor was always substantially higher than the damageAgainst, say 7f vs 5f. This meant I had been calculating damage incorrectly all along! TRAGEDY!!!

First, let’s determine the design (this may change in future, but for now here it is): I want the faster sphere to damage the slower one. That’s it. The way I’ll find out who is faster is by subtracting my speed from my opponent’s. If the result is higher than 0f, then I will have lost that collision and I must therefore take damage. I will also include a small variation where I account for both of our original mass. The heavier sphere will get a small advantage. So, in words:

opponentSpeed (plus)
opponentMassModifier (all minus)
mySpeed (plus)
myMassModifier

Take a look at this snippet…

This is the first line in a function called 
CalculateDamage. This function is used to 
determine who won the 50-50 in a collision 
and how much damage was caused to whom.

damageRawValue = (
  opponentVelocityMagnitude +
  opponentVelocityMagnitude *
    ((opponentOriginalMass / playerAttributes.maxHP) *
    GameManager.singleton.massDifferetialDamageInfluence) -
  myVelocityMagnitude +
  myVelocityMagnitude *
    ((playerAttributes.maxHP / opponentOriginalMass) *
    GameManager.singleton.massDifferetialDamageInfluence)
);

OK, so let’s do some arithmetic…

First, values! Let’s give our variables the following values:

– opponentVelocityMagnitude = 6f;
– myVelocityMagnitude = 3f;
– opponentOriginalMass = 10f;
– playerAttributes.maxHP = 12f;
– GameManager.singleton.massDifferetialDamageInfluence = 0.1f;

Now let’s replace them as necessary:

myDamageRawValue =
6 + 6 * (10 / 12) * 0.1 – 3 + 3 * (12 / 10) * 0.1 =
6 + 0.5 – 3 + 0.36 =
6.86 – 3 =
3.86;

opponentDamageRawValue =
3 + 3 * (12 / 10) * 0.1 – 6 + 6 * (10 / 12) * 0.1 =
3 + 0.36 – 6 + 0.5 =
3.86 – 6 =
-2.14;

Aaaagh! Why are their absolute values different! Here’s why, silly (talking to myself!)

Here’s what I think:

myDamageRawValue =
6 + 6 * (10 / 12) * 0.13 + 3 * (12 / 10) * 0.1;
opponentDamageRawValue =
3 + 3 * (12 / 10) * 0.16 + 6 * (10 / 12) * 0.1;

Here’s what the computer thinks:

myDamageRawValue =
6 + 6 * (10 / 12) * 0.13 + 3 * (12 / 10) * 0.1;
opponentDamageRawValue =
3 + 3 * (12 / 10) * 0.16 + 6 * (10 / 12) * 0.1;

Nothing that a few well placed brackets couldn’t solve.

myDamageRawValue =
(6 + 6 * (10 / 12) * 0.1)(3 + 3 * (12 / 10) * 0.1) =
(6 + 0.5)(3 + 0.36) =
6.53.36 =
3.14;

opponentDamageRawValue =
(3 + 3 * (12 / 10) * 0.1)(6 + 6 * (10 / 12) * 0.1) =
(3 + 0.36)(6 + 0.5) =
3.366.5 =
-3.14;

That was a little stupid, wasn’t it, Mike? I hear you all think. And you would be entirely accurate. Sometimes, I am THIS silly…

– Mike

MC2 – The Story – Should I continue developing?

On March 31st, 2018 I went to Calgary, to the Video Games Live event. We had a booth there, showcasing MC2. Here’s how it looked like:

This was the first showing ever for the game, and the game was in pre-alpha at this stage. I primarily wanted to showcase Brawl mode (which is the one with the round ring, where players need to knock each other off the ring), and gauge whether people liked the game enough to want to play it more at home. In order to make it more official, I asked all of the adult players who stopped to play to tell me whether I should continue developing MC2 going forward. So here’s what my trusty assistant Zoë (8 year old) and I set up:

What you see on the right is a makeshift easel holding coloured paper that reads as follows: “SHOULD WE CONTINUE DEVELOPING MC^2? NAY (left, red), YAY (right, green)”.

At least 50+ people stopped to play (I was too busy to keep count, unfortunately) and I’m happy to say that most of them seemed to be very happy with the game, especially the younger audience. We had a few people even coming back to play more after they’d already tried it! Here’s a short sample of a highlight reel (I intend to make more!):

So, hopefully you’re as excited to see this as I am to find out… How did the whole impromptu easel survey go?

29 upvotes, 0 downvotes. Onwards then? Well, yes, but I’m still not sure MC2 is going to have customers… There is one thing in particular I intend to do differently next time. I will setup the same easel, however, I will sneakily add some negative doodles as well. I don’t want people to have to brave standing out in being the only one or the first one who dislikes the game. Hopefully, that will help me gauge whether MC2 is any good more accurately!

My deepest thanks go to all those who played MC2 on Saturday in Calgary. Thanks so much for making it a fun event and bolstering my morale in continuing development! ONWARDS! 😀

– Mike

MC2 – The Story – Characters

I’ve always wanted to make a game that had different characters. However, I had to keep in mind I had to keep things simple in the art department, because simple = cheap, both in terms of money and time. So I decided to build various different types of sphere “cages”, if you will. Here’s how these look in game at this time:

At this point I was faced with a dilemma: do I make the characters significantly different from one another, as they would be in a fighting game, for example, or do I make them very similar to one another to the point of them basically being equivalent to skins (at least in the eyes of most of the user base), like the cars in Rocket League, for example.

Going with the latter would be a no brainer, budget-wise, however, I didn’t think that the spheres had enough character, if you’ll pardon me the pun, to stand out as purely cosmetic. Going with the former, like for instance giving each sphere a special move, would significantly increase the scope of my work, as well as risk making it so that some may be significantly better than others, as is often the case with fighting games. So I decided to settle for a hybrid: no special qualities, but substantial variation in the spheres’ attributes. I decided to remain closer to the Rocket League model as well, by leaving these differences obscure to the player.

I’ll try to explain what I mean by “attribute”, without giving the secret numbers away! 🙂

All of the spheres have the following attributes (for now):

Max Health (which is also the mass)
Max Angular Velocity (the maximum speed at which a sphere can spin)
Torque Force (in simple terms, how quickly a sphere accelerates)
Air Force (in simple terms, how quickly a sphere accelerates in the air)
Jump Height (minimum height the sphere jumps when input is sent)
Jump Extension Strength (how much higher when the input is held)
Jump Extension Duration (how long will the held input apply additional force)
Slow Down Speed (how fast the sphere will come to a stand still)
Impact Force (how hard the sphere hits)

There are more attributes that I’m not willing to disclose, at least not for now, but suffice it to say, the spheres are different, very different. Mere tweaking of these properties, even by small amounts gives a completely different feel to the spheres.

Here’s a simple example: say hello to Orbital (left) and Full Metal (right):

Ignoring the colours, as those only indicate who is controlling the sphere, how would you say these two spheres differ? Which one do you think is lighter? Which one is faster? Which one flies well? Which one prefers to stay on the ground? These are the kinds of questions I would like the MC2 players to ask themselves. And, I’m not going to lie, I hope for them to form their own legends and speculations about all this. I hope the game will be successful enough that a small amount of dedicated players will run all sorts of empirical test to figure out the objective answer to these questions. One can dream, right?

And this is how I designed the “characters” in MC2. Hope you found this interesting.

Thanks for reading!

– Mike

MC2 – Technical – The Importance of Having Mass

When I began developing MC2 I decided that there had to be some kind of way for every match to get more exciting over time. While other games with similar round arenas make it so that the arena itself shrinks over time, or similar, this is not what I wanted to explore at the time. I wanted to explore the concept of damage instead. I wanted damage to have an effect on my player.

There are many games that have tried this before in various ways. For instance, in the Resident Evil series having sustained damage makes your character walk slowly and clumsily. I didn’t want the player’s mobility to be impacted by the lowered health. I wanted the player to be just as capable of moving when damaged. So I thought of a system similar to the Super Smash series, but I wanted it to be less abstract. So I decided that the spheres would have an armour, like a cage, and that this armour could fall to pieces.

The Art

1. I modeled a carved sphere in Blender, like this:

2. I applied the Cell Fracture plugin on it to split it:

3. Now pieces can fall off, like this:

The code

Note that the C# code below is extrapolated from my entire structure so you can understand it. It’s not exactly representative of what’s in there, but it should give you an idea of what I built. I’m also not explaining ABSOLUTELY everything. The following content presumes substantial knowledge of C# and Unity3D.

WARNING, THIS GETS TECHNICAL!

When a collision with a Player is detected...

void OnCollisionEnter(Collision c) {
  if (c.transform.tag == "_Player") {
    // Store the player info
    PlayerBall p = c.transform.GetComponent();
    // Sending information from the opponent I just
    // collided with to the function dedicated
    // to calculate the damage
    CalculateDamage(
      p.myVelocityMagnitude,
      p.playerAttributes.maxHP
    );
  }
}
Now let's calculate the damage!
void CalculateDamage(
  float opponentVelocityMagnitude,
  float opponentOriginalMass
) {
  // Calculate the damage percentage
  // based on the maximum amount of health
  // this sphere has. Note that a sphere's
  // maxHP is also its mass. So a 40 HP
  // sphere is 40 Kg heavy, originally
  float damageRawValue = (
    opponentVelocityMagnitude +
    opponentVelocityMagnitude *
    ((opponentOriginalMass / playerAttributes.maxHP) *
    GameManager.singleton.massDifferetialDamageInfluence) -
    myVelocityMagnitude +
    myVelocityMagnitude *
    ((playerAttributes.maxHP / opponentOriginalMass) *
    GameManager.singleton.massDifferetialDamageInfluence)
  );
  // Notice that damageRawValue will
  // be greater than 0f if this sphere's
  // opponent had a higher velocity
  // before impact (as well as a higher
  // original mass, multiplied by the
  // massDifferentialDamageInfluence
  // variable kept in my GameManager
  // If the damage is lesser than 0f, then
  // it means this sphere took no damage.
  // The other one must have
  damageRawValue = Mathf.Clamp(
    damageRawValue, 0f, Mathf.Abs(damageRawValue)
  ) / playerAttributes.maxHP;
  // Now that we calculated the damage
  // percentage, time to apply it TakeDamage(damageRawValue);
}
Applying the damage and lowering the mass
void TakeDamage(float damagePercent) {
  // Lower the HP by the percent
  // calculated before
  playerAttributes.currentHP -=
    damagePercent * playerAttributes.maxHP;
  // Clamp the HP between 0f and maxHP
  playerAttributes.currentHP = Mathf.Clamp(
    playerAttributes.currentHP, 0f, playerAttributes.maxHP
  );
  // Change the mass to be the same as
  // currentHP
  playerStructure.mainRigidBody.mass =
    playerAttributes.currentHP;
  // On to detach things! DetachParts();
}
Lastly, detaching the pieces.
void DetachParts() {
  // We need a counted for a loop
  // to detach parts, starting at 0 int
  detachCount = 0;
  // We need to calculate how many pieces
  // we have to detach. Note that I need a
  // CeilToInt because HP is a float, not
  // an int. Also, note that I already have
  // two lists for the parts that I initialised
  // and populated earlier. list_rigidBodies
  // contains the rigidbodies of all of the
  // parts that belong to this player.
  // list_gameRigidBodies contains the
  // rigidbodies of all of the parts that are
  // still attached to the player
  int partsToDetach = Mathf.CeilToInt(
    (
      playerStructure.list_gameRigidBodies.Count /
      playerStructure.list_rigidBodies.Count -
      playerAttributes.currentHP /
      playerAttributes.maxHP
    ) * playerStructure.list_rigidBodies.Count  
  );
  // I'm going to need an index randomiser int tempRand;
  // As long as there are parts to detach and
  // the detachCount hasn't reached its target...
  while (
    playerStructure.list_gameRigidBodies.Count > 0 &&
      detachCount < partsToDetach
    ) {
    // Assign the random ID for the part
    tempRand = Random.Range(0, playerStructure.list_gameRigidBodies.Count);
    // Activate rigidbody and collider
    playerStructure.list_gameRigidBodies[tempRand].isKinematic =
      false;
    playerStructure.list_gameBoxColliders[tempRand].enabled =
      true;
    // Change the layer so the detached parts
    // don't damage the surrounding players
    playerStructure.list_gameRigidBodies[tempRand].gameObject.layer =
      GameManager.singleton.debrisSpentLayer;
    // Unparent the chosen part
    playerStructure.list_gameRigidBodies[tempRand].transform.parent =
      null;
    // Make if fly away from the Player
    // using a force that originates at
    // the center of the player, with a
    // random magnitude between two constants
    // that I keep in my GameManager singleton
    // ignoring the mass of each part (VelocityChange)
    playerStructure.list_gameRigidBodies[tempRand].AddForce(
      (playerStructure.list_gameRigidBodies[tempRand].transform.position - transform.position).normalized *
      Random.Range(GameManager.singleton.debrisForces[0], GameManager.singleton.debrisForces[1]),
      ForceMode.VelocityChange
    );
    // Remove the chosen part from the game
    // lists
    playerStructure.list_gameRigidBodies.RemoveAt(tempRand);
    playerStructure.list_gameBoxColliders.RemoveAt(tempRand);
    // Increment the counter
    detachCount++;
  }
}

The result

There, the sphere’s armour is falling apart because some of its parts are flying off. I quite like this effect myself.

Wait a second champ!

You may now ask: so what’s the deal with mass? Well, I actually don’t need to do anything about it really. Each of the collisions in the game is controlled by the Unity physics engine, which already accounts for mass when two objects collide. Since I’ve lowered the mass of the green sphere via code, it will be lighter next time it’s hit by the red sphere, which will make the green one fly further when hit. Neat, eh?

Till next time!

– Mike

MC2 – The Story – Humble Beginnings

After the release of my first commercial indie game on Steam, OVO Smash! (October 10th 2017), I’ve been prototyping concepts rapidly to see if I could come up with something interesting enough to develop as a new full fledged project. So on February 16th, 2018 I came up with this idea:

I wanted to try and make a multiplayer game that would be:
Possible for me to complete with my minimal resources
Immediately fun to play
Incredibly easy to pick up
Somewhat harder to learn to master

So I began thinking: what are the multiplayer games I’ve had the most fun playing recently? The games in question would have be designed in such a way that there would be minimal need for numerous and complex (and expensive) assets.

Rocket League immediately came to mind. Amazingly intelligent gameplay with variations of the same car, in variations of the same stadium, with very few mechanics (drive, jump and boost). These few ingredients create an incredibly deep experience. I would love to recreate something similar, even if smaller in scale and scope. – Simple but deep

I’m also a big fan of the Street Fighter franchise, and while Street Fighter is a very complex game now, in its first iterations it was somewhat simpler. It had charge characters and quarter circle characters, who all had standard moves and some special moves. Usually the special moves were either horizontal (like the Hadouken or the Sonic Boom) or vertical (like the Shoryuken or the Flash Kick). – Spacial awareness

Hadouken – Horizontal
Shoryuken – Vertical

Lastly, I also recalled that when a was a much younger fella, I used to play an Xbox game called Fuzion Frenzy with my buddies in couch multiplayer. One of the minigames in this collection was called “Sumo”, and it was about balls knocking each other off of an ever-shrinking ring. – Spheres, simplicity

Special mentions also go to Dive Kick, Nidhogg and Towerfall Ascension. All of these games involve two or more opponents studying one another and trying to psyche each other out. I wanted to recreate something similar. – Mind games

So I got to work and within about a day I got to a pretty decent result. I quickly had some spheres that were capable of colliding with one another. Unfortunately, I wasn’t mindful enough to collect footage at different stages of development, so the only thing I can show you is a much more advanced build. Apologies.

Here were my basic ideas:
1. As the spheres collide with one another, the one with more momentum wins the collision confrontation and damages the other by an amount that depends on speed at moment of impact (collision.relativeVelocity) and weight of the sphere (rigidbody.mass).
2. The more damage the sphere takes, the lighter it becomes. Lighter spheres are easier to knock around.
3. Whoever is left alive last wins the match.
4. The spheres had to be able to jump, to dodge opponent spheres.
5. All of the locomotion in the game had to be largely based on semi-realistic physics (meaning using the Unity physics engine to a substantial degree).

Pretty soon, in a few days, I was able to test the game with my kids. While I expected success, I certainly hadn’t anticipated the degree of success. The kids were very excited and enthusiastic. They wanted to keep playing. And as we played a few emergent properties of gameplay became apparent:
1. Jumping near the edge of the arena was dangerous, because while in the air you’re like a sitting duck, very easy to hit.
2. It’s possible to jump onto your opponents, stomping them. This would also then allow you to jump again from a yet higher position and stomp them again.
3. It’s possible to jump into your opponents from underneath, executing an uppercut if you will. If done at the right time this can be a very effective way of damaging opponents.

And this is how MC2 started. At the time, I had no idea how to call it, so I dubbed it “project Bouncers”.

Stay tuned for more. 🙂

– Mike