I dont get what __index does :(

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

I dont get what __index does :(

Post by weitnow »

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:

http://hump.readthedocs.io/en/latest/camera.html

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})

User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: I dont get what __index does :(

Post by raidho36 »

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.
User avatar
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

Re: I dont get what __index does :(

Post by weitnow »

Thank you raidho36 for your qualified answer....

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: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: I dont get what __index does :(

Post by grump »

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.
User avatar
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

Re: I dont get what __index does :(

Post by weitnow »

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: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: I dont get what __index does :(

Post by grump »

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.
Post Reply

Who is online

Users browsing this forum: No registered users and 60 guests