-- Updated for version 1.2.83 of Defold

Welcome to this Defold API Cheat Sheet.

Defold is a tool which you can use to make games.

Visit the Defold Official Site to learn more.

This ref can be downloaded as a .zip file at the bottom of the page.

This ref is meant as easy API reference. Check the Book of Defold too.

Explore the vmath module of Defold. Many of the functions below have built in versions. The information below is provided as a reference in case you have need.

You can use ZeroBrane Studio to quickly test code samples.

Angles, Radians, Degrees

With Defold (and in math), 0 degrees is equal to east, 90 to north, 180 to west, 270 to south, and 360 to east again.

Radians are often used in game development as an alternative to degrees for representing angles. Many programming languages have built in functions for converting between the two. Radians are far more useful, are cleaner, and easier to use once you understand them. If you do not have a strong understanding of them you should dig into any resources you can find which explain them until they click for you.

Radians are based on the radius of a circle (the distance between the center of a circle and any point along its length) - 1 radius measure is equal to 1 radian along the circle's length. 1 radian is about 57 degrees.

There are 2pi radians in a circle. In most math, and in Defold, we begin to count from 0 facing right and then begin to count counter clockwise upward for pi/2 (90 degrees), then continue to count until we are facing left at pi (180 degrees), then continue to count until we are facing downward at 3pi/2 (270 degrees), and then continuing to count until we are again facing right  at 2pi (360 degrees) to complete a full circle.

There are about 6.283... radians for the length of a circle. That is equal to 2 * pi. To visualize this better imagine you have a picture of a circle and a dot at its center. You take some string and cut it to the length from center of the circle to any point on the circle's circumference. You place the cut string along the circumference, and repeat measuring, cutting string, and placing. You will find that your seventh piece of string doesn't fit - only about 28% of its length fits. So you have 6.28... pieces of string.

math.pi = 3.14...
math.deg() converts radians into degrees
math.rad() converts degrees into radians

To convert from degrees to radians divide the degrees by (180/pi).
To convert from radians to degrees multiply the radians by (180/pi).

print(math.deg(2 * math.pi)) -- 360
print((2 * math.pi) * (180/math.pi)) -- 360

print(math.rad(360)) -- 2pi ... 6.2831853071796
print(360 / (180/math.pi)) -- 2pi ... 6.2831853071796
print(2*math.pi) -- 2pi ... 6.2831853071796

2pi = one full circle
pi = one half circle
2pi/3 = one third circle
pi/2 = one fourth circle
2pi/5 = one fifth circle
pi/3 = one sixth circle
2pi/7 = one seventh circle
pi/4 = one eighth circle
2pi/9 = one ninth circle
pi/5 = one tenth circle
2pi/11 = one eleventh circle
pi/6 = one twelfth circle

30 degrees = pi/6 radians
45 degrees = pi/4 radians
60 degrees = pi/3 radians
90 degrees = pi/2 radians
180 degrees = pi radians
270 degrees = 3pi/2 radians
360 degrees = 2pi radians

Dot Product (inner product) - Calculating Angle Differences

The dot product of two vectors tells you how far apart they are in a single number - the angle amount between them. It produces a scalar value - how much of one vector is pointing in the direction of another.

vector1.x * vector2.x + vector1.y * vector2.y

This is equal to

vector1.magnitude * vector2.magnitude * math.cos(angle between vector 1 and vector 2)

If vector1 and vector2 are unit vectors (magnitude of 1) then their dot product will be equal to just math.cos of the angle between the two vectors. Defold does have built in functionality for creating and using vectors and normalization of vectors which you should use when working with the built in vectors.

If you are using unit vectors then the dot product of two vectors can give you useful information. This can be useful when you want to avoid other CPU expensive functionality.

If > 0 : angle between vectors is less than 90 degrees - it is acute
If < 0 : angle between vectors is more than 90 degrees - it is obtuse
If == 0 : angle between vectors is 90 degrees - the vectors are orthogonal
If == 1 : angle between the two vectors is 0 degrees - vectors are parallel and point in same direction
If == -1 : angle between the two vectors is 180 degrees - vectors are parallel, point in opposite directions 

This information can be used to find relative orientation of other objects in your game. Such as if certain objects are facing others. If you rotate one of the vectors by 90 degrees first you can find if objects are to the left or the right of each other.

Rounding errors may give you values very close to these options in situations where they should be exact (such as being exactly 0). You may want to add extra code to see if values are close enough for you to accept the various conditions.

Cross Product (vector product) tells you the perpendicular direction of any two vectors, how much a vector is perpendicular to another. It can give the axis to rotate around to face something. The 2d form returns a scalar. Its 3d form returns a vector.

cross_product_vectors = function (x1, y1, x2, y2)
	return x1*y2 - y1*x2 -- 0 == parallel
end

cross_product_vectors_3d = function (x1, y1, z1, x2, y2, z2)
	resX = y1 * z2 - z1 * y2
	resY = z1 * x2 - x1 * z2
	resZ = x1 * y2 - y1 * x2
	return resX, resY, resZ
end

