跳转至内容

BYTEPATH #4 - Exercises

In the previous three tutorials we went over a lot of code that didn't have anything to do directly with the game. All of that code can be used independently of the game you're making which is why I call it the engine code in my head, even though I guess it's not really an engine. As we make more progress in the game I'll constantly be adding more and more code that falls into that category and that can be used across multiple games. If you take anything out of these tutorials that code should definitely be it and it has been extremely useful to me over time.

在前面三篇教程里,我们写了很多和游戏本体并没有直接关系的代码。这些代码其实可以脱离当前这个游戏单独拿去复用,所以我自己会在脑子里把它们归到“引擎代码”这一类,虽然严格来说它又算不上真正的引擎。随着游戏继续往下做,我还会不断加进来更多类似的代码,它们同样可以被多个项目共用。如果你想从这几篇教程里真正带走点什么,那最值得带走的,基本就是这些代码了。它们这些年来对我一直都很有用。

Before moving on to the next part where we'll start with the game itself you need to be comfortable with some of the concepts taught in the previous tutorials, so here are some more exercises.

在进入下一部分、正式开始做游戏本体之前,你最好先把前几篇里讲到的一些概念吃透一点。所以这里再补一组练习,帮你把这些内容过扎实。

Exercises

52. Create a getGameObjects function inside the Area class that works as follows:

52.Area 类里实现一个 getGameObjects 函数,行为如下:

lua
-- Get all game objects of the Enemy class
all_enemies = area:getGameObjects(function(e)
    if e:is(Enemy) then
        return true
    end
end)

-- Get all game objects with over 50 HP
healthy_objects = area:getGameObjects(function(e)
    if e.hp and e.hp >= 50 then
        return true
    end
end)

It receives a function that receives a game object and performs some test on it. If the result of the test is true then the game object will be added to the table that is returned once getGameObjects is fully run.

它接收一个函数,这个函数的参数是某个游戏对象,并对它做一次判定。如果判定结果为真,那么这个对象就会被加入到最终返回的表中。

53. What is the value in a, b, c, d, e, f and g?

53. abcdefg 的值分别是什么?

lua
a = 1 and 2
b = nil and 2
c = 3 or 4
d = 4 or false
e = nil or 4
f = (4 > 3) and 1 or 2
g = (3 > 4) and 1 or 2

54. Create a function named printAll that receives an unknown number of arguments and prints them all to the console. printAll(1, 2, 3) will print 1, 2 and 3 to the console and printAll(1, 2, 3, 4, 5, 6, 7, 8, 9) will print from 1 to 9 to the console, for instance. The number of arguments passed in is unknown and may vary.

54. 写一个名为 printAll 的函数,它接收数量不定的参数,并把它们全部打印到控制台。比如 printAll(1, 2, 3) 会打印 1、2、3;printAll(1, 2, 3, 4, 5, 6, 7, 8, 9) 会依次打印 1 到 9。也就是说,传进来的参数个数是不固定的。

55. Similarly to the previous exercise, create a function named printText that receives an unknown number of strings, concatenates them all into a single string and then prints that single string to the console.

55. 和上一题类似,再写一个名为 printText 的函数。它接收数量不定的字符串,把它们拼接成一个完整字符串,然后把这个结果打印到控制台。

56. How can you trigger a garbage collection cycle?

56. 怎样手动触发一次垃圾回收?

57. How can you show how much memory is currently being used up by your Lua program?

57. 怎样查看当前 Lua 程序占用了多少内存?

58. How can you trigger an error that halts the execution of the program and prints out a custom error message?

58. 怎样主动抛出一个错误,让程序停止执行,并输出一段自定义错误信息?

59. Create a class named Rectangle that draws a rectangle with some width and height at the position it was created. Create 10 instances of this class at random positions of the screen and with random widths and heights. When the d key is pressed a random instance should be deleted from the environment. When the number of instances left reaches 0, another 10 new instances should be created at random positions of the screen and with random widths and heights.

59. 创建一个名为 Rectangle 的类,它会在创建时所在的位置绘制一个具有宽和高的矩形。在屏幕随机位置生成 10 个这个类的实例,每个实例的宽高也都是随机的。按下 d 键时,应当随机删除其中一个实例。当实例数量减到 0 时,再次随机生成 10 个新的矩形实例,位置和宽高仍然随机。

60. Create a class named Circle that draws a circle with some radius at the position it was created. Create 10 instances of this class at random positions of the screen with random radius, and also with an interval of 0.25 seconds between the creation of each instance. After all instances are created (so after 2.5 seconds) start deleting once random instance every [0.5, 1] second (a random number between 0.5 and 1). After all instances are deleted, repeat the entire process of recreation of the 10 instances and their eventual deletion. This process should repeat forever.

60. 创建一个名为 Circle 的类,它会在创建时所在的位置绘制一个带半径的圆。先在屏幕随机位置生成 10 个实例,半径也随机,但每个实例之间的创建间隔为 0.25 秒。等 10 个实例都创建完之后,也就是 2.5 秒后,开始以每隔 [0.5, 1] 秒随机删除一个实例。等所有实例都删光之后,再重复一次“创建 10 个圆并逐个删除”的全过程,而且这个过程要一直循环下去。

61. Create a queryCircleArea function inside the Area class that works as follows:

61.Area 类里实现一个 queryCircleArea 函数,行为如下:

lua
-- Get all objects of class 'Enemy' and 'Projectile' in a circle of 50 radius around point 100, 100
objects = area:queryCircleArea(100, 100, 50, {'Enemy', 'Projectile'})

It receives an x, y position, a radius and a list of strings containing names of target classes. Then it returns all objects belonging to those classes inside the circle of radius radius centered in position x, y.

它接收一个 xy 坐标、一个 radius,以及一个包含目标类名的字符串列表。然后返回所有位于以 x, y 为圆心、radius 为半径的圆形区域内,并且属于这些类的对象。

62. Create a getClosestGameObject function inside the Area class that works follows:

62.Area 类里实现一个 getClosestGameObject 函数,行为如下:

lua
-- Get the closest object of class 'Enemy' in a circle of 50 radius around point 100, 100
closest_object = area:getClosestObject(100, 100, 50, {'Enemy'})

It receives the same arguments as the queryCircleArea function but returns only one object (the closest one) instead.

它接收的参数与 queryCircleArea 完全一样,但最终只返回一个对象,也就是其中距离最近的那个。

63. How would you check if a method exists on an object before calling it? And how would you check if an attribute exists before using its value?

63. 在调用某个对象的方法之前,你会怎样先检查这个方法是否存在?同样地,在读取某个属性值之前,又该怎样确认这个属性已经存在?

64. Using only one for loop, how can you write the contents of one table to another?

64. 只使用一个 for 循环的话,怎样把一个表的内容写入另一个表?