Player Basics Answers

80. This exercise is asking for an understanding of how to make something happen every n seconds where n might be variable. This was already explored in a previous article but it's good to remember how to do it properly.

One way of doing it is that instead of using the every call, we use two after calls to simulate every:

 

This works because of how the after call works in this library, and when it's structured in this way it can emulate every, as was explained previously. Another way of doing this, which will be the way we'll do it in the end, is to do it completely manually and not use the timer at all. We'll go over this way in the next article I think.

81. In instances where long-lived objects are referenced inside short-lived objects there's no need to worry about dereferencing things manually. The short-lived object will die, and then the reference to the long-lived object will die as well as the short-lived object is collected and removed from memory. In the case of short-lived objects being referenced inside long-lived objects, though, then we need to be more careful. For instance, in this case if the Player object held references to all ShootEffects it creates, then we'd need to manually nil those references otherwise they would never be collected.

So in the general case: when long-lived contains short-lived referenced = manually dereference; and when short-lived contains long-lived referenced = no worry. In cases where the difference between how long objects will live for is not known then all caution must be used since it will depend on the situation.

82. This is simply a matter of using pushRotate with the center being the position of the player and the angle being math.pi (180 degrees):

 

83. For this, we need to figure out where the center of the line is and then use that as the center for rotation. The line is drawn from the center of the player to a distance of 2*self.w along the current angle, so it makes sense to assume that half of that would be self.w:

 

Note that since we only want to rotate the line, we only wrap the line that draws the line under push/pop calls.

84. This one is the same idea as the previous one, except instead of using the center of the line as the center of rotation we just use the center of the player:

 

85. This one is a bit trickier but it follows the same idea as the previous exercise:

 

The only difference here is that we have to figure out that we can stack pushRotate calls like this whenever we want multiple types of rotations on the same target.

86. To change the size and speed of created projectiles we just need to make use of the fact that those variables are set to a value in the opts table if one is provided:

 

And so by setting s = 5 and v = 150 in the opts table of the addGameObject function, those projectile attributes will be set to those values. Note that this only works because in the Projectile object constructor we say self.s = opts.s or 2.5, meaning that it will be set to the value that was passed in in opts.s first and then default to 2.5 if no such value was given.

87. This is simply a matter of changing the angle of each projectile spawned by +-30 degrees and spawning 3 projectiles instead of 1:

 

88. This one is a bit trickier because we have to change the initial position of the 2 extra projectiles but also taking into account the angle of the player. This is asking for the application of one of the series of exercises in the last article, where you had to get from point A to point C and all you had were distances and angles to work with.

This is something similar, with point A being the initial position of the center of the player, point B being the position of the center projectile, and points C being the position of the 2 remaining side projectiles.

 

As shown in those series of exercises, whenever we want to get from one point to another and all we have to work with are a series of points, distance and angles between them, we should just add together the distance*math.cos(angle) pattern. In this case, we start from point B which we previously knew to be 1.5*d away from the center at self.r angle. From this, we want to get to a point that is 0.5*d away, but at self.r+-90 degrees instead, since that will let you walk to the sides in parallel to the angle that the player is pointing towards.

89. This question can be solved by tweening the v attribute in a projectile over time. In this particular instance, we'll tween it to 400 over 0.5 seconds in its constructor:

 

And we need to also change its initial velocity to 100:

 

90. A new way of achieving the same effect is by just changing the color in the current_color attribute to the new one when appropriate. Like this:

 

This is a much simpler way of getting the same job done. I originally made this object like I outlined in the article and only after writing it I realized that there was a much simpler way. Generally for small objects like this, simplifying things like this exercise did is not super necessary, but for more complex objects and for more complex operations it can be useful to have less moving parts to worry about, so it's important to keep a look out for when things could be made simpler at no cost.

91. We can change the flash function by changing it so that flash_frames is simply a boolean that tells if the flash effect is active or not, and then by introducing a timer that will change this boolean based on the duration we want for the effect:

 

This is very similar to how the slow function works. The only other change we'd have to make is to remove the commented out piece of code from the love.draw function:

 

As for if it's a preference or not, as far as I can see it's mostly a matter of preference. I don't see any big disadvantages to defining things in terms of frames instead of time or the other way around. As for the timer module it can't use frames now but I don't see any reason why it couldn't if changes were made to it.