If the z of both vectors in the 3d version is zero then the 3d form will return the "same end result" as the 2d form.

print(cross_product_vectors(1,2,3,4)) -- -2
print(cross_product_vectors_3d(1,2,0,3,4,0)) -- 0	0	-2



Angle Between Two 2D Vectors - difference in orientation

angle_between_vectors = function (x1, y1, x2, y2)
	local arc = math.sqrt((x1*x1 + y1*y1) * (x2 * x2 + y2 * y2))
	if arc > 0 then
		arc = math.acos((x1*x2 + y1*y2) / arc)
		if x1*y2 - y1*x2 < 0 then
			arc = -arc
		end
	end
	return arc
end

print(angle_between_vectors(1,1,-1,-1)) -- 3.14... 180 degrees

Angles in Defold

When changing the direction of a 2d object in Defold, by using the Euler (pronounced oiler) property, the angle starts facing right and 0 degrees, goes up to 90 degrees and so on.

go.animate("." "euler.z", go.PLAYBACK_LOOP_PINGPONG, 360, go.EASING_LINEAR, 10) 

Animates the current Game Object so that its angle direction on the z plane is animated back and forth between its current (default 0) and + 360 amount of difference. If you were to first set the euler.z to another value first you would see the animation would go back and forth between a 360 degree arc from that value and +360 degrees of that value.

go.set(".", "euler.z", 180)
go.animate("." "euler.z", go.PLAYBACK_LOOP_PINGPONG, 360, go.EASING_LINEAR, 10) 

Points and Vectors

A point is a coordinate - it can be x,y for a coordinate on a 2D space, or x,y,z for a coordinate on a 3D space.

A vector is a direction toward a point (relative to an origin) along with a magnitude (length).

Convert Radian Angle to a 2D Vector

angle_to_vector = function (angle, magnitude)
	magnitude = magnitude or 1 -- if no magnitude supplied make it a unit vector
	local x = math.cos ( angle ) * magnitude
	local y = math.sin ( angle ) * magnitude
	return x, y
end

Converting Vectors to Radian Angle
vector_to_angle = function (x,y)
	return math.atan2 (y, x)
end

temp_angle = math.pi
temp_vector_x, temp_vector_y = angle_to_vector(temp_angle)
print(temp_vector_x, temp_vector_y) -- -1	1.2246063538224e-016
new_angle = vector_to_angle(temp_vector_x, temp_vector_y)
print(new_angle) -- 3.1415926535898

x = math.cos(math.pi)
y = math.sin(math.pi)
radian = math.atan2(y,x)
print(radian)
print(math.pi)

Get magnitude (length) of 2D Vector

get_vector_magnitude = function (x,y)
	return math.sqrt( x * x + y * y)
end

print(get_vector_magnitude(2,9)) -- 9.21...

Get magnitude (length) of 3D Vector

get_vector_magnitude_3d = function (x,y,z)
	return math.sqrt( x * x + y * y + z * z)
end

Rotating 2D Vectors

Vectors can be rotated without computation by 90 or 180 degrees simply by swapping / negating their x,y values.

x,y = -y,x to rotate 90 degrees counterclockwise
x,y = y,-x to rotate 90 degrees clockwise
x,y = -x, -y to rotate 180 degrees

Rotating a vector based on a radian angle

rotate_vector = function(x, y, angle)
	local c = math.cos(angle)
	local s = math.sin(angle)
	return c*x - s*y, s*x + c*y
end

print(rotate_vector(1,1, math.pi)) -- rotates by 180 degrees to -1, -1

Scaling 2D Vectors

To scale a vector means to increase its magnitude (length) by another magnitude - here called a scalar. A scaled vector has the same orientation but a new magnitude.

scale_vector = function (x,y,scalar)
	return x * scalar, y * scalar
end

If you scale a vector by its inverse length (1 / magnitude of vector) the vector will get a length of 1 - it will become a unit vector - it will become normalized.

Normalizing 2D Vectors

Normalization of vectors maintains their orientation, but reduces their magnitude (length) to 1. This new vector is called a unit vector, and is very useful for certain calculations. 

normalize_vector = function (x,y)
	if x == 0 and y == 0 then return 0, 0 end
	local magnitude = math.sqrt(x * x + y * y)
	return x / magnitude, y / magnitude
end

print(normalize_vector(100,0)) --> 1,0


Checking Circular Collisions - Check for collisions between circle shapes

circular_collision_check = function (ax, ay, bx, by, ar, br)
	-- x and y positions both both objects
	-- along with their radius
	local combined_radius = ar + br
	local dx = bx - ax
	local dy = by - ay
	local dist = math.sqrt(dx * dx + dy * dy) -- check distance between objects
	return dist < combined_radius -- check if the distance is less than the combined radius (overlap)
end

print(circular_collision_check(1,1,30,25,5,10)) -- false
print(circular_collision_check(1,2,36,25,50,100)) -- true

Distance Between 2D Points - Find distance between objects on a 2d space

distance_between_points = function (x1,y1,x2,y2)
	local dX = x2 - x1
	local dY = y2 - y1
	return math.sqrt((dX^2) + (dY^2))
