## I dont get what __index does :(

General discussion about LÖVE, Lua, game development, puns, and unicorns.
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

### I dont get what __index does :(

hello together

I try to improve in lua. Therefore i am looking at some sourcecode and try to understand, how it works.

Right now I don't understand the sourcecode of:

at the beginning of the code it has:

local camera = {}
camera.__index = camera

i do understand, that __index is a methamethod....but it would usually be used to add properties or function from a metatable to annother table....

but in this example camara is a table and camara.__index points to camera. I don't understand, what it exactly does?

Can somebody explain?

Here is the complete source-code

Code: Select all

local cos, sin = math.cos, math.sin

local camera = {}
camera.__index = camera

-- Movement interpolators (for camera locking/windowing)
camera.smooth = {}

function camera.smooth.none()
return function(dx,dy) return dx,dy end
end

local function new(x,y, zoom, rot, smoother)
x,y  = x or love.graphics.getWidth()/2, y or lo-ve.graphics.getHeight()/2
zoom = zoom or 1
rot  = rot or 0
smoother = smoother or camera.smooth.none() -- for locking, see below
return setmetatable({x = x, y = y, scale = zoom, rot = rot, smoother = smoother}, camera)
end

function camera:lookAt(x,y)
self.x, self.y = x, y
return self
end

function camera:move(dx,dy)
self.x, self.y = self.x + dx, self.y + dy
return self
end

function camera:position()
return self.x, self.y
end

function camera:zoom(mul)
self.scale = self.scale * mul
return self
end

function camera:zoomTo(zoom)
self.scale = zoom
return self
end

function camera:attach(x,y,w,h, noclip)
x,y = x or 0, y or 0
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()

self._sx,self._sy,self._sw,self._sh = love.graphics.getScissor()
if not noclip then
love.graphics.setScissor(x,y,w,h)
end

local cx,cy = x+w/2, y+h/2
love.graphics.push()
love.graphics.translate(cx, cy)
love.graphics.scale(self.scale)
love.graphics.rotate(self.rot)
love.graphics.translate(-self.x, -self.y)
end

function camera:detach()
love.graphics.pop()
love.graphics.setScissor(self._sx,self._sy,self._sw,self._sh)
end

function camera:draw(...)
local x,y,w,h,noclip,func
local nargs = select("#", ...)
if nargs == 1 then
func = ...
elseif nargs == 5 then
x,y,w,h,func = ...
elseif nargs == 6 then
x,y,w,h,noclip,func = ...
else
error("Invalid arguments to camera:draw()")
end

self:attach(x,y,w,h,noclip)
func()
self:detach()
end

-- world coordinates to camera coordinates
function camera:cameraCoords(x,y, ox,oy,w,h)
ox, oy = ox or 0, oy or 0
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()

-- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center
local c,s = cos(self.rot), sin(self.rot)
x,y = x - self.x, y - self.y
x,y = c*x - s*y, s*x + c*y
return x*self.scale + w/2 + ox, y*self.scale + h/2 + oy
end

-- camera coordinates to world coordinates
function camera:worldCoords(x,y, ox,oy,w,h)
ox, oy = ox or 0, oy or 0
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()

-- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y)
local c,s = cos(-self.rot), sin(-self.rot)
x,y = (x - w/2 - ox) / self.scale, (y - h/2 - oy) / self.scale
x,y = c*x - s*y, s*x + c*y
return x+self.x, y+self.y
end

-- camera scrolling utilities
function camera:lockX(x, smoother, ...)
local dx, dy = (smoother or self.smoother)(x - self.x, self.y, ...)
self.x = self.x + dx
return self
end

function camera:lockY(y, smoother, ...)
local dx, dy = (smoother or self.smoother)(self.x, y - self.y, ...)
self.y = self.y + dy
return self
end

function camera:lockPosition(x,y, smoother, ...)
return self:move((smoother or self.smoother)(x - self.x, y - self.y, ...))
end

function camera:lockWindow(x, y, x_min, x_max, y_min, y_max, smoother, ...)
-- figure out displacement in camera coordinates
x,y = self:cameraCoords(x,y)
local dx, dy = 0,0
if x < x_min then
dx = x - x_min
elseif x > x_max then
dx = x - x_max
end
if y < y_min then
dy = y - y_min
elseif y > y_max then
dy = y - y_max
end

-- transform displacement to movement in world coordinates
local c,s = cos(-self.rot), sin(-self.rot)
dx,dy = (c*dx - s*dy) / self.scale, (s*dx + c*dy) / self.scale

-- move
self:move((smoother or self.smoother)(dx,dy,...))
end

-- the module
return setmetatable({new = new, smooth = camera.smooth},
{__call = function(_, ...) return new(...) end})



raidho36
Party member
Posts: 1987
Joined: Mon Jun 17, 2013 12:00 pm

### Re: I dont get what __index does :(

A table can have any fields and none of them do anything special. A metatable can also have any fields but it has a number of fields that have special function. The __index field controls table access fallback - if the value is not found in original table, __index metamethod will be invoked. The __index field can be a function that calculates which value to return for a given key, or another table in which Lua would search for missing value.

weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

### Re: I dont get what __index does :(

Until now i always used metamethods like this:
tableA = {}
tableB= {}
setmetatable(tableA, tableB)
tableB.__index = {x = 10}
print(tableA.x)
which of course prints 10....tableA has no x but the metamethod __index a was invoked whiched caused it to print 10

but in the other example the creator of camera.lua used it like this:
local tableA = {}
tableA.__index = tableA
Until now I haven't really figured out, what he is doing with that concept :/
He sets tableA.__index to itself?

grump
Party member
Posts: 595
Joined: Sat Jul 22, 2017 7:43 pm

### Re: I dont get what __index does :(

camera becomes the metatable of the table that is created when function new(...) is called.

Or, in classic OOP nomenclature: camera is the class of the object that the constructor creates. In Lua, those are all tables, and the relation between class and object is defined by the metatable of the object.

By setting the __index field of the metatable of the newly created object table to the class table (camera), the functions (methods) defined in the class camera will be called when they aren't found in the object. Wenn called, they get passed the self table that is the actual object instance, not the class. This makes it possible to share methods between all objects because they'll operate on the object given by self.

Code: Select all

Camera = require "camera" -- the class
local mycamera = Camera(...) -- object of the class; this actually calls function new(...)

mycamera:move(...) --[[ move does not exist in mycamera, so the metatable function
__index will be invoked, which finds and calls the function that is defined in the Camera class/table.
The mycamera object/table will be passed as self.
]]
Last edited by grump on Thu Aug 24, 2017 5:36 pm, edited 1 time in total.

weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

### Re: I dont get what __index does :(

thank you grump....your answer is much appreciated....i think i understand now. I like lua a lot...especially with love2d....but the funny thing is, I originally choose lua because of it's simplicity (since i am a beginning hobby programmer, with not a lot expirience). eventhough i get slowly the concepts of metatable, i really think oop-languages like python are almost easier to understand, then using metatable as a way to get oop in lua to work. but anyhow...thank you guys for your explanation and sorry for my bad english, its not my national language.

grump
Party member
Posts: 595
Joined: Sat Jul 22, 2017 7:43 pm

### Re: I dont get what __index does :(

I too love Lua for its simplicity and flexibility. The metatable stuff is the probably the most difficult concept to grasp about it, but it really isn't that hard to understand. It just needs a little bit of practice and reading the documentation. Reading other people's code helps too. Even though I understand it pretty well now, there's still Aha! moments for me when I see creative use of metatables in other people's code.

### Who is online

Users browsing this forum: No registered users and 6 guests