• R/O
  • HTTP
  • SSH
  • HTTPS

english: Commit

LÖVE Wiki のテキスト形式によるダンプデータです (英語版)。


Commit MetaInfo

Revisão33c1fcdf1b0d300e7cf476774739687c4ced53bc (tree)
Hora2022-06-21 22:39:34
Autorpancakevirus <megumi_engines@user...>
Commiterpancakevirus

Mensagem de Log

Category:Tutorials のページを追加 (これでチュートリアルはすべてだと思います)

TODO:

- Cameras:camera と Cameras:camera (Polski) の内容が違う。後で調査のこと。
- 画像アセットをどうにかする。

Mudança Sumário

Diff

--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Callback Functions.txt
@@ -0,0 +1,127 @@
1+The [[:Category:Callbacks|callback]] functions in LÖVE are called by [[love.run]] to perform various tasks and are all optional. However, a fully-featured game experience would probably utilize nearly all of them, so it's wise to know what they are.
2+
3+A callback, for those new to programming or otherwise unfamiliar with the term, is a function which works backwards in a sense. In a regular function like [[love.graphics.draw]] or math.floor, you call it and LÖVE or Lua does something. A callback, on the other hand, is a function that you code and LÖVE calls at certain times. This makes it easy to keep your code organized and optimal. For example, since love.load will only get called once when the game is first started (before any other callback), it's a fine place to put code which loads game content and otherwise prepares things.
4+
5+==[[love.load]]==
6+<source lang="lua">
7+function love.load()
8+ image = love.graphics.newImage("cake.jpg")
9+ love.graphics.setNewFont(12)
10+ love.graphics.setColor(0,0,0)
11+ love.graphics.setBackgroundColor(255,255,255)
12+end
13+</source>
14+This function gets called only once, when the game is started, and is usually where you would load resources, initialize variables and set specific settings. All those things can be done anywhere else as well, but doing them here means that they are done once only, saving a lot of system resources.
15+
16+==[[love.update]]==
17+<source lang="lua">
18+function love.update(dt)
19+ if love.keyboard.isDown("up") then
20+ num = num + 100 * dt -- this would increment num by 100 per second
21+ end
22+end
23+</source>
24+This function is called continuously and will probably be where most of your math is done. 'dt' stands for "[[love.timer.getDelta|delta time]]" and is the amount of seconds since the last time this function was called (which is usually a small value like 0.025714).
25+
26+==[[love.draw]]==
27+<source lang="lua">
28+function love.draw()
29+ love.graphics.draw(image, imgx, imgy)
30+ love.graphics.print("Click and drag the cake around or use the arrow keys", 10, 10)
31+end
32+</source>
33+<code>[[love.draw]]</code> is where all the drawing happens (if that wasn't obvious enough already) and if you call any of the <code>[[love.graphics.draw]]</code> outside of this function then it's not going to have any effect. This function is also called continuously so keep in mind that if you change the font/color/mode/etc at the end of the function then it will have an effect on things at the beginning of the function. For example:
34+<source lang="lua">
35+function love.load()
36+ love.graphics.setColor(0,0,0)
37+end
38+
39+function love.draw()
40+ love.graphics.print("This text is not black because of the line below", 100, 100)
41+ love.graphics.setColor(255,0,0)
42+ love.graphics.print("This text is red", 100, 200)
43+end
44+</source>
45+
46+==[[love.mousepressed]]==
47+{{newin|[[0.10.0]]|100|type=variant}}
48+<source lang="lua">
49+function love.mousepressed(x, y, button, istouch)
50+ if button == 1 then
51+ imgx = x -- move image to where mouse clicked
52+ imgy = y
53+ end
54+end
55+</source>
56+This function is called whenever a mouse button is pressed and it receives the button and the coordinates of where it was pressed. The button can be any of the button index that was pressed. This function goes very well along with <code>[[love.mousereleased]]</code>.
57+
58+==[[love.mousereleased]]==
59+{{newin|[[0.10.0]]|100|type=variant}}
60+<source lang="lua">
61+function love.mousereleased(x, y, button, istouch)
62+ if button == 1 then
63+ fireSlingshot(x,y) -- this totally awesome custom function is defined elsewhere
64+ end
65+end
66+</source>
67+This function is called whenever a mouse button is released and it receives the button and the coordinates of where it was released. You can have this function together with <code>[[love.mousepressed]]</code> or separate, they aren't connected in any way.
68+
69+==[[love.keypressed]]==
70+<source lang="lua">
71+function love.keypressed(key)
72+ if key == 'b' then
73+ text = "The B key was pressed."
74+ elseif key == 'a' then
75+ a_down = true
76+ end
77+end
78+</source>
79+This function is called whenever a keyboard key is pressed and receives the key that was pressed. The key can be any of the [[KeyConstant|constants]]. This functions goes very well along with <code>[[love.keyreleased]]</code>.
80+
81+==[[love.keyreleased]]==
82+<source lang="lua">
83+function love.keyreleased(key)
84+ if key == 'b' then
85+ text = "The B key was released."
86+ elseif key == 'a' then
87+ a_down = false
88+ end
89+end
90+</source>
91+This function is called whenever a keyboard key is released and receives the key that was released. You can have this function together with <code>[[love.keypressed]]</code> or separate, they aren't connected in any way.
92+
93+==[[love.focus]]==
94+<source lang="lua">
95+function love.focus(f)
96+ if not f then
97+ print("LOST FOCUS")
98+ else
99+ print("GAINED FOCUS")
100+ end
101+end
102+</source>
103+This function is called whenever the user clicks off and on the LÖVE window. For instance, if they are playing a windowed game and a user clicks on his Internet browser, the game could be notified and automatically pause the game.
104+<source lang="lua">
105+function love.focus(f) gameIsPaused = not f end
106+
107+function love.update(dt)
108+ if gameIsPaused then return end
109+
110+ -- The rest of your love.update code goes here
111+end
112+</source>
113+
114+==[[love.quit]]==
115+<source lang="lua">
116+function love.quit()
117+ print("Thanks for playing! Come back soon!")
118+end
119+</source>
120+This function is called whenever the user clicks the window's close button (often an X). For instance, if the user decides they are done playing, they could click the close button. Then, before it closes, the game can save its state.
121+
122+Those are the callback functions and their basic usage.
123+[[Category:Tutorials]]
124+{{#set:LOVE Version=0.6.0}}
125+{{#set:Description=Callback Functions}}
126+== Other languages ==
127+{{i18n|Tutorial:Callback Functions}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Cameras_camera.txt
@@ -0,0 +1,8 @@
1+Place for source code for camera module.
2+
3+== Other Languages ==
4+{{i18n|Tutorial:Cameras:camera}}
5+{{#set:LOVE Version=0.7}}
6+{{#set:Description=camera module from camera tutorial.}}
7+
8+[[Category:Tutorials:Camera]]
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Drawing Order.txt
@@ -0,0 +1,88 @@
1+As LÖVE doesn't have a built-in z-ordering system, you may encounter some issues when trying to create a game that automatically draws a character in front or behind objects depending on their respective positions such as is customarily found in adventure games. This tutorial will show you how to do this in a very simplistic manner.
2+
3+Note: In this tutorial, when I refer to an object being "in front" of the character I mean that it is between the character and the screen (ie: you). "Behind" means that the character is between the screen and the object.
4+
5+First, we need some resources:
6+<source lang="lua">
7+-- the background for our scene
8+scene = love.graphics.newImage("room.png")
9+-- the character we will be moving around
10+person = love.graphics.newImage("guy.png")
11+-- an object to move around
12+object = love.graphics.newImage("ball.png")
13+</source>
14+
15+Alright, now that we have our resources we need some variables to contain the positions of our person and objects:
16+<source lang="lua">
17+-- the character position
18+character = {400,400} -- x,y
19+
20+-- a bunch of objects, each with a position
21+objects = {}
22+objects[1] = {550,370}
23+objects[2] = {220,390}
24+objects[3] = {600,410}
25+objects[4] = {300,450}
26+objects[5] = {400,530}
27+</source>
28+
29+Make sure that your list of objects are ordered by their y-position. This becomes important when drawing them. For a general application, one can first use the Lua function <code>table.sort</code>.
30+
31+<source lang="lua">
32+function orderY(a,b)
33+ return a[2] < b[2]
34+end
35+table.sort(objects, orderY)
36+</source>
37+
38+Although, You must be careful not to store the index to an object directly. As the objects index will change after the sort (You may wish to make a copy for drawing purposes only)
39+
40+To draw these objects, we are going to use
41+<source lang="lua">
42+love.graphics.draw(object, objects[i][1] - object:getWidth()/2, objects[i][2] - object:getHeight())
43+</source>
44+The <code>object</code> parameter specifies the image we're going to draw and the next two arguments specify where the upper left corner of the image should be drawn on the screen. We subtract by half of the width and the height of the image to place the image's bottom horizontal center at <code>object[i]</code>'s specified x and y coordinate.
45+
46+Ok, now we are ready to draw the whole shebang, assuming that you have created some way of moving your character around the screen (or else this is just pointless as you won't see the difference). If you don't know how to do that, I suggest looking at some of our other tutorials for assistance. For simplicity I am just going to show you the entire <code>[[love.draw]]</code> function and then explain what happens:
47+<source lang="lua">
48+function love.draw()
49+ love.graphics.draw(scene, love.graphics:getWidth() / 2 - scene:getWidth()/2,
50+ love.graphics:getHeight() / 2 - scene:getHeight() / 2) -- draw at the center of the screen
51+
52+ local drawn = false -- true when the character has been drawn
53+
54+ for i,v in ipairs(objects) do
55+ if not drawn and objects[i][2] > character[2] then
56+ love.graphics.draw(person, character[1] - person:getWidth()/2, character[2] - person:getHeight())
57+ drawn = true
58+ end
59+ love.graphics.draw(object, objects[i][1] - object:getWidth()/2, objects[i][2] - object:getHeight())
60+ end
61+
62+ if not drawn then -- if the person is below all objects it won't be drawn within the for loop
63+ love.graphics.draw(person, character[1] - person:getWidth()/2, character[2] - person:getHeight())
64+ end
65+
66+ -- any foreground objects go here
67+
68+end
69+</source>
70+First of all we draw our scene as it normally is in the back (like any potential foreground objects will always be in the front).
71+Then I create a variable called <code>drawn</code>. This will tell us if the character has been drawn to ensure that he isn't re-drawn multiple times which will cause him to be in front of objects where he shouldn't be.
72+Next I go into a for loop and iterate through all of our objects (which are ordered from furthest away to closest). Then I check if the object is supposed to be in front of our character, if it is then you should draw the character (and set the drawn variable). The reason for this is because this for loop will go through and draw the objects (which are all the same image in this case, but that doesn't have to be so) until it comes to an object which should be in front of the chracter which is when it draws the character and then continues to draw the rest of the objects.
73+If it comes to the end of the for loop and hasn't drawn the character yet it means that the character is in front of all the objects so it draws it at the end.
74+
75+That's all. Download the demo and give it a go. It may be very simple but this tutorial is only about drawing order and if you want to know how to check if the character is colliding with the object or you want the character to go where you have clicked then you're on your own (until a tutorial is made for that).
76+If this is not straightforward enough, please feel free to comment on it on our [http://www.love2d.org/forums/ forum].
77+
78+== See Also ==
79+
80+An alternative, scalable implementation : [[Skip list:Drawing Order]]
81+
82+[[Category:Tutorials]]
83+
84+{{#set:LOVE Version=0.6.1}}
85+{{#set:Description=Drawing Order}}
86+
87+== Other languages ==
88+{{i18n|Tutorial:Drawing Order}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Efficient Tile-based Scrolling.txt
@@ -0,0 +1,281 @@
1+This tutorial introduces the [[SpriteBatch]] class for more efficient tile-based scrolling. For a tutorial on basic tile-based scrolling, see [[Tutorial:Tile-based_Scrolling]].
2+
3+[[Image:Tutorial-SpritebatchScreenshot.jpg|thumb|Screenshot of tile-based scrolling with a simple map generator.]]
4+
5+== [[Quad]]s and [[SpriteBatch]] ==
6+The [[love.graphics.draw]] method can draw a portion of an image specified by a [[Quad]]. If quads are drawn from different parts of a single image, we can make the system more efficient by using a SpriteBatch and not changing the quads every frame.
7+
8+When creating a SpriteBatch, we must specify the image that we take the quads ("tiles") from and the maximum number of quads that we will be adding. In this case, the maximum number of tiles visible on the screen.
9+<source lang="lua">
10+tilesetBatch = love.graphics.newSpriteBatch(tilesetImage, tilesDisplayWidth * tilesDisplayHeight)
11+</source>
12+
13+== Map Initialization ==
14+We initialize a map with the following. See the [[Tutorial:Tile-based_Scrolling|Tile-based Scrolling Tutorial]] for an explanation.
15+<source lang="lua">
16+function love.load()
17+ mapWidth = 60
18+ mapHeight = 40
19+
20+ map = {}
21+ for x=1,mapWidth do
22+ map[x] = {}
23+ for y=1,mapHeight do
24+ map[x][y] = love.math.random(0,3)
25+ end
26+ end
27+
28+ mapX = 1
29+ mapY = 1
30+ tilesDisplayWidth = 26
31+ tilesDisplayHeight = 20
32+
33+ zoomX = 1
34+ zoomY = 1
35+end
36+</source>
37+
38+== Adding a SpriteBatch as Tilemap ==
39+[[Image:Resource-ExampleEfficientTileset.png|thumb|Example tileset.]]
40+Next, we load a tileset, create quads for the tiles we want to use, and make a SpriteBatch object to hold the tiles. As an example, we are going to use a free tileset from [http://silveiraneto.net/2009/02/02/my-free-tileset-version-7/ http://silveiraneto.net/...].
41+
42+<source lang="lua">
43+function love.load()
44+ ... --map init
45+
46+ tilesetImage = love.graphics.newImage( "tileset.png" )
47+ tilesetImage:setFilter("nearest", "linear") -- this "linear filter" removes some artifacts if we were to scale the tiles
48+ tileSize = 32
49+
50+ -- grass
51+ tileQuads[0] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
52+ tilesetImage:getWidth(), tilesetImage:getHeight())
53+ -- kitchen floor tile
54+ tileQuads[1] = love.graphics.newQuad(2 * tileSize, 0 * tileSize, tileSize, tileSize,
55+ tilesetImage:getWidth(), tilesetImage:getHeight())
56+ -- parquet flooring
57+ tileQuads[2] = love.graphics.newQuad(4 * tileSize, 0 * tileSize, tileSize, tileSize,
58+ tilesetImage:getWidth(), tilesetImage:getHeight())
59+ -- middle of red carpet
60+ tileQuads[3] = love.graphics.newQuad(3 * tileSize, 9 * tileSize, tileSize, tileSize,
61+ tilesetImage:getWidth(), tilesetImage:getHeight())
62+
63+ tilesetBatch = love.graphics.newSpriteBatch(tilesetImage, tilesDisplayWidth * tilesDisplayHeight)
64+end
65+</source>
66+
67+We only wish to add to the SpriteBatch the tiles that are presently visible. To do this, we make a function that updates the tileset and call it whenever the map focus changes. We also call it once in the initialization.
68+<source lang="lua">
69+function updateTilesetBatch()
70+ tilesetBatch:clear()
71+ for x=0, tilesDisplayWidth-1 do
72+ for y=0, tilesDisplayHeight-1 do
73+ tilesetBatch:add(tileQuads[map[x+mapX][y+mapY]], x*tileSize, y*tileSize)
74+ end
75+ end
76+ tilesetBatch:flush()
77+end
78+</source>
79+
80+Finally, to draw the SpriteBatch, we just send it to <code>[[love.graphics.draw]]</code>.
81+<source lang="lua">
82+function love.draw()
83+ love.graphics.draw(tilesetBatch)
84+end
85+</source>
86+
87+== Discrete Moving ==
88+Moving around the map is done the same way as in [[Tutorial:Tile-based_Scrolling|the Tile-based Scrolling tutorial]]; we check if any keys are pressed and update the map accordingly. We must also remember to update the SpriteBatch.
89+<source lang="lua">
90+-- central function for moving the map
91+function moveMap(dx, dy)
92+ oldMapX = mapX
93+ oldMapY = mapY
94+ mapX = math.max(math.min(mapX + dx, mapWidth - tilesDisplayWidth), 1)
95+ mapY = math.max(math.min(mapY + dy, mapHeight - tilesDisplayHeight), 1)
96+ -- only update if we actually moved
97+ if math.floor(mapX) ~= math.floor(oldMapX) or math.floor(mapY) ~= math.floor(oldMapY) then
98+ updateTilesetBatch()
99+ end
100+end
101+
102+function love.keypressed(key)
103+ if key == "up" then
104+ moveMap(0, -1)
105+ end
106+ if key == "down" then
107+ moveMap(0, 1)
108+ end
109+ if key == "left" then
110+ moveMap(-1, 0)
111+ end
112+ if key == "right" then
113+ moveMap(1, 0)
114+ end
115+end
116+</source>
117+
118+== Continuous Movement ==
119+We make the movement a bit nicer by allowing mapX and mapY to take on non-integer values. When adding quads to the SpriteBatch, we will only consider the integer part while the drawing will shift the SpriteBatch to handle the fractional part. We replace the [[love.keypressed]] callback with a [[love.update]] callback and move the map in small steps.
120+<source lang="lua">
121+function love.update(dt)
122+ if love.keyboard.isDown("up") then
123+ moveMap(0, -0.2 * tileSize * dt)
124+ end
125+ if love.keyboard.isDown("down") then
126+ moveMap(0, 0.2 * tileSize * dt)
127+ end
128+ if love.keyboard.isDown("left") then
129+ moveMap(-0.2 * tileSize * dt, 0)
130+ end
131+ if love.keyboard.isDown("right") then
132+ moveMap(0.2 * tileSize * dt, 0)
133+ end
134+end
135+</source>
136+
137+We add a floor to the SpriteBatch update.
138+<source lang="lua">
139+function updateTilesetBatch()
140+ tilesetBatch:clear()
141+ for x=0, tilesDisplayWidth-1 do
142+ for y=0, tilesDisplayHeight-1 do
143+ tilesetBatch:add(tileQuads[map[x+math.floor(mapX)][y+math.floor(mapY)]],
144+ x*tileSize/2, y*tileSize/2)
145+ end
146+ end
147+ tilesetBatch:flush()
148+end
149+</source>
150+
151+Finally, we shift the SpriteBatch by the fractional part.
152+<source lang="lua">
153+function love.draw()
154+ love.graphics.draw(tilesetBatch,
155+ math.floor(-(mapX%1)*tileSize), math.floor(-(mapY%1)*tileSize))
156+ love.graphics.print("FPS: "..love.timer.getFPS(), 10, 20)
157+end
158+</source>
159+
160+== Putting It All Together ==
161+We have also added zoomX and zoomY variables to this code to allow, e.g., 16x16 tiles to be drawn as 32x32.
162+<source lang="lua">
163+local map -- stores tiledata
164+local mapWidth, mapHeight -- width and height in tiles
165+
166+local mapX, mapY -- view x,y in tiles. can be a fractional value like 3.25.
167+
168+local tilesDisplayWidth, tilesDisplayHeight -- number of tiles to show
169+local zoomX, zoomY
170+
171+local tilesetImage
172+local tileSize -- size of tiles in pixels
173+local tileQuads = {} -- parts of the tileset used for different tiles
174+local tilesetSprite
175+
176+function love.load()
177+ setupMap()
178+ setupMapView()
179+ setupTileset()
180+ love.graphics.setFont(12)
181+end
182+
183+function setupMap()
184+ mapWidth = 60
185+ mapHeight = 40
186+
187+ map = {}
188+ for x=1,mapWidth do
189+ map[x] = {}
190+ for y=1,mapHeight do
191+ map[x][y] = love.math.random(0,3)
192+ end
193+ end
194+end
195+
196+function setupMapView()
197+ mapX = 1
198+ mapY = 1
199+ tilesDisplayWidth = 26
200+ tilesDisplayHeight = 20
201+
202+ zoomX = 1
203+ zoomY = 1
204+end
205+
206+function setupTileset()
207+ tilesetImage = love.graphics.newImage( "tileset.png" )
208+ tilesetImage:setFilter("nearest", "linear") -- this "linear filter" removes some artifacts if we were to scale the tiles
209+ tileSize = 32
210+
211+ -- grass
212+ tileQuads[0] = love.graphics.newQuad(0 * tileSize, 20 * tileSize, tileSize, tileSize,
213+ tilesetImage:getWidth(), tilesetImage:getHeight())
214+ -- kitchen floor tile
215+ tileQuads[1] = love.graphics.newQuad(2 * tileSize, 0 * tileSize, tileSize, tileSize,
216+ tilesetImage:getWidth(), tilesetImage:getHeight())
217+ -- parquet flooring
218+ tileQuads[2] = love.graphics.newQuad(4 * tileSize, 0 * tileSize, tileSize, tileSize,
219+ tilesetImage:getWidth(), tilesetImage:getHeight())
220+ -- middle of red carpet
221+ tileQuads[3] = love.graphics.newQuad(3 * tileSize, 9 * tileSize, tileSize, tileSize,
222+ tilesetImage:getWidth(), tilesetImage:getHeight())
223+
224+ tilesetBatch = love.graphics.newSpriteBatch(tilesetImage, tilesDisplayWidth * tilesDisplayHeight)
225+
226+ updateTilesetBatch()
227+end
228+
229+function updateTilesetBatch()
230+ tilesetBatch:clear()
231+ for x=0, tilesDisplayWidth-1 do
232+ for y=0, tilesDisplayHeight-1 do
233+ tilesetBatch:add(tileQuads[map[x+math.floor(mapX)][y+math.floor(mapY)]],
234+ x*tileSize, y*tileSize)
235+ end
236+ end
237+ tilesetBatch:flush()
238+end
239+
240+-- central function for moving the map
241+function moveMap(dx, dy)
242+ oldMapX = mapX
243+ oldMapY = mapY
244+ mapX = math.max(math.min(mapX + dx, mapWidth - tilesDisplayWidth), 1)
245+ mapY = math.max(math.min(mapY + dy, mapHeight - tilesDisplayHeight), 1)
246+ -- only update if we actually moved
247+ if math.floor(mapX) ~= math.floor(oldMapX) or math.floor(mapY) ~= math.floor(oldMapY) then
248+ updateTilesetBatch()
249+ end
250+end
251+
252+function love.update(dt)
253+ if love.keyboard.isDown("up") then
254+ moveMap(0, -0.2 * tileSize * dt)
255+ end
256+ if love.keyboard.isDown("down") then
257+ moveMap(0, 0.2 * tileSize * dt)
258+ end
259+ if love.keyboard.isDown("left") then
260+ moveMap(-0.2 * tileSize * dt, 0)
261+ end
262+ if love.keyboard.isDown("right") then
263+ moveMap(0.2 * tileSize * dt, 0)
264+ end
265+end
266+
267+function love.draw()
268+ love.graphics.draw(tilesetBatch,
269+ math.floor(-zoomX*(mapX%1)*tileSize), math.floor(-zoomY*(mapY%1)*tileSize),
270+ 0, zoomX, zoomY)
271+ love.graphics.print("FPS: "..love.timer.getFPS(), 10, 20)
272+end
273+</source>
274+
275+[[Category:Tutorials]]
276+
277+{{#set:LOVE Version=0.6.0}}
278+{{#set:Description=Efficient Tile-based Scrolling}}
279+
280+== Other languages ==
281+{{i18n|Tutorial:Efficient Tile-based Scrolling}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Fine Tile-based Scrolling.txt
@@ -0,0 +1,127 @@
1+This is an expansion upon the code in [[Tutorial:Tile-based Scrolling|Tile-based Scrolling]]. It assumes a tile size of 16x16 and a window size of 320x240.
2+
3+<source lang="lua">
4+function love.load()
5+ -- our tiles
6+ tile = {}
7+ for i=0,3 do -- change 3 to the number of tile images minus 1.
8+ tile[i] = love.graphics.newImage( "tile"..i..".png" )
9+ end
10+
11+ -- the map (random junk + copy and paste)
12+ map={
13+ { 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0},
14+ { 3, 1, 0, 0, 2, 2, 2, 0, 3, 0, 3, 0, 1, 1, 1, 0, 0, 3, 0, 0, 0},
15+ { 3, 1, 0, 0, 2, 0, 2, 0, 3, 0, 3, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0},
16+ { 3, 1, 1, 0, 2, 2, 2, 0, 0, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0},
17+ { 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3},
18+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 2},
19+ { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
20+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
21+ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
22+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
23+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
24+ { 0, 2, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0},
25+ { 0, 2, 0, 0, 0, 3, 0, 3, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 1},
26+ { 0, 2, 0, 0, 0, 3, 0, 3, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0},
27+ { 0, 2, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, 0, 0},
28+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
29+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
30+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
31+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
32+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
33+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
34+ { 0, 1, 0, 0, 2, 2, 2, 0, 3, 0, 3, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0},
35+ { 0, 1, 0, 0, 2, 0, 2, 0, 3, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
36+ { 0, 1, 1, 0, 2, 2, 2, 0, 0, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0},
37+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3},
38+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0},
39+ { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
40+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
41+ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
42+ }
43+
44+ -- map variables
45+ map_w = #map[1] -- Obtains the width of the first row of the map
46+ map_h = #map -- Obtains the height of the map
47+ map_x = 0
48+ map_y = 0
49+ map_display_buffer = 2 -- We have to buffer one tile before and behind our viewpoint.
50+ -- Otherwise, the tiles will just pop into view, and we don't want that.
51+ map_display_w = 20
52+ map_display_h = 15
53+ tile_w = 16
54+ tile_h = 16
55+end
56+
57+function draw_map()
58+ offset_x = map_x % tile_w
59+ offset_y = map_y % tile_h
60+ firstTile_x = math.floor(map_x / tile_w)
61+ firstTile_y = math.floor(map_y / tile_h)
62+
63+ for y=1, (map_display_h + map_display_buffer) do
64+ for x=1, (map_display_w + map_display_buffer) do
65+ -- Note that this condition block allows us to go beyond the edge of the map.
66+ if y+firstTile_y >= 1 and y+firstTile_y <= map_h
67+ and x+firstTile_x >= 1 and x+firstTile_x <= map_w
68+ then
69+ love.graphics.draw(
70+ tile[map[y+firstTile_y][x+firstTile_x]],
71+ ((x-1)*tile_w) - offset_x - tile_w/2,
72+ ((y-1)*tile_h) - offset_y - tile_h/2)
73+ end
74+ end
75+ end
76+end
77+
78+function love.update( dt )
79+ local speed = 300 * dt
80+ -- get input
81+ if love.keyboard.isDown( "up" ) then
82+ map_y = map_y - speed
83+ end
84+ if love.keyboard.isDown( "down" ) then
85+ map_y = map_y + speed
86+ end
87+
88+ if love.keyboard.isDown( "left" ) then
89+ map_x = map_x - speed
90+ end
91+ if love.keyboard.isDown( "right" ) then
92+ map_x = map_x + speed
93+ end
94+ if love.keyboard.isDown( "escape" ) then
95+ love.event.quit()
96+ end
97+
98+ -- check boundaries. remove this section if you don't wish to be constrained to the map.
99+ if map_x < 0 then
100+ map_x = 0
101+ end
102+
103+ if map_y < 0 then
104+ map_y = 0
105+ end
106+
107+ if map_x > map_w * tile_w - map_display_w * tile_w - 1 then
108+ map_x = map_w * tile_w - map_display_w * tile_w - 1
109+ end
110+
111+ if map_y > map_h * tile_h - map_display_h * tile_h - 1 then
112+ map_y = map_h * tile_h - map_display_h * tile_h - 1
113+ end
114+end
115+
116+function love.draw()
117+ draw_map()
118+end
119+</source>
120+
121+[[Category:Tutorials]]
122+
123+{{#set:LOVE Version=0.6.0}}
124+{{#set:Description=Fine Tile-based Scrolling}}
125+
126+== Other languages ==
127+{{i18n|Tutorial:Fine Tile-based Scrolling}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Fire Toward Mouse.txt
@@ -0,0 +1,85 @@
1+This [[:Category:Tutorials|tutorial]] describes how to make a bullet fire toward the mouse when the user clicks. It is assumed that you know the basics of LOVE and Lua. All code takes place within main.lua.
2+
3+== Initialization ==
4+<source lang="lua">
5+function love.load()
6+ love.graphics.setBackgroundColor(0.21, 0.67, 0.97)
7+
8+ bulletSpeed = 250
9+
10+ bullets = {}
11+ player = {x=250, y=250, width=15, height=15}
12+end
13+</source>
14+
15+The first line just sets the background color as a nice blue. bulletSpeed is our variable that defines how fast a bullet will travel in pixels per second. The table bullets will hold a list of all our bullets and the table player holds all the info about our player.
16+
17+Each bullet will be its own table inside the bullets table. It will contain the properties x, y, dx, and dy. The dx and dy variables define how much the bullet should move in pixels per second on the x and y axis.
18+
19+== Drawing Everything ==
20+<source lang="lua">
21+function love.draw()
22+ love.graphics.setColor(1, 1, 1)
23+ love.graphics.rectangle("fill", player.x, player.y, player.width, player.height)
24+
25+ love.graphics.setColor(0.5, 0.5, 0.5)
26+ for i,v in ipairs(bullets) do
27+ love.graphics.circle("fill", v.x, v.y, 3)
28+ end
29+end
30+</source>
31+
32+The first thing we do in the draw function is to set the color as white. After that, we draw a rectangle (which will represent the player).
33+
34+The next segment sets the color as gray for the bullet. The for statement will go through each value in our table of bullets. i is the index of the current bullet and v is its value. For each bullet we draw it as a circle on the screen
35+
36+== Determining the Bullet's New Position ==
37+<source lang="lua">
38+function love.update(dt)
39+ for i,v in ipairs(bullets) do
40+ v.x = v.x + (v.dx * dt)
41+ v.y = v.y + (v.dy * dt)
42+ end
43+end
44+</source>
45+
46+Once again we go through the list of bullets. For each one we update its x and y position. We do this by taking the current position and adding the change multiplied by the delta time.
47+
48+== Firing the Bullet ==
49+<source lang="lua">
50+function love.mousepressed(x, y, button)
51+ if button == 1 then
52+ local startX = player.x + player.width / 2
53+ local startY = player.y + player.height / 2
54+ local mouseX = x
55+ local mouseY = y
56+
57+ local angle = math.atan2((mouseY - startY), (mouseX - startX))
58+
59+ local bulletDx = bulletSpeed * math.cos(angle)
60+ local bulletDy = bulletSpeed * math.sin(angle)
61+
62+ table.insert(bullets, {x = startX, y = startY, dx = bulletDx, dy = bulletDy})
63+ end
64+end
65+</source>
66+
67+The if statement at the beginning of this makes it so that we only fire a bullet if the user left clicks. The ''startX'' and ''startY'' variables define the origin of the bullet. We want the bullet to start at the center of the player so we use ''player.x + player.width / 2'' to get that.
68+
69+To get angle we use ''math.atan2'' and pass it the difference in y and the difference in x. This function is very useful for finding the angle between any two objects.
70+
71+We find ''bulletDx'' and ''bulletDy'' by using some more trig. These varibales will define how fast the bullet will move in the x and y plane.
72+
73+The final line here inserts our new bullet into the list of bullets
74+
75+== Conclusion ==
76+When all put together you get the start of a top-down shooter game. Try out making the player movable and making the bullets disappear when they go off screen.
77+
78+--[[User:Somethingmoreunique|Somethingmoreunique]] 03:22, 25 December 2011 (GMT)
79+
80+[[Category:Tutorials]]
81+{{#set:LOVE Version=11.2}}
82+{{#set:Description=Firing bullets toward the mouse}}
83+
84+== Other Languages ==
85+{{i18n|Tutorial:Fire Toward Mouse}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Fonts and Text.txt
@@ -0,0 +1,91 @@
1+Adding and using fonts in LÖVE isn't very complicated, but what you have to keep in mind is that you need to set the font before you can use it. There is no way to render text directly from a font object, it must always be done via the <code>[[love.graphics.print]]</code> function which will render text based on the current font.
2+There are three types of fonts available in love:
3+* The default font (Bitstream Vera Sans)
4+* Any font file supported by FreeType 2
5+* An image containing glyphs (ImageFont)
6+
7+==Creating a font object using the default font==
8+The default font is available for everyone and anyone and can be created using the following code:
9+<source lang="lua">
10+font = love.graphics.newFont(14) -- the number denotes the font size
11+</source>
12+
13+==Creating a font object using a font file==
14+Font files are just normal files that you download from the internet (or create yourself) that contains font information. They can be used just like the default font, just that you specify the filepath along with the font size:
15+<source lang="lua">
16+font = love.graphics.newFont("AwesomeFont.ttf", 15)
17+</source>
18+Keep in mind the that some fonts you download come with restrictions on when/how you can use them.
19+
20+==Creating a font object using an image==
21+An image font is a little tougher to explain, as it all depends on a specifically formatted image. If you look at this [[Image:Resource-Imagefont.png|example image]] you will see that it contains glyphs along one row, each separated by a specific color. This color is used to separate the glyphs and needs to be found at between every character and at the beginning of the list (all the way to the left). Creating a font based on this image would be as follows:
22+<source lang="lua">
23+font = love.graphics.newImageFont("imagefont.png",
24+ " abcdefghijklmnopqrstuvwxyz" ..
25+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0" ..
26+ "123456789.,!?-+/():;%&`'*#=[]\"")
27+</source>
28+
29+'''Warning: Make sure that the image starts and also ends with the separation color or else the last character (in this case " ) won't work.'''
30+
31+==Using the font object==
32+Now that you have created your font object, you need to set it as the current font before it can be used. That is done with the following code:
33+<source lang="lua">
34+-- font = the font object you made before
35+love.graphics.setFont(font)
36+</source>
37+
38+One can also immediately use a TTF-font by calling
39+<source lang="lua">
40+love.graphics.setNewFont(filename, size)
41+</source>
42+Or, in the case of the default font,
43+<source lang="lua">
44+love.graphics.setNewFont(size)
45+</source>
46+
47+==Drawing and formatting text==
48+So now that you have your wonderful new font object, you want to use it for something. To draw text, you simply call the <code>[[love.graphics.print]]</code> function:
49+<source lang="lua">
50+love.graphics.print("This is some awesome text", 100, 100)
51+</source>
52+You can easily draw numbers as well:
53+<source lang="lua">
54+num = 15
55+love.graphics.print(num, 100, 150)
56+</source>
57+
58+The default text rendering function can handle line breaks (the '\n' character) and will draw text aligned to the left:
59+<source lang="lua">
60+love.graphics.print("This is the first line\nThis is the second one.\n(and a third)\n\nfifth", 100, 200)
61+</source>
62+The parameters '100' and '200' are the ''x''- and ''y''-locations of the text, respectively. In LÖVE versions prior to 0.6.0, <code>[[love.graphics.draw]]</code> was instead used to draw text.
63+
64+However, LÖVE can also draw text with word wrapping and alignment by using the more complicated <code>[[love.graphics.printf]]</code> function:
65+<source lang="lua">
66+love.graphics.printf("A really long sentence which will probably be broken into many pieces by my love.", 500, 100, 250, 'right')
67+</source>
68+Where, here, the parameters '500' and '100' are ''x''- and ''y''-locations, '250' is the maximum text width, and 'right' is the text alignment.
69+
70+This way it is relatively easy to draw completely centered text if you pass the width of the window as the word-wrap limit and 0 as the x-position:
71+<source lang="lua">
72+love.graphics.printf("This text will be centered no matter what.\n(and you LOVE it)", 0, 400, 800, 'center')
73+</source>
74+
75+Text will always align to the left by default if you omit the [[AlignMode|alignment value]]:
76+<source lang="lua">
77+love.graphics.printf("Aligned to the left, yes very much so.", 100, 500, 150)
78+</source>
79+
80+That is how to draw text. For more information about the specific functions and their use, please visit the documentation.
81+
82+''Note: All fonts (even the image font) will be affected by the current color, there is no need to set the color mode to 'modulate'.''
83+
84+[[Category:Tutorials]]
85+
86+{{#set:LOVE Version=0.6.0}}
87+{{#set:Description=Fonts and Text}}
88+{{#set:Tutorial=Yes}}
89+
90+== Other languages ==
91+{{i18n|Tutorial:Fonts and Text}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Graphic Transformations.txt
@@ -0,0 +1,62 @@
1+This tutorial covers the basics of using graphic transformations.
2+
3+== [[love.graphics.push]]/[[love.graphics.pop]] ==
4+
5+These two functions allow you to save and return to the previous transformation state.
6+Every push must be paired up with a pop, and each pair can also be called within another push/pop.
7+
8+Here's an example:
9+
10+<source lang="lua">
11+function love.draw()
12+ love.graphics.push() -- Store the previous transformation state
13+ -- Shift the coordinate system down 10, right 10
14+ love.graphics.translate(10,10)
15+ love.graphics.point(0,0)
16+ love.graphics.pop() -- Return to the previous transformation state
17+ love.graphics.point(0,0) -- The origin is back at (0,0)
18+end
19+</source>
20+
21+== Order of Transformations ==
22+
23+Graphic transformations are not commutative. This means the call order affects the
24+final result.
25+
26+Here's an example:
27+
28+<source lang="lua">
29+function love.draw()
30+ love.graphics.push()
31+ love.graphics.translate(10,10)
32+ love.graphics.scale(-1,-1)
33+ love.graphics.point(10,10) -- The point is located at global (0,0)
34+ love.graphics.pop()
35+
36+ love.graphics.scale(-1,-1)
37+ love.graphics.translate(10,10)
38+ love.graphics.point(10,10) -- The point is located at global (-20,-20)
39+end
40+</source>
41+
42+There are two ways to visualize the above code.The first way is to think of each transformation as
43+relative to the new coordinate system from previous transformations. For example,
44+the scaling to the first point would be applied relative to the new origin at (10,10).
45+
46+The second way (which is more intuitive in my humble opinion) is to visualize each transformation in
47+REVERSE ORDER relative to the global coordinate system. Let's take the first point as an example.
48+Scaling is applied first and places the new point at (-10,-10). Lastly, the translation moves the new
49+point to (0,0).
50+
51+== See Also ==
52+* [[love.graphics.scale]]
53+* [[love.graphics.shear]]
54+* [[love.graphics.rotate]]
55+* [[love.graphics.translate]]
56+
57+[[Category:Tutorials]]
58+{{#set:LOVE Version=0.8.0}}
59+{{#set:Description=Covers the basic of using graphic transformations}}
60+
61+== Other Languages ==
62+{{i18n|Tutorial:Graphic Transformations}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Gridlocked Player.txt
@@ -0,0 +1,321 @@
1+In this tutorial, we will create a VERY basic game wherein you can move a "player" around the screen in fixed increments, but the player graphic moves in smaller increments. This could be useful if you are creating a game that is tile-based, and want your player to stay aligned to the grid, but don't want them to appear to teleport around.
2+
3+== Starting Code ==
4+
5+To start with, we need to create a player. The player will have several aspects before we're done, so we're going to make the player variable a table inside of [[love.load]]().
6+<source lang="lua">
7+function love.load()
8+ player = {}
9+end
10+</source>
11+
12+Next we'll need to see what we're doing. We can render the player as a rectangle using [[love.graphics.rectangle]]() in [[love.draw]]().
13+<source lang="lua">
14+function love.draw()
15+ love.graphics.rectangle("fill", 0, 0, 32, 32)
16+end
17+</source>
18+
19+Let's fill in the player table a little so that the player has a position. Note that we're using the shorthand way of putting variables into a table: just define them inside the curly brackets, using commas to separate them. (We also need to change the parameters in love.graphics.rectangle to use these new values.)
20+<source lang="lua">
21+function love.load()
22+ player = {
23+ x = 256,
24+ y = 256
25+ }
26+end
27+
28+function love.draw()
29+ love.graphics.rectangle("fill", player.x, player.y, 32, 32)
30+end
31+</source>
32+
33+[[File:Grid_player_1.gif]]
34+
35+Now that the player has position, let's add in some controls using [[love.keypressed]](). All we do is check to see if the key matches, and change the value in the player table.
36+<source lang="lua">
37+function love.keypressed(key)
38+ if key == "down" then
39+ player.y = player.y + 32
40+ end
41+end
42+</source>
43+
44+So we now have a little square that can teleport down by one grid unit (32 pixels in our case, the same length that we made our player).
45+
46+== Expansion ==
47+
48+We can expand this to more keys using elseif. Notice that everything is still in units of 32, a common tile size that plays nice with [[PO2_Syndrome]].
49+<source lang="lua">
50+function love.keypressed(key)
51+ if key == "up" then
52+ player.y = player.y - 32
53+ elseif key == "down" then
54+ player.y = player.y + 32
55+ elseif key == "left" then
56+ player.x = player.x - 32
57+ elseif key == "right" then
58+ player.x = player.x + 32
59+ end
60+end
61+</source>
62+
63+So we now have a happy little square that can jump around the screen as fast as you can hit the keyboard. Now let's add in the smooth transitions. To do this, we're going to need to shift up the variables in the player table. Don't forget that this will affect all references to the player table.
64+
65+There are two things that we will now need. One, we need actual XY coordinates as opposed to the gridlocked coordinates that will now serve as destination coordinates. Two, we need to update the actual coordinates in love.update() to move towards the destination coordinates. We can do that with a simple math problem:
66+<source lang="lua">
67+actual_x = actual_x - (actual_x - destination_x)
68+</source>
69+Or, in real Lua this time:
70+<source lang="lua">
71+function love.load()
72+ player = {
73+ grid_x = 256,
74+ grid_y = 256,
75+ act_x = 200,
76+ act_y = 200
77+ }
78+end
79+
80+function love.update(dt)
81+ player.act_y = player.act_y - (player.act_y - player.grid_y)
82+ player.act_x = player.act_x - (player.act_x - player.grid_x)
83+end
84+
85+function love.draw()
86+ love.graphics.rectangle("fill", player.act_x, player.act_y, 32, 32)
87+end
88+
89+function love.keypressed(key)
90+ if key == "up" then
91+ player.grid_y = player.grid_y - 32
92+ elseif key == "down" then
93+ player.grid_y = player.grid_y + 32
94+ elseif key == "left" then
95+ player.grid_x = player.grid_x - 32
96+ elseif key == "right" then
97+ player.grid_x = player.grid_x + 32
98+ end
99+end
100+</source>
101+
102+As you probably noticed, you probably can't see any difference. We need to use [[love.update]]'s [[dt]] parameter to control speed, by multiplying the difference of the positions by dt:
103+<source lang="lua">
104+function love.update(dt)
105+ player.act_y = player.act_y - ((player.act_y - player.grid_y) * dt)
106+ player.act_x = player.act_x - ((player.act_x - player.grid_x) * dt)
107+end
108+</source>
109+
110+Still not quite right though. Now the player is unbearably slow (but at least he's consistent from computer to computer!). Let's give the player a speed attribute to control how fast he moves, by multiplying dt by the speed:
111+<source lang="lua">
112+function love.load()
113+ player = {
114+ grid_x = 256,
115+ grid_y = 256,
116+ act_x = 200,
117+ act_y = 200,
118+ speed = 10
119+ }
120+end
121+
122+function love.update(dt)
123+ player.act_y = player.act_y - ((player.act_y - player.grid_y) * player.speed * dt)
124+ player.act_x = player.act_x - ((player.act_x - player.grid_x) * player.speed * dt)
125+end
126+</source>
127+
128+== Putting it all together ==
129+
130+Here is the full code:
131+<source lang="lua">
132+function love.load()
133+ player = {
134+ grid_x = 256,
135+ grid_y = 256,
136+ act_x = 200,
137+ act_y = 200,
138+ speed = 10
139+ }
140+end
141+
142+function love.update(dt)
143+ player.act_y = player.act_y - ((player.act_y - player.grid_y) * player.speed * dt)
144+ player.act_x = player.act_x - ((player.act_x - player.grid_x) * player.speed * dt)
145+end
146+
147+function love.draw()
148+ love.graphics.rectangle("fill", player.act_x, player.act_y, 32, 32)
149+end
150+
151+function love.keypressed(key)
152+ if key == "up" then
153+ player.grid_y = player.grid_y - 32
154+ elseif key == "down" then
155+ player.grid_y = player.grid_y + 32
156+ elseif key == "left" then
157+ player.grid_x = player.grid_x - 32
158+ elseif key == "right" then
159+ player.grid_x = player.grid_x + 32
160+ end
161+end
162+</source>
163+
164+== Adding collision ==
165+
166+Now let's add some world detail. To start with, we need to create a table of values that will dictate whether we can walk onto a grid or not.
167+
168+<source lang="lua">
169+function love.load()
170+map = {
171+ { 1, 1, 1, 1 },
172+ { 1, 0, 0, 1 },
173+ { 1, 0, 1, 1 },
174+ { 1, 1, 1, 1 }
175+}
176+end
177+</source>
178+
179+This map table holds four subtables, each of which holds four values. Each subtable is a horizontal row in the map, with each value representing a single tile in that row. We used 1s and 0s because they're easy to type.
180+
181+Now let's draw these values to the screen. Since we only have two types, we can get away with just drawing one of the types... let's say the 1s. We loop through the subtables by using a simple for loop, and then loop through the values inside each subtable.
182+<source lang="lua">
183+function love.draw()
184+ for y=1, #map do
185+ for x=1, #map[y] do
186+ if map[y][x] == 1 then
187+ love.graphics.rectangle("line", x * 32, y * 32, 32, 32)
188+ end
189+ end
190+ end
191+end
192+</source>
193+
194+A couple things to note about this double loop. The map table is arranged the way that we will see it. This means that are coordinates are flipped from how we usually think... instead of being x and then y, the map is y and then x. Also, the map is in units of 32 (one player width). That means that when we draw the unwalkable squares, we have to multiply their positions by 32.
195+
196+[[File:Grid_player_2.gif]]
197+
198+Now let's make a function to test if the player can walk over a spot on our map. This function will return true if we can walk over the spot, and false if we cannot. The function will be given two values: our change in x and our change in y.
199+
200+<source lang="lua">
201+function testMap(x, y)
202+ if map[(player.grid_y / 32) + y][(player.grid_x / 32) + x] == 1 then
203+ return false
204+ end
205+ return true
206+end
207+</source>
208+
209+Things to note about this function. Since we're working in map units, the values passed in will usually just be 1, -1, or 0. That's why they are not divided by 32, unlike the player grid coordinates.
210+
211+Speaking of the player grid coordinates, the reason we did not have to pass those in is because the player is a global variable.
212+
213+So now we can put this function into use by sticking it in the keypressed function. Remember, the test function works in map units, rather than pixel units, so if we're trying to move up one grid, we pass (0, -1).
214+
215+<source lang="lua">
216+function love.keypressed(key)
217+ if key == "up" then
218+ if testMap(0, -1) then
219+ player.grid_y = player.grid_y - 32
220+ end
221+ elseif key == "down" then
222+ if testMap(0, 1) then
223+ player.grid_y = player.grid_y + 32
224+ end
225+ elseif key == "left" then
226+ if testMap(-1, 0) then
227+ player.grid_x = player.grid_x - 32
228+ end
229+ elseif key == "right" then
230+ if testMap(1, 0) then
231+ player.grid_x = player.grid_x + 32
232+ end
233+ end
234+end
235+</source>
236+
237+You may have noticed that if you try to run this now, the program crashes. This is because our player starts outside of our map. If we expand the map we can fix the bug. Here is the full code with the expanded map.
238+
239+<source lang="lua">
240+function love.load()
241+ player = {
242+ grid_x = 256,
243+ grid_y = 256,
244+ act_x = 200,
245+ act_y = 200,
246+ speed = 10
247+ }
248+ map = {
249+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
250+ { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
251+ { 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
252+ { 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1 },
253+ { 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1 },
254+ { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
255+ { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
256+ { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
257+ { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
258+ { 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1 },
259+ { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
260+ { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
261+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
262+ }
263+end
264+
265+function love.update(dt)
266+ player.act_y = player.act_y - ((player.act_y - player.grid_y) * player.speed * dt)
267+ player.act_x = player.act_x - ((player.act_x - player.grid_x) * player.speed * dt)
268+end
269+
270+function love.draw()
271+ love.graphics.rectangle("fill", player.act_x, player.act_y, 32, 32)
272+ for y=1, #map do
273+ for x=1, #map[y] do
274+ if map[y][x] == 1 then
275+ love.graphics.rectangle("line", x * 32, y * 32, 32, 32)
276+ end
277+ end
278+ end
279+end
280+
281+function love.keypressed(key)
282+ if key == "up" then
283+ if testMap(0, -1) then
284+ player.grid_y = player.grid_y - 32
285+ end
286+ elseif key == "down" then
287+ if testMap(0, 1) then
288+ player.grid_y = player.grid_y + 32
289+ end
290+ elseif key == "left" then
291+ if testMap(-1, 0) then
292+ player.grid_x = player.grid_x - 32
293+ end
294+ elseif key == "right" then
295+ if testMap(1, 0) then
296+ player.grid_x = player.grid_x + 32
297+ end
298+ end
299+end
300+
301+function testMap(x, y)
302+ if map[(player.grid_y / 32) + y][(player.grid_x / 32) + x] == 1 then
303+ return false
304+ end
305+ return true
306+end
307+</source>
308+
309+[[File:Grid_player_3.gif]]
310+
311+There are several ways this could be improved.
312+* The art could be touched up, of course, using the techniques covered in this article: [http://tommybrunn.com/2011/01/how-to-make-placeholder-art/]
313+* We could also implement some extra controls, such as binding the Escape key to [[love.event.push]]('quit'), which would quit the game.
314+* The player is inside of a closed map, but if the map was open and the player tried to leave it, the game would crash. We could easily add some checks to prevent this from happening.
315+* The map starts off at 32,32 when it would make more sense for it to start at 0,0. A little bit of arithmetic could fix this pretty easily, but it does make the code a bit more complex and hard to follow.
316+But for the purposes of this tutorial we have enough already.
317+
318+[[Category:Tutorials]]
319+
320+{{#set:LOVE Version=0.8.0}}
321+{{#set:Description=A tutorial for learning how to create a gridlocked player.}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Hamster Ball.txt
@@ -0,0 +1,112 @@
1+[[Image:Tutorial-HamsterBall.jpg|thumb|Screenshot of the hamster ball.]][[Image:Resource-HamsterBall.png|thumb|Hamster Ball Image (Note: The tutorial assumes you name this hamster.png)]]
2+This game is a very simple example of how to add a resource (in this case a simple image) to the engine and then move that around with the arrow keys. Here is the entire source, in case you haven't downloaded it:
3+<source lang="lua">
4+-- Tutorial 1: Hamster Ball
5+-- Add an image to the game and move it around using
6+-- the arrow keys.
7+-- compatible with löve 0.6.0 and up
8+
9+function love.load()
10+ hamster = love.graphics.newImage("hamster.png")
11+ x = 50
12+ y = 50
13+ speed = 300
14+end
15+
16+function love.update(dt)
17+ if love.keyboard.isDown("right") then
18+ x = x + (speed * dt)
19+ end
20+ if love.keyboard.isDown("left") then
21+ x = x - (speed * dt)
22+ end
23+
24+ if love.keyboard.isDown("down") then
25+ y = y + (speed * dt)
26+ end
27+ if love.keyboard.isDown("up") then
28+ y = y - (speed * dt)
29+ end
30+end
31+
32+function love.draw()
33+ love.graphics.draw(hamster, x, y)
34+end
35+</source>
36+
37+It's not the most complicated program in the world, but we have to start somewhere. Keep in mind that everything after the <tt>--</tt> characters in the code is a comment and will be ignored by the program.
38+
39+<source lang="lua">
40+-- You can write whatever you want here!
41+</source>
42+
43+Alright, next you need to know that for things to work you need to have a function called load. This is where the game is initiated and where everything begins. Although they aren't strictly required, it's best to also include <tt>[[love.update|love.update()]]</tt> and <tt>[[love.draw|love.draw()]]</tt> for now. The meaning of the various functions will be described shortly.
44+
45+<source lang="lua">
46+-- This is an empty program
47+function love.load()
48+end
49+
50+function love.update(dt)
51+end
52+
53+function love.draw()
54+end
55+</source>
56+
57+Alright, let's get down to explaining what the specific code for this game does.
58+
59+The load function looks like this:
60+
61+<source lang="lua">
62+function love.load()
63+ hamster = love.graphics.newImage("hamster.png")
64+ x = 50
65+ y = 50
66+ speed = 300
67+end
68+</source>
69+
70+What we are doing here is adding the file <tt>hamster.png</tt> to our game assigning that image to a variable called <tt>hamster</tt>. We are also declaring three variables: <tt>x</tt>, <tt>y</tt> and <tt>speed</tt>. These will all play a part in the program later.
71+
72+The update function looks like this:
73+<source lang="lua">
74+function love.update(dt)
75+ if love.keyboard.isDown("right") then
76+ x = x + (speed * dt)
77+ end
78+ if love.keyboard.isDown("left") then
79+ x = x - (speed * dt)
80+ end
81+
82+ if love.keyboard.isDown("down") then
83+ y = y + (speed * dt)
84+ end
85+ if love.keyboard.isDown("up") then
86+ y = y - (speed * dt)
87+ end
88+end
89+</source>
90+
91+First of all you will see that this function accepts a parameter called <tt>[[dt]]</tt> (an abbreviation of "delta-time") which represents the amount of time which has passed since this function was last called. It is in seconds, but because of the speed of todays processors is usually smaller than 1 (values like 0.01 are common). We are using this value to move the hamster ball at the same speed, no matter how fast the player's computer is.
92+
93+In the function we check whether the keys right, left, up or down are pressed by calling the <tt>[[love.keyboard.isDown|love.keyboard.isDown(key)]]</tt> function with the appropriate parameters (a full list of the keyboard keys can be found [[KeyConstant|here]]). If any of the right keys are pressed then the <tt>x</tt> or <tt>y</tt> values will be incremented by the appropriate amount (in this case <tt>speed</tt> times <tt>dt</tt> which means that the ball will move at a speed of 300 pixels per second; try changing the <tt>speed</tt> value in the load function to see what happens).
94+
95+The draw function looks like this:
96+<source lang="lua">
97+function love.draw()
98+ love.graphics.draw(hamster, x, y)
99+end
100+</source>
101+
102+Not a lot happening, but this is where the magic is done. The image contained in the <tt>hamster</tt> variable is drawn at the <tt>x</tt> and <tt>y</tt> coordinate.
103+
104+That is basically it for your first game. Try messing around with the variables in the <tt>love.load</tt> function to see what effects they have.
105+
106+Remember that .love files can be opened in standard archiving software, like WinZip or 7zip. They are actually just renamed .zip-files!
107+
108+{{#set:LOVE Version=0.6.0}}
109+{{#set:Description=Image loading, key movement}}
110+[[Category:Tutorials]]
111+== Other languages ==
112+{{i18n|Tutorial:Hamster Ball}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Introduction to Shaders.txt
@@ -0,0 +1,55 @@
1+This is a simple and basic [[:Category:Tutorials|tutorial]] explaining the basics of [[Shader|shaders]]. Here is a small example:
2+
3+<source lang="lua">
4+function love.load()
5+ shader = love.graphics.newShader("shader.fs")
6+end
7+
8+function love.draw()
9+ love.graphics.setShader(shader)
10+ love.graphics.rectangle("fill", 0, 0, 100, 100)
11+ love.graphics.setShader()
12+end
13+</source>
14+
15+The most important thing to remember when writing your shader is that the entry point is not the same as in pure GL. It's modified in LOVE.
16+
17+<source lang="glsl">
18+vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
19+</source>
20+
21+So instead of setting gl_FragCoord, you'd return the vec4 for the pixel color. Your texture coordinates are supplied for you, as well as the current texture, the system-wide current color setting, and the screen coordinate position of the current pixel. In pure GL, you'd supply your own uniform values for that stuff.
22+
23+You can also send data to the shader in the form of uniform variables, like I mentioned above:
24+
25+<source lang="lua">
26+shader:send(name, value[s])
27+</source>
28+
29+The value can be a number or a table of numbers for a vec2/3/4. Or more numbers for a matrix. [[Shader:send|Full list here]].
30+
31+If you're looking for a big repository of shaders already written for LOVE, you're out of luck as far as I know. There is, however, a [http://love2d.org/forums/viewtopic.php?f=4&t=3733 "share a shader"] thread. That's the closest you can get right now.
32+
33+If you don't know how shaders work, you can think of them as a small program that the graphics processor runs for '''each pixel'''. When you draw a rectangle, OpenGL transforms those coordinates into pixels on the screen (rasterization) and then runs those pixels through your shader. It's a very fast and efficient way to make modifications to images on the fly, and modern photorealistic or otherwise graphics would be nearly impossible (extremely impractical) without them.
34+
35+The effect function in your shader returns a vec4 that represents the color you want to choose for the current pixel. There are a many functions built-in for math and for reading from textures. Here's a sample effect that'd simply draw a black and white texture.
36+<source lang="glsl">
37+vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
38+{
39+ vec4 c = Texel(texture, texture_coords); // This reads a color from our texture at the coordinates LOVE gave us (0-1, 0-1)
40+ return vec4(vec3(1.0, 1.0, 1.0) * (max(c.r, max(c.g, c.b))), 1.0); // This just returns a white color that's modulated by the brightest color channel at the given pixel in the texture. Nothing too complex, and not exactly the prettiest way to do B&W :P
41+}
42+</source>
43+
44+-- Source: [http://www.love2d.org/forums/viewtopic.php?f=3&t=32442]
45+
46+== See Also ==
47+* [[Shader]]
48+
49+[[Category:Tutorials]]
50+
51+{{#set:LOVE Version=0.9.0}}
52+{{#set:Description=Simple Introduction to Shaders}}
53+
54+== Other Languages ==
55+{{i18n|Tutorial:Introduction_to_Shaders}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Isometric Graphics.txt
@@ -0,0 +1,88 @@
1+[[Isometric graphic]]s are quite popular in [[RPG]]s and [[strategy]] [[game]]s, so learning how to draw a grid of isometric cubes could be useful. For the sake of this [[tutorial]] I will assume that you are using cubes of equal size as we are working on making a grid of the cubes.
2+
3+First, you need some source images. If you take a look at the source we have two wonderful cubes that are supposed to represent grass and dirt (using vaguely green and brown colors respectfully). For the sake of reference I have included a border around the cubes which will show up as an actual grid as it makes it easier to discern where one cube ends and the other begins. You should also make note at the fact that the bottom and right borders is missing, this is because the cubes are supposed to form a grid nicely and we don't want to get a double-border anywhere. In your own cubes you can probably draw whatever you want to connect the cubes as you don't HAVE to have a border around it, but I will do it for this example.
4+
5+''Note: This code is made for cubes, but works also if you want to create a grid with only the top face. This will result in the two values block_height and block_depth (as seen below) being the same.''
6+
7+First of all, once we have added the images to our game, we need some values. The width and the height of each cube (easily taken from the width and height of our source images) and a third value: the block_depth. This just means the height of the top face (easier to call it "depth" than to have to write "block_face_height" or something each time) and, in this case, is half the height of the cube itself:
8+<source lang="lua">
9+block_width = grass:getWidth()
10+block_height = grass:getHeight()
11+block_depth = block_height / 2
12+</source>
13+These values will be used in doing the lovely math below.
14+
15+
16+Next, we need the grid itself. A simple 2-dimensional array will do, which we will fill with the value 1 (which represents a grass cube). I also specify a grid size so I can change things easily (if I want to):
17+<source lang="lua">
18+grid_size = 20
19+grid = {}
20+for x = 1,grid_size do
21+ grid[x] = {}
22+ for y = 1,grid_size do
23+ grid[x][y] = 1
24+ end
25+end
26+</source>
27+For good measure (and to show where the various points would be) let's change two of the grid positions into the value 2 (which represents a dirt cube):
28+<source lang="lua">
29+grid[2][4] = 2
30+grid[6][5] = 2
31+</source>
32+
33+
34+The actual [[love.draw|drawing]] of the grid is like this (grid_x and grid_y are variables I declared earlier to keep a track of where the center of the grid should be; these would be used when moving the grid):
35+<source lang="lua">
36+for x = 1,grid_size do
37+ for y = 1,grid_size do
38+ if grid[x][y] == 1 then
39+ love.graphics.draw(grass,
40+ grid_x + ((y-x) * (block_width / 2)),
41+ grid_y + ((x+y) * (block_depth / 2)) - (block_depth * (grid_size / 2)))
42+ else -- grid[x][y] == 2
43+ love.graphics.draw(dirt,
44+ grid_x + ((y-x) * (block_width / 2)),
45+ grid_y + ((x+y) * (block_depth / 2)) - (block_depth * (grid_size / 2)))
46+ end
47+ end
48+end
49+</source>
50+But I will focus on just the grass part, to make things easier:
51+<source lang="lua">
52+love.graphics.draw(grass,
53+ grid_x + ((y-x) * (block_width / 2)),
54+ grid_y + ((x+y) * (block_depth / 2)) - (block_depth * (grid_size / 2)))
55+</source>
56+This draws the grass cubes starting from the top and moving down along the top-right side, then moves one step to the bottom-left and does it again. This ensures that the cubes are all drawn in the right order so that the ones that are in the "back" will not overlap the ones in the front.
57+This part of the code ensures that the grid_x and grid_y variables point to the center of the grid:
58+<source lang="lua">
59+- (block_depth * (grid_size / 2))
60+</source>
61+
62+
63+Note:If you don't like that the x-coordinate goes from the top to the right and the y-coordinate goes from the top to the left, you can easily switch them by switching their places in the line:
64+<source lang="lua">grid_x + ((y-x) * (block_width / 2)),</source>
65+Which would result in this line:
66+<source lang="lua">grid_x + ((x-y) * (block_width / 2)),</source>
67+
68+
69+Now what about adding a 3rd dimension?
70+This is easy by adding the following code to the end of the y-coordinate you pass to ''love.graphics.draw'':
71+<source lang="lua">- block_depth</source>
72+(multiplied by every subsequent level you go up)
73+So if we wanted to add another level to our grid you would simply put this into the nested for-loops:
74+<source lang="lua">love.graphics.draw(grass,
75+ grid_x + ((y-x) * (block_width / 2)),
76+ grid_y + ((x+y) * (block_depth / 2)) - (block_depth * (grid_size / 2)) - block_depth)
77+</source>
78+
79+
80+I hope this has taught you how to draw a simple isometric grid which you can use for fun and profit (if you ever make a profit remember me ^^).
81+
82+[[Category:Tutorials]]
83+
84+{{#set:LOVE Version=0.5.0}}
85+{{#set:Description=Isometric Graphics}}
86+
87+== Other languages ==
88+{{i18n|Tutorial:Isometric_Graphics}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Networking with UDP-TheClient.txt
@@ -0,0 +1,172 @@
1+The complete source for the UDP client
2+<source lang=lua>
3+
4+-- to start with, we need to require the 'socket' lib (which is compiled
5+-- into love). socket provides low-level networking features.
6+local socket = require "socket"
7+
8+-- the address and port of the server
9+local address, port = "localhost", 12345
10+
11+local entity -- entity is what we'll be controlling
12+local updaterate = 0.1 -- how long to wait, in seconds, before requesting an update
13+
14+local world = {} -- the empty world-state
15+local t
16+
17+-- love.load, hopefully you are familiar with it from the callbacks tutorial
18+function love.load()
19+
20+ -- first up, we need a udp socket, from which we'll do all
21+ -- out networking.
22+ udp = socket.udp()
23+
24+ -- normally socket reads block until they have data, or a
25+ -- certain amout of time passes.
26+ -- that doesn't suit us, so we tell it not to do that by setting the
27+ -- 'timeout' to zero
28+ udp:settimeout(0)
29+
30+ -- unlike the server, we'll just be talking to the one machine,
31+ -- so we'll "connect" this socket to the server's address and port
32+ -- using setpeername.
33+ --
34+ -- [NOTE: UDP is actually connectionless, this is purely a convenience
35+ -- provided by the socket library, it doesn't actually change the
36+ --'bits on the wire', and in-fact we can change / remove this at any time.]
37+ udp:setpeername(address, port)
38+
39+ -- seed the random number generator, so we don't just get the
40+ -- same numbers each time.
41+ math.randomseed(os.time())
42+
43+ -- entity will be what we'll be controlling, for the sake of this
44+ -- tutorial its just a number, but it'll do.
45+ -- we'll just use random to give us a reasonably unique identity for little effort.
46+ --
47+ -- [NOTE: random isn't actually a very good way of doing this, but the
48+ -- "correct" ways are beyond the scope of this article. the *simplest*
49+ -- is just an auto-count, they get a *lot* more fancy from there on in]
50+
51+ entity = tostring(math.random(99999))
52+
53+ -- Here we do our first bit of actual networking:
54+ -- we set up a string containing the data we want to send (using 'string.format')
55+ -- and then send it using 'udp.send'. since we used 'setpeername' earlier
56+ -- we don't even have to specify where to send it.
57+ --
58+ -- thats...it, really. the rest of this is just putting this context and practical use.
59+ local dg = string.format("%s %s %d %d", entity, 'at', 320, 240)
60+ udp:send(dg) -- the magic line in question.
61+
62+ -- t is just a variable we use to help us with the update rate in love.update.
63+ t = 0 -- (re)set t to 0
64+end
65+
66+-- love.update, hopefully you are familiar with it from the callbacks tutorial
67+function love.update(deltatime)
68+
69+ t = t + deltatime -- increase t by the deltatime
70+
71+ -- its *very easy* to completely saturate a network connection if you
72+ -- aren't careful with the packets we send (or request!), we hedge
73+ -- our chances by limiting how often we send (and request) updates.
74+ --
75+ -- for the record, ten times a second is considered good for most normal
76+ -- games (including many MMOs), and you shouldn't ever really need more
77+ -- than 30 updates a second, even for fast-paced games.
78+ if t > updaterate then
79+ -- we could send updates for every little move, but we consolidate
80+ -- the last update-worth here into a single packet, drastically reducing
81+ -- our bandwidth use.
82+ local x, y = 0, 0
83+ if love.keyboard.isDown('up') then y=y-(20*t) end
84+ if love.keyboard.isDown('down') then y=y+(20*t) end
85+ if love.keyboard.isDown('left') then x=x-(20*t) end
86+ if love.keyboard.isDown('right') then x=x+(20*t) end
87+
88+
89+ -- again, we prepare a packet *payload* using string.format,
90+ -- then send it on its way with udp:send
91+ -- this one is the move update mentioned above
92+ local dg = string.format("%s %s %f %f", entity, 'move', x, y)
93+ udp:send(dg)
94+
95+ -- and again! this is a require that the server send us an update for
96+ -- the world state
97+ --
98+ -- [NOTE: in most designs you don't request world-state updates, you
99+ -- just get them sent to you periodically. theres various reasons for
100+ -- this, but theres one *BIG* one you will have to solemnly take note
101+ -- of: 'anti-griefing'. World-updates are probably one of biggest things
102+ -- the average game-server will pump out on a regular basis, and greifing
103+ -- with forged update requests would be simple effective. so they just
104+ -- don't support update requests, instead giving them out when they feel
105+ -- its appropriate]
106+ local dg = string.format("%s %s $", entity, 'update')
107+ udp:send(dg)
108+
109+ t=t-updaterate -- set t for the next round
110+ end
111+
112+
113+ -- there could well be more than one message waiting for us, so we'll
114+ -- loop until we run out!
115+ repeat
116+ -- and here is something new, the much anticipated other end of udp:send!
117+ -- receive return a waiting packet (or nil, and an error message).
118+ -- data is a string, the payload of the far-end's send. we can deal with it
119+ -- the same ways we could deal with any other string in lua (needless to
120+ -- say, getting familiar with lua's string handling functions is a must.
121+ data, msg = udp:receive()
122+
123+ if data then -- you remember, right? that all values in lua evaluate as true, save nil and false?
124+
125+ -- match is our freind here, its part of string.*, and data is
126+ -- (or should be!) a string. that funky set of characters bares some
127+ -- explanation, though.
128+ -- (need summary of patterns, and link to section 5.4.1)
129+ ent, cmd, parms = data:match("^(%S*) (%S*) (.*)")
130+ if cmd == 'at' then
131+ -- more patterns, this time with sets, and more length selectors!
132+ local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
133+ assert(x and y) -- validation is better, but asserts will serve.
134+
135+ -- don't forget, even if you matched a "number", the result is still a string!
136+ -- thankfully conversion is easy in lua.
137+ x, y = tonumber(x), tonumber(y)
138+ -- and finally we stash it away
139+ world[ent] = {x=x, y=y}
140+ else
141+ -- this case shouldn't trigger often, but its always a good idea
142+ -- to check (and log!) any unexpected messages and events.
143+ -- it can help you find bugs in your code...or people trying to hack the server.
144+ -- never forget, you can not trust the client!
145+ print("unrecognised command:", cmd)
146+ end
147+
148+ -- if data was nil, then msg will contain a short description of the
149+ -- problem (which are also error id...).
150+ -- the most common will be 'timeout', since we settimeout() to zero,
151+ -- anytime there isn't data *waiting* for us, it'll timeout.
152+ --
153+ -- but we should check to see if its a *different* error, and act accordingly.
154+ -- in this case we don't even try to save ourselves, we just error out.
155+ elseif msg ~= 'timeout' then
156+ error("Network error: "..tostring(msg))
157+ end
158+ until not data
159+
160+end
161+
162+-- love.draw, hopefully you are familiar with it from the callbacks tutorial
163+function love.draw()
164+ -- pretty simple, we just loop over the world table, and print the
165+ -- name (key) of everything in their, at its own stored co-ords.
166+ for k, v in pairs(world) do
167+ love.graphics.print(k, v.x, v.y)
168+ end
169+end
170+
171+-- And thats the end of the udp client example.
172+</source>
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Networking with UDP-TheServer.txt
@@ -0,0 +1,102 @@
1+The complete source for the UDP server
2+
3+<source lang=lua>
4+local socket = require "socket"
5+
6+-- begin
7+local udp = socket.udp()
8+
9+-- normally socket reads block until they have data, or a
10+-- certain amount of time passes.
11+-- that doesn't suit us, so we tell it not to do that by setting the
12+-- 'timeout' to zero
13+udp:settimeout(0)
14+
15+-- unlike the client, the server has to be specific about where its
16+-- 'bound', or the poor clients will never find it.
17+-- thus while we can happily let the client auto-bind to whatever it likes,
18+-- we have to tell the server to bind to something known.
19+--
20+-- the first part is which "interface" we should bind to...a bit beyond this tutorial, but '*' basically means "all of them"
21+-- port is simpler, the system maintains a list of up to 65535 (!) "ports"
22+-- ...really just numbers. point is that if you send to a particular port,
23+-- then only things "listening" to that port will be able to receive it,
24+-- and likewise you can only read data sent to ports you are listening too.
25+-- generally speaking, if an address is which machine you want to talk to, then a port is what program on that machine you want to talk to.
26+--
27+-- [NOTE: on some operating systems, ports between 0 and 1024 are "reserved for
28+-- privileged processes". its a security precaution for those system.
29+-- generally speaking, just not using ports in that range avoids a lot of problems]
30+udp:setsockname('*', 12345)
31+
32+local world = {} -- the empty world-state
33+
34+-- We declare a whole bunch of local variables that we'll be using the in
35+-- main server loop below. you probably recognise some of them from the
36+--client example, but you are also probably wondering what's with the fruity
37+-- names, 'msg_or_ip'? 'port_or_nil'?
38+--
39+-- well, we're using a slightly different function this time, you'll see when we get there.
40+local data, msg_or_ip, port_or_nil
41+local entity, cmd, parms
42+-- indefinite loops are probably not something you used to if you only
43+-- know love, but they are quite common. and in fact love has one at its
44+-- heart, you just don't see it.
45+-- regardless, we'll be needing one for our server. and this little
46+-- variable lets us *stop* it :3
47+local running = true
48+
49+-- the beginning of the loop proper...
50+print "Beginning server loop."
51+while running do
52+ -- this line looks familiar, I'm sure, but we're using 'receivefrom'
53+ -- this time. its similar to receive, but returns the data, sender's
54+ -- ip address, and the sender's port. (which you'll hopefully recognise
55+ -- as the two things we need to send messages to someone)
56+ -- we didn't have to do this in the client example because we just bound
57+ -- the socket to the server. ...but that also ignores messages from
58+ -- sources other than what we've bound to, which obviously won't do at
59+ -- all as a server.
60+ --
61+ -- [NOTE: strictly, we could have just used receivefrom (and its
62+ -- counterpart, sendto) in the client. there's nothing special about the
63+ -- functions to prevent it, indeed. send/receive are just convenience
64+ -- functions, sendto/receive from are the real workers.]
65+ data, msg_or_ip, port_or_nil = udp:receivefrom()
66+ if data then
67+ -- more of these funky match paterns!
68+ entity, cmd, parms = data:match("^(%S*) (%S*) (.*)")
69+ if cmd == 'move' then
70+ local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
71+ assert(x and y) -- validation is better, but asserts will serve.
72+ -- don't forget, even if you matched a "number", the result is still a string!
73+ -- thankfully conversion is easy in lua.
74+ x, y = tonumber(x), tonumber(y)
75+ -- and finally we stash it away
76+ local ent = world[entity] or {x=0, y=0}
77+ world[entity] = {x=ent.x+x, y=ent.y+y}
78+ elseif cmd == 'at' then
79+ local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
80+ assert(x and y) -- validation is better, but asserts will serve.
81+ x, y = tonumber(x), tonumber(y)
82+ world[entity] = {x=x, y=y}
83+ elseif cmd == 'update' then
84+ for k, v in pairs(world) do
85+ udp:sendto(string.format("%s %s %d %d", k, 'at', v.x, v.y), msg_or_ip, port_or_nil)
86+ end
87+ elseif cmd == 'quit' then
88+ running = false;
89+ else
90+ print("unrecognised command:", cmd)
91+ end
92+ elseif msg_or_ip ~= 'timeout' then
93+ error("Unknown network error: "..tostring(msg))
94+ end
95+
96+ socket.sleep(0.01)
97+end
98+
99+print "Thank you."
100+
101+-- and that the end of the udp server example.
102+</source>
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Networking with UDP.txt
@@ -0,0 +1,277 @@
1+This is an introduction to networking, using ''Luasocket''. Don't run away! Luasocket is compiled into LÖVE, and is really not that bad once you get used to it.
2+
3+This tutorial assumes that you are familiar with [[Tutorial:Callback Functions|Callbacks]], and Lua in general. Networking should be considered a moderately advanced topic.
4+
5+There are two basic kinds of sockets, and we'll be covering UDP in this tutorial. UDP networking is message-oriented (as opposed to TCP being stream-oriented), meaning that it's oriented around distinct (and otherwise independent) messages called ''datagrams''.
6+
7+In the long run it pays to have a solid understanding on how networking works, but for now lets just get cracking. :3
8+We'll start with the LÖVE client, then follow up with a stand-alone server written in Lua.
9+
10+==The Client==
11+To start, we need to require the "socket" lib. ''socket'' provides low-level networking features.
12+<source lang="lua">
13+local socket = require "socket"
14+
15+-- the address and port of the server
16+local address, port = "localhost", 12345
17+
18+local entity -- entity is what we'll be controlling
19+local updaterate = 0.1 -- how long to wait, in seconds, before requesting an update
20+
21+local world = {} -- the empty world-state
22+local t
23+</source>
24+
25+===[[love.load]]===
26+First up, we need a UDP socket, from which we'll do all our networking.
27+<source lang="lua">
28+function love.load()
29+ udp = socket.udp()
30+</source>
31+Normally socket reads block (cause your game to stop and wait) until they have data. That doesn't suit us, so we tell it not to do that by setting the ''timeout'' to zero.
32+<source lang="lua">
33+ udp:settimeout(0)
34+</source>
35+Unlike the server, we'll just be talking to the one machine, so we'll "connect" this socket to the server's address and port using ''udp:setpeername''.
36+
37+{{notice|UDP is actually connectionless, this is purely a convenience provided by the socket library. It doesn't actually change the 'bits on the wire', and in fact we can change/remove this at any time.}}
38+
39+<source lang=lua>
40+ udp:setpeername(address, port)
41+</source>
42+
43+Seed the [[wikipedia:PRNG|PRNG]], so we don't just get the same numbers each time. ''entity'' will be what we'll be controlling, for the sake of this tutorial.
44+It's just a number, but it'll do. We'll just use ''math.random'' to give us a reasonably unique identity for little effort.
45+
46+{{notice|A random number to identify yourself isn't actually a very good way of doing this, but the "correct" ways are beyond the scope of this article.)}}
47+
48+<source lang="lua">
49+ math.randomseed(os.time())
50+ entity = tostring(math.random(99999))
51+</source>
52+
53+Here we do our first bit of actual networking: we set up a string containing the data we want to send (using ''string.format'') and then send it using ''udp.send''.
54+Since we used ''udp:setpeername'' earlier we don't even have to specify where to send it.
55+
56+Thats... it, really. The rest of this is just putting this context and practical use.
57+<source lang=lua>
58+ local dg = string.format("%s %s %d %d", entity, 'at', 320, 240)
59+ udp:send(dg) -- the magic line in question.
60+
61+ -- t is just a variable we use to help us with the update rate in love.update.
62+ t = 0 -- (re)set t to 0
63+end
64+</source>
65+
66+===[[love.update]]===
67+We start with a little bit of nonsense involving ''t'' we declared earlier;
68+It's '''very easy''' to completely saturate a network connection if you aren't careful with the packets we send (or request!), so we hedge our chances by limiting how often we send (and request) updates.
69+
70+''(For the record, ten times a second is considered good for most normal games (including many [[wikipedia:Massively Multiplayer Online game|MMO]]s), and you shouldn't ever really need more than 30 updates a second, even for fast-paced games.)''
71+
72+We could send updates for every little move, but we'll consolidate the last update-worth here into a single packet, drastically reducing our bandwidth use.
73+<source lang="lua">
74+function love.update(deltatime)
75+ t = t + deltatime -- increase t by the deltatime
76+
77+ if t > updaterate then
78+ local x, y = 0, 0
79+ if love.keyboard.isDown('up') then y=y-(20*t) end
80+ if love.keyboard.isDown('down') then y=y+(20*t) end
81+ if love.keyboard.isDown('left') then x=x-(20*t) end
82+ if love.keyboard.isDown('right') then x=x+(20*t) end
83+</source>
84+
85+Again, we prepare a packet ''payload'' using string.format, then send it on its way with udp:send. This is the move update mentioned above.
86+<source lang=lua>
87+ local dg = string.format("%s %s %f %f", entity, 'move', x, y)
88+ udp:send(dg)
89+</source>
90+
91+And again! This is a request that the server send us an update for the world state.
92+
93+{{notice|In most designs you don't request world-state updates, you just get them sent to you periodically.
94+There's various reasons for this, but there's one '''BIG''' one you will have to solemnly take note of: "anti-griefing". World-updates are probably one of biggest things the average game-server will pump out on a regular basis, and griefing with forged update requests would be simple effective.
95+So they just don't support update requests, instead giving them out when they feel its appropriate}}
96+
97+<source lang=lua>
98+ local dg = string.format("%s %s $", entity, 'update')
99+ udp:send(dg)
100+
101+ t=t-updaterate -- set t for the next round
102+ end
103+</source>
104+
105+
106+There could well be more than one message waiting for us, so we'll loop until we run out!
107+
108+And here is something new, the much anticipated other end of <code>udp:send</code>!
109+<code>udp:receive</code> will return a waiting packet (or nil, and an error message).
110+''data'' is a string, the '''payload''' of the far-end's ''udp:send''. We can deal with it the same ways we could deal with any other string in Lua (needless to say, getting familiar with Lua's [http://www.lua.org/manual/5.1/manual.html#5.4 string handling functions] is a must.)
111+<source lang=lua>
112+ repeat
113+ data, msg = udp:receive()
114+
115+ if data then -- you remember, right? that all values in lua evaluate as true, save nil and false?
116+</source>
117+
118+<code>string.match</code> is our friend here, its part of ''string.*'', and ''data'' is (or should be!) a '''string'''. That funky set of characters bares some explanation, though. ''(Which I haven't gotten to, but I'll leave you with a link to [http://www.lua.org/manual/5.1/manual.html#5.4.1 5.4.1:Patterns])
119+<source lang=lua>
120+ ent, cmd, parms = data:match("^(%S*) (%S*) (.*)")
121+ if cmd == 'at' then
122+ local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
123+</source>
124+Confirming that the values you received are what you expect is important, since you never known who or what is on the other end (or in between...). Since this is just an example, we'll just use asserts.
125+
126+And don't forget, even if you matched a "number", the result is still a '''string'''! Thankfully conversion is easy in Lua using <code>tonumber()</code>.
127+<source lang=lua>
128+ assert(x and y)
129+ x, y = tonumber(x), tonumber(y)
130+ world[ent] = {x=x, y=y}
131+</source>
132+This case shouldn't trigger often, but its always a good idea to check (and log!) any unexpected messages and events. It can help you find bugs in your code...or people trying to hack the server.
133+Never forget, you can not trust the client!
134+<source lang=lua>
135+ else
136+ print("unrecognised command:", cmd)
137+ end
138+</source>
139+If ''data'' was <code>nil</code>, then ''msg'' will contain a short description of the problem (which are also double as error IDs...).
140+The most common will be <code>'timeout'</code>, since we <code>socket:settimeout()</code> to zero, any time there isn't data ''waiting'' for us, it'll <code>'timeout'</code>. But we should check to see if its a ''different'' error, and act accordingly.
141+In this case we don't even try to save ourselves, we just error out.
142+
143+<source lang=lua>
144+ elseif msg ~= 'timeout' then
145+ error("Network error: "..tostring(msg))
146+ end
147+ until not data
148+end
149+</source>
150+
151+===love.draw===
152+Draw is stunningly simple, since its not really the meat of this example.
153+It just loops over the ''world'' table, and print the name (key) of everything in their, at its own stored co-ords.
154+
155+<source lang=lua>
156+function love.draw()
157+ -- pretty simple, we
158+ for k, v in pairs(world) do
159+ love.graphics.print(k, v.x, v.y)
160+ end
161+end
162+</source>
163+
164+And that's the end of the Client code.
165+==The Server==
166+The server is a little different, for starters its a stand-alone Lua program: it doesn't run in LÖVE.
167+
168+Once again we begin by <code>require</code>ing socket, and creating a UDP socket.
169+
170+''(LuaSocket ''isn't'' compiled into Lua by default. If you are on Windows just get the all-in-one [https://github.com/rjpcomputing/luaforwindows/releases] installer, I wouldn't know for Mac, and Linux? you guys know what to do :3)''
171+<source lang=lua>
172+local socket = require "socket"
173+local udp = socket.udp()
174+</source>
175+
176+And once again, we set the <code>'timeout'</code> to zero.
177+
178+But next we do something a little different; unlike the client, the server has to be specific about where its 'bound', or the poor clients will never find it. Thus while we can happily let the client auto-bind to whatever it likes, we have to tell the server to bind to something known.
179+
180+The first part is which ''interface'' we should bind to, <code>'*'</code> basically means "all of them". ''port'' is simple, the system maintains a list of up to 65535 (!) "ports" ... really just numbers.
181+
182+Point is that if you send to a particular port, then only things "listening" to that port will be able to receive it, and likewise you can only read data sent to ports you are listening too.
183+
184+Generally speaking, if an address is which machine you want to talk to, then a port is what program on that machine you want to talk to.
185+
186+{{notice| On some operating systems, ports between ''0'' and ''1024'' are "reserved for privileged processes". Its a security precaution for those system. Generally speaking, just not using ports in that range avoids a lot of problems}}
187+
188+<source lang=lua>
189+udp:settimeout(0)
190+udp:setsockname('*', 12345)
191+</source>
192+
193+We declare a whole bunch of local variables that we'll be using the in main server loop below. you probably recognise some of them from the client example, but you are also probably wondering what's with the fruity names, ''msg_or_ip''? ''port_or_nil''?
194+
195+Well, we're using a slightly different function this time, you'll see when we get there.
196+
197+<source lang=lua>
198+local world = {} -- the empty world-state
199+local data, msg_or_ip, port_or_nil
200+local entity, cmd, parms
201+</source>
202+Indefinite loops are probably not something you are used to if you only know love, but they are quite common. And in fact love has one at its heart, you just don't see it. Regardless, we'll be needing one for our server. And this little variable lets us ''stop'' it :3
203+<source lang=lua>
204+local running = true
205+
206+print "Beginning server loop."
207+while running do
208+</source>
209+This next line looks familiar, I'm sure, but we're using <code>udp:receivefrom()</code> this time. its similar to receive, but returns the data, sender's ip address, and the sender's port (which you'll hopefully recognise as the two things we need to send messages to someone). We didn't have to do this in the client example because we just bound the socket to the server, but that also ignores messages from sources other than what we've bound to, which obviously won't do at all as a server.
210+
211+''(Strictly, we could have just used <code>udp:receivefrom()</code> (and its counterpart, <code>udp:sendto()</code>) in the client. there's nothing special about the functions to prevent it, however <code>send</code>/<code>receive</code> are convenient and perform slightly better.)''
212+
213+<source lang=lua>
214+ data, msg_or_ip, port_or_nil = udp:receivefrom()
215+ if data then
216+ -- more of these funky match paterns!
217+ entity, cmd, parms = data:match("^(%S*) (%S*) (.*)")
218+</source>
219+The server implements a few more commands than the client does, the 'move' command updates the position of an entity ''relative to its current position'', 'at' simply sets an entity's location (which we saw in the client), then there's ''update'', which loops through the server's world-state and sends 'at' commands back to the client. and finally there's 'quit', which kills the server.
220+<source lang=lua>
221+ if cmd == 'move' then
222+ local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
223+ assert(x and y) -- validation is better, but asserts will serve.
224+ -- don't forget, even if you matched a "number", the result is still a string!
225+ -- thankfully conversion is easy in lua.
226+ x, y = tonumber(x), tonumber(y)
227+ -- and finally we stash it away
228+ local ent = world[entity] or {x=0, y=0}
229+ world[entity] = {x=ent.x+x, y=ent.y+y}
230+ elseif cmd == 'at' then
231+ local x, y = parms:match("^(%-?[%d.e]*) (%-?[%d.e]*)$")
232+ assert(x and y) -- validation is better, but asserts will serve.
233+ x, y = tonumber(x), tonumber(y)
234+ world[entity] = {x=x, y=y}
235+ elseif cmd == 'update' then
236+ for k, v in pairs(world) do
237+ udp:sendto(string.format("%s %s %d %d", k, 'at', v.x, v.y), msg_or_ip, port_or_nil)
238+ end
239+ elseif cmd == 'quit' then
240+ running = false;
241+</source>
242+There's nothing much left to see, other than the ''socket.sleep' call, which helps reduce the CPU load of the server.
243+Generally, people seem to prefer to just rely on blocking behaviour (which we turned off) to keep CPU usage down, but its nice to know how do this without blocking.
244+<source lang=lua>
245+ else
246+ print("unrecognised command:", cmd)
247+ end
248+ elseif msg_or_ip ~= 'timeout' then
249+ error("Unknown network error: "..tostring(msg))
250+ end
251+
252+ socket.sleep(0.01)
253+end
254+
255+print "Thank you."
256+</source>
257+
258+==Conclusion==
259+* [[Tutorial:Networking with UDP-TheClient | The Complete Client Source]]
260+* [[Tutorial:Networking with UDP-TheServer | The Complete Server Source]]
261+
262+[[wikipedia:User Datagram Protocol|UDP]] is simple in its usage, but also relies on the developer to get a lot more right, since UDP doesn't make any assurances about the order that datagrams arrive, or even that they arrive at all. These are things that you obviously have to take into account when designing your protocol.
263+
264+Additionally UDP datagrams have limited sizes; the luasocket Documentation specifically notes that it doesn't support anything over 8k, and frankly you should assume much less.
265+
266+==See also==
267+
268+* [[Networking with TCP]]
269+* [http://w3.impa.br/~diego/software/luasocket/reference.html luaSocket Reference]
270+* [http://www.beej.us/guide/bgnet/ Beej's Networking Tutorial]
271+[[Category:Tutorials]]
272+
273+{{#set:LOVE Version=0.7.1}}
274+{{#set:Description=Networking with UDP}}
275+
276+== Other languages ==
277+{{i18n|Tutorial:Networking with UDP}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Object Follows Another Object.txt
@@ -0,0 +1,181 @@
1+== Overview ==
2+In this tutorial, you'll be learning how to make an object follow another object.
3+
4+[[#Part 1: Creating the Objects|Part 1: Creating the Objects]]<br>
5+[[#Part 2: Giving Movement|Part 2: Giving Movement]]<br>
6+[[#Part 3: The Whole Code|Part 3: The Whole Code]]
7+
8+== Part 1: Creating the Objects ==
9+To start off, you need to prepare the main.lua. First, we will create and render two objects, a red circle, and a green rectangle. These will be the objects used for this tutorial.
10+
11+<source lang="lua">
12+function love.load()
13+ circle = {}
14+ circle.x = 150 -- This will render the circle at 150px to the right along the x-axis.
15+ circle.y = 150 -- This will render the circle at 150px below along the y-axis.
16+
17+ rect = {}
18+ rect.x = 300 -- This will render the rectangle at 300px to the right along the x-axis.
19+ rect.y = 150 -- This will render the rectangle at 150px below along the y-axis.
20+ rect.w = 100 -- This will render the rectangle with a width of 100px.
21+ rect.h = 100 -- This will render the rectangle with a height of 100px.
22+end
23+
24+function love.update(dt)
25+
26+end
27+
28+function love.draw()
29+ -- This will render the red circle.
30+ love.graphics.setColor(255, 0, 0)
31+ love.graphics.circle("fill", circle.x, circle.y, 50)
32+
33+ -- This will render the green rectangle.
34+ love.graphics.setColor(0, 255, 0)
35+ love.graphics.rectangle("fill", rect.x, rect.y, rect.w, rect.h)
36+end
37+</source>
38+
39+You will now have something like this:
40+
41+[[File:Part_1._Creating_the_Objects.png]]
42+
43+== Part 2: Giving Movement ==
44+Next we will make the two objects move. One of them would be controlled by the player. The other one will follow the object controlled by the player. For the purpose of this tutorial, the player will be controlling the red circle. To do this, we will give the circle a speed value and add <code>[[love.keyboard.isDown]]</code> in the <code>love.update(dt)</code> function.
45+
46+<source lang="lua">
47+function love.load()
48+ ...
49+ -- Add below the circle axes.
50+ circle.speed = 500 -- This will give the circle a movement speed of 500.
51+end
52+
53+function love.update(dt)
54+ -- These conditional statements add keyboard input.
55+ if love.keyboard.isDown("d") then -- If player is holding down 'D',
56+ circle.x = circle.x + (circle.speed * dt) -- Move circle to the right.
57+ end
58+
59+ if love.keyboard.isDown("a") then -- If player is holding down 'A',
60+ circle.x = circle.x - (circle.speed * dt) -- Move circle to the left.
61+ end
62+
63+ if love.keyboard.isDown("w") then -- If player is holding down 'W',
64+ circle.y = circle.y - (circle.speed * dt) -- Move circle upwards.
65+ end
66+
67+ if love.keyboard.isDown("s") then -- If player is holding down 'S',
68+ circle.y = circle.y + (circle.speed * dt) -- Move circle downwards.
69+ end
70+end
71+
72+function love.draw()
73+ ...
74+end
75+</source>
76+
77+You will now have something like this:
78+
79+[[File:Part_2.1_Giving_Movement.gif]]
80+
81+We aren't done yet though. We have only gave the red circle some movement. Next, we need to give the green rectangle movement and make it follow the red circle. To do that, we will give the green rectangle a speed value. Next we will check the location of the green rectangle in comparison to the red circle. If the right conditions are met, the green rectangle will move towards the red circle.
82+
83+<source lang="lua">
84+function love.load()
85+ ...
86+ -- Add below the rectangle values.
87+ rect.speed = 100 -- This will give the rectangle a movement speed of 100.
88+end
89+
90+function love.update(dt)
91+ ...
92+ -- Add below the circle movement code.
93+
94+ -- These will check the locations of the green rectangle in comparison to the red square.
95+
96+ if rect.x < circle.x then -- If the rectangle is to the left of the circle:
97+ rect.x = rect.x + (rect.speed * 2.5 * dt) -- Rectangle moves towards the right.
98+ end
99+
100+ if rect.x > circle.x then -- If the rectangle is to the right of the circle:
101+ rect.x = rect.x - (rect.speed * 2.5 * dt) -- Rectangle moves towards the left.
102+ end
103+
104+ if rect.y < circle.y then -- If the rectangle is above the circle:
105+ rect.y = rect.y + (rect.speed * 2.5 * dt) -- Rectangle moves downward.
106+ end
107+
108+ if rect.y > circle.y then -- If the rectangle is below the circle:
109+ rect.y = rect.y - (rect.speed * 2.5 * dt) -- Rectangle moves upward.
110+ end
111+end
112+
113+function love.draw()
114+ ...
115+end
116+</source>
117+
118+You will now have something like this:
119+
120+[[File:Part_2.2_Object_Follows.gif]]
121+
122+Congratulations! You've finished the tutorial!
123+
124+== Part 3: The Whole Code ==
125+<source lang="lua">
126+function love.load()
127+ circle = {}
128+ circle.x = 150 -- This will render the circle at 150px to the right along the x-axis.
129+ circle.y = 150 -- This will render the circle at 150px below along the y-axis.
130+ circle.speed = 500 -- This will give the circle a movement speed of 500.
131+
132+ rect = {}
133+ rect.x = 300 -- This will render the rectangle at 300px to the right along the x-axis.
134+ rect.y = 150 -- This will render the rectangle at 150px below along the y-axis.
135+ rect.w = 100 -- This will render the rectangle with a width of 100px.
136+ rect.h = 100 -- This will render the rectangle with a height of 100px.
137+ rect.speed = 100 -- This will give the rectangle a movement speed of 100.
138+end
139+
140+function love.update(dt)
141+ if love.keyboard.isDown("d") then -- If player is holding down 'D',
142+ circle.x = circle.x + (circle.speed * dt) -- Move circle to the right.
143+ end
144+
145+ if love.keyboard.isDown("a") then -- If player is holding down 'A',
146+ circle.x = circle.x - (circle.speed * dt) -- Move circle to the left.
147+ end
148+
149+ if love.keyboard.isDown("w") then -- If player is holding down 'W',
150+ circle.y = circle.y - (circle.speed * dt) -- Move circle upwards.
151+ end
152+
153+ if love.keyboard.isDown("s") then -- If player is holding down 'S',
154+ circle.y = circle.y + (circle.speed * dt) -- Move circle downwards.
155+ end
156+
157+ if rect.x < circle.x then -- If the rect is to the left of the circle:
158+ rect.x = rect.x + (rect.speed * 2.5 * dt) -- Rectangle moves towards the right.
159+ end
160+
161+ if rect.x > circle.x then -- If the rect is to the right of the circle:
162+ rect.x = rect.x - (rect.speed * 2.5 * dt) -- Rectangle moves towards the left.
163+ end
164+
165+ if rect.y < circle.y then -- If the rect is above the circle:
166+ rect.y = rect.y + (rect.speed * 2.5 * dt) -- Rectangle moves downward.
167+ end
168+
169+ if rect.y > circle.y then -- If the rect is below the circle:
170+ rect.y = rect.y - (rect.speed * 2.5 * dt) -- Rectangle moves upward.
171+ end
172+end
173+
174+function love.draw()
175+ love.graphics.setColor(255, 0, 0)
176+ love.graphics.circle("fill", circle.x, circle.y, 50)
177+
178+ love.graphics.setColor(0, 255, 0)
179+ love.graphics.rectangle("fill", rect.x, rect.y, rect.w, rect.h)
180+end
181+</source>
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Object Follows Mouse.txt
@@ -0,0 +1,145 @@
1+== Overview ==
2+In this tutorial, you'll be learning how to make an object follow the mouse pointer inside the game's window.
3+
4+[[#Part 1: Detecting the Mouse|Part 1: Detecting the Mouse]]<br>
5+[[#Part 2: The Object Follows|Part 2: The Object Follows]]<br>
6+[[#Part 3: The Whole Code|Part 3: The Whole Code]]
7+
8+== Part 1: Detecting the Mouse ==
9+So to start off, you need to prepare your main.lua. Now what we first need to do is to store the mouse's coordinates into two variables representing the x and y coordinate respectively. To do this, we will be using [[love.mouse.getPosition]]. For tutorial purposes, we will also be printing the coordinates to the screen so that we can see if the game is constantly updating the values in the variables.
10+
11+<source lang="lua">
12+mouse = {}
13+
14+function love.load()
15+
16+end
17+
18+function love.update(dt)
19+ mouse.x, mouse.y = love.mouse.getPosition() -- This gets the x and y coordinates of the mouse and assigns those to these respectively.
20+end
21+
22+function love.draw()
23+ love.graphics.setColor(255, 255, 255)
24+ love.graphics.print("Mouse Coordinates: " .. mouse.x .. ", " .. mouse.y)
25+end
26+</source>
27+:Note: We're putting the variables in the love.update function so that the game will constantly change the values within the variable. If you just declare it inside love.load and print it, it will always print the first mouse coordinates the game will detect and will never update the variables' values.
28+
29+You will now have something like this:
30+
31+[[File:Part_1-_Detecting_the_Mouse.gif]]
32+
33+== Part 2: The Object Follows ==
34+Next we make the object follow. To do that, we will first create an object. For tutorial purposes, the object we will be creating is a red circle.
35+
36+<source lang="lua">
37+...
38+circle = {}
39+
40+function love.load()
41+ circle.x = 300 -- This will render the circle at 300px to the right along the x-axis.
42+ circle.y = 300 -- This will render the circle at 300px below along the y-axis.
43+end
44+
45+function love.update(dt)
46+ ...
47+end
48+
49+function love.draw()
50+ -- Please draw the circle above the Mouse Coordinate text.
51+ love.graphics.setColor(255, 0, 0) -- Sets the circle's color to red.
52+ love.graphics.circle("fill", circle.x, circle.y, 50) -- Draws a red circle at the given coordinates with a radius of 50.
53+ ...
54+end
55+</source>
56+
57+[[File:Part_2.1-_The_Object_Follows.PNG]]
58+
59+Now that we have the red circle, we need to make it follow the mouse. To do this, we will be comparing the objects coordinate's to the mouse's current coordinates and if the conditions are met, then the object will move towards the mouse. The basics of character movement applies here. We need to declare the circle's movement speed and we must multiply this speed to the delta time.
60+
61+<source lang="lua">
62+...
63+circle = {}
64+
65+function love.load()
66+ ...
67+ -- Add below the circle's coordinates
68+ circle.speed = 300 -- The circle's movement speed is 300.
69+end
70+
71+function love.update(dt)
72+ ...
73+ -- Add below the love.mouse.getPosition()
74+
75+ -- If the circle is to the left of the mouse:
76+ if circle.x < mouse.x then
77+ circle.x = circle.x + (circle.speed * 2.5 * dt)
78+ end
79+
80+ -- If the circle is to the right of the mouse:
81+ if circle.x > mouse.x then
82+ circle.x = circle.x - (circle.speed * 2.5 * dt)
83+ end
84+
85+ -- If the circle is above the mouse:
86+ if circle.y < mouse.y then
87+ circle.y = circle.y + (circle.speed * 2.5 * dt)
88+ end
89+
90+ -- If the circle is below the mouse:
91+ if circle.y > mouse.y then
92+ circle.y = circle.y - (circle.speed * 2.5 * dt)
93+ end
94+end
95+
96+function love.draw()
97+ ...
98+end
99+</source>
100+:Note: The value of "2.5" there is an optional value. What this does is it increases the speed of the circle when it moves so that we don't have to keep on adjusting the movement speed that we set or so that we don't have to make any intricate operations on the delta time. You can change or remove completely if you want.
101+
102+Now you have something like this:
103+
104+[[File:Part_2.2-_The_Object_Follows.gif]]
105+
106+Congratulations! You have successfully made an object follow the mouse.
107+
108+== Part 3: The Whole Code ==
109+<source lang="lua">
110+mouse = {}
111+circle = {}
112+
113+function love.load()
114+ circle.x = 300
115+ circle.y = 300
116+
117+ circle.speed = 300
118+end
119+
120+function love.update(dt)
121+ mouse.x, mouse.y = love.mouse.getPosition()
122+
123+ if circle.x < mouse.x then
124+ circle.x = circle.x + (circle.speed * 2.5 * dt)
125+ end
126+ if circle.x > mouse.x then
127+ circle.x = circle.x - (circle.speed * 2.5 * dt)
128+ end
129+ if circle.y < mouse.y then
130+ circle.y = circle.y + (circle.speed * 2.5 * dt)
131+ end
132+ if circle.y > mouse.y then
133+ circle.y = circle.y - (circle.speed * 2.5 * dt)
134+ end
135+end
136+
137+function love.draw()
138+ love.graphics.setColor(255, 0, 0)
139+ love.graphics.circle("fill", circle.x, circle.y, 50)
140+
141+ love.graphics.setColor(255, 255, 255)
142+ love.graphics.print("Mouse Coordinates: " .. mouse.x .. ", " .. mouse.y)
143+end
144+</source>
145+[[Category:Tutorials]]
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Physics.txt
@@ -0,0 +1,205 @@
1+In this example we will create a red ball that rolls around on a green ground.
2+
3+The finished example is at the end of this page. All of these functions may be placed in one file: main.lua
4+
5+We'll start in the [[love.load]]() function.
6+
7+=== love.load() ===
8+
9+First we need to set up a [[love.physics.newWorld|world]] for the physics bodies to exist in.
10+<source lang="lua">
11+function love.load()
12+ love.physics.setMeter(64) --the height of a meter our worlds will be 64px
13+ world = love.physics.newWorld(0, 9.81*64, true) --create a world for the bodies to exist in with horizontal gravity of 0 and vertical gravity of 9.81
14+</source>
15+
16+Now that a [[love.physics.newWorld|world]] has been created, we can add [[Body|bodies]], [[Shape|shapes]], and [[Fixture|fixture]] to it.
17+
18+<source lang="lua">
19+ objects = {} -- table to hold all our physical objects
20+
21+ --let's create the ground
22+ objects.ground = {}
23+ objects.ground.body = love.physics.newBody(world, 650/2, 650-50/2) --remember, the shape (the rectangle we create next) anchors to the body from its center, so we have to move it to (650/2, 650-50/2)
24+ objects.ground.shape = love.physics.newRectangleShape(650, 50) --make a rectangle with a width of 650 and a height of 50
25+ objects.ground.fixture = love.physics.newFixture(objects.ground.body, objects.ground.shape) --attach shape to body
26+
27+ --let's create a ball
28+ objects.ball = {}
29+ objects.ball.body = love.physics.newBody(world, 650/2, 650/2, "dynamic") --place the body in the center of the world and make it dynamic, so it can move around
30+ objects.ball.shape = love.physics.newCircleShape( 20) --the ball's shape has a radius of 20
31+ objects.ball.fixture = love.physics.newFixture(objects.ball.body, objects.ball.shape, 1) -- Attach fixture to body and give it a density of 1.
32+ objects.ball.fixture:setRestitution(0.9) --let the ball bounce
33+
34+ --let's create a couple blocks to play around with
35+ objects.block1 = {}
36+ objects.block1.body = love.physics.newBody(world, 200, 550, "dynamic")
37+ objects.block1.shape = love.physics.newRectangleShape(0, 0, 50, 100)
38+ objects.block1.fixture = love.physics.newFixture(objects.block1.body, objects.block1.shape, 5) -- A higher density gives it more mass.
39+
40+ objects.block2 = {}
41+ objects.block2.body = love.physics.newBody(world, 200, 400, "dynamic")
42+ objects.block2.shape = love.physics.newRectangleShape(0, 0, 100, 50)
43+ objects.block2.fixture = love.physics.newFixture(objects.block2.body, objects.block2.shape, 2)
44+</source>
45+
46+Now to wrap up the [[love.load]]() function, let's set up the screen size and background color.
47+
48+<source lang="lua">
49+ --initial graphics setup
50+ love.graphics.setBackgroundColor(0.41, 0.53, 0.97) --set the background color to a nice blue
51+ love.window.setMode(650, 650) --set the window dimensions to 650 by 650 with no fullscreen, vsync on, and no antialiasing
52+end
53+</source>
54+
55+Okay, that's enough for the initial set up of the physics engine.
56+Now we need to edit the [[love.update]]() function.
57+
58+=== love.update() ===
59+
60+<source lang="lua">
61+function love.update(dt)
62+ world:update(dt) --this puts the world into motion
63+
64+ --here we are going to create some keyboard events
65+ if love.keyboard.isDown("right") then --press the right arrow key to push the ball to the right
66+ objects.ball.body:applyForce(400, 0)
67+ elseif love.keyboard.isDown("left") then --press the left arrow key to push the ball to the left
68+ objects.ball.body:applyForce(-400, 0)
69+ elseif love.keyboard.isDown("up") then --press the up arrow key to set the ball in the air
70+ objects.ball.body:setPosition(650/2, 650/2)
71+ objects.ball.body:setLinearVelocity(0, 0) --we must set the velocity to zero to prevent a potentially large velocity generated by the change in position
72+ end
73+end
74+</source>
75+
76+Now that the world is updating, we can draw the ground and ball.
77+
78+=== love.draw() ===
79+
80+First, the ground.
81+
82+<source lang="lua">
83+function love.draw()
84+ love.graphics.setColor(0.28, 0.63, 0.05) -- set the drawing color to green for the ground
85+ love.graphics.polygon("fill", objects.ground.body:getWorldPoints(objects.ground.shape:getPoints())) -- draw a "filled in" polygon using the ground's coordinates
86+</source>
87+
88+And finally, we can draw the circle that represents the ball and the blocks.
89+
90+<source lang="lua">
91+ love.graphics.setColor(0.76, 0.18, 0.05) --set the drawing color to red for the ball
92+ love.graphics.circle("fill", objects.ball.body:getX(), objects.ball.body:getY(), objects.ball.shape:getRadius())
93+
94+ love.graphics.setColor(0.20, 0.20, 0.20) -- set the drawing color to grey for the blocks
95+ love.graphics.polygon("fill", objects.block1.body:getWorldPoints(objects.block1.shape:getPoints()))
96+ love.graphics.polygon("fill", objects.block2.body:getWorldPoints(objects.block2.shape:getPoints()))
97+end
98+</source>
99+
100+There you have it! Put this file in a [[zip|zip file]], rename it to physics.love (or whatever), run it. And you'll have a ball rolling around in a lush green environment like I promised.
101+
102+[[Image:Tutorial-PhysicsBall.jpg|thumb|Screenshot of the mostly finished product.]]
103+
104+
105+== The main.lua ==
106+<source lang="lua">
107+function love.load()
108+ -- the height of a meter our worlds will be 64px
109+ love.physics.setMeter(64)
110+ -- create a world for the bodies to exist in with horizontal gravity
111+ -- of 0 and vertical gravity of 9.81
112+ world = love.physics.newWorld(0, 9.81*64, true)
113+
114+ objects = {} -- table to hold all our physical objects
115+
116+ -- let's create the ground
117+ objects.ground = {}
118+ -- remember, the shape (the rectangle we create next) anchors to the
119+ -- body from its center, so we have to move it to (650/2, 650-50/2)
120+ objects.ground.body = love.physics.newBody(world, 650/2, 650-50/2)
121+ -- make a rectangle with a width of 650 and a height of 50
122+ objects.ground.shape = love.physics.newRectangleShape(650, 50)
123+ -- attach shape to body
124+ objects.ground.fixture = love.physics.newFixture(objects.ground.body,
125+ objects.ground.shape)
126+
127+ -- let's create a ball
128+ objects.ball = {}
129+ -- place the body in the center of the world and make it dynamic, so
130+ -- it can move around
131+ objects.ball.body = love.physics.newBody(world, 650/2, 650/2, "dynamic")
132+ -- the ball's shape has a radius of 20
133+ objects.ball.shape = love.physics.newCircleShape(20)
134+ -- Attach fixture to body and give it a density of 1.
135+ objects.ball.fixture = love.physics.newFixture(objects.ball.body,
136+ objects.ball.shape, 1)
137+ objects.ball.fixture:setRestitution(0.9) -- let the ball bounce
138+
139+ -- let's create a couple blocks to play around with
140+ objects.block1 = {}
141+ objects.block1.body = love.physics.newBody(world, 200, 550, "dynamic")
142+ objects.block1.shape = love.physics.newRectangleShape(0, 0, 50, 100)
143+ -- A higher density gives it more mass.
144+ objects.block1.fixture = love.physics.newFixture(objects.block1.body,
145+ objects.block1.shape, 5)
146+
147+ objects.block2 = {}
148+ objects.block2.body = love.physics.newBody(world, 200, 400, "dynamic")
149+ objects.block2.shape = love.physics.newRectangleShape(0, 0, 100, 50)
150+ objects.block2.fixture = love.physics.newFixture(objects.block2.body,
151+ objects.block2.shape, 2)
152+
153+ -- initial graphics setup
154+ -- set the background color to a nice blue
155+ love.graphics.setBackgroundColor(0.41, 0.53, 0.97)
156+ love.window.setMode(650, 650) -- set the window dimensions to 650 by 650
157+end
158+
159+
160+function love.update(dt)
161+ world:update(dt) -- this puts the world into motion
162+
163+ -- here we are going to create some keyboard events
164+ -- press the right arrow key to push the ball to the right
165+ if love.keyboard.isDown("right") then
166+ objects.ball.body:applyForce(400, 0)
167+ -- press the left arrow key to push the ball to the left
168+ elseif love.keyboard.isDown("left") then
169+ objects.ball.body:applyForce(-400, 0)
170+ -- press the up arrow key to set the ball in the air
171+ elseif love.keyboard.isDown("up") then
172+ objects.ball.body:setPosition(650/2, 650/2)
173+ -- we must set the velocity to zero to prevent a potentially large
174+ -- velocity generated by the change in position
175+ objects.ball.body:setLinearVelocity(0, 0)
176+ end
177+end
178+
179+function love.draw()
180+ -- set the drawing color to green for the ground
181+ love.graphics.setColor(0.28, 0.63, 0.05)
182+ -- draw a "filled in" polygon using the ground's coordinates
183+ love.graphics.polygon("fill", objects.ground.body:getWorldPoints(
184+ objects.ground.shape:getPoints()))
185+
186+ -- set the drawing color to red for the ball
187+ love.graphics.setColor(0.76, 0.18, 0.05)
188+ love.graphics.circle("fill", objects.ball.body:getX(),
189+ objects.ball.body:getY(), objects.ball.shape:getRadius())
190+
191+ -- set the drawing color to grey for the blocks
192+ love.graphics.setColor(0.20, 0.20, 0.20)
193+ love.graphics.polygon("fill", objects.block1.body:getWorldPoints(
194+ objects.block1.shape:getPoints()))
195+ love.graphics.polygon("fill", objects.block2.body:getWorldPoints(
196+ objects.block2.shape:getPoints()))
197+end
198+</source>
199+[[Category:Tutorials]]
200+
201+{{#set:LOVE Version=0.10.0}}
202+{{#set:Description=A tutorial for learning to use [[love.physics]].}}
203+
204+== Other languages ==
205+{{i18n|Tutorial:Physics}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_PhysicsCollisionCallbacks.txt
@@ -0,0 +1,274 @@
1+__FORCETOC__
2+__TOC__
3+
4+== Preface ==
5+If you do not have a good grasp on [[love.physics]], you should first check out this [[Tutorial:Physics|physics tutorial]].
6+
7+In this tutorial we will create a collision between two objects that calls certain callbacks set by [[World:setCallbacks]].
8+
9+{{notice|Making changes to a [[World]] is not allowed inside of the [[beginContact]], [[endContact]], [[preSolve]], and [[postSolve]] callback functions, as BOX2D locks the world during these callbacks.}}
10+
11+
12+== Tutorial ==
13+=== main.lua setup ===
14+Let's start by setting up main.lua with 3 love functions: [[love.load]], [[love.update]], and [[love.draw]]
15+
16+<source lang="lua">
17+function love.load()
18+
19+end
20+function love.update(dt)
21+
22+end
23+function love.draw()
24+
25+end
26+</source>
27+
28+=== World setup ===
29+Now that we have a framework setup, let's setup a [[World|physics world]] in [[love.load]] with [[love.physics.newWorld|newWorld]].
30+We will also use [[World:update]].
31+
32+<source lang="lua">
33+function love.load()
34+ --Store the new world in a variable such as "world"
35+ world = love.physics.newWorld(0, 200, true) --Gravity is being set to 0 in the x direction and 200 in the y direction.
36+end
37+
38+function love.update(dt)
39+ --Never forget to update your world every frame.
40+ world:update(dt)
41+end
42+</source>
43+
44+Now we want to create a ball and a ground. To do this we will need [[love.physics.newBody|newBody]], [[love.physics.newCircleShape|newCircleShape]], and [[love.physics.newRectangleShape|newRectangleShape]]. We'll connect the bodies to the shapes using [[love.physics.newFixture|newFixture]].
45+
46+<source lang="lua">
47+function love.load()
48+ ... -- don't include this, it's just indicating where the existing code for the function should be
49+
50+ ball = {}
51+ ball.b = love.physics.newBody(world, 400,200, "dynamic") -- set x,y position (400,200) and let it move and hit other objects ("dynamic")
52+ ball.b:setMass(10) -- make it pretty light
53+ ball.s = love.physics.newCircleShape(50) -- give it a radius of 50
54+ ball.f = love.physics.newFixture(ball.b, ball.s) -- connect body to shape
55+ ball.f:setRestitution(0.4) -- make it bouncy
56+ ball.f:setUserData("Ball") -- give it a name, which we'll access later
57+ static = {}
58+ static.b = love.physics.newBody(world, 400,400, "static") -- "static" makes it not move
59+ static.s = love.physics.newRectangleShape(200,50) -- set size to 200,50 (x,y)
60+ static.f = love.physics.newFixture(static.b, static.s)
61+ static.f:setUserData("Block")
62+end
63+</source>
64+
65+The objects are there now, but you can't yet see them. Let's draw them.
66+
67+<source lang="lua">
68+function love.draw()
69+ love.graphics.circle("line", ball.b:getX(),ball.b:getY(), ball.s:getRadius(), 20)
70+ love.graphics.polygon("line", static.b:getWorldPoints(static.s:getPoints()))
71+end
72+</source>
73+
74+Now we should see a ball fall down and hit a solid rectangle.
75+
76+=== World Callbacks===
77+But what if we want more information on the two objects colliding? Now we will use [[World:setCallbacks]] to further dissect their collision(s).
78+
79+First thing we do is set the world callbacks with [[World:setCallbacks]].
80+There are four callbacks for a collision: beginContact, endContact, preSolve, and postSolve.
81+: '''beginContact''' gets called when two fixtures start overlapping (two objects collide).
82+: '''endContact''' gets called when two fixtures stop overlapping (two objects disconnect).
83+: '''preSolve''' is called just before a frame is resolved for a current collision
84+: '''postSolve''' is called just after a frame is resolved for a current collision.
85+<source lang="lua">
86+function love.load()
87+ ... -- substitute for the rest of love.load
88+
89+ world = love.physics.newWorld(0, 200, true)
90+ --These callback function names can be almost any you want:
91+ world:setCallbacks(beginContact, endContact, preSolve, postSolve)
92+
93+ text = "" -- we'll use this to put info text on the screen later
94+ persisting = 0 -- we'll use this to store the state of repeated callback calls
95+</source>
96+
97+Now define each function you just named.
98+<source lang="lua">
99+function beginContact(a, b, coll)
100+
101+end
102+
103+function endContact(a, b, coll)
104+
105+end
106+
107+function preSolve(a, b, coll)
108+
109+end
110+
111+function postSolve(a, b, coll, normalimpulse, tangentimpulse)
112+
113+end
114+</source>
115+These functions are called every time one of the collision actions happen. They pass in two fixtures and a collision object. The postsolve callback also contains the normal and tangent impulse for each collision contact point. These parameters can also be named to whatever you want. In this tutorial, we choose a, b, and coll.
116+* '''a''' is the first [[Fixture| fixture object]] in the collision.
117+* '''b''' is the second fixture object in the collision.
118+* '''coll''' is the [[Contact|contact object]] created.
119+* '''normalimpulse''' is the amount of impulse applied along the normal of the first point of collision. It only applies to the postsolve callback, and we can ignore it for now.
120+* '''tangentimpulse''' is the amount of impulse applied along the tangent of the first point of collision. It only applies to the postsolve callback, and we can ignore it for now.
121+
122+Say we want to print to screen whenever a callback is called. We just need to modify the '''text''' variable we added to love.load() earlier by appending a string every time a collision action happens. We need a bit of extra code to keep the output clean too.
123+
124+A list of functions you can use on contacts can be found at the [[Contact]] page.
125+
126+<source lang="lua">
127+function love.update(dt)
128+ ... -- substitute for the rest of love.update
129+
130+ if string.len(text) > 768 then -- cleanup when 'text' gets too long
131+ text = ""
132+ end
133+end
134+
135+function love.draw()
136+ ... -- substitute for the rest of love.draw
137+
138+ love.graphics.print(text, 10, 10)
139+end
140+
141+function beginContact(a, b, coll)
142+ x,y = coll:getNormal()
143+ text = text.."\n"..a:getUserData().." colliding with "..b:getUserData().." with a vector normal of: "..x..", "..y
144+end
145+
146+
147+function endContact(a, b, coll)
148+ persisting = 0 -- reset since they're no longer touching
149+ text = text.."\n"..a:getUserData().." uncolliding with "..b:getUserData()
150+end
151+
152+function preSolve(a, b, coll)
153+ if persisting == 0 then -- only say when they first start touching
154+ text = text.."\n"..a:getUserData().." touching "..b:getUserData()
155+ elseif persisting < 20 then -- then just start counting
156+ text = text.." "..persisting
157+ end
158+ persisting = persisting + 1 -- keep track of how many updates they've been touching for
159+end
160+
161+function postSolve(a, b, coll, normalimpulse, tangentimpulse)
162+-- we won't do anything with this function
163+end
164+</source>
165+
166+And now you know how to use world callbacks!
167+
168+To better explore how this world behaves and see when the callbacks are invoked, add some controls to allow you to push around the ball:
169+
170+<source lang="lua">
171+function love.update(dt)
172+ world:update(dt)
173+
174+ if love.keyboard.isDown("right") then
175+ ball.b:applyForce(1000, 0)
176+ elseif love.keyboard.isDown("left") then
177+ ball.b:applyForce(-1000, 0)
178+ end
179+ if love.keyboard.isDown("up") then
180+ ball.b:applyForce(0, -5000)
181+ elseif love.keyboard.isDown("down") then
182+ ball.b:applyForce(0, 1000)
183+ end
184+
185+ if string.len(text) > 768 then -- cleanup when 'text' gets too long
186+ text = ""
187+ end
188+end
189+</source>
190+
191+
192+== Finished ==
193+=== Screenshots ===
194+[[Image:Box2d-love-physics-callbacks-demo.png|thumb|400px|Screenshot of the finished product.]]
195+=== main.lua ===
196+<source lang="lua">
197+function love.load()
198+ world = love.physics.newWorld(0, 200, true)
199+ world:setCallbacks(beginContact, endContact, preSolve, postSolve)
200+
201+ ball = {}
202+ ball.b = love.physics.newBody(world, 400,200, "dynamic")
203+ ball.b:setMass(10)
204+ ball.s = love.physics.newCircleShape(50)
205+ ball.f = love.physics.newFixture(ball.b, ball.s)
206+ ball.f:setRestitution(0.4) -- make it bouncy
207+ ball.f:setUserData("Ball")
208+ static = {}
209+ static.b = love.physics.newBody(world, 400,400, "static")
210+ static.s = love.physics.newRectangleShape(200,50)
211+ static.f = love.physics.newFixture(static.b, static.s)
212+ static.f:setUserData("Block")
213+
214+ text = "" -- we'll use this to put info text on the screen later
215+ persisting = 0 -- we'll use this to store the state of repeated callback calls
216+end
217+
218+function love.update(dt)
219+ world:update(dt)
220+
221+ if love.keyboard.isDown("right") then
222+ ball.b:applyForce(1000, 0)
223+ elseif love.keyboard.isDown("left") then
224+ ball.b:applyForce(-1000, 0)
225+ end
226+ if love.keyboard.isDown("up") then
227+ ball.b:applyForce(0, -5000)
228+ elseif love.keyboard.isDown("down") then
229+ ball.b:applyForce(0, 1000)
230+ end
231+
232+ if string.len(text) > 768 then -- cleanup when 'text' gets too long
233+ text = ""
234+ end
235+end
236+
237+function love.draw()
238+ love.graphics.circle("line", ball.b:getX(),ball.b:getY(), ball.s:getRadius(), 20)
239+ love.graphics.polygon("line", static.b:getWorldPoints(static.s:getPoints()))
240+
241+ love.graphics.print(text, 10, 10)
242+end
243+
244+function beginContact(a, b, coll)
245+ x,y = coll:getNormal()
246+ text = text.."\n"..a:getUserData().." colliding with "..b:getUserData().." with a vector normal of: "..x..", "..y
247+end
248+
249+function endContact(a, b, coll)
250+ persisting = 0
251+ text = text.."\n"..a:getUserData().." uncolliding with "..b:getUserData()
252+end
253+
254+function preSolve(a, b, coll)
255+ if persisting == 0 then -- only say when they first start touching
256+ text = text.."\n"..a:getUserData().." touching "..b:getUserData()
257+ elseif persisting < 20 then -- then just start counting
258+ text = text.." "..persisting
259+ end
260+ persisting = persisting + 1 -- keep track of how many updates they've been touching for
261+end
262+
263+function postSolve(a, b, coll, normalimpulse, tangentimpulse)
264+end
265+</source>
266+
267+[[Category:Tutorials]]
268+{{#set:Name=World Collision Callbacks Tutorial}}
269+{{#set:LOVE Version=0.8.0}}
270+{{#set:Description=A tutorial for learning how to use [[World:setCallbacks]].}}
271+{{#set:Screenshot=File:WorldCallbacksTutorial.png}}
272+
273+== Other languages ==
274+{{i18n|Tutorial:PhysicsCollisionCallbacks}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_PhysicsDrawing.txt
@@ -0,0 +1,147 @@
1+This is not so much a tutorial but an explained code snippet that helps with physics debugging.
2+
3+== Drawing Physics Collisions ==
4+
5+When developing with Box2D (aka love.physics) you will likely get to a point where the collisions don't quite match up with what you expect them to be due to some minor mistake.
6+
7+At the end of this guide there's a complete snippet that will draw all collisions at the correct location. If you just want the code feel free to jump down and just copy & paste it. But we will go over what the code does bit by bit.
8+
9+love.physics works via a few different sets of objects. Most notably. "World", "Body", "Shape" and "Fixture".
10+
11+* "World" is the physics world. You can have multiple ones but only objects within the same world will collide.
12+
13+* "Body" is the location of your object within the physics world. It defines which world this object belongs to, if it can move and the mass of the object (which will be calculated from the size of your shape by default). It also holds a reference to the fixture.
14+
15+* "Shape" is the collision itself. If two shapes collide, the physics system will handle it. It also holds a reference to the fixture.
16+
17+* "Fixture" is how we attach a shape to a body. It defines a few additional properties how collisions will be handled (such as friction, collision channels and a few more). It also holds a reference to the body and the shape.
18+
19+In order to draw all shapes we need to start at the world. It handles all collisions. So it's gotta contain a list of things. Specifically. It contains a list of bodies which we can get in the following way:
20+
21+<source lang="lua">
22+listOfBodies = World:getBodyList()
23+</source>
24+
25+We don't need a list of bodies though. We just wanna do something for every body. So we make a for loop out of it:
26+
27+<source lang="lua">
28+for _, body in pairs(World:getBodyList()) do
29+ -- ToDo
30+end
31+</source>
32+
33+A body can have multiple shapes which are attached with multiple fixtures. So we have to iterate over the list of fixtures as well:
34+
35+<source lang="lua">
36+for _, body in pairs(World:getBodyList()) do
37+ for _, fixture in pairs(body:getFixtureList()) do
38+ -- ToDo
39+ end
40+end
41+</source>
42+
43+A fixture however can only have one shape. So now we already have a reference to all collision fixtures (and therefore shapes) there are within this loop!
44+
45+We can simply store a reference to the shape by doing
46+
47+<source lang="lua">
48+for _, body in pairs(World:getBodyList()) do
49+ for _, fixture in pairs(body:getFixtureList()) do
50+ local shape = fixture:getShape()
51+
52+ -- ToDo Draw collision
53+ end
54+end
55+</source>
56+
57+So next up is the drawing. There are multiple types of shapes. To be specific we have
58+
59+* CircleShape
60+
61+* PolygonShape
62+
63+* EdgeShape
64+
65+* ChainShape
66+
67+== Drawing circle shapes ==
68+
69+So let's first look at the circle. We will draw it with the following code:
70+
71+<source lang="lua">
72+local cx, cy = body:getWorldPoints(shape:getPoint())
73+love.graphics.circle("fill", cx, cy, shape:getRadius())
74+</source>
75+
76+cx & cy stand for "CircleX" and "CircleY". The position we want to draw it at.
77+
78+body:getWorldPoints() will take any amount of points and convert them into world space (a point being two numbers. One for x and one for y). In other words. It will do "x + body:getX()", "y + body:getY()" for all points provided.
79+
80+Then we simply draw the circle at the position we just calculated with the radius of the shape. I choose "fill" as first parameter. You can also use "line". "fill" means it'll be drawn as circle. "fill" will draw it as a ring.
81+
82+== Drawing a polygon shapes ==
83+
84+Next up is the PolygonShape. A polygon is a list of points with up to 8 vertices (aka 16 numbers representing x and y. e.g. (x1, y1, x2, y1, ..., xn, yn) )
85+
86+We can abuse a little bit of functionality of lua to make this a super small snippet of code. We can get all the points by calling "shape:getPoints()" (once we verified it's a polygon shape).
87+
88+This will return up to 16 individual numbers. However. If we put this directly into another function without following parameter. It will simply put the next number as next parameter.
89+
90+<source lang="lua">
91+add = function(a, b)
92+ print( a + b )
93+end
94+
95+f = function()
96+ return 1, 2
97+end
98+
99+add(2, 2) --> Will print 4
100+
101+add(f()) --> Will print 3. We returned multiple parameters which are simply considered as following parameters. So a -> 1, b -> 2.
102+
103+add(f(), 0) --> Will print 1. We returned multiple parameters. However those are directly followed by another value. So only the first return value is used and the others will be discarded. a -> 1, b -> 0
104+</source>
105+
106+Knowing this we can do the following:
107+
108+<source lang="lua">
109+love.graphics.polygon("fill", body:getWorldPoints(shape:getPoints()))
110+</source>
111+
112+Since there is no following parameter it will simply put as many points in the function as the shape has. We don't have to handle anything else!
113+
114+== Drawing edge and chain Shapes ==
115+
116+Lastly we have edge and chain shapes. They are essentially the same. Internally they are handled a bit differently. But for our case we can assume an EdgeShape to be the same as a ChainShape with two points. A ChainShape can have two or more points (this is the only shape without a limit).
117+
118+However. Both are made up of lines that may or may not loop around. And both have the function "shape:getPoints()" as well! So we do not have to treat them separately.
119+
120+We pretty much do the same as we did for the polygon. But instead of drawing a polygon we draw a line.
121+
122+<source lang="lua">
123+love.graphics.line(body:getWorldPoints(shape:getPoints()))
124+</source>
125+
126+== Final code ==
127+
128+This leaves us with the final code snippet that will draw all of our collisions at the correct location on the screen!
129+
130+Happy debugging!
131+
132+<source lang="lua">
133+for _, body in pairs(world:getBodyList()) do
134+ for _, fixture in pairs(body:getFixtureList()) do
135+ local shape = fixture:getShape()
136+
137+ if shape:typeOf("CircleShape") then
138+ local cx, cy = body:getWorldPoints(shape:getPoint())
139+ love.graphics.circle("fill", cx, cy, shape:getRadius())
140+ elseif shape:typeOf("PolygonShape") then
141+ love.graphics.polygon("fill", body:getWorldPoints(shape:getPoints()))
142+ else
143+ love.graphics.line(body:getWorldPoints(shape:getPoints()))
144+ end
145+ end
146+end
147+</source>
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Tile-based Scrolling.txt
@@ -0,0 +1,120 @@
1+In this little tutorial we will cover a widely used technique used to draw game backgrounds: tilemaps. Using this technique, our backgrounds are going to be made up of pieces (tiles) that, drawn together, will allow us to create bigger and more complex levels without using huge amounts of memory. The basic idea is to have a 2d value table, where each value represents a tile. Using that table, we will know what tiles to draw at a certain position, given some basic parameters like the map width, height and the current coordinates of an imaginary viewport. Don't worry if you don't understand these terms right now, I'll explain them in more detail as we start coding.
2+So, let's start with some variables:
3+<source lang="lua">
4+-- our tiles
5+ tile = {}
6+ for i=0,3 do -- change 3 to the number of tile images minus 1.
7+ tile[i] = love.graphics.newImage( "tile"..i..".png" )
8+ end
9+
10+ love.graphics.setNewFont(12)
11+
12+ -- map variables
13+ map_w = 20
14+ map_h = 20
15+ map_x = 0
16+ map_y = 0
17+ map_offset_x = 30
18+ map_offset_y = 30
19+ map_display_w = 14
20+ map_display_h = 10
21+ tile_w = 48
22+ tile_h = 48
23+</source>
24+
25+We first create a Lua table to store our tiles. As I already said, these are little bitmaps we'll use to draw our maps, something like mosaics, which are made up of smaller pieces. Since this will be a very simple tilemap, we'll just use four tiles, loading them inside a for loop. Now, the next thing we have to do is set up a handful of map and tile variables to be able to draw the map correctly. This ones should be pretty self-explanatory: besides height and width of the tiles and our tilemap, we also have the size of the region of tiles to display. The two offset variables are used to define the point where we will start drawing out tilemap. You might want to play a little with these variables to see their effects. Now, to the map structure itself:
26+<source lang="lua">
27+map={
28+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
29+ { 0, 1, 0, 0, 2, 2, 2, 0, 3, 0, 3, 0, 1, 1, 1, 0, 0, 0, 0, 0},
30+ { 0, 1, 0, 0, 2, 0, 2, 0, 3, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0},
31+ { 0, 1, 1, 0, 2, 2, 2, 0, 0, 3, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
32+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
33+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0},
34+ { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
35+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
36+ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
37+ { 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
38+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
39+ { 0, 2, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0},
40+ { 0, 2, 0, 0, 0, 3, 0, 3, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0},
41+ { 0, 2, 0, 0, 0, 3, 0, 3, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0},
42+ { 0, 2, 2, 2, 0, 3, 3, 3, 0, 1, 1, 1, 0, 2, 2, 2, 0, 0, 0, 0},
43+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
44+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
45+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
46+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
47+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
48+}
49+</source>
50+
51+
52+As you can see, not much magic here, we just define a 2d table where each number represents an index of our tile table. In our example, the zero represents grass, the one represents dirt, the two represents stone and the three represents water. Obviously, your tiles may represent whatever you want, even parts of a bigger structure if you so desire.
53+Let's continue:
54+<source lang="lua">
55+function draw_map()
56+ for y=1, map_display_h do
57+ for x=1, map_display_w do
58+ love.graphics.draw(
59+ tile[map[y+map_y][x+map_x]],
60+ (x*tile_w)+map_offset_x,
61+ (y*tile_h)+map_offset_y )
62+ end
63+ end
64+end
65+</source>
66+
67+
68+To keep our <code>[[love.draw]]</code> callback clean, I decided to move our little map drawing routine its own function. Again, nothing really impressive here, we just go through our map table, checking every column (x values) for each row (y values). You can draw as many tiles as you want, just change the <code>map_display_h</code> and <code>map_display_w</code> variables accordingly. Just note that if you give them too high values you'll start drawing tiles off-screen, wasting time and resources. You can change the coordinates of the region to be drawn just by changing the <code>map_x</code> and <code>map_y</code> values.
69+
70+Obviously, you have to call <code>draw_map()</code> in your <code>[[love.draw]]</code> callback. If you run your example right now, you should see our little tilemap on screen. You can't do any scrolling right now, but we'll get onto that right now, adding the following to our <code>[[love.keypressed]]</code> callback:
71+<source lang="lua">
72+function love.keypressed(key, unicode)
73+ if key == 'up' then
74+ map_y = map_y-1
75+ if map_y < 0 then map_y = 0; end
76+ end
77+ if key == 'down' then
78+ map_y = map_y+1
79+ if map_y > map_h-map_display_h then map_y = map_h-map_display_h; end
80+ end
81+
82+ if key == 'left' then
83+ map_x = math.max(map_x-1, 0)
84+ end
85+ if key == 'right' then
86+ map_x = math.min(map_x+1, map_w-map_display_w)
87+ end
88+end
89+</source>
90+
91+
92+This is fairly simple: first, we check if the arrow keys are being pressed and we update the <code>map_x</code> and <code>map_y</code> variables accordingly. Remember, here we're talking on tile coordinates so when we're increasing or decreasing <code>map_x</code> or <code>map_y</code> by one, we're actually moving 64 px (the size of a single tile). Finally, to avoid off-map scrolling, we include some boundary checking code. The ''y''-coordinates shows a simple way of checking the boundaries while the boundary checks for ''x''-coordinates use a more concise variant.
93+
94+<source lang="lua">
95+function love.draw()
96+ draw_map()
97+end
98+</source>
99+
100+Finally, we use our draw_map () that we created earlier to actually display the tiles.
101+
102+Now go and run your script. Isn't LÖVE cool? You bet it is, congratulations on making your first tilemap scroller!
103+While this little example should be enough to get you up and running, there are quite a few possible enhancements:
104+* Writing our maps by hand is a little stupid, we should make them with tools like [[Tiled]] and load them in our game.
105+* Drawing characters inside the tilemap.
106+* Fine scrolling: As you probably noticed, the map scrolls tile by tile and you probably don't want that if you need to move your characters/object pixel by pixel. ([[Tutorial:Fine_Tile-based_Scrolling|Example]])
107+* Multi-layered maps: Most real tile engines are able to render more than one layer. Together with fine scrolling, you would be able to scroll a near layer at a certain speed and move another one behind it more slowly.
108+* Character to map collisions.
109+
110+== See Also ==
111+[[Tutorial:Fine_Tile-based_Scrolling|Fine Tile-based Scrolling]]<br>
112+[[Tutorial:Efficient_Tile-based_Scrolling|Efficient Tile-based Scrolling]]
113+
114+[[Category:Tutorials]]
115+
116+{{#set:LOVE Version=0.6.0}}
117+{{#set:Description=Tile-based Scrolling}}
118+
119+== Other languages ==
120+{{i18n|Tutorial:Tile-based_Scrolling Functions}}
\ No newline at end of file
--- /dev/null
+++ b/mediawiki/Tutorials/Tutorial_Using Input.txt
@@ -0,0 +1,140 @@
1+Capturing input events with LÖVE is really easy; in this [[:Category:Tutorials|tutorial]] we'll cover how to capture keyboard and mouse events using both object methods and [[:Category:Callbacks|callbacks]]. We'll start our tutorial by putting together an almost empty LÖVE program:
2+<source lang="lua">
3+local text
4+
5+function love.load()
6+ love.graphics.setNewFont(12)
7+ text = "Nothing yet"
8+end
9+
10+function love.update(dt)
11+
12+end
13+
14+function love.draw()
15+ love.graphics.print( text, 330, 300 )
16+end
17+</source>
18+
19+==Capturing keyboard events==
20+The easiest way to know if the user is pressing a key is calling the <code>[[love.keyboard.isDown]]</code> method, which has the following syntax:
21+<source lang="lua">
22+love.keyboard.isDown( key )
23+</source>
24+The key parameter is a string representing the key we want to see if it's currently pressed. A simple example:
25+<source lang="lua">
26+if love.keyboard.isDown( " " ) then
27+ text = "The SPACE key is held down!"
28+end
29+</source>
30+You can find the complete list of keys [[KeyConstant|here]]. The best place to perform this check is inside the <code>[[love.update]]</code> [[:Category:Callbacks|callback]]: that way we're able to get input from the user and update our variables before drawing our stuff into the screen. So, our modified <code>[[love.update]]</code> callback should look like this:
31+<source lang="lua">
32+function love.update(dt)
33+ if love.keyboard.isDown( " " ) then
34+ text = "The SPACE key is held down!"
35+ end
36+end
37+</source>
38+While this is fine and dandy if we only need to know which key or keys are currently pressed, we might also need to specify different behaviors when a certain key is pressed and/or released. An elegant way of doing this is using the keyboard callbacks <code>[[love.keypressed]]</code> and <code>[[love.keyreleased]]</code>. They work in a similar way of the already known <code>[[love.update]]</code> or <code>[[love.draw]]</code> callbacks, executing our code every time that event is triggered. For example:
39+<source lang="lua">
40+function love.keypressed( key )
41+ if key == "return" then
42+ text = "RETURN has been pressed!"
43+ end
44+end
45+
46+function love.keyreleased( key )
47+ if key == "return" then
48+ text = "RETURN has been released!"
49+ end
50+end
51+</source>
52+As you can see, these two callbacks will provide you a key variable which you can use to check if a given key has been pressed, released or both. Up to this point, our source file should look like this:
53+<source lang="lua">
54+function love.load()
55+ love.graphics.setFont(12)
56+ text = "Nothing yet"
57+end
58+
59+function love.update(dt)
60+ if love.keyboard.isDown( " " ) then
61+ text = "The SPACE key is held down!"
62+ end
63+end
64+
65+function love.draw()
66+ love.graphics.print( text, 330, 300 )
67+end
68+
69+function love.keypressed( key )
70+ if key == "return" then
71+ text = "RETURN is being pressed!"
72+ end
73+end
74+
75+function love.keyreleased( key )
76+ if key == "return" then
77+ text = "RETURN has been released!"
78+ end
79+end
80+</source>
81+
82+==Capturing mouse events==
83+So, we already know how to interact with our users through a keyboard. But what about that little rodent that sits on their desks? Well, mouse input works in a fairly similar way: we have a <code>[[love.mouse.isDown]]</code> method and the <code>[[love.mousepressed]]</code> and <code>[[love.mousereleased]]</code> callbacks. Let's add a few lines to our <code>[[love.update]]</code> callback:
84+<source lang="lua">
85+if love.mouse.isDown("r") then
86+ text = "Right mouse button has been pressed"
87+end
88+</source>
89+As you can see, it's very similar to the <code>[[love.keyboard.isDown]]</code> and, again, you can see the full list of mouse-related parameters [[MouseConstant|here]]. You can even check if the mouse wheel has been rolled up or down using this method. We also have two handy methods to know the current position of the mouse pointer inside our game window: <code>[[love.mouse.getX]]</code> and <code>[[love.mouse.getY]]</code>. Each one will return the current coordinate of the mouse pointer. Let's see an example by adding these line to the beginning of our <code>love.update</code> callback:
90+<source lang="lua">
91+mouse_x = love.mouse.getX()
92+mouse_y = love.mouse.getY()
93+</source>
94+And this line to our <code>love.draw</code> callback:
95+<source lang="lua">
96+love.graphics.print( "Mouse X: ".. mouse_x .. " Mouse Y: " .. mouse_y, 10, 20 )
97+</source>
98+
99+The <code>[[love.mousepressed]]</code> and <code>[[love.mousereleased]]</code> callbacks work in a very similar way as their keyboard counterparts:
100+<source lang="lua">
101+function love.mousepressed(x, y, button)
102+ if button == 1 then -- "Versions prior to 0.10.0 use the MouseConstant 'l'"
103+ text = "Left mouse button has been pressed"
104+ end
105+end
106+
107+function love.mousereleased(x, y, button)
108+ if button == 1 then -- "Versions prior to 0.10.0 use the MouseConstant 'l'"
109+ text = "Left mouse button has been released"
110+ end
111+end
112+</source>
113+A cool feature of this callback is that you can know not only if a button has been pressed but also the position of the mouse pointer when the user pressed the button. This can be really useful if you need to put together some basic user interface elements like buttons or other objects that can interact with the mouse. A simple example:
114+<source lang="lua">
115+function love.mousepressed(x, y, button)
116+ if button == 'l' then
117+ text = "Left mouse button has been pressed at X:"..x.." Y: "..y
118+ end
119+end
120+</source>
121+Finally, we have another two useful mouse-related methods: <code>[[love.mouse.setVisible]]</code> and <code>[[love.mouse.isVisible]]</code>. The first one will let you hide or show the mouse pointer and the second one will obviously let you know if the mouse pointer is visible or not. Let's add even more code to our <code>[[love.keypressed]]</code> callback:
122+<source lang="lua">
123+if key == 'h' then
124+ if love.mouse.isVisible() then
125+ love.mouse.setVisible(false)
126+ else
127+ love.mouse.setVisible(true)
128+ end
129+ -- OR:
130+ -- love.mouse.setVisible(not love.mouse.isVisible())
131+end
132+</source>
133+In these few lines we check if the mouse pointer is visible or not and then we change its visibility: if it's visible we hide it and if it's already hidden we then show it. Fairly easy, isn't it?
134+
135+[[Category:Tutorials]]
136+{{#set:LOVE Version=0.6.0}}
137+{{#set:Description=Using Input}}
138+
139+== Other Languages ==
140+{{i18n|Tutorial:Using Input}}
\ No newline at end of file
Show on old repository browser