end

print(distance_between_points(0,0,1,1)) -- 1.4142...
print(distance_between_points(0,0,0,8)) -- 8
print(distance_between_points(12,4,45,64)) -- 8

Distance Between 3D Points - Find distance between objects in a 3d space

distance_between_points_3d = function (x1,y1,z1,x2,y2,z2)
	local dX = x2 - x1
	local dY = y2 - y1
	local dZ = z2 - z1
	return math.sqrt((dX^2) + (dY^2) + (dZ^2))
end
print(distance_between_points_3d(0,0,0,1,1,0)) -- 1.4142...

Get the distance between two x positions

get_distance_x = function (x1, x2)
  return math.sqrt( (x2 - x1) ^ 2)
end

print(get_distance_x(-5,10)) -- 15

Get the distance between two y positions

get_distance_y = function (y1, y2)
  return math.sqrt( (y2 - y1) ^ 2)
end

print(get_distance_y(-5,10)) -- 15

Average of radian angles

average_angles = function (...)
	local x,y = 0,0
	for i=1, select("#", ...) do
		local a = select(i, ...)
		x, y = x + math.cos(a), y + math.sin(a)
	end
	return math.atan2(y, x)
end

print(average_angles(1.4, 1.2, 1.6))

Find the angle in degrees between 0,0 and a point

angle_of_point = function (x, y)
	local radian = math.atan2(y,x)
	local angle = radian*180/math.pi
	if angle < 0 then angle = 360 + angle end
	return angle
end

print(angle_of_point(0,-4))

Find the degrees between two points

angle_between_points = function (x1, y1, x2, y2)
	local dX, dY = x2 - x1, y2 - y1
	return angle_of_point(dX, dY)
end

print(angle_between_points(0,0,1,1)) -- 45

Find smallest angle between two angles - for dealing with "angles" below 0 or greater than 360 and finding the shortest turn to reach the second

smallest_angle_difference = function ( a1, a2 )
	local a = a1 - a2
	
	if ( a > 180 ) then
		a = a - 360
	elseif (a < -180) then
		a = a + 360
	end
	
	return a
end

print(smallest_angle_difference(720,270)) -- 90

Round up to the nearest multiple of a number - say you have a number 450 and you want to round it to 500, or round to 1000 if the number was 624 - this sort of thing is useful for dynamic layouts

round_up_nearest_multiple = function (input, target)
	return math.ceil( input / target) * target
end

print(round_up_nearest_multiple(24, 100)) -- 100
print(round_up_nearest_multiple(124, 100)) -- 200

Rounds up or down to the nearest container size multiple

round_nearest_multiple = function (input, target)
	local result = math.floor( (input / target) + 0.5) * target
	if result == 0 then result = target end -- ensure non-zero container size
	return result
end

print(round_nearest_multiple(24, 100)) -- 100
print(round_nearest_multiple(124, 100)) -- 100
print(round_nearest_multiple(155, 100)) -- 200

Clamps a number into a range

clamp_number = function (number, low, high)
	return math.min(math.max(number, low), high)
end

print(clamp_number(45, 0, 100)) -- 45
print(clamp_number(45, 50, 100)) -- 50
print(clamp_number(101, 0, 100)) -- 100

Lerp - linear interpolation - useful to use with delta time (dt) to get smooth movements

lerp_number = function (start, stop, amount)
	amount = clamp_number(amount, 0, 1) -- amount is also called the "factor"
	return((1-amount) * start + amount * stop)
end

print(lerp_number(0,1,0.4)) -- 0.4
print(lerp_number(20,100,0.1)) -- 28


Normalize (percentage) two numbers so that they sum to unity (1)
Note that there are multiple meanings for "normalization"
This kind of normalization is useful for example for turning event counts into probabilities
Or conditional probabilities, such as rolling a dice
Also useful in graphics stats
When normalizing vectors it means change the magnitude to 1 so that it's more useful for orientation

normalize_numbers = function (a,b)
	n = a + b
	if n == 0 then return 0,0,0
	else
		return a/n,b/n,n
	end
end

print(normalize_numbers(5,10)) -- 0.333...	0.666...	3
print(normalize_numbers(1,99)) -- 0.01	0.99	100

Get sign of number : 1 if positive, -1 if negative, 0 if 0

get_sign = function (number)
	return number > 0 and 1 or number < 0 and -1 or 0
end

Round a number

round_number = function(number)
	return math.floor(number + 0.5)
end

-- normalize all values of an array to be within the range of 0 to 1 based on their "weight"
-- divide each number in your sample by the sum of all the numbers in your sample

Matrices

A matrix is an array of related values. Vectors can be represented as matrices.  In most game dev situations, you will be using matrices which have the same number of rows and columns.

A B
C D

The above is a matrix with a 2x2 dimension. A is element 1,1 and D is element 2,2. 

A B C D
E F G H

The above is a matrix with a 2x4 dimension. A is element 1,1 and H is element 4,2.

Vectors can be represented as matrices either as a long row or a tall column. These representations allow you to modify matrices with vectors.

x y z

or

x
y
z

Adding, Subtracting of Matrices

To add two matrices together you simply add the elements together. Same with subtraction.

A B
C D
+
W X
Y Z
=
A+W B+X
C+Y Z+D

Multiplying Matrices

You can multiply a matrix by a single number, a scalar, by multiplying that number by each element individually.

2
x
1 0
2 -4
=
2 0
4 -8

To multiply two matrices together it requires to do the dot product of the rows and columns - multiply matching members and then add them up together. 

Consider two matrices multiplied together

1 2 3
4 5 6
x
7 8
9 10
11 12
=
(1,2,3)*(7,9,11) (1,2,3)*(8,10,12) 
(4,5,6)*(7,9,11) (4,5,6)*(8,10,12)
=
1*7+2*9+3*11 1*8+2*10+3*12
4*7+5*9+6*11 4*8+5*10+6*12
=
58 64
139 154


To be able to multiply two matrices, the number of columns in the first matrix must equal the number of rows in the second matrix. The resulting matrix will have the same number of rows as the second matrix, and the same number of columns as the first matrix. A 1x3 matrix multiplied by a 3x4 matrix produces a 1x4 matrix.

A B
C D
*
W X
Y Z
=
A*W+B*Y A*X+B*Z
C*W+D*Y C*X+D*Z

Matrix multiplication is not commutative, order matters. If you multiply two matrices together in a different order you will get different results.

1 2
3 4
x
5 6
7 8
=
(1,2)*(5,7) (1,2)*(6,8)
(3,4)*(5,7) (3,4)*(6,8)
=
1*5+2*7 1*6+2*8
3*5+4*7 3*6+4*8
=
19 22
43 50

vs

5 6
7 8
x
1 2
3 4
=
(5,6)*(1,3) (5,6)*(2,4)
(7,8)*(1,3) (7,8)*(2,4)
=
5*1+6*3 5*2+6*4
7*1+8*3 7*2+8*4
=
23 34
31 46

You can write your own functions for deal with matrices, but Defold has most of what you need built into its own API.

Matrices are mostly used with graphics programming such as transformation matrices in rendering.

Quaternions

Unit quaternions (magnitude of 1) are useful for representing orientation. Imagine a sphere with a dot at its center. Imagine an airplane's tail end attached to the dot. The airplane can be rotated around the sphere to face any direction, and it can be rotated so that its upward direction is changed. If you can imagine this then you can imagine how a unit quaternion looks like and how it can be useful. While Euler angles are convenient for 2D z rotation, for anything 3D you will want to use quaternions for representing orientation change.




local function find_center_of_points_2d(points)
  local total_x = total_x or 0
  local total_y = total_y or 0
  local count = #points

  for id, point in pairs(points) do
    total_x = total_x + point.x
    total_y = total_y + point.y
  end
  
  if not (total_x == 0) then total_x = total_x / count end
  if not (total_y == 0) then total_y = total_y / count end
  
  return total_x, total_y
end

points_2d = {{x=0,y=0}, {x=10,y=10}, {x=100,y=100}, {x=-10,y=-100}, {x=54,y=-247} }

midpoint_x, midpoint_y = find_center_of_points_2d(points_2d)
print(midpoint_x, midpoint_y)

local function find_center_of_points_3d(points)
  local total_x = total_x or 0
  local total_y = total_y or 0
  local total_z = total_z or 0
  local count = #points

  for id, point in pairs(points) do
    total_x = total_x + point.x
    total_y = total_y + point.y
    total_z = total_z + point.z
  end
  
  if not (total_x == 0) then total_x = total_x / count end
  if not (total_y == 0) then total_y = total_y / count end
  if not (total_z == 0) then total_z = total_z / count end
  
  return total_x, total_y, total_z
end

points_3d = {{x=0,y=0, z=22}, {x=10,y=10, z=15}, {x=100,y=100, z=0}, {x=-10,y=-100, z=0}, {x=54,y=-247, z=0} }

midpoint3d_x, midpoint3d_y, midpoint3d_z = find_center_of_points_3d(points_3d)
print(midpoint3d_x, midpoint3d_y, midpoint3d_z)
Lua 5.1
The name Lua comes from the Portuguese word for moon.
The official manual for Lua 5.1 can be found here: 
http://www.lua.org/manual/5.1/manual.html
Programming in Lua (first edition) can be found here: 
https://www.lua.org/pil/contents.html
Do not use features from Lua versions past Lua 5.1 in Defold scripts.
You can run small Lua code examples here:
http://www.lua.org/cgi-bin/demo
Note that this doc is Lua 5.1 for Defold
		

Lua Coding Pro Tips

Write simple code that's easy to understand.
Keep is simple, stupid.
Comment code where necessary, but your code should be obvious too.
Your future you will thank you for simplicity.
You may be clever, but your future you may forget.
If you don't follow this your future you will be unhappy.

Avoding writing code as compact as possible. 
Break your code into multiple lines.
More packed into a single line doesn't mean it's faster, and can be more difficult to read.
Clarity is very important.
What a single line of code does should be obvious.

Use math instead of conditional statements.
Knowing more math can help you to do less work.
For most cases, math is superior than using conditionals. It's more flexible.
Code with many conditionals is more likely to be buggy.

Avoid duplicating function calls.
If you have a chunk of code which calls the same functions over and over consider a rewrite.
It makes refactoring more difficult, and increases chance for bugs.
Fewer function calls makes your code easier to update and port.

Don't create extra Lua tables when you don't need to.
If you wish to return many values you can do so directly, you don't have to wrap them in a table.
Creating many tables can make the garbage collection hang often.
If your code is creating many Lua tables consider a refactor to eliminate them. Ask for help!

Don't get lost in feature creep. Only code features you need NOW.
Don't write tools that you don't need to. 
Use tools by others first, then refactor them out later if you need to.
Be productive, don't get lost in things that don't actually matter.
This is where many indie game devs fail - they make tools and don't focus on shipping their game!

Keep your code tidy.
Don't keep duplicate functionality all over your code.

Spend your time learning the features of Lua very well.
Tables
Metatables
Coroutines
Modules
Closures
Upvalues - aka "external local variables" 
Tail call recrusion


Study the sample code here: http://lua-users.org/wiki/SampleCode

Read this: http://www.luafaq.org/

Learn the API of some of the popular modules such as LuaSocket


Identifiers
Identifiers can be composed of strings, digits, underscores, but cannot begin with a digit.
Lua is case sensitive. "and" is reserved, but "AND" and "And" are not.
You should not use non-English locale character in identifiers.
Don't use any _CAPS style identifiers. There are for internal use only.

Reserved identifiers (names). You cannot use these as identifiers.

and
break
do
else
elseif
end
false
for
function
if
in
local
nil
not
or
repeat
return
then
true
until
while

Comments
-- comment to end of line

--[[
multiline comment 
--]]

---[[
print("this will print")
--]]

Types
Using "type(...)" on an identifier returns one of the below string values.		  
		  
nil
boolean
number
string
table
function
thread
userdata

ALL Lua values, when used as booleans, evalutate to true except for "nil" and "false".
This does not mean that values which evalulate to true are equal to true.


Strings, escape sequences

'...' and "..." and [[...]] define what's inside a string
The various types are for allowing easy inclusion of others as parts of strings.
Escape sequences are ignored when using double bracket quotes.

Lua uses C-style escape sequences.

\a -- bell - originally used to make sounds - a stands for "alert"
\b -- backspace
\f -- formfeed
\n -- newline
\r -- carriage return
\t -- horizontal tab
\v -- vertical tab
\\ -- backslash
\" -- qutoation mark / double quote
\' -- apostrophe / single quote

You can specify decimal style ASCII character codes with \ddd where each d is a digit.

Look up ASCII table codes for a reference.

Use .. for concactenation of strings : print("This costs $" .. 5 .. " to buy!")

Numbers can be concatenated onto strings, and doing so coerces them to the string type first.

Each time you concatenate you are creating a new string in memory.

Lua has a library of useful string functions.

string.byte(string, n) -- returns the ASCII value of the character of the nth character
string.char(...) -- retruns a string constructed from a comma delimiated list of ASCII values
string.find(string, string2) -- returns the starting and ending character of the first mention of the substring "string2" within "string"
string.format(rule, thing1, thing2, ...) -- returns a single formatted result composing one or more comma seperated things based on the rule
string.gsub(string, pattern, thing, n) -- returns a modified string modified by pattern and thing for a maximum of n times (n is optional): string.gsub("Hello", "l", 7, 1) --> He7lo

string.format follows similar rules as the standard C printf function. 
The rule is composed of regular text and control directives and flags that define where to place the arguments.

Directives
%c - converts number to a single character (like string.char) : string.format("%c", 90) --> Z
%o - convert to octal (base 8) : string.format("%o", 777) --> 1411
%f - convert to floating point
%d - convert to decimal
%x - convert to hexadecimal
%X - convert to hexadecimal in uppercase
%s - convert to string
%e - convert to scientific notation
%E - convert to scientific notation in upper case
%q - formats string so that Lua can read it : print(string.format("%q", '"hello"' )) -> "\"hello\""
%% - outputs a % character

--Flags
- : left justify align result : string.format("(%8s)", "ping") --> (    ping), string.format("(%-8s)", "pong") --> (pong    )
+ : always prefix with - or + sign : string.format("%+d", 2 ) --> +2
n : add spaces until total characters fit n : string.format("(%3s)", "pig") --> (pig), string.format("(%6s)", "pig") --> (   pig)
0n : left fill (pad) with n number zeroes : string.format("%03d", 2) --> 002
# : changes behavior of various formats : octal prefixes with 0 if necessary, hex prefixes with 0x/0X, e/F/f always show decimal, 

--Operators
From most precedence to least
^ (exponentiation)
not (logical)
# (length) - (negation) (these unary operators operate on single operands) : -5; print(#"hello")
* / %
+ -
.. (right associative string concatenation)
< > <= >= ~= == (equality)
and (stops on false or nil)
or (stop on true and not false or nil)

x and y or z -- ternary operator

--Assignment and coercion
a = 1 -- single assignment
b = a -- variables can hold any value
b = 5 + 5 -- a second variable which shadows the first, observe for yourself below

local x, x = 1, 2 -- example of multiple assignment
local i = 0
repeat
   i = i + 1
   local name, value = debug.getlocal(1, i)
   if name == 'x' then
      print(name..' = '..value)
   end
until not name

c = "c"
d = 25.4 -- all numbers are double-precision floating-point numbers, there are no integers, modern CPUs are fast
z, y = y, z -- Lua evaluates all values and then executes assignment which allows swapping of values
w[i], x[j] = x[j], w[i]
aa, bb, cc = 1 -- aa --> 1, bb --> nil, cc --> nil
xx, yy, zz = 0, 0, 0 -- print(xx,yy,zz) --> 0	0	0 

health = 0 or health -- if health is nil then it will be set to 0, else it will be set to itself

ab, bc = 1, 2, 3 -- 3 is discarded

a = nil -- a is destroyed, eligible for garbage collection
a = zzzzzz -- if zzzzzz is not defined then a will = nil
a = "1" + "2" -- a = 3
a = 1 .. 2 -- a = "12"; type(a) --> string

--Control Structures
do ... end -- code between do ... end has local scope
if ... then ... elseif ... then ... else ... end -- conditional exeuction
while ... do ... end -- loop as long as what is between while ... do is true
repeat ... until ... -- if what is after until is true continue to do what is between repeat and until
for variable = start, end, step do ... end -- do what is between do and end until the variable set to start is equal to the end
for variables in interator do ... end
break -- exists loops

local pets = {"Tom", "Lucy", "Dino", "Ruby", "Disco"}
while #pets > 0 do -- while table pets is not empty
	local pet = table.remove(pets, 1) -- pet gets the value of the removed pet name
	if pet == "Ruby" then break end -- example of break
	print(pet)
end

for i = 1,10 do 
	print(i.." fish") 
end -- count up to 10 fish

for i = 10,0,-1 do 
	print(i.." HP") 
end -- count down to 0 HP

do
	local name = "Ana"
	print("Hello, " .. name .. "!")
end
print(name .. " are you still there?") -- name is no longer available

local coins = 7
if coins > 0 then print("You're rich! You have " .. coins .. "C!") end
if coins == 0 then
	print("You're poor! Go out and make some money!")
elseif coins == 1 then
	print("You have a single coin. Cherish it.")
else
	print("You have so many coins!!!")
end

repeat
	coins = coins - 1
	print("I'm stealing your riches! You only have " .. coins .. "C left!")
until coins == 0

local loot = { keys = 2, "sword", "axe", "poition", coins = 99 }
for key, val in ipairs(loot) do -- ipairs only cares for numerical indexed elements
	print(key, val)
end
for key, val in pairs(loot) do -- pairs cares for all elements
	print(key, val)
end

; can be used to have multiple statements on a single line purely to avoid ambiguity
spaces are not always necessary either
a,b=1,2; print(a+b)
a,b=1,2 print(a+b) -- works too
print(1)print(2)print(1+2) -- works, but don't do this

--Table Constructors
table = {} - empty table
t = {"y",2,3} - array
t = {[1]="y",[2]=2,[3]=3} -- explicit assignment
t = {["key"]="value"}; print(t.key) --> value
t = {key="value"}; print(t.key); --> value
t = {x=1; "hi"}; print(t[1],t.x) -- mixed content

--Functions

print "Hello!" -- () must be included to execute *most* functions
print { key = "value" } -- excemptions are single object / string calls

function hello_world(name) -- simple function
	print("Hello, "..name)
end
hello_world("Defold")

local yello_world = function(name) -- anonymous function
	print("Yello, "..name)
end
yello_world("Refold")

local dragon = {}
function dragon.attack()
	print("Dragon Fire!")
end
dragon.attack()

(function (name) print("Hello, "..name) end)("Aefold") -- self-executing anonymous function

function get_dice_rolls(d, n)
	-- this kind of function could have added logic to allow any number of dice and any side number...
	-- for better random numbers, use an Mersenne Twister implementation
	math.randomseed(os.time()) -- comment this line to always get the same "random" result (5,5,4)
	if d == 6 and n == 3 then return math.random(6), math.random(6), math.random(6) end
end
local d1, d2, d3 = get_dice_rolls(6, 3)
print(d1,d2,d3)

function print_list(...) -- varargs, variable number of arguments -- use with caution
	print(...)
end
print_list(1,2,3,4,5, "donut")

local tiger = {name = "Dusty"}
function tiger.get_name(self)
	return self.name -- "self" could be anything
end
print(tiger.get_name(tiger))
print(tiger:get_name()) -- shortcut to pass what's before the colon as the argument

local lion = {name = "Rufus"} -- another way to write the above
function lion:get_name()
	return self.name
end
print(lion:get_name())
print(lion.get_name(lion))

--Object Orientation
-- This is not at all necessary, but you can see it is possible.
local Inventory = { gold = 0 }
function Inventory:new (o)
	o = o or {} -- if o is nil / not provided as an argument then set it to a blank table
	setmetatable(o, self)
	self.__index = self
	return o
end
function Inventory.take(self, v)
	self.gold = self.gold - v
end
function Inventory.give(self, v)
	self.gold = self.gold + v
end
my_stuff = Inventory:new{gold = 0}
my_stuff:give(777)
my_stuff:take(-1)
print(my_stuff.gold) -- I have loads of gold
your_stuff = Inventory:new()
print(your_stuff.gold) -- you have no gold

--Metatables

-- Any table can have a metatable attached to it. 
-- A metatable is a table with special keys set that can define unique behavior for its various operations.

t = {} -- define normal table
mt = {} -- soon to be meta table but empty still
setmetatable(t, mt) -- sets mt to be t's metatable - however if t's metatable has a __metatable field then returns t
getmetatable(t) -- returns mt - returns either __metatable field of t's metatable, t's metatable, or nil

-- The first three lines of the above could be shortened to:
t = setmetatable({}, {}) -- setmetatable returns its first argument

rawget(t,i) -- gets t[i] of a table directly
rawset(t,i,v) -- sets t[i] of a table directly
rawequal(t1,t2) -- returns boolean equality, checks directly

-- Metatables respond to keys which are strings and begin with two underscores __ 
-- The values of these keys are usually set to functions or tables.

__add -- +
__sub -- -
__mod -- %
__unm -- unary - for negation
__concat -- ..
__lt --  <
__index -- get values based on keys
__call -- call tables as functions
__metatable -- value from getmetatable()
__mul -- *
__div -- /
__pow -- ^
__len -- # length
__eq -- checking for equality ==
__le -- <=
__newindex -- set values of keys
__tostring -- convert table to string
__mode -- see: https://www.lua.org/pil/17.html

-- __index is the most used metatable key - Lua looks for __index keys to find values
-- if Lua doesn't find the value of the key in the main table it looks for the __index
-- and then looks for the same key within the table of __index
-- if __index contains a function then it's called with its parent table and the key as the arguments

stuff = { thing = "ball"}
t = setmetatable({}, { __index = stuff })
print(t.thing) -- prints "ball"

t2 = setmetatable({}, { 
	__index = function(t,key)
		if key == "goof" then
			return "goofs and gafs"
		else
			print("Just so you know!")
			return cashtable[key]
		end
	end
})
print(t2.goof) -- prints "goofs and gafs"
t2.goof2 = "dosh" -- prints "dosh" but not "Just so you know!"
print(t2.goof2)
cashtable = { gabber = "cash" }
print(t2.gabber) -- prints "Just so you know!" and the value of gabber key in cashtable

-- __newindex contains either a function or a table
-- Lua looks for a __newindex table when you attempt to set values of keys

toys = {}
t = setmetatable({}, {__newindex = toys})
t.best = "bear"
print(t.best) -- prints nil
print(toys.best) -- prints "bear"

t2 = setmetatable({}, {
	__newindex = function(t,key,value)
		if key == "cat" then
			rawset(t,key,"I love cats!")
		else
			rawset(t,key,value)
		end
	end
})
t2.cat = "Luna"
print(t2.cat) -- prints "I love cats!"
t2.dog = "Spot"
print(t2.dog) -- prints "Spot"

-- rawget and rawset allow you to bypass __index and __newindex functionality commonly used to avoid recursion
-- these are a bypass only, not related to performance

-- you can set custom functionality for operators with metatables such as + - / * and so on
t = setmetatable ({10,20,30}, {
	__add = function(t,val)
		tt = {}
		for _, v in ipairs(t) do
			table.insert(tt, v+val)
			print(v+val)
		end
		return new
	end
})
t = t + 9 -- inserts a copy of each value in the table + 9

-- __call allows you to call tables as functions
-- it is commonly used for forwarding function calls to 
-- for example be able to stay game instead of game.start
t = setmetatable ({}, {
	__call = function(...)
		local args ={...}
		for i = 1, #args do
			print(args[i])
		end
	end
})
t(5, 2, 6, 4, 555) -- prints each value

-- __tostring is used by tostring to convert a table to a string
-- when you print() a table usually get you get something like "table: 0x00321ca0" 
-- you can change this behavior to print its contents
t = setmetatable({777}, {
	__tostring = function (t)
		return t[1]
	end
})
print(t)

--Lua Library

--Enviroment, globals

getfenv([f]) -- returns enviroment of a function f, if f is 1 return current enviroment, if f is 0 return global enviroment, if the set enviroment has a field __fenv that is returned instead
setfenv(f,t) -- see: https://www.lua.org/pil/14.3.html
_G -- a global variable that holds the global enviroment _G._G == _G
-- for n in pairs(_G) do print(n) end -- print out all global top level enviroment
-- for n in pairs(_G.gui) do print(n) end -- print contents of gui related - this can help you explore Defold
_VERSION -- current Lua interpreter version (Lua 5.1)

--Loading, executing

require(module) -- loads a module
dofile(file) -- load, executes, returns returned values
load(ld) -- loads chunk from string or if ld is a function it's called to get the chunk
loadfile(file) --
loadstring(s)
pcall(f)
xpcall(f,h)

--Output, errors

print() -- prints comma seperated list of arguments to console
pprint() -- Defold adds support for pprint() which prints the contents of tables in a pretty way
error() -- terminates program with error message (does Defold modify this behavior?)
assert(v [,message]) -- calls error() if v is nil/false and if not then returns the argument(s), it can be used to execute prepared loaded code ex: assert(loadstring(s))() - you can set message to any kind of error message

--Information, conversion

select(index, ...) -- if index is a number returns arguments after argument at the location of index, else index must be the string "#" and then the number of arguments is returned -- print(select(3,1,2,3,4)) -- prints "3 4"; print(select("#",1,2,3,4,5)) -- prints "5"
type(x) -- returns the type of x as a string
tonumber(x [,b]) -- converts string to a number, b optional to define base (default 10)
unpack(t) -- returns the contents of a table as individual values

--Iterators

ipairs(t) -- ipairs only cares for numerical indexed elements - returns index, value pairs of array t
pairs(t) -- pairs cares for all elements - returns key value pairs of table t
next(t [,index]) -- traverse all fields of a table -- if index is nil it starts at the first value -- returns next index of the following field -- you can use next to check if a table is empty
nextvar

--Garbage Collection

collectgarbage(opt [,arg])

--Modules / packages

module(name, ...)

package.loadlib(lib,func)
package.path, package.cpath
package.loaded
package.preload
package.seeall(module)

--Coroutines

coroutine.create(f)
coroutine.resume(coroutine,arguments)
coroutine.yield(arguments)
coroutine.status(coroutine)
coroutine.running()
coroutine.wrap(f)

--Tables

table.insert(t, [i,] v)
table.remove(t [,i])
table.maxn(t)
table.sort(t [,cf])
table.concat(t [,s [, i [, j]]])

--Maths

--Basic operations

math.abs(x)
math.mod(x,y)
math.floor(x)
math.ceil(x)
math.min(arguments)
math.math(arguments)

--Exponential, logarithmic

math.sqrt(x)
math.pow(x,y)
__pow(x,y) -- what is called when the ^ operator is used
math.exp(x)
math.log(x)
math.log10(x)

--Trigonometry

math.deg(a)
math.rad(a)
math.pi
math.sin(a)
math.cos(a)
math.tan(a)
math.asin(x)
math.acos(x)
math.atan(x)
math.atan2(y,x)

--Splitting on powers of 2
math.frexp(x)
math.ldexp(x,y)

--PRNG (pseudo-random number generator)
math.random([n [,m])
math.randomseed(n)

--Input / Output (I/O)

io.open(fn [,m])
file:close()
file:read(formats)
file:lines()
file:write(values)
file:seek([p][,of])
file:flush()

--Simple I/O

io.input([file])
io.output([file])
io.close([file])
io.read(formats)
io.lines([fn])
io.write(values)
io.flush()

--Standard files and utility functions

io.stdin, io.stdout, io.stderr
io.popen([prog [,mode]])
io.type(x)
io.tmpfile()

--Operating System (OS)

--System interaction

os.execute(cmd)
os.exit([code])
os.getenv(var)
os.setlocale(s[,c])
os.remove(fn)
os.rename(of,nf)
os.tmpname()

--Date/time

os.clock()
os.time([tt])
os.date([fmt[,t]])
os.difftime(t2, t1)

--Time formatting directives

%c
%x
%y
%j
%m
%b
%d
%U
%w
%a
%H
%p
%H
%p
%M
%S
%Z
%X
%y
%B
%W
%A
%I

--Debugging

--Basics

debug.debug()
debug.getinfo(f[,w])
debug.getlocal(n,i)
debug.getupvalue(f,i)
debug.traceback([msg])
debug.setlocal(n,i,v)
debug.setupvalue(f,i,v)
debug.sethook([h,m[,n]])
debug.gethook()

debug.info result fields
source
short_src
linedefined
what
name
namewhat
nups
func

debug.getinfo options
n
f
S

--Command line syntax
lua [options][script[arguments]]

Options
-
-e stats
-l filename
-i executes script then goes into interactive mode
-v prints Lua version number
-- stops parsing options

Lua enviroment varaibles
LUA_INIT
LUA_PATH
LUA_CPATH
_PROMPT[2]

Special Lua variables
arg
_PROMPT[x]

Lua compiler command line syntax
luac[options][filenames]

-
-l
-o filename
-p
-s
-v
--

-- Y combinator
function Y(f)
    local function recurse(...)
        return f(recurse, ...)
    end
    return recurse
end

factorial = Y(function(factorial, n)
    if n == 1 then
    return 1
    else
        return factorial(n - 1) * n 
    end
end)

print(factorial(5)) --> 120


-- Fibonacci series
fibotable = {[1] = 0, [2] = 1}
setmetatable(fibotable, {
    __index = function (t, i)
        t[i] = t[i-1]+t[i-2]
        return t[i]
    end
})
print(fibotable[11])

Defold.com - Book of Defold