Player Build and Attacks Answers

93. This one is asking for the reverse of what the article talked about, which means it's simply a matter of reversing the comparisons wherever necessary:

 


94. This exercise is asking that instead of using the depth attribute as the parameter to be compared, we use the y attribute. On top of that, it's asking us to use the y attribute and make it so that the objects with higher y drawn last. This is the same ordering idea as the one used in the article (and the opposite of the one used in the last exercise), so:

 

We can also keep the line that sorts by creation_time here since sometimes in a 2.5D game like that objects can have the same y attribute as well and flickering can also occur.


95. This is simply a matter of change the definition of the Projectile class with the addCollisionClass call:

 

It's important to note that we can't change the Player projectile class instead and make it ignore Projectile (even though the end result would be the same), because the Projectile collision class is defined only after the Player collision class. This is a small quirk of the physics library we're using.


96. The addAmmo function looks like this right now:

 

The question is asking that we take into account the possibility that the value in amount might be negative, and take precautions against ammo going below 0. We can easily do that by wrapping out initial calculation into a math.max call:

 

In this way, the result of the addition of ammo and amount will first be checked so that it doesn't go above max_ammo, and immediately after that checked so that it doesn't go below 0. The same applies to the other functions:

 
 


97. This is entirely up to preference. The only change I'd make is that if we're handling the values in the same function then it might make more sense to name that function changeResource instead of addResource, since we would be adding and removing from some resource in the same function.


98. This exercise is a matter of changing the values around the love.math.random calls in the constructor of the InfoText class. This is what it looks like now:

 

So to change the probability of a character being changed to 20%, we need to change the first if love.math.random(1, 20) <= 1, which is a 5%, to something like love.math.random(1, 5) <= 1 or love.math.random(1, 10) <= 2, which would be 20%. And to change the probability of the foreground color being changed to 5% we need to change it from love.math.random(1, 10) <= 1, which is 10%, to something like love.math.random(1, 20) <= 1. And finally, to change the probability of a background color being changed to 30% we need to change it from love.math.random(1, 10) <= 2, which is 20%, to something like love.math.random(1, 10) <= 3.

So the final result would look like this:

 


99. This is simply a matter of defining those tables in globals.lua:

 

And then also changing all references to from self.all_colors to justall_colors.


100. The current way the InfoText object is spawned from the Boost object looks like this:

 

To randomize its starting position based on the constraints the exercise asks for we can do something like this:

 

And this would solve the exercise itself. However, upon testing this looks a bit off sometimes. A slightly better solution, in my opinion, is something like this:

 

In this way instead of randomizing to a position between some width and height, we always go for either the position to one of the extremes of that range. This makes the results more predictable and prevents the problem of the text appearing on top of the boost resource, which would make it unreadable.


101. This exercise is very involved and can be solved in any number of ways. The solution outlined here is only one possible out of many!

The question starts with the assumption that you have all InfoText objects that are currently alive in a table named all_info_texts and then asks you to make it so that the current InfoText object doesn't visually collide with any other. This is an important problem to solve because like in the last exercise, if the text becomes unreadable at any point then it stops serving its purpose. And if multiple texts are being printed on top of each other the chances that they'll become unreadable are high, so we want to prevent that from happening.

The first thing we need to do to get InfoText objects to not visually collide with each other is to define their sizes. Their width is defined by the width of the text when using the font this object uses, and their height is defined by the height of this font:

 

After we have the position and size of each InfoText object, we wanna go through the list containing all of them and seeing if it collides with the current InfoText object. We'll wrap this into a local function called collidesWithOtherInfoText which returns true when a collision is happening and false otherwise. Note that here a collision refers to the overlapping of rectangles that defines each object.

 

Here we introduce a function named areRectanglesOverlapping, which takes in the positions of two rectangles and returns true if they're overlapping. A check to see if rectangles overlap can be found with some simple googling, like on this StackOverflow answer. And so according to that answer, we can create the function in utils.lua and it looks like this:

 

Finally, after collidesWithOtherInfoText is defined what we can do is just call it, see if it returns true, and if it does then we move this InfoText object to a nearby position somewhat randomly. Then we call this check again to see if it still collides with another, and if it does, we move it randomly again. And we repeat this until this InfoText object isn't colliding with any other one. However intuitive this might seem or that it might get stuck in an infinite loop, this solution actually works out pretty well. The way I decided to do it was just with a while loop, and the amount I decided to move the InfoText by was by its width/height either left/right or up/down, as you can see below:

 

And so with this we end up solving the problem. Moving the InfoText object by in self.w and self.h steps both leads to more predictable results, but also leads to fewer iterations of the than if we just moved it by a random amount.