|
| 1 | +# Random Robot Objects |
| 2 | + |
| 3 | +This object-oriented programming example program demonstrates two different Lua patterns - classes with metatables (Robot) and simple tables with methods (box). It consists of a Robot class definition and simple box object. |
| 4 | + |
| 5 | +The box object demonstrates a simpler object-oriented structure of a table with methods. Lua's power of [first-class functions](https://softwarepatternslexicon.com/lua/lua-programming-fundamentals/first-class-functions-and-closures/) is represented here. |
| 6 | + |
| 7 | +A first-class function means they can be: |
| 8 | + |
| 9 | +* Stored in tables (like in the `box` table) |
| 10 | +* Assigned to variables (like `display = function(self) ... end`) |
| 11 | +* Passed as arguments to other functions |
| 12 | +* Returned from functions |
| 13 | + |
| 14 | +The `box` object demonstrates this with `display` and `move` functions stored as values in the box, just like `x`, `y` and `size` are numbers. |
| 15 | + |
| 16 | +The Robot demonstrates uses of [metatables](https://www.tutorialspoint.com/lua/lua_metatables.htm). |
| 17 | + |
| 18 | +* `Robot.__index = Robot` sets up the metatable |
| 19 | +* `setmetatable(robot, Robot)` links each instance to the Robot table |
| 20 | +* This enables [method lookup](https://cyevgeniy.github.io/luadocs/02_basic_concepts/ch04.html) - when you call `robot:move()`, Lua looks in the Robot table to find the `move` function |
| 21 | + |
| 22 | +Advanced ways to extend the program: |
| 23 | + |
| 24 | +* add more robot behaviors - make robots change colors when they collide with each other |
| 25 | +* score counter - count how many times the box teleports to robots |
| 26 | +* different robot types - a FastRobot that moves twice as fast as the others |
| 27 | +* mouse interaction - Create new robots at the mouse position when clicked |
| 28 | +* Box trail - a line showing the box's history |
| 29 | +* Chase - make robots chase the box |
| 30 | +* power-ups - add collectible items that change robot speed, size or behavior |
| 31 | +* animated sprites - multiple images to animate movement |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | +```lua |
| 36 | +require("L5") |
| 37 | + |
| 38 | +-- Note: The Robot class definition below could be moved to a separate file robot.lua |
| 39 | +-- and then loaded with: local Robot = require("robot") |
| 40 | + |
| 41 | +Robot = {} |
| 42 | +Robot.__index = Robot -- Tells Lua to use Robot's metatable to find methods |
| 43 | + |
| 44 | +-- Global vars |
| 45 | +robots = {} -- Table to hold all robot instances |
| 46 | +robotImg = nil |
| 47 | + |
| 48 | +function setup() |
| 49 | + size(800, 600) |
| 50 | + windowTitle("Robots OOP example") |
| 51 | + robotImg = loadImage("assets/robot.png") |
| 52 | + imageMode(CENTER) |
| 53 | + rectMode(CENTER) |
| 54 | + strokeWeight(3) |
| 55 | + fill("gold") |
| 56 | + stroke("goldenrod") |
| 57 | + |
| 58 | + -- Initialize box position |
| 59 | + box.x = random(width) |
| 60 | + box.y = random(height) |
| 61 | + |
| 62 | + -- Create 10 robots |
| 63 | + for i = 1, 10 do |
| 64 | + table.insert(robots, Robot:new()) |
| 65 | + end |
| 66 | +end |
| 67 | + |
| 68 | +function draw() |
| 69 | + background("lightblue") |
| 70 | + |
| 71 | + -- Update and draw box |
| 72 | + box:move() |
| 73 | + box:display() |
| 74 | + |
| 75 | + -- Update and draw all robots |
| 76 | + for i = 1, #robots do |
| 77 | + robots[i]:move() |
| 78 | + robots[i]:display() |
| 79 | + end |
| 80 | +end |
| 81 | + |
| 82 | +-- Robot class definition |
| 83 | +function Robot:new(x, y, w, h) |
| 84 | + local robot = { |
| 85 | + x = x or random(width), |
| 86 | + y = y or random(height), |
| 87 | + w = w or 70, |
| 88 | + h = h or 70, |
| 89 | + xspeed = random(-2, 2), |
| 90 | + yspeed = random(-2, 2) |
| 91 | + } |
| 92 | + setmetatable(robot, Robot) -- Links the instance to Robot class |
| 93 | + return robot |
| 94 | +end |
| 95 | + |
| 96 | +function Robot:move() |
| 97 | + self.x = self.x + self.xspeed |
| 98 | + self.y = self.y + self.yspeed |
| 99 | + |
| 100 | + -- Bounce off walls |
| 101 | + if self.y > height or self.y < 0 then |
| 102 | + self.yspeed = self.yspeed * -1 |
| 103 | + end |
| 104 | + if self.x > width or self.x < 0 then |
| 105 | + self.xspeed = self.xspeed * -1 |
| 106 | + end |
| 107 | +end |
| 108 | + |
| 109 | +function Robot:display() |
| 110 | + image(robotImg, self.x, self.y, self.w, self.h) |
| 111 | +end |
| 112 | + |
| 113 | +-- Box object using simple table with methods |
| 114 | +-- Demonstrates first-class functions stored as table values |
| 115 | +box = { |
| 116 | + x = nil, -- Initialized in setup() after random() is seeded |
| 117 | + y = nil, |
| 118 | + size = 40, |
| 119 | + |
| 120 | + display = function(self) |
| 121 | + square(self.x, self.y, self.size) |
| 122 | + end, |
| 123 | + |
| 124 | + move = function(self) |
| 125 | + -- Teleport to nearest robot if close enough |
| 126 | + for i = 1, #robots do |
| 127 | + if dist(self.x, self.y, robots[i].x, robots[i].y) < self.size then |
| 128 | + self.x = robots[i].x |
| 129 | + self.y = robots[i].y |
| 130 | + break |
| 131 | + end |
| 132 | + end |
| 133 | + end |
| 134 | +} |
| 135 | +``` |
| 136 | + |
| 137 | +## Related References |
| 138 | + |
| 139 | +* [for](/reference/for) |
| 140 | +* [imageMode()](/reference/imageMode) |
| 141 | +* [loadImage()](/reference/loadImage) |
| 142 | +* [rectMode()](/reference/rectMode) |
| 143 | +* [table](/reference/table) |
| 144 | +* [random()](/reference/random) |
| 145 | + |
0 commit comments