Libraries Answers

6. This question is asking for a specific implementation of some class. We can use the examples from rxi/classic to figure out how to do everything we need. First, let's create the skeleton of the class in Circle.lua:

 

Then the question mentions how the constructor should receive x, y and radius arguments, and how those should also be the attributes the class will have. Based on the Creating a new class example on the github page, we can come up with this:

 

The question then says how there should be update and draw methods:

 

And then we can implement the main function of drawing the circle:

 

To instantiate an object of this class we need to go back to main.lua, create the object there and then update and draw it:

 

Here the circle variable is an instance of the Circle class. All of this can be done by looking at the examples in the github page as well as some searching around the LÖVE wiki.

7. This question is asking for more of the same, but now so that we can learn how classic deals with inheritance. Inheritance will be used very sparingly throughout the game (I think there's only really 1 class that other classes inherit from if I remember correctly), but it's still a necessary thing to know how to do. Based on the logic used for the first question, we can look at the examples in the github page and arrive at this:

 

The way inheritance works with this library is that whenever you want to execute functionality from your child class, you need to add the line ClassName.super.methodName(self) to what you're doing. So, for instance, in the draw function, HyperCircle.super.draw(self) draws the inner filled circle, and then the next 3 lines draw the outer circle that the HyperCircle class is concerned with.

8. The : operator in Lua is used as a shorthand for passing self as the first argument of a function when calling it. For instance, both of these lines are the same thing:

 

This is a very common pattern in Lua when you have functions that are operating on some object that are also defined on that object, which happens often with object oriented programming. For instance, let's say we have a table that contains fields x, y and add in it. x and y are values, and add is a function adds those two values together and returns them. One way to define this would be like this:

 

Note that the add function receives a self argument. This argument corresponds to a table that contains that x and y attributes which we want to add. If we call it like this:

 

Then we're passing the t table itself to the add function, and so the return result will be 9. Similarly, we could call it like this:

 

And we'd achieve the same result. We could also define another table u with different x and y values, and then call t.add(u) and we'd get a different result other than 9, however this is generally not what people do. In general the way objects are built in Lua are like more like the first example where we called t:add() , since the table will be operating on its own values instead of on another table's values.

9. This question expands on the previous question to test if you really understood the idea that tables can have functions defined in them that will change the table's own attributes.

The value of counter_table.value is initially what it was defined to be, which is 1. And then after the counter_table:increment() call it got changed to 2. counter_table:increment() is the same as counter_table.increment(counter_table), which means that the self variable in that function definition, in this example, corresponds to the counter_table variable itself, which is why counter_table.value was able to be incremented in the first place.

If we had defined another table called counter_table_2 which had its .value attribute defined to 5, and then called counter_table.increment(counter_table_2), counter_table.value would still be 1 and counter_table_2.value would be 6.

10. This question expands even further on the same concept to really make sure you get it. If you had to get help from the answers for the previous two questions and you couldn't get close to the answer by yourself then you need to spend more time on this idea before you move on. Understanding this is truly essential to understanding how Lua works.

The question is simply asking for a construct similar to the one used in the previous exercise. First it asks for a function that returns a table that contains attributes a, b, c and sum. Those should be initialized, respectively, to 1, 2, 3 and sum should be a function:

 

After this it says that sum should add the previous 3 attributes together, with the final result being stored in the c attribute. This means that like the previous exercise, the sum function will receive some table that we'll name self, and it could be any other table, but we'll most likely call the sum function from that contains that function definition itself:

 

11. It is possible for a table to have a method and an attribute of the same name, however things won't work as expected. Either the method or the attribute will overwrite what was there before and then that identifier will only function as one of them. For instance, if the method t.x is defined first and it's a function that does something, but then the attribute t.x is defined as the value 5, in the end it will be the value 5 and not the function, since the value was defined later and overwrote the function definition.

Because objects will be tables in Lua, this means that method names cannot be the same as attribute names, and that you can't have multiple methods with the same name, or multiple attributes with the same name in a Lua object. Of course, because Lua is flexible, there are ways to change this behavior using metatables and do a bunch of tricky things that to the end user will make it seem like you can have multiple definitions under the same name, but no Lua OOP library I know of does that and we won't really need it.

12. The global table is Lua is named _G and it holds references to all global variables in Lua. Whenever you defined a new variable, like a = 5, what you're really doing is saying _G['a'] = 5, and you can access the a variable by saying _G.a, for instance (on top of just saying a normally).

13. There is no guarantee that ParentClass is already defined in that situation. Based on the way we defined the loading of classes, the only thing that we know for sure is that classes are loaded in alphabetical order, other than that the order in which they're loaded is undefined. This means that with the way we do it now, there's no way to guarantee one class is always loaded before the other.

One way to solve this is to simply manually load classes that other classes depend on and them automatically load all other classes. In the game there are only a few classes that fit this definition so this is a suitable solution.

14. In this new way of doing it, the class is returned instead of automatically being assigned to a global variable. So the only thing we have to change in the requireFiles function is making sure that assignment to a global variable happens. The way the current function looks is like this:

 

If we print the file variable we'll get strings like this, for instance: objects/ObjectName , where ObjectName will be the name of some class, and there will be multiple of those strings. What we want to do is take ObjectName out of this full objects/ObjectName string, and then use that as the name of our global variable, so essentially we'll be doing _G[ObjectName] = require(file). The only thing we have to do then is successfully remove the class name from the full path that we have in the file variable.

To achieve this we can first find the last / character. It has to be the last because the full path can have other folders in it in the future, like objects/Enemies/EnemyName. To do this I just googled "find last specific character in string Lua" and I got this page https://stackoverflow.com/questions/14554193/last-index-of-character-in-string where someone already had the answer for the exact character we need even. So applying that to our case:

 

First we find the index of the last forward slash using the code from the StackOverflow question. Then we take that index and use the string.sub function to split the string, from the index found + 1 (because we don't want the forward slash in the final string) to the end of the string. This gets us exactly what we want and so the class_name variable will contain the name of the class we wanted. Now it's just a matter of loading that globally:

 

Another thing that can be done here is that unload a class if it was previously loaded. This might never be useful but it's useful to know that it can be done: by calling package.loaded[file] = nil before the require(file) call, we can clear the cache that holds all files that have been previously loaded and force a full reload of that file. This is useful in a number of situations, like if we wanted to implement hot-reloading of our code.

15. For this question all that really has to be done is to test the code and see that whenever mouse1 is pressed (not released nor held) the function runs. This is an alternate thing you can do with the bind function, which is to just bind a key to a function that will be executed when the key is pressed.

16. For this question we need to first bind the keypad + key to an action named add. To do that we need to figure out what's the string used to represent keypad +. The github page links to this page for key constants and says that for the keyboard they are the same, which means that keypad + is kp+. And so the code looks like this:

 

Then the question asks to increment a sum variable every 0.25 seconds when the add action key is held down and to print the result to the console. This is simply an application of the pressRepeat function:

 

17. Multiple keys can be bound to the same action. What will happen when an action is checked for is that all the keys will be checked for at the same time, so if any of the keys was pressed an event will be generated for that action. Similarly, multiple actions can be bound to the same key and whenever the key is pressed, all actions bound to it will have an event generated for them.

18. This one is a matter of simply applying everything we went over so far, just using gamepad constants instead of mouse or keyboard ones:

 

19. Here we see how values that are not booleans can be used. In the case of triggers, down can be used to access the value which will be somewhere between 0 and 1, depending on how hard the trigger is being pressed.

 

20. Same exercise as the previous, but for vertical/horizontal stick positions:

 

21. For this question we need to print 10 random numbers with a 0.5 interval between each print using only a for and an after call inside that loop. The thing to do on instinct is something like this:

 

But this will print 10 numbers exactly at the same time after an initial interval of 0.5 seconds, which is not what we wanted. What we did here is just call timer:after 10 times. Another thing one might try is to somehow chain after calls together like this:

 

And then somehow translate that into a for, but there's no reasonable way to do that. The solution lies in figuring out that if you use the i index from the loop and multiply that by the 0.5 delay, you'll get delays of 0.5, then 1, then 1.5, ... until you get to the last value of 5. And that looks like this:

 

The first number is printed after 0.5 seconds and then the others follow. If we needed the first number to printed immediately (instead of with an initial 0.5 seconds delay) then we needed to use i-1 instead of i.

22. This question asks for a bunch of tweens that happens in sequence after one another. This is just a simple application of the tween function using the optional last argument to chain tweens together. That looks like this:

 

23. For this one we need to define two structures, one for which will be the front layer and one that will the background layer of the HP bar. We'll define them simply like tables:

 

Here we simply define the x, y position and w, h size of the rectangle for both the front and back layer. To draw them we can simply use love.graphics.rectangle:

 

After drawing it, all we need to do is bind the d key to make the front layer move, and then after a small delay make the background layer move as well. We can use the tween function from a timer to achieve this:

 

And so at first we decrease the width of the front bar by 25, and then after 0.25 seconds we do the same for the background bar. One important thing to notice is that all calls that use the timer have a name. This is because whenever we press the key and another previous tween is happening (like if you press the key multiple times really fast), then we want to cancel the previous tween so that two tweens aren't operating on the same variable at once.

24. The easiest way to do this is to change the timer:after call to be timer:every instead:

 

The duration of the every call should be the sum of the duration of both the expand and shrink tween inside it, so in this case it goes on for 12 seconds, since each tween goes for 6 seconds.

25. The only difference with this exercise is that instead of using every we have to use multiple after calls to simulate every, which is something that the timer library supports:

 

26. This question asks for the application of the naming system in a tween, like in question 23. So the easiest way to do that is to break down each part of the behavior (expand, shrink) and tie it to the different keys:

 

With this, whenever the user presses either e or s, the circle will expand or shrink appropriately. However, if the other key is pressed while the tween from the previous press is happening, then two tweens will be operating on the same variable at the same time and bugs will happen. For instance, if you press e and then 2 seconds later you press s, for 4 seconds both tweens will be active.

To fix this we need to actively cancel other tweens that might be active. In the case of expand, cancel shrink, and in the case of shrink, cancel expand:

 

We don't need to also call the cancel function for the same tag (i.e. calling timer:cancel('expand') when e is pressed) because when the tween call has a tag attached to it it automatically does that once the tag is repeated in another call.

27. The problem this question is asking about is how to change a variable that is not inside a table with the tween function. The second argument of the tween method receives a table, and then in the next argument after that the attribute that is to be changed can be specified. But how do we do this if a variable is not in a table, like a free floating global variable? The answer is to remember that all global variables in Lua are inside the _G table:

 

In this way, the a variable will have its value changed in the way the question asked. It's worth noting that I don't think there's a way of doing this if the variable was defined locally, since in that case the variable wouldn't be in the global environment table.

For the answers for the table exercises, it's assumed that the moses library was initiated to the fn global variable.

28. This is an application of the each function as it is shown in the examples:

 

29. This is an application of the count function as it is shown in the examples:

 

30. This is an application of the map function as it is shown in the examples:

 

31. This is an application of the map function but is a bit more involved:

 

Here we make use of the type function, which returns the type of a value as a string. After verifying which type we're dealing with we proceed with what's asked for each type.

32. This is an application of the reduce function as it is shown in the examples:

 

33. This is an application of the include function as it is shown in the examples. I use this a lot but I usually use the any alias instead, since I remember what it does better with that name:

 

34. This is an application of the detect function as it is shown in the examples:

 

35. This is an application of the select or filter function as it is shown in the examples:

 

This is the same as:

 

So what this function should do is return true for values that should stay and false or nil otherwise. The reject function works the same, except with the opposite values being returned: values that should be removed should return true instead.

36. Same as the previous exercise:

 

37. This is an application of the all function as it is shown in the examples:

 

38. This is an application of the shuffle function as it is shown in the examples:

 

Note that the d list isn't actually shuffled in place. A new shuffled table is returned and then you have to go from there. In a lot of functions this is the case but in some it isn't, so generally you should test to see if the function you're using modifies the table in place or not.

39. This is an application of the reverse function as it is shown in the examples:

 

40. This is an application of the pull or remove function as it is shown in the examples:

 

41. This is an application of the union function as it is shown in the examples:

 

42. This is an application of the intersection function as it is shown in the examples:

 

43. This is an application of the append function as it is shown in the examples: