Full Code of miko/Love2d-samples for AI

master 50a8b4b43d51 cached
47 files
64.7 KB
21.7k tokens
1 requests
Download .txt
Repository: miko/Love2d-samples
Branch: master
Commit: 50a8b4b43d51
Files: 47
Total size: 64.7 KB

Directory structure:
gitextract_xy8xzx00/

├── CodeCapture/
│   ├── CodeCapture.lua
│   ├── README.md
│   └── main.lua
├── CollisionExample/
│   ├── README.md
│   └── main.lua
├── Fireworks/
│   ├── Firework.lua
│   ├── FireworkEngine.lua
│   ├── Particle.lua
│   ├── README.md
│   ├── Vector.lua
│   ├── class.lua
│   └── main.lua
├── GameOfLife/
│   ├── Readme.md
│   └── main.lua
├── LICENSE
├── MikoIntroScreen/
│   ├── Intro.lua
│   ├── README.md
│   ├── class.lua
│   ├── conf.lua
│   ├── main.lua
│   └── zero-project - 01 - Celtic dream.ogg
├── Minefield/
│   ├── conf.lua
│   ├── main.lua
│   └── menu.lua
├── Obey/
│   ├── B.lua
│   ├── Char.lua
│   ├── E.lua
│   ├── O.lua
│   ├── README.md
│   ├── Y.lua
│   ├── class.lua
│   └── main.lua
├── README.md
├── SidescrollerCollision/
│   ├── README.md
│   └── main.lua
├── SpriteSheet/
│   ├── README.md
│   ├── SpriteSheet.lua
│   └── main.lua
├── TexturedPolygon/
│   ├── README.md
│   └── main.lua
└── VerbNounParser/
    ├── Console.lua
    ├── Door.lua
    ├── Key.lua
    ├── Parser.lua
    ├── README.md
    ├── Window.lua
    └── main.lua

================================================
FILE CONTENTS
================================================

================================================
FILE: CodeCapture/CodeCapture.lua
================================================
local M={}
M.KONAMI={'up','up','down','down','left','right','left','right','b','a'}

local STATES={}
local CURRSTATE

local function setNextState(char, state)
  if not state then 
    state=STATES
  end
  if not state[char] then
    state[char]={}
  end
  return state[char]
end

local function getNextState(char, state)
  if not state then 
    state=STATES
  end
  return state[char]
end

function M.setCode(c, fn)
  if type(c)=='string' then
    local c2={}
    for char in c:gmatch('.') do c2[#c2+1]=char end
    c=c2
  end
  local st
  for k,v in ipairs(c) do
    st=setNextState(v, st)
  end
  st.done=fn
end

function M.keypressed(a)
  CURRSTATE=getNextState(a, CURRSTATE)
  if CURRSTATE then
    if CURRSTATE.done then
      CURRSTATE.done()
      CURRSTATE=nil
    else
      --tracking...
    end
  else
    -- start from beginning
    CURRSTATE=getNextState(a)
  end
end

return M



================================================
FILE: CodeCapture/README.md
================================================
CodeCapture
===========

This sample is inspired by the [KonamiCode] thread.

This is a simple library, which can be used to register a sequence of codes (key and/or mouse pressess), ofr which the given function should be called.

The code is implemented as a simple finite state machine, so you can register many different codes at the same time, and if they share a common prefix, they also share the state.

This sample has several magic codes:

  *  "qwerty"
  *  "second"
  *  "secundo"
  *  KONAMI (UP UP DOWN DOWN LEFT RIGHT LEFT RIGHT b a)
  *  a MOUSE-LEFT b MOUSE-RIGHT
  *  "quit" and "exit"

Each sequence causes the change of text displayed, except the last ones, which quit the program.

[KonamiCode]: http://love2d.org/forums/viewtopic.php?f=5&t=2632



================================================
FILE: CodeCapture/main.lua
================================================
local CodeCapture=require 'CodeCapture'

function love.load()
  CodeCapture.setCode("qwerty", function() MODE='ONE' end)
  CodeCapture.setCode('second', function() MODE='TWO' end)
  CodeCapture.setCode('secundo', function() MODE='DUO' end)
  CodeCapture.setCode(CodeCapture.KONAMI, function() MODE='KONAMI' end)
  CodeCapture.setCode({'a','mouse-l','b','mouse-r'}, function() MODE='WITH MOUSE' end)
  CodeCapture.setCode('quit', function() love.event.quit() end)
  CodeCapture.setCode('exit', function() love.event.quit() end)

  MODE='NONE'
end

function love.draw()
  love.graphics.print(MODE, 10, 10)
end

function love.keypressed(a,b)
  CodeCapture.keypressed(a)
end

function love.mousepressed(x,y,b)
  CodeCapture.keypressed('mouse-'..b)
end



================================================
FILE: CollisionExample/README.md
================================================
Collision example
===========

This sample is inspired by the [RestrictRectangleMovement] thread.

The sample illustrates (in just one of many ways) how you can restrict movement
of your cursor (character) to stay on screen and not go thru other obstacles.

How the collision works.
========================

Every new frame function love.update() checks if any of the arrow keys is pressed, and if so, computes the new position of the character, keeping the old position ofr reference. Then the function checks if this new position is off-screen (by calling isOnScreen()), or if the character at this new position collides with any other object. If there is collision, then the move is not allowed, so the previously stored position is recalled, and the new position is discarded.

Every object has its position x,y and its size - width w and height. So the collision is detected when any two rectangles collide.

[RestrictRectangleMovement]: http://love2d.org/forums/viewtopic.php?f=3&t=5072



================================================
FILE: CollisionExample/main.lua
================================================
local lg=love.graphics
function love.load()
  W, H=lg.getWidth(), lg.getHeight()
  local w,h=40,40
  Obstacles={}
  for i=1,20 do
    table.insert(Obstacles, {x=math.random(W-w), y=math.random(H-h), w=w, h=h})
  end
  w,h=20,20
  Cursor={x=math.random(W-w), y=math.random(H-h), w=w, h=h}
  while isColliding() do
    Cursor.x, Cursor.y=math.random(W-w), math.random(H-h)
  end
  collision=false
end

function love.draw()
  lg.setColor(255,0,0,255)
  for k,v in ipairs(Obstacles) do
    lg.rectangle('fill', v.x, v.y, v.w, v.h)
  end
  lg.setColor(0, 255,0,255)
  lg.rectangle('fill', Cursor.x, Cursor.y, Cursor.w, Cursor.h)
  lg.setColor(255, 255,255,255)
  if collision then
    lg.print('COLLISION!!!', W/2, 0)
  end

end

local isDown=love.keyboard.isDown
function love.update(dt)
  local dx,dy=0,0
  if isDown('right') or isDown('d') then
    dx=1
  elseif isDown('left') or isDown('a') then
    dx=-1
  elseif isDown('up') or isDown('w') then
    dy=-1
  elseif isDown('down') or isDown('s') then
    dy=1
  end
  local currX, currY=Cursor.x, Cursor.y
  Cursor.x, Cursor.y=Cursor.x+dx, Cursor.y+dy
  collision=false
  if not isOnScreen() or isColliding() then
    Cursor.x, Cursor.y=currX, currY
    collision=true
  end
end

function isOnScreen()
  if Cursor.x>0 and Cursor.x+Cursor.w<W and
     Cursor.y>0 and Cursor.y+Cursor.h<H then
    return true
  else
    return false
  end
end

function isCollidingWith(obj)
  local ox, oy=obj.x-Cursor.x, obj.y-Cursor.y -- let's pretent Cursor is at (0,0)
  if ox+obj.w<0 or oy+obj.h<0 or
    ox>Cursor.w or oy>Cursor.h then
    return false
  else
    return true
  end
end

function isColliding()
  for k,v in ipairs(Obstacles) do
    if isCollidingWith(v) then
      return true
    end
  end
  return false
end


================================================
FILE: Fireworks/Firework.lua
================================================
require 'class'
local Vector=require 'Vector'
local Particle=require 'Particle'
STATE={ROCKET=1, EXPLODE=2, LIVE=3, DEAD=4}

local M=class(function(self, x, y)
  self.Position=Vector(x, y)
  self.state=STATE.ROCKET
  self.Particles={}
  self.numParticles=math.random(150, 450)
  self.elapsed=0
  self.R=math.random(50, 255)
  self.G=math.random(50, 255)
  self.B=math.random(50, 255)
  self.StartPosition=Vector(math.random(0, love.graphics.getWidth()), love.graphics.getHeight())
  self.elapsed=0
  self.livetime=math.random(3,20)/10
end)

function M:update(dt)
  self.elapsed=self.elapsed+dt
  local state=self.state
  if state==STATE.LIVE or state==STATE.EXPLODE then
    if state==STATE.EXPLODE then
      for i=1,math.random(50,120) do
        self:addParticle(self.Position.x, self.Position.y)
      end
      if #self.Particles>= self.numParticles then
        self.state=STATE.LIVE
      end
    end

    for k=#self.Particles,1,-1 do
     local p=self.Particles[k]
     if p:isDead() then
       table.remove(self.Particles, k) 
     else
       p:update(dt)
     end
    end
    if state==STATE.LIVE and #self.Particles==0 then
      self.state=STATE.DEAD
    end
  elseif state==STATE.DEAD then
    return
  elseif state==STATE.ROCKET then
    local pct=self.elapsed/self.livetime*100
    if pct>=100 then
      self.elapsed=0
      self.state=STATE.EXPLODE
    end
  else
    error('UNKNOWN STATE: '..state)
  end
end

function M:draw()
  if self.state==STATE.ROCKET then
    local pct=self.elapsed/self.livetime
    local d=(self.StartPosition-self.Position)*pct
    local d2=(self.StartPosition-self.Position)*(pct+0.03)
    local pos1=self.StartPosition-d
    local pos2=self.StartPosition-d2
    
    love.graphics.setColor(self.R, self.G, self.B, 255)
    love.graphics.setLineWidth(3)
    love.graphics.line(pos1.x, pos1.y, pos2.x, pos2.y)
    love.graphics.circle('fill', self.StartPosition.x, self.StartPosition.y, 10, 10)
  else
    for k,v in ipairs(self.Particles) do
      v:draw()
    end
  end
end

function M:isDead()
  return self.state==STATE.DEAD
end

function M:addParticle(x, y)
  table.insert(self.Particles, Particle(x, y, self.R, self.G, self.B))
end

return M


================================================
FILE: Fireworks/FireworkEngine.lua
================================================
require 'class'
Firework=require 'Firework'

local M=class(function(self)
  self.Fireworks={}
end)

function M:update(dt)
  for k=#self.Fireworks,1,-1 do
    local f=self.Fireworks[k]
    if f:isDead() then
      table.remove(self.Fireworks, k)
    else
      f:update(dt)
    end
  end
end

function M:draw()
  for k,v in ipairs(self.Fireworks) do
    v:draw()
  end
  love.graphics.setColor(255,255,255,255)
  love.graphics.print('Fireworks: '..#self.Fireworks, 10, 10)
end

function M:addFirework(x, y)
  table.insert(self.Fireworks, Firework(x, y))
end

return M



================================================
FILE: Fireworks/Particle.lua
================================================
require 'class'
local Vector=require 'Vector'
local lg=love.graphics

local M=class(function(self, x, y, R, G, B, v)
  self.dead=false
  self.Position=Vector(x, y)
  self.Velocity=Vector(math.random(10,50),0):rotate(math.random(0, 360))
  self.elapsed=0
  self.livetime=math.random(20,50)/10
  self.R=R or math.random(50, 255)
  self.G=G or math.random(50, 255)
  self.B=B or math.random(50, 255)
  self.variable=v or 'R'
  self[self.variable]=math.random(50, 255)
end)

function M:update(dt)
  self.elapsed=self.elapsed+dt
  self.Position=self.Position+self.Velocity*dt
  self.Velocity=self.Velocity+Vector(0,50)*dt
  if self.elapsed>=self.livetime then
    self.dead=true
  end
end

function M:isDead()
  return self.dead
end

function M:draw()
  local alpha=math.ceil(255-255*(self.elapsed/self.livetime))
  if alpha<0 then alpha=0 end
  lg.setColor(self.R, self.G, self.B, alpha)
  lg.circle('fill', self.Position.x, self.Position.y, 2, 7)
end
return M



================================================
FILE: Fireworks/README.md
================================================
Fireworks example
==============

This is an example of fireworks, inspired by the [facepunch] thread, which is mentioned in [love2d] forum.

Nothing complicated here, just keep clicking with lefto mouse button.

[love2d]: http://love2d.org/forums/viewtopic.php?f=3&t=3909
[facepunch]: http://www.facepunch.com/threads/1136691



================================================
FILE: Fireworks/Vector.lua
================================================
require 'class'

local M=class(function(self, x, y)
  self.x=x or 0
  self.y=y or 0
end)

function M:isVector()
  return getmetatable(self)==M
end

function M:__add(v)
  return M(self.x+v.x, self.y+v.y)
end

function M:__sub(v)
  return M(self.x-v.x, self.y-v.y)
end

function M:__mul(m)
  if type(self)=='number' and M.isVector(m) then
    self, m=m, self
  end
  if type(m)=='number' then
    return M(self.x*m, self.y*m)
  else
    return self.x*m.x+self.y*m.y
  end
end

function M:len()
  return (self*self)^0.5
end

function M:rotate(phi)
  phi=math.rad(phi)
  local c, s = math.cos(phi), math.sin(phi)
  self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
  return self
end


function M:__tostring()
  return string.format('<%s,%s>', self.x, self.y)
end

return M


================================================
FILE: Fireworks/class.lua
================================================
--[[
-- $Id: class.lua 10 2008-07-01 22:18:32Z basique $
-- Simple class implementation
-- Taken from http://lua-users.org/wiki/SimpleLuaClasses
-- Original author unknown
--]]


function class(base,ctor)
  local c = {}     -- a new class instance
  if not ctor and type(base) == 'function' then
      ctor = base
      base = nil
  elseif type(base) == 'table' then
   -- our new class is a shallow copy of the base class!
      for i,v in pairs(base) do
          c[i] = v
      end
      c._base = base
  end
  -- the class will be the metatable for all its objects,
  -- and they will look up their methods in it.
  c.__index = c

  -- expose a ctor which can be called by <classname>(<args>)
  local mt = {}
  mt.__call = function(class_tbl,...)
    local obj = {}
    setmetatable(obj,c)
	if ctor then
       ctor(obj,...)
    else
    -- make sure that any stuff from the base class is initialized!
       if base and base.init then
         base.init(obj,...)
       end
    end
    return obj
  end
  c.init = ctor
  c.is_a = function(self,klass)
      local m = getmetatable(self)
      while m do
         if m == klass then return true end
         m = m._base
      end
      return false
    end
  setmetatable(c,mt)
  return c
end


================================================
FILE: Fireworks/main.lua
================================================
FireworkEngine=require 'FireworkEngine'
function love.load()
  FE=FireworkEngine()
  love.graphics.setBlendMode('additive')
end

function  love.update(dt)
  FE:update(dt)
end

function love.draw()
  FE:draw()
end

function love.mousepressed(x, y, b)
  if b=='l' then
    FE:addFirework(x, y)
  end
end

function love.keypressed(k)
  if k=='q' or k=='escape' then
    love.event.quit()
  end
end



================================================
FILE: GameOfLife/Readme.md
================================================
Game of Life
============

Game of Life inspired by [this thread](http://love2d.org/forums/viewtopic.php?f=4&t=2858)

Controls:

    0, 1, 2 - set cell border width
    left,right - decrease/increase no of columns
    up, down - decrease/increase no of rows
    +/- - increase/decrease cell size
    n - next cell generation
    r,space - toggle running mode
    c - clear the table
    x - make some random cells alive
    q,escape - quit
    left mouse button - toggle cell dead/alive
    right mouse button - check the status of a cell

Sample screenshot:
------------------

![Screenshot](../../raw/master/GameOfLife/life.png)


================================================
FILE: GameOfLife/main.lua
================================================
-- Game of Life by miko
-- Controls:
-- 0, 1, 2 - set cell border width
-- left,right - decrease/increase no of columns
-- up, down - decrease/increase no of rows
-- +/- - increase/decrease cell size
-- n - next cell generation
-- r,space - toggle running mode
-- c - clear the table
-- x - make some random cells alive
-- q,escape - quit
-- left mouse button - toggle cell dead/alive
-- right mouse button - check the status of a cell

local lg=love.graphics

function love.load()
  rows, cols=30,30
  cellsize=20
  lineWidth=1+1
  elapsed=0
  tick=0.1
  canvas=lg.newCanvas()
  lg.setNewFont(20)
  status=nil
  init()
end

function init()
  CELLS={}
  for c=1,cols do
    CELLS[c]={}
    for r=1,cols do
      CELLS[c][r]=false
    end
  end
  generation=1
end

function love.draw()
  if not cached then
    cached=true
    lg.setCanvas(canvas)
    if lineWidth>0 then
      lg.setLineWidth(lineWidth)
    end
    for c=1,cols do
      for r=1,rows do
        local cell=CELLS[c][r]
        if cell then
          lg.setColor(255,0,0,255)
        else
          lg.setColor(0,0,0,255)
        end
        lg.rectangle('fill', (c-1)*cellsize, (r-1)*cellsize, cellsize, cellsize)
        if lineWidth>0 then
          lg.setColor(255,255,255,255)
          lg.rectangle('line', (c-1)*cellsize, (r-1)*cellsize, cellsize, cellsize)
        end
      end
    end
    lg.setCanvas()
  end
  lg.setColor(255,255,255,255)
  lg.draw(canvas, 0, 0, 0)
  local msg=string.format("Cols=%d Rows=%d CellSize=%d Gen=%d %s RUNNING FPS=%d ", cols, rows, cellsize, generation, running and '' or 'NOT', love.timer.getFPS())
  if status then msg=msg.."\n"..status end

  lg.setColor(0,255,0,255)
  lg.print(msg, 0,0,0)
  lg.setColor(0,0,255,255)
  lg.print(msg, 1,1,0)
  lg.setColor(255,0,0,255)
  lg.print(msg, 2,2,0)
end

function mouse2cell(x, y)
  local cx, cy=math.floor(x/cellsize), math.floor(y/cellsize)
  if cx>=0 and cx<cols and cy>=0 and cy<rows then
    return cy+1, cx+1
  end
end

function love.update(dt)
  if not running then return end
  elapsed=elapsed+dt
  if elapsed>=tick then
    elapsed=elapsed-tick
    nextGeneration()
    cached=nil
  end
end

function love.mousepressed(x, y, b)
  --local cx, cy=mouse2cell(x, y)
  local mr, mc=mouse2cell(x, y)
  status=nil
  if mr then
    if b=='l' then
      CELLS[mc][mr]=not CELLS[mc][mr] 
      status=string.format('Cell c=%d,r=%d changed to %s', mc, mr, CELLS[mc][mr] and 'ALIVE' or 'DEAD')
    elseif b=='r' then
      status=string.format('Cell c=%d,y=%d %s neighbours: %d', mc, mr, CELLS[mc][mr] and 'ALIVE' or 'DEAD', countNeighbours(mc, mr))
    end
    cached=nil
  end
  
end

function love.keypressed(a, b)
  if a=='q' or a=='escape' then
    love.event.push("q")
  end
  if a=='r' or a==' ' then
    running=not running
  end
  if a=='n' then
    nextGeneration()
    cached=nil
  end
  if a=='c' then
    init()
    cached=nil
  end
  if a=='1' or a=='2' or a=='0' then
    lineWidth=tonumber(a)
    cached=nil
  end
  if a=='down' then
    rows=rows+1
    cached=nil
    init()
  end
  if a=='up' then
    rows=rows-1
    cached=nil
    init()
  end
  if a=='right' then
    cols=cols+1
    cached=nil
    init()
  end
  if a=='left' then
    cols=cols-1
    cached=nil
    init()
  end
  if a=='+' or a=='=' then
    cellsize=math.min(cellsize+1, 30)
    cached=nil
  end
  if a=='-' or a=='_' then
    cellsize=math.max(cellsize-1, 1)
    cached=nil
  end
  if a=='x' then
    for i=1,cols*rows*0.1 do
      CELLS[math.random(1,cols)][math.random(1, rows)]=true
    end
    cached=nil
  end
end

function countNeighbours(c, r)
  local n=0
  local cy=c
  local cx=r
  if cx>1 and cy>1 then
    if CELLS[cy-1][cx-1] then n=n+1 end
  end
  if cy>1 then
    if CELLS[cy-1][cx] then n=n+1 end
  end
  if cx<cols and cy>1 then
    if CELLS[cy-1][cx+1] then n=n+1 end
  end

  if cx>1 then
    if CELLS[cy][cx-1] then n=n+1 end
  end
  if cx<cols then
      if CELLS[cy][cx+1] then n=n+1 end
  end

  if cx>1 and cy<rows then
    if CELLS[cy+1][cx-1] then n=n+1 end
  end
  if cy<rows then
    if CELLS[cy+1][cx] then n=n+1 end
  end
  if cx<cols and cy<rows then
    if CELLS[cy+1][cx+1] then n=n+1 end
  end
  return n
end

function nextGeneration()
  generation=generation+1
  local NEWCELLS={}
  --for c, COL in ipairs(CELLS) do
  for c=1,cols do
    NEWCELLS[c]={}
    --for r, cell in ipairs(COL) do
    for r=1, rows do
      local cell=CELLS[c][r]
      --local n=countNeighbours(r, c)
      local n=countNeighbours(c, r)
      if cell then
        if n==2 or n==3 then
          NEWCELLS[c][r]=true
        else
          NEWCELLS[c][r]=false
        end
      else
        if n==3 then
          NEWCELLS[c][r]=true
        else
          NEWCELLS[c][r]=false
        end
      end

    end
  end
  CELLS=NEWCELLS
end


================================================
FILE: LICENSE
================================================
All the code within this repository is licensed under the terms of the MIT license reproduced below. So it is free to use for both personal and commercial purposes.

===============================================================================

Copyright (C) 2011 Michal Kolodziejczyk, miko@wp.pl

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

===============================================================================


================================================
FILE: MikoIntroScreen/Intro.lua
================================================
require 'class'

--love=love or {graphics={}} -- plain lua compatibility
local lg=love.graphics
if not lg.newFramebuffer then
  lg.newFramebuffer=lg.newCanvas -- love 0.8 compatilibity
end

local WIDTH, HEIGHT=lg.getWidth(), lg.getHeight()
local _SAVED={}
local iterator

local empty=function() end
local function save()
  for k,v in pairs({'draw', 'update', 'keypressed', 'keyreleased'}) do
    _SAVED[v]=love[v] or empty
  end
end

local function restore()
  for k,v in pairs(_SAVED) do
    if v==empty then
      love[k]=nil
    else
      love[k]=v
    end
  end
end

local function tween(pct, sval, eval)
  return sval+pct/100*(eval-sval)
end

local function srand(x, y)
  return math.floor(math.random(x, y))
end

local function makeSample(len, pitch)
  len=len or 0.1
  pitch=pitch or 440
  local overtime=1.5
  local tick = love.sound.newSoundData(overtime*len * 44100, 44100, 16, 1)
  for i = 0,len*44100*overtime do
    local t = i / 44100
    local sample = math.sin(t * pitch * math.pi * 2) * len
    tick:setSample(i, sample)
  end
  return tick
end

                                                        
local O=class(function(self, data, ctype)
  OBJNAME=(OBJNAME or 0)+1
  self.name=OBJNAME
  if ctype then
    self.ctype=ctype
  end
  if type(data)=='string' then
    if not ctype then
      self.ctype='text'
    end
    self.text=data or '???'
  else
    if not ctype then
      self.ctype='image'
    end
  end
  self.data=data
end)

function O:setPosition(x, y)
  self.x, self.y=x or 0, y or 0
  return self
end
function O:setRotation(r)
  self.r=r or 0
  return self
end
function O:setScale(sx, sy)
  sx=sx or 1
  if not sy then sy=sx end
  self.sx, self.sy=sx, sy
  return self
end
function O:setFont(font)
  if type(font)=='number' then
    font=self:getFont(font)
  end
  self.font=font or ''
  return self
end
function O:setColor(r, g, b, a)
  local color
  if type(r)=='table' then
    color=r
  else
    color={r, g, b, a}
  end
  self.color=color
  return self
end

function O:center()
  if self.ctype~='text' then
    return
  end
  local w=self:getFont():getWidth(self.text)
  self.x=(WIDTH-w)/2
  return self
end

function O:start()
  self._DATA={}
  if self.ctype=='text' then
    local font=self:getFont()
    local rot=self.r
    lg.setFont(font)
    local H=font:getHeight()
    local dw=0
    for c in self.text:gmatch('.') do
      local W=font:getWidth(c)
      local o={x=self.x+dw, y=self.y, sx=srand(0, WIDTH), sy=srand(0, HEIGHT), char=c}
      o.scolor={srand(0, 255), srand(0, 255),srand(0, 255)}
      o.r=rot
      o.sr=srand(0, 360*4)
      dw=dw+W
      o.fb=lg.newFramebuffer(W, H)

      o.cx, o.cy=W/2, H/2
      o.sSX=math.random(100)/10
      lg.setCanvas(o.fb)
      lg.print(c, 0, 0)
      table.insert(self._DATA, o)
    end
  elseif self.ctype=='image' then
    local o={x=self.x, y=self.y, sx=srand(0, WIDTH), sy=srand(0, HEIGHT)}
    o.r=self.r
    o.sr=srand(0, 360*4)
    local W, H=self.data:getWidth(), self.data:getHeight()
    o.cx, o.cy=W/2, H/2
    o.sSX=math.random(100)/10
    o.fb=self.data
    self._DATA[1]=o
  elseif self.ctype=='audio' then
    love.audio.play(self.data)
  end
end

function O:stop()
  if self.ctype=='audio' then
    love.audio.stop(self.data)
  end
end

function O:getFont(size)
  if not self.font then 
    lg.setNewFont(size) 
    self.font=lg.getFont() 
  end
  return self.font
end

function O:draw(pct)
  lg.setColor(255, 255, 255, 255)
  local color=self.color
  local A=tween(pct, 0, 255)
  if self.ctype=='text' then
    for k,v in ipairs(self._DATA) do
      local x=tween(pct, v.sx, v.x)
      local y=tween(pct, v.sy, v.y)
      local scolor=v.scolor

      local R=tween(pct, scolor[1], color[1])
      local G=tween(pct, scolor[2], color[2])
      local B=tween(pct, scolor[3], color[3])
      local rot=tween(pct, v.sr or 0, self.r or 0)
      local sx=tween(pct, v.sSX, 1)
      --local sy=tween(pct, v.sSY, 1)
      if self.hilited==k then
        lg.setColor(255, 255, 255, 255)
      else
        lg.setColor(R, G, B, A)
      end
      lg.push()
      lg.translate(x+v.cx, y+v.cy)
      lg.rotate(math.rad(rot))
      lg.translate(-v.cx, -v.cy)
      --lg.scale(sx, sx)
      lg.draw(v.fb, 0, 0)
      lg.pop()
    end
  elseif self.ctype=='image' then
    local v=self._DATA[1]
    local x=tween(pct, v.sx, v.x)
    local y=tween(pct, v.sy, v.y)
    local scolor=v.scolor

    --[[
    local R=tween(pct, scolor[1], color[1])
    local G=tween(pct, scolor[2], color[2])
    local B=tween(pct, scolor[3], color[3])
    --]]
    local rot=tween(pct, v.sr or 0, self.r or 0)
    local sx=tween(pct, v.sSX, 1)
    lg.setColor(255, 255, 255, A)
    --local sy=tween(pct, v.sSY, 1)
    --lg.setColor(R, G, B)
    lg.push()
    --lg.scale(sx, sx)
    lg.translate(x+v.cx, y+v.cy)
    lg.rotate(math.rad(rot))
    lg.translate(-v.cx, -v.cy)
    lg.draw(v.fb, 0, 0)
    lg.pop()
  end
end

function O:setHilited(id)
  self.hilited=id
end

function O:__tostring()
  return string.format('<Object %s %s>', self.ctype, self.name or 'unnamed')
end

local Object=O

--
local M=class(function(self)
  self.Objects={}
  self:setDuration(6)
  self:setDelay(2)
end)

function M:addText(txt)
  local obj=Object(txt)
  table.insert(self.Objects, obj)
  return obj
end

function M:addImage(filename)
  local img
  if type(filename)=='string' then
    img=lg.newImage(filename)
  else
    img=filename
  end
  local obj=Object(img)
  table.insert(self.Objects, obj)
  return obj
end

function M:addAudio(audio)
  if type(audio)=='string' then
    audio=love.audio.newSource(audio, 'static')
  end
  local obj=Object(audio, 'audio')
  table.insert(self.Objects, obj)
  return obj
end
function M:setDuration(d)
  self.duration=d or 6
  return self
end

function M:setDelay(d)
  self.delay=d or 2
  return self
end

function M:makeChaos()
  return self
end

-- len - in seconds, just before duration
function M:setBlinks(len, obj, ...)
  if not obj then return self end
  self.blink=len
  self.blinkObjects=self.blinkObjects or {}
  table.insert(self.blinkObjects, obj)
  return self:setBlinks(len, ...)
end

function M:_setupBlinks()
  local count=0
  for k,v in pairs(self.blinkObjects) do
    count=count+#v._DATA
  end
  self.blinkChars=count
  self.blinkdt=self.blink/count
  function self.nextCharIterator()
    local T=self.blinkObjects
    local objKey,obj=next(T)
    local idxKey, idx
    return function()
      idxKey, idx=next(obj._DATA, idxKey)
      if not idx then
        objKey,obj=next(T, objKey)
        if not obj then return end
        idxKey, idx=next(obj._DATA, idxKey)
      end
      return obj, idxKey, idx
    end
  end
  SAMPLES={}
  for obj, idxk, idxo in self:nextCharIterator() do
    local c=idxo.char:upper()
    if not SAMPLES[c] then
      local x=0
      if c==' ' then
        x=1
      elseif c=='!' then
        x=2
      else
        x=c:byte()-45 -- 49 for "0", 65 for "A"
      end
      SAMPLES[c]=makeSample(self.blinkdt, 2^((x-2)/12)*400)
    end
  end
end

function M:start()
  local s=self
  save()
  math.randomseed(os.time())
  love.update=function(dt) s:update(dt) end
  love.draw=function() s:draw() end
  love.keypressed=function(a, b) s:keypressed(a, b) end
  self.elapsed=0
  lg.setColor(255, 255, 255, 255)
  for k,v in ipairs(self.Objects) do
    v:start()
  end
  lg.setCanvas()
  if self.blink then
    self:_setupBlinks()
  end
  return self
end

function M:stop()
  for k,v in ipairs(self.Objects) do
    v:stop()
  end
  restore()
  return self
end

function M:keypressed(a, b)
  if a==' ' then
    self.paused=not self.paused
  else
    self:stop()
  end
end

function M:update(dt)
  if self.paused then return end
  self.elapsed=self.elapsed+dt
  if self.elapsed>self.duration+self.delay then
    self:stop()
  elseif self.elapsed>self.duration then
    if self.pct~=100 then
      self.pct=100
    end

    if self.blink and self.elapsed-self.duration<=self.blink then
      BLINKDT=(BLINKDT or 0)+dt
      if BLINKDT>self.blinkdt then
        BLINKDT=BLINKDT-self.blinkdt
        if self.objHilited then
          self.objHilited:setHilited()
        end

        --local obj=self.blinkObjects[math.random(1, #self.blinkObjects)]
        iterator=iterator or self:nextCharIterator()
        local obj, idxk, idxo=iterator()
        SRC=SRC or {}
        local src=love.audio.newSource(SAMPLES[idxo.char:upper()])
        src:setVolume(2)
        src:play()
        SRC[#SRC+1]=src
        --obj:setHilited(math.random(#obj._DATA))
        obj:setHilited(idxk)
        self.objHilited=obj
      end
    else
      if self.objHilited then
        self.objHilited:setHilited()
      end
    end

    return
  end
  self.pct=self.elapsed/self.duration*100
end

function M:draw()
  local pct=self.pct
  if not pct then return end
  for k,v in ipairs(self.Objects) do
    v:draw(pct)
  end
end

return M


================================================
FILE: MikoIntroScreen/README.md
================================================
LOVEJam Intro Screen
===========

This sample is inspired by the [LOVEJam] site.

This is a splash screen intro, and also an engine, where you can easily make similar intros for yourself.

The intro consists of some linef of texts and some images and audio files. The texts will be split by letters, and the images and letters will be put randomly, then will find their way home. Also, the letters get some random colors at the beginning.


[LOVEJam]: http://love2d.org/jam



================================================
FILE: MikoIntroScreen/class.lua
================================================
--[[
-- $Id: class.lua 10 2008-07-01 22:18:32Z basique $
-- Simple class implementation
-- Taken from http://lua-users.org/wiki/SimpleLuaClasses
-- Original author unknown
--]]


function class(base,ctor)
  local c = {}     -- a new class instance
  if not ctor and type(base) == 'function' then
      ctor = base
      base = nil
  elseif type(base) == 'table' then
   -- our new class is a shallow copy of the base class!
      for i,v in pairs(base) do
          c[i] = v
      end
      c._base = base
  end
  -- the class will be the metatable for all its objects,
  -- and they will look up their methods in it.
  c.__index = c

  -- expose a ctor which can be called by <classname>(<args>)
  local mt = {}
  mt.__call = function(class_tbl,...)
    local obj = {}
    setmetatable(obj,c)
	if ctor then
       ctor(obj,...)
    else
    -- make sure that any stuff from the base class is initialized!
       if base and base.init then
         base.init(obj,...)
       end
    end
    return obj
  end
  c.init = ctor
  c.is_a = function(self,klass)
      local m = getmetatable(self)
      while m do
         if m == klass then return true end
         m = m._base
      end
      return false
    end
  setmetatable(c,mt)
  return c
end


================================================
FILE: MikoIntroScreen/conf.lua
================================================
function love.conf(t)
	t.title = "miko lovejam intro"
	t.author = "miko"
	t.identity = "mario"
	t.screen.width = 800
	t.screen.height = 600
end


================================================
FILE: MikoIntroScreen/main.lua
================================================
local Intro=require 'Intro'
function love.load()
  I=Intro()
  local t1=I:addText('LoveJam Test Jam entry!'):setPosition(20, 50):setColor(0, 255, 0):setFont(60):center()
  local t2=I:addText('Made with Love2d'):setPosition(400, 200):setColor(0, 0, 255):setFont(30)
  local t3=I:addText('(C) 2011 miko - average Love user'):setPosition(10, 500):setColor(255,0,0):setFont(40):center()
  I:addImage('logo.png'):setPosition(200, 180)
  I:addImage('face-grin.png'):setPosition(400, 350)

  I:addAudio('zero-project - 01 - Celtic dream.ogg')
  I:setDuration(5)
  I:setDelay(5)
  I:setBlinks(2, t1, t2)
  I:start()
end

function love.update(dt)
  love.event.quit()
end
--[[
function love.keypressed(a, b)
  love.event.quit()
end
--]]


================================================
FILE: Minefield/conf.lua
================================================
function love.conf(t)
	t.modules.joystick = false
	t.modules.audio = false
	t.modules.keyboard = true
	t.modules.event = true
	t.modules.image = false
	t.modules.graphics = true
	t.modules.timer = true
	t.modules.mouse = false
	t.modules.sound = false
	t.modules.physics = false
	t.console = false
	t.title = "Minefield"
	t.author = "MiKo"
	t.screen.fullscreen = false
	t.screen.vsync = true
	t.screen.fsaa = 0
	--t.screen.height = 800
	--t.screen.width = 1024
end


================================================
FILE: Minefield/main.lua
================================================
local lg=love.graphics
ORGWIDTH, ORGHEIGHT=lg.getWidth(), lg.getHeight()
local Menu=require 'menu'

function love.load()
  ReplayDelay=0.2
  lg.setBackgroundColor(255,255,255)
  mode='menu'
  fullscreen=false
  diagonal=true
  initScreen()
  initGame()
end

function initScreen()
  W, H=lg.getWidth(), lg.getHeight()
  --CellSize=30
  CellSize=math.floor(math.min(W/25, H/25))

  CX,CY=math.floor(W/CellSize), math.floor(H/CellSize)
  BorderWidthX=(W-(CX-2)*CellSize)/2
  BorderWidthY=(H-(CY-2)*CellSize)/2
  CX,CY=CX-2,CY-2
  lg.setNewFont(CellSize)
end

function initGame()
  CenterX=math.floor(CX/2)
  PX, PY=CenterX, CY+1 -- player position
  Bombs, Visited={}, {}
  for x=1,CX do
    Bombs[x]={}
    Visited[x]={}
  end
  local bomblimit=math.floor(CX*CY/10)
  for i=1,bomblimit do
    local x,y=0,0
    repeat
      x, y=math.random(1, CX), math.random(1, CY)
    until not Bombs[x][y] and not (x==CenterX and (y==1 or y==CY))
    Bombs[x][y]=true
  end
  crashed=nil
  won=nil
  showingBombs=nil
  History={}
  elapsed=0
end

function drawCell(X, Y, Color)
  if Color then
    lg.setColor(Color)
  end
  lg.rectangle('fill', BorderWidthX+CellSize*(X-1), BorderWidthY+CellSize*(Y-1), CellSize, CellSize)
end

function drawPlayer(X, Y)
  lg.setColor(255, 255, 0)
  lg.circle('fill', BorderWidthX+CellSize*(X-0.5), BorderWidthY+CellSize*(Y-0.5), CellSize/2, CellSize)
end

function drawBomb(X, Y)
  lg.circle('fill', BorderWidthX+CellSize*(X-0.5), BorderWidthY+CellSize*(Y-0.5), CellSize/4, CellSize)
end

function drawBorders()
  lg.setColor(0, 0, 255)
  lg.rectangle('fill', 0, 0, W, BorderWidthY)
  lg.rectangle('fill', 0, H-BorderWidthY, W, BorderWidthY)
  lg.rectangle('fill', 0, 0, BorderWidthX, H)
  lg.rectangle('fill', W-BorderWidthX, 0, BorderWidthX, H)
  lg.setColor(0, 255, 0)
  drawCell(math.floor(CX/2), CY+1)
  drawCell(math.floor(CX/2), 0)
end

function drawVisited()
  lg.setColor(200, 100, 100)
  for x=1,CX do
    for y=1,CY do
      if Visited[x][y] then
        drawCell(x, y)
      end
    end
  end
end

function countBombs()
  local n=0
  if diagonal then
    for x=PX-1,PX+1 do
      for y=PY-1,PY+1 do
        if Bombs[x] and Bombs[x][y] then n=n+1 end
      end
    end
  else
    if Bombs[PX-1] and Bombs[PX-1][PY] then n=n+1 end
    if Bombs[PX+1] and Bombs[PX+1][PY] then n=n+1 end
    if Bombs[PX] and Bombs[PX][PY-1] then n=n+1 end
    if Bombs[PX] and Bombs[PX][PY+1] then n=n+1 end
  end
  return n
end

function drawMsgs()
  local n=countBombs()
  lg.setColor(255, 0, 0)
  lg.printf('Bombs: '..n, 0,0, W, 'right')
  lg.printf(string.format('Time: %d s', elapsed), 0,0, W, 'left')
  if replaying then
    lg.printf('Replaying...', 0, H/2, W, 'center')
  else
    if crashed then
      lg.printf('Bum!\n\nPress SPACE to play again, R for replay, M for menu', 0, H/2, W, 'center')
    end
    if won then
      lg.printf('Congratulations! You win in '..math.floor(elapsed)..' seconds!\n\nPress SPACE to play again, R for replay, M for menu', 0, H/2, W, 'center')
    end
  end
end

function drawBombs()
  lg.setColor(0, 0, 0)
  for x=1,CX do
    for y=1,CY do
      if Bombs[x][y] then
        drawBomb(x, y)
      end
    end
  end

end

function drawHelp()
  lg.setColor(0,0,0)
  lg.printf([[Your goal is to go from the bottom gate to the top gate of the minefield, without stepping on a mine. The counter at the top right corner shows the number of mines in all 8 neighbouring cells.

  Use cursor keys/ WASD for movement, q/ESCAPE for quit.

  In the menu you can change some options (screen resolution, etc).
  
  Press any key to return to menu, then select Play.]], W*0.2, H/5, W*0.6, 'center')
end

function love.draw()
  if mode=='help' then
    drawHelp()
    return
  elseif mode=='menu' then
    Menu:draw()
    return
  end

  drawBorders()
  drawVisited()
  drawPlayer(PX, PY)
  if showingBombs then
    drawBombs()
  end
  drawMsgs()
end

function replayGame()
  histIndex=1
  replaying=true
  Visited={}
  for x=1,CX do
    Visited[x]={}
  end
end

function love.keypressed(a, b)
  if a=='q' or a=='escape' then
    love.event.quit()
  end
  if mode=='menu' then
    Menu:keypressed(a, b)
    return
  elseif mode=='help' then
    mode='menu'
    return
  end
  if a=='b' then
    showingBombs=not showingBombs 
  end
  if replaying then return end
  if crashed or won then
    if a==' ' then
      initGame()
    end
    if a=='r' then
      replayGame()
    end
    if a=='m' then
      mode='menu'
    end
  else
    local moved
    if (a=='up' or a=='w') and (PY>1 or PX==CenterX) then PY=PY-1; moved=true end
    if (a=='down' or a=='s') and PY<CY then PY=PY+1; moved=true end
    if (a=='left' or a=='a') and PX>1 and PY<=CY then PX=PX-1; moved=true end
    if (a=='right' or a=='d') and PX<CX and PY<=CY then PX=PX+1; moved=true end
    if moved then
      table.insert(History, {PX, PY})
      if not Visited[PX][PY] then
        Visited[PX][PY]=true
      end
      if Bombs[PX][PY] then
        crashed=true
        showingBombs=true
      end
      if PY==0 then
        won=true
        showingBombs=true
      end
    end
  end
end

function love.update(dt)
  if mode=='play' and not crashed and not won then
    elapsed=elapsed+dt
  end
  if not replaying then return end
  timer=(timer or 0)+dt
  if timer>ReplayDelay then
    timer=timer-ReplayDelay
    local move=History[histIndex]
    histIndex=histIndex+1
    if not move then
      timer=nil
      replaying=nil
      histIndex=nil
    else
      PX, PY=unpack(move)
      Visited[PX][PY]=true
    end
  end
end

function resize(W, H)
  lg.setMode(W, H, fullscreen , true)
  initScreen()
end

function love.quit()
  fullscreen=false
  resize(ORGWIDTH, ORGHEIGHT)
end



================================================
FILE: Minefield/menu.lua
================================================
local lg=love.graphics
local Options={
  {name='play', title='Play the game!'},
  {name='help', title='Help'},
  {name='diagonal', title='Check diagonal positions?', options={'YES','NO'}, value='YES'},
  --{name='resolution', title='Screen resolution', options={'1280x1024', '1024x800', '800x600', '640x480', '320x240', '256x192'}, value='1024x800'},
  {name='resolution', title='Screen resolution', options={}, value=nil},
  {name='fullscreen', title='Fullscreen', options={'YES', 'NO'}, value='NO'},
  {name='quit', title='Quit'}
}
 
local modes=lg.getModes()
for k,v in ipairs(modes) do
  Options[4].options[k]=v.width..'x'..v.height
  if v.width==ORGWIDTH and v.height==ORGHEIGHT then
    Options[4].value=Options[4].options[k]
  end
end
table.insert(Options[4].options, '256x192')
if not Options[4].value then
  Options[4].value=Options[4].options[1]
end
local Menu={
  currentOption=1
}


function Menu:draw()
  for k,v in ipairs(Options) do
    if k==self.currentOption then
      lg.setColor(50,50,255)
    else
      lg.setColor(50,50,50)
    end
    if v.value then
      lg.printf(string.format('%s [%s]', v.title, v.value), 0, (2+k)*CellSize*2, W, 'center')
    else
      lg.printf(v.title, 0, (2+k)*CellSize*2, W, 'center')
    end
  end
end

function Menu:keypressed(a, b)
  if a=='up' or a=='w' then
    self.currentOption=self.currentOption-1
    if self.currentOption==0 then self.currentOption=#Options end
    return
  elseif a=='down' or a=='s' then
    self.currentOption=self.currentOption+1
    if self.currentOption>#Options then self.currentOption=1 end
    return
  elseif a=='enter' or a=='return' then
    self:onSelect(Options[self.currentOption].name)
  end
  local o=Options[self.currentOption]
  if o.options then
    local idx, previdx
    for k,v in ipairs(o.options) do
      if v==o.value then
        idx=k
        previdx=k
        break
      end
    end
    if a=='right' or a=='d' then
      idx=idx+1
      if idx>#o.options then idx=1 end
    elseif a=='left' or a=='a' then
      idx=idx-1
      if idx<1 then idx=#o.options end
    end
    if previdx~=idx then
      o.value=o.options[idx]
      self:onChange(o.name, o.value)
    end
  else
    if a=='right' or a=='left' or a=='d' or a=='a' then
      self:onSelect(o.name)
    end
  end
end

function Menu:onChange(k, v)
  if k=='resolution' then
    local w, h=v:match('(%d+)x(%d+)')
    resize(w, h)
  end
  if k=='fullscreen' then
    if v=='YES' then
      fullscreen=true
    else
      fullscreen=false
    end
    resize(W, H)
  end
  if k=='diagonal' then
    if v=='YES' then
      diagonal=true
    else
      diagonal=false
    end
  end
end
function Menu:onSelect(k)
  if k=='quit' then
    love.event.quit()
  elseif k=='play' then
    mode='play'
    initGame()
  elseif k=='help' then
    mode='help'
  end
end
return Menu



================================================
FILE: Obey/B.lua
================================================
local Char=require('Char')
local lg=love.graphics

local M=class(Char, function(self, W, H)
  Char.init(self, 'B', W, H)
  self.color={0, 255,0,255}
  local P={}
  local p=5
  for i=-90, 90, p do
    P[#P+1]=W*math.cos(math.rad(i))
    P[#P+1]=H*0.3*math.sin(math.rad(i))
  end
  self.POINTS=P
end)

function M:_draw()
  lg.setColor(self.color)
  lg.translate(-self.W/2, -self.H/5)
  lg.polygon('fill', self.POINTS)
  lg.translate(0, 2*self.H/5)
  lg.polygon('fill', self.POINTS)
  lg.translate(self.W/2, -self.H/5)
  lg.setColor(0, 0, 0, 255)
  lg.circle('fill', 0.6*self.W/2, -0.6*self.H/3, self.H/15)
  lg.circle('fill', 0.6*self.W/2, 0.6*self.H/3, self.H/15)
end

return M


================================================
FILE: Obey/Char.lua
================================================
require 'class'
local lg=love.graphics

local M=class(function(self, name, W, H)
  self.W, self.H=W, H
  self.position={0,0}
  self.rotation=0
  self._scale={1,1}
  self.name=name or 'unnamed'
end)

function M:draw()
  lg.push()
  lg.translate(self.position[1], self.position[2])
  lg.rotate(math.rad(self.rotation))
  lg.scale(self._scale[1], self._scale[2])
  --predraw
  if self._draw then
    self:_draw()
  end
  --postdraw
  lg.pop()
end

function M:setPosition(x, y)
  self.position={x, y}
  return self
end
function M:setScale(sx, sy)
  self._scale={sx, sy or sx}
  return self
end
function M:setRotation(r)
  self.rotation=r
  return self
end

function M:rotate(dr)
  local newrotation=self.rotation+dr
  if self.animated then
    self._startRotation=self.rotation
    self._endRotation=newrotation
  else
    self.rotation=newrotation
  end
  return self
end

function M:move(dx, dy)
  local newposition={self.position[1]+dx, self.position[2]+dy}
  if self.animated then
    self._startPosition=self.position
    self._endPosition=newposition
  else
    self.position=newposition
  end
  return self
end
function M:scale(dsx, dsy)
  dsy=dsy or dsx
  local newscalex=self._scale[1]*dsx
  local newscaley=self._scale[2]*dsy
  if self.animated then
    self._startScale=self._scale
    self._endScale={newscalex, newscaley}
  else
    self._scale={newscalex, newscaley}
  end
  return self
end

function M:setAnimation(duration)
  if not duration then
    self.animated=nil
  else
    self.animated=true
    self.duration=duration
    self._startPosition=self.position
    self._endPosition=self.position
    self._startRotation=self.rotation
    self._endRotation=self.rotation
    self._startScale=self.scale
    self._endScale=self.scale
  end
  return self
end

function M:update(dt)
  if not self.animated then return end
  if not self._elapsed then
    self._elapsed=0
  else
    self._elapsed=self._elapsed+dt
  end
  if self._elapsed>=self.duration then
    self.animated=nil
    self._scale=self._endScale
    self.position=self._endPosition
    self.rotation=self._endRotation 
    self:onAnimationFinished()
  else
    local pct=self._elapsed/self.duration
    self.rotation=self._startRotation*(1-pct)+self._endRotation*pct
    self._scale={
      self._startScale[1]*(1-pct)+self._endScale[1]*pct,
      self._startScale[2]*(1-pct)+self._endScale[2]*pct
    }
    self.position={
      self._startPosition[1]*(1-pct)+self._endPosition[1]*pct,
      self._startPosition[2]*(1-pct)+self._endPosition[2]*pct
    }
  end
end

function M:onAnimationFinished()
end
return M


================================================
FILE: Obey/E.lua
================================================
local Char=require('Char')
local lg=love.graphics

local M=class(Char, function(self, W, H)
  Char.init(self, 'E', W, H)
  self.color={0, 0, 255,255}
end)

function M:_draw()
  lg.setColor(self.color)
  local H2=self.H/2
  local W2=self.W/2
  local w=math.min(self.W/10, self.H/10)
  lg.setLineWidth(2*w)
  lg.line(W2,-H2+w, -W2+w,-H2+w, -W2+w,0, W2,0, -W2+w,0, -W2+w,H2-w, W2,H2-w)
end

return M


================================================
FILE: Obey/O.lua
================================================
local Char=require('Char')
local lg=love.graphics

local M=class(Char, function(self, W, H)
  Char.init(self, 'O', W, H)
  self.color={255,255,0,255}
  self.dx=1.1*self.W/2*math.cos(math.rad(45))
  self.dy=-1.1*self.H/2*math.sin(math.rad(45))
end)

function M:_draw()
  lg.setColor(self.color)
  lg.circle('fill', 0, 0, self.W/2, self.W/2 )
  lg.circle('fill', self.dx, self.dy, 0.1*self.W, self.W/2 )
  lg.circle('fill', -self.dx, self.dy, 0.1*self.W, self.W/2 )
end

return M


================================================
FILE: Obey/README.md
================================================
Obeying avatar
===========

This sample is inspired by the [AngryLovers] thread.

It creates an avatar animation. The key here is to [obey].


[AngryLovers]: http://love2d.org/forums/viewtopic.php?f=5&t=4573
[obey]: http://love2d.org/forums/viewtopic.php?f=3&t=9



================================================
FILE: Obey/Y.lua
================================================
local Char=require('Char')
local lg=love.graphics

local M=class(Char, function(self, W, H)
  Char.init(self, 'Y', W, H)
  self.color={0,0,255, 255}
end)

function M:_draw()
  lg.setColor(self.color)
  local W2=self.W/2
  local H2=self.H/2
  local w=math.min(self.W/10, self.H/10)
  lg.setLineWidth(2*w)
  lg.line(-W2,-H2, 0,0, 0,H2, 0,0, W2,-H2)
end

return M


================================================
FILE: Obey/class.lua
================================================
--[[
-- $Id: class.lua 10 2008-07-01 22:18:32Z basique $
-- Simple class implementation
-- Taken from http://lua-users.org/wiki/SimpleLuaClasses
-- Original author unknown
--]]


function class(base,ctor)
  local c = {}     -- a new class instance
  if not ctor and type(base) == 'function' then
      ctor = base
      base = nil
  elseif type(base) == 'table' then
   -- our new class is a shallow copy of the base class!
      for i,v in pairs(base) do
          c[i] = v
      end
      c._base = base
  end
  -- the class will be the metatable for all its objects,
  -- and they will look up their methods in it.
  c.__index = c

  -- expose a ctor which can be called by <classname>(<args>)
  local mt = {}
  mt.__call = function(class_tbl,...)
    local obj = {}
    setmetatable(obj,c)
	if ctor then
       ctor(obj,...)
    else
    -- make sure that any stuff from the base class is initialized!
       if base and base.init then
         base.init(obj,...)
       end
    end
    return obj
  end
  c.init = ctor
  c.is_a = function(self,klass)
      local m = getmetatable(self)
      while m do
         if m == klass then return true end
         m = m._base
      end
      return false
    end
  setmetatable(c,mt)
  return c
end


================================================
FILE: Obey/main.lua
================================================
if type(love._version)~='string' then
  error('love 0.8+ required!')
end

local lg=love.graphics
--W,H=512, 512
W,H=90,90

local O=require 'O'(W, H):setPosition(W/4, H/4):setScale(0.5)
local B=require 'B'(W, H):setPosition(3*W/4, H/4):setScale(0.5)
local E=require 'E'(W, H):setPosition(W/4, 3*H/4):setScale(0.5)
local Y=require 'Y'(W, H):setPosition(3*W/4, 3*H/4):setScale(0.5)

local time=3

if false then
  -- RECTANGLE
  O:setAnimation(time):move(W/4,0.9*-H/10):scale(2,0.6)
  B:setAnimation(time):rotate(-90):scale(0.4, 1.6):move(-W/4, -H/8)
  E:setAnimation(time):move(W/4,H/10):rotate(90):scale(1,2)
  Y:setAnimation(time):move(-W/4,-H/4):scale(2,0.8)
else --CIRCLE
  O:setAnimation(time):move(W/4,0.8*-H/10):scale(0.8, 0.7)
  B:setAnimation(time):rotate(-90):scale(0.4,0.7):move(-W/4, -H/8)
  E:setAnimation(time):move(W/4,H/10):rotate(90):scale(1)
  Y:setAnimation(time):move(-W/4,-H/4):scale(0.8)
end

function Y:onAnimationFinished()
  local scr=lg.newScreenshot():encode('miko.png')
end

function love.load()
  lg.setMode(W, H)
  Chars={O, B, E, Y}
end

function love.draw()
  for k,v in ipairs(Chars) do
    v:draw()
  end
end
function love.update(dt)
  for k,v in ipairs(Chars) do
    v:update(dt)
  end
end



================================================
FILE: README.md
================================================
Love2d samples
==============

This is a repository for sample games and applications which I am playing with while learning [love2d][love2d] platform. Some of those are inspired by forum posts, the others are to test some features.

[love2d]: http://love2d.org/


================================================
FILE: SidescrollerCollision/README.md
================================================
Sidescroller Collision example
===========

This sample is a follow-up to my earlier [CollisionExample]. This time this is about a sidescroller type of game, where you can only move left or right, and jump up. This collision sample is tile-based, i.e. the obstacles are represented as tile map.

The sample illustrates (in just one of many ways) how you can restrict movement
of your cursor (character) to stay on screen and not go thru other obstacles.

So: move with LEFT/RIGHT, jump with SPACE. Toggle debug with d.

How the collision works.
========================

There are two different cases: one for moving left/right, and another one for fumping up/falling down. You need to check it separately, because you want to move right/left while falling, etc.
The map is tile-based, but the character movement is arbitrary, so you character could occupy more than one tile - you need to check for this when looking for collisions. So first find out which tiles would be occupied, then check if any of them would collide.
There is another constraint of the movement - the character must stay on the map.

[CollisionExample]: https://github.com/miko/Love2d-samples/tree/master/CollisionExample



================================================
FILE: SidescrollerCollision/main.lua
================================================
function love.load()
  CELLSIZE=32
  PLAYERSIZE=16

  Player={x=92, y=100, G=-100, S=100, jumping=false, falling=false, Cells={}}
  createMap()
end

function love.update(dt)
  playermove(dt)
end

function love.draw()
  love.graphics.setColor(255,255,255)
  for y=1,#map do
    for x=1,#map[y] do
      if map[y][x] == 1 then
        love.graphics.rectangle("fill",x*CELLSIZE,y*CELLSIZE,CELLSIZE,CELLSIZE)
      else
        if DEBUG then
          love.graphics.rectangle("line",x*CELLSIZE,y*CELLSIZE,CELLSIZE,CELLSIZE)
        end
      end
    end
  end
  love.graphics.setColor(255,0,0,128)
  love.graphics.rectangle("fill",Player.x,Player.y,PLAYERSIZE, PLAYERSIZE)
  if DEBUG then
    love.graphics.setColor(0,255,0)
    love.graphics.print(string.format("Player at (%06.2f , %06.2f) jumping=%s falling=", Player.x, Player.y, tostring(Player.jumping), tostring(Player.falling)), 50,0)
    love.graphics.print(string.format("Player occupies cells(%d): %s", #Player.Cells, table.concat(Player.Cells, ' | ')), 450,0)
  end
end

-- is user off map?
function isOffMap(x, y)
  if x<CELLSIZE or x+PLAYERSIZE> (1+#map[1])*CELLSIZE
   or y<CELLSIZE or y+PLAYERSIZE>(1+#map)*CELLSIZE 
  then
    return true
  else
    return false
  end
end

function createMap()
  map = {
      {0,0,0,0,0,0,0,0,0,0,},
      {0,0,0,1,0,0,0,0,0,0,},
      {0,0,0,0,0,0,0,0,1,0,},
      {0,0,0,0,0,0,0,1,0,0,},
      {0,0,0,1,0,0,0,0,0,0,},
      {0,0,0,0,0,0,1,0,0,0,},
      {1,1,1,1,1,1,1,1,1,1,},
  }
end

-- which tile is that?
function posToTile(x, y)
  local tx=math.floor(x/CELLSIZE)
  local ty=math.floor(y/CELLSIZE)
  return tx, ty
end

-- Find out which cells are occupied by a player (check for each corner)
function playerOnCells(x, y)
  local Cells={}
  local tx,ty=posToTile(x, y)
  local key=tx..','..ty
  Cells[key]=true
  Cells[#Cells+1]=key

  tx,ty=posToTile(x+PLAYERSIZE, y)
  key=tx..','..ty
  if not Cells[key] then
    Cells[key]=true
    Cells[#Cells+1]=key
  end

  tx,ty=posToTile(x+PLAYERSIZE, y+PLAYERSIZE)
  key=tx..','..ty
  if not Cells[key] then
    Cells[key]=true
    Cells[#Cells+1]=key
  end

  tx,ty=posToTile(x, y+PLAYERSIZE)
  key=tx..','..ty
  if not Cells[key] then
    Cells[key]=true
    Cells[#Cells+1]=key
  end
  return Cells
end

local isDown = love.keyboard.isDown
function playermove(dt)
  -- Moving right or left?
  local newX, newY
  if isDown("left") then
    newX=Player.x-Player.S*dt
  end
  if isDown("right") then
    newX=Player.x+Player.S*dt
  end
  if newX then -- trying to move to a side
    local offmap=isOffMap(newX, Player.y)
    local colliding=isColliding(playerOnCells(newX, Player.y))
    if not offmap and not colliding then
      Player.x=newX
    end
  end

  -- jumping up or falling down
  Player.G = Player.G + Player.S*dt

  if not Player.jumping and isDown(" ") and not Player.falling then
    Player.jumping = true 
    Player.G = -100
  end

    -- check only for upper or lower collision
  newY= Player.y + Player.G*dt -- always falling

  local coll=isColliding(playerOnCells(Player.x, newY))
  if coll then
    if Player.G>=0 then -- falling down on the ground
      Player.jumping=false
      Player.falling=false
    end
    Player.G=0
  else
    Player.falling=true -- falling down
  end

  if not isOffMap(Player.x, newY) and not coll then
    Player.y=newY
  end
  if DEBUG then
    Player.Cells=playerOnCells(Player.x, Player.y) -- 
  end
end

-- list of tiles
function isColliding(T)
  local collision=false
  for k,v in ipairs(T) do
    local x,y=v:match('(%d+),(%d+)')
    x,y=tonumber(x), tonumber(y)
    if not map[y] or not map[y][x] then
      collision=true -- off-map
    elseif map[tonumber(y)][tonumber(x)] == 1 then
      collision=true
    end
  end
  return collision
end

function love.keypressed(k)
  if k=='escape' then
    love.event.quit()
  end
  if k=='d' then DEBUG=not DEBUG end
end



================================================
FILE: SpriteSheet/README.md
================================================
SpriteSheet
===========

This sample is inspired by the [spritesheet] thread.

This is a simple library, which can be used to create and play many animations from within one spritesheet.

[spritesheet]: http://love2d.org/forums/viewtopic.php?f=4&t=3103



================================================
FILE: SpriteSheet/SpriteSheet.lua
================================================
local lg=love.graphics

local Animation={}
Animation.__index=Animation

function Animation.new(spritesheet)
  local obj={parent=spritesheet, name=name, frames={}, currentFrame=0, delay=0.1, playing=true, elapsed=0}
  return setmetatable(obj, Animation)
end

function Animation:draw(x, y)
  local quad=self.frames[self.currentFrame]
  if quad then
    lg.drawq(self.parent.img, quad, x, y)
  end
end

function Animation:update(dt)
  if #self.frames==0 or not self.playing then return end
  self.elapsed=self.elapsed+dt
  if self.elapsed>=self.delay then
    self.elapsed=self.elapsed-self.delay
    self.currentFrame=self.currentFrame+1
    if self.currentFrame>#self.frames then
      self.currentFrame=1
    end
  end
end

function Animation:addFrame(col, row)
  local parent=self.parent
  local w,h=parent.w, parent.h
  local quad=lg.newQuad((col-1)*w, (row-1)*h, w, h, parent.imgw, parent.imgh)
  self.frames[#self.frames+1]=quad
  return self
end

function Animation:play()
  self.playing=true
end

function Animation:stop()
  self.playing=false
  self.currentFrame=1
  self.elapsed=0
end

function Animation:pause()
  self.playing=false
end

function Animation:setDelay(s)
  self.delay=s
  return self
end

function Animation:getDelay()
  return self.delay
end

function Animation:isPaused()
  return self.playing==false
end
  
local SpriteSheet={}
SpriteSheet.__index=SpriteSheet

function SpriteSheet.new(img, w, h)
  if type(img)=='string' then
    img=lg.newImage(img)
  end
  local obj={img=img, w=w, h=h, Animations={}}
  obj.imgw=img:getWidth()
  obj.imgh=img:getHeight()
  return setmetatable(obj, SpriteSheet)
end

function SpriteSheet:createAnimation(...)
  local a=Animation.new(self)
  return a
end

return SpriteSheet


================================================
FILE: SpriteSheet/main.lua
================================================
local SpriteSheet=require 'SpriteSheet'

function love.load()
  local img='spritesheet.png'
  framewidth=32
  frameheight=32
  S=SpriteSheet.new(img, framewidth, frameheight)
  selected=0
  Animations={}
  for row=1,5 do
    local a=S:createAnimation()
    for col=1,4 do
      a:addFrame(col, row)
    end
    Animations[#Animations+1]=a
  end
  a=S:createAnimation()
  for row=1,5 do
    for col=1,4 do
      a:addFrame(col, row)
    end
  end
  Animations[#Animations+1]=a
end

function love.update(dt)
  for k,v in ipairs(Animations) do v:update(dt) end
end

function love.draw()
  for k,v in ipairs(Animations) do
    v:draw(k*framewidth, 0)
    if k==selected then
      love.graphics.setColor(255,0,0,127)
      love.graphics.rectangle('fill', k*framewidth,0, framewidth, frameheight)
      love.graphics.setColor(255,255, 255,255)
    end
  end
  local a=Animations[selected]
  if a then
    love.graphics.print(string.format("Animation: %d Delay: %f", selected, a:getDelay()), 100, 100)
  end
    love.graphics.printf("Press 1.."..#Animations.." to select an animation. \r\nWhen selected, press SPACE to toggle playing, and RIGHT/LEFT to increase/decrease the delay between frames.", 0, 150, 800)
    
end

function love.keypressed(k)
  if k=='q' or k=='escape' then
    love.event.quit()
  end
  local n=tonumber(k)
  local a=Animations[n]
  if a then
    selected=n
  else
    a=Animations[selected]
    if a then
      if k==" " then
        if a:isPaused() then
          a:play()
        else
          a:pause()
        end    
      elseif k=="right" then
        a:setDelay(a:getDelay()-0.01)    
      elseif k=="left" then
        a:setDelay(a:getDelay()+0.01)
      else
        selected=0
      end
    else
      selected=0
    end    
  end
end


================================================
FILE: TexturedPolygon/README.md
================================================
Textured Polygon
===========

This sample is inspired by the [TexturedPolygon] thread.

Given the texture image, it places it (multiple times) on your framebuffer (only on non-black pixels). So create your image (e.g. filled polygon) first, and then call texturize(framebuffer, texture) to get your image.

[TexturedPolygon]: http://love2d.org/forums/viewtopic.php?f=4&t=3561



================================================
FILE: TexturedPolygon/main.lua
================================================

-- Parameters:
--  target - framebuffer with black/white pixels
--  texture - file name or imageData
-- Returns:
--  Image
function texturize(target, texture)
  if type(texture)=='string' then
    texture=love.image.newImageData(texture)
  end
  tx, ty=texture:getWidth(), texture:getHeight()
  local function placeTexture(x, y, r, g, b, a)
    if r+g+b==0 then -- black
      return 0,0,0,0
    else -- non-black, needs a texture
      return texture:getPixel(x%tx, y%ty)
    end
  end
  local id=target:getImageData()
  id:mapPixel(placeTexture)
  return love.graphics.newImage(id)
end

-- make texturized polygon
function makePolygon(V, texture)
  local t=love.image.newImageData(texture)

  local minX, maxX, minY, maxY
  for n=1,#V, 2 do
    if not minX or minX>V[n] then minX=V[n] end
    if not maxX or maxX<V[n] then maxX=V[n] end
    if not minY or minY>V[n+1] then minY=V[n+1] end
    if not maxY or maxY<V[n+1] then maxY=V[n+1] end
  end
  local w,h=maxX-minX+1, maxY-minY+1
  local fb
  if love.graphics.newCanvas then -- 0.8+
    fb=love.graphics.newCanvas(w, h)
  else --0.7
    fb=love.graphics.newFramebuffer(w, h)
  end
  love.graphics.setCanvas(fb)
  love.graphics.setColor(255,255,255)
  love.graphics.translate(-minX, -minY)
  love.graphics.polygon('fill', V)
  love.graphics.translate(minX, minY)
  love.graphics.setCanvas()
  return texturize(fb, texture)
end

function love.load()
  local vertices={0,0, 100,0, 200,100, 100,400, 0,300, -100,200, 0,0}
  local textures={'face-crying.png', 'face-grin.png', 'face-plain.png', 'face-sad.png', 'face-smile-big.png', 'face-smile.png', 'face-surprise.png', 'face-wink.png'}
  Polygons={}
  for k,v in ipairs(textures) do
    Polygons[k]=makePolygon(vertices, v)
  end
  X, Y, r=200,200,0
end

function love.draw()
  local idx=math.floor(5*r%#Polygons)+1
  love.graphics.draw(Polygons[1], X-5, Y-5, 0, 1, 1, X, Y)
  love.graphics.draw(Polygons[idx], X, Y, r, 1, 1, X, Y)
end

function love.update(dt)
  r=r+dt
end



================================================
FILE: VerbNounParser/Console.lua
================================================
local M={}
local MT={}
MT.__index=M

function M.new(P)
  local o=setmetatable({}, MT)
  o:initialize(P)
  return o
end

function M:getName()
  return 'Console'
end

function M:initialize(P)
  self.prompt='> '
  self.line=''
  self.data={}
  self.w=love.graphics.getWidth()
  self.h=200
  self.x=0
  self.y=love.graphics.getHeight()-self.h
  self.showCursor=false
  self.cursorTime=0
  self.callback=function(msg) print('Entered: '..msg); self:addLine(msg)  end
end

function M:setCallback(cb)
  self.callback=cb
end

function M:update(dt)
  self.cursorTime=self.cursorTime+dt
  if self.cursorTime>0.5 then
    self.cursorTime=self.cursorTime-0.5
    self.showCursor=not self.showCursor
  end
end

function M:draw()
  love.graphics.setScissor(self.x, self.y, self.w, self.h)
  love.graphics.setColor(255,255,255,128)
  love.graphics.rectangle('fill', self.x, self.y, self.w, self.h)
  love.graphics.setColor(55,55,55,228)
  --love.graphics.setLineWidth(3)
  love.graphics.rectangle('line', self.x, self.y, self.w, self.h)

  for k=1, #self.data do
    love.graphics.print(self.data[k], self.x+5, self.y+self.h-40-(#self.data-k)*15)
  end

  local l=self.prompt..self.line
  if self.showCursor then l=l..'_' end
  love.graphics.print(l, self.x+5, self.y+self.h-20)
  love.graphics.setScissor()
end

function M:keyPressed(k, u)
  if k=='delete' or k=='backspace' then
    if #self.line>0 then
      self.line=self.line:sub(1, -2)
    end
  elseif k=='return' then
    if type(self.callback)=='function' then
      self.callback(self.line, self)
    end
    self.line=''
  else
    if u>31 then
      if u<127 then
        self.line=self.line..string.char(u)
      else
        self.line=self.line..k
      end
    end
  end
end

function M:addLine(l)
  if type(l)=='table' then
    for k,v in ipairs(l) do
      self:addLine(v)
    end
  else
    table.insert(self.data, l)
    if #self.data>8 then
      table.remove(self.data, 1)
    end
  end
end

return M



================================================
FILE: VerbNounParser/Door.lua
================================================
local M={}
local MT={}
MT.__index=M

function M.new(P)
  local o=setmetatable({}, MT)
  o:initialize(P)
  return o
end

function M:getName()
  return 'Door'
end

function M:initialize(P)
  self.color=P.color or 'black'
  self.open=false
  self.x=100+math.random(500)
  self.y=250
  self.w=80
  self.h=100
end

function M:openAction(P)
  local found=false
  if #P>0 then
    -- find color
    for k,v in ipairs(P) do
      if v:lower()==self.color:lower() then
        found=true
        break
      end
    end
  else
    found=true
  end
  if found then
    if not self.open then
      self.open=true
      return true, 'Door '..self.color..' opened'
    else
      return true, 'Door '..self.color..' already open!'
    end
  else
    return nil, 'Not for me'
  end
end

function M:closeAction(P)
  local found=false
  if #P>0 then
    -- find color
    for k,v in ipairs(P) do
      if v:lower()==self.color:lower() then
        found=true
        break
      end
    end
  else
    found=true
  end
  if found then
    if self.open then
      self.open=false
      return true, 'Door '..self.color..' closed'
    else
      return true, 'Door '..self.color..' already closed!'
    end
  else
    return nil, 'Not for me'
  end
end

local Colors={red={255,0,0}, green={0,255,0}, black={0,0,0}}
function M:draw()
  if Colors[self.color] then
    love.graphics.setColor(Colors[self.color])
  end
  if self.open then
    love.graphics.rectangle('fill', self.x, self.y, self.w/4, self.h)
  else
    love.graphics.rectangle('fill', self.x, self.y, self.w, self.h)
  end
  
end

return M


================================================
FILE: VerbNounParser/Key.lua
================================================
local M={}
local MT={}
MT.__index=M

function M.new(P)
  local o=setmetatable({}, MT)
  o:initialize(P)
  return o
end

function M:getName()
  return 'Key'
end

function M:initialize(P)
  self.taken=false
  self.x=100+math.random(500)
  self.y=250
end

function M:takeAction(P)
  if not self.taken then
    self.taken=true
    return true, 'Key taken'
  else
    return true, 'Key already taken!'
  end
end

function M:dropAction(P)
  if self.taken then
    self.taken=false
    return true, 'Key dropped'
  else
    return true, 'Key already dropped!'
  end
end

function M:draw()
  love.graphics.setColor(0, 0, 0)
  local x, y
  if self.taken then
    x, y=20, 20
  else
    x, y=self.x, self.y
  end
  love.graphics.rectangle('fill', x+10, y, 50, 20)
  love.graphics.circle('fill', x, y+10, 20)
end

return M


================================================
FILE: VerbNounParser/Parser.lua
================================================
local P={}
local MT={}
MT.__index=P

function P.new(...)
  local o=setmetatable({}, MT)
  o:initialize(...)
  return o
end

function P:registerObject(o)
  table.insert(self.Objects, o)
end

function P:findObjects(name)
  local o={}
  for k,v in ipairs(self.Objects) do
    if name:lower()==v:getName():lower() then
      o[#o+1]=v
    end
  end
  return o
end

function P:initialize(...)
  self.Objects={}
end

function P:parse(buf)
  -- tokenize
  local tokens={}
  for token in buf:gmatch('%w+') do
    table.insert(tokens, token:lower())
  end
  -- find object
  local objects
  for k,v in ipairs(tokens) do
    local o=self:findObjects(v)
    if #o>0 then
      objects=o
      table.remove(tokens, k)
      break
    end
  end
  if not objects then
    return nil, 'No objects found'
  end
  -- find action
  local object=objects[1] -- assuming all objects found have the same methods
  for k,v in ipairs(tokens) do
    local method=v..'Action'
    if type(object[method])=='function' then
      table.remove(tokens, k)
      local res={}
      for a,b in ipairs(objects) do
        local st,re=b[method](b, tokens)
        if st then
          res[#res+1]=re
        end
      end
      return true, res
    end
  end
  return nil, 'Unknown action for this object '..object:getName()
end

function P:getObjects()
  return self.Objects
end

return P




================================================
FILE: VerbNounParser/README.md
================================================
VerbNounParser
===========

This sample is inspired by the [verb-noun parser] thread.

The idea is to register a sef of objects (instances of classes with given name and a set of actions, or methods). So you can have classes like Door or Window, and objects, like reddoor, greendoor or window. Now when user writes "open door", the parser first tokenizes this into tokens, then looks for all objects with a name equals to any token ("open", "door"), and when found - for this token, looks for a function called token+"Action" (like "openAction"), and calls it with remaining tokens (minus object name and action name). 

Note that the Door class implements "color discriminator" - if you pass a color name, only door object with this color will respond.

So try following commands:
```
open window
open door
close red door
close green door
Open door
Close door red ad green please!
Please, take the key.
Drop my key now.
exit
```

[verb-noun parser]: http://love2d.org/forums/viewtopic.php?f=4&t=10291



================================================
FILE: VerbNounParser/Window.lua
================================================
local M={}
local MT={}
MT.__index=M

function M.new(P)
  local o=setmetatable({}, MT)
  o:initialize(P)
  return o
end

function M:getName()
  return 'Window'
end

function M:initialize(P)
  self.open=false
  self.x=100+math.random(500)
  self.y=150
  self.w=50
  self.h=50
end

function M:openAction(P)
  if not self.open then
    self.open=true
    return true, 'Window opened'
  else
    return true, 'Window already open!'
  end
end

function M:closeAction(P)
  if self.open then
    self.open=false
    return true, 'Window closed'
  else
    return true, 'Window already closed!'
  end
end

function M:draw()
  love.graphics.setColor(0, 100, 255)
  if self.open then
    love.graphics.rectangle('fill', self.x, self.y, self.w/4, self.h)
  else
    love.graphics.rectangle('fill', self.x, self.y, self.w, self.h)
  end
  
end

return M


================================================
FILE: VerbNounParser/main.lua
================================================
local Parser=require 'Parser'
local Door=require 'Door'
local Window=require 'Window'
local Key=require 'Key'
local Console=require 'Console'

local Objects
function love.load()
  love.graphics.setBackgroundColor(255, 255, 255)
  P=Parser.new()

  local blackdoor=Door.new({color='black'})
  local greendoor=Door.new({color='green'})
  local reddoor=Door.new({color='red'})

  local window=Window.new()
  console=Console.new()
  local key=Key.new()

  P:registerObject(greendoor)
  P:registerObject(reddoor)
  P:registerObject(blackdoor)
  P:registerObject(window)
  P:registerObject(key)
  console:setCallback(function(buf)
    if buf=='exit' or buf=='quit' then
      love.event.quit()
    end
    local st, res=P:parse(buf)
    if st then
      console:addLine(res)
    else
      console:addLine('Error: '.. res)
    end
  end)
end

function love.draw()
  for k,v in ipairs(P:getObjects()) do
    v:draw()
  end
  console:draw()
end

function love.update(dt)
  console:update(dt)
end

function love.keypressed(k, u)
  console:keyPressed(k, u)
end

Download .txt
gitextract_xy8xzx00/

├── CodeCapture/
│   ├── CodeCapture.lua
│   ├── README.md
│   └── main.lua
├── CollisionExample/
│   ├── README.md
│   └── main.lua
├── Fireworks/
│   ├── Firework.lua
│   ├── FireworkEngine.lua
│   ├── Particle.lua
│   ├── README.md
│   ├── Vector.lua
│   ├── class.lua
│   └── main.lua
├── GameOfLife/
│   ├── Readme.md
│   └── main.lua
├── LICENSE
├── MikoIntroScreen/
│   ├── Intro.lua
│   ├── README.md
│   ├── class.lua
│   ├── conf.lua
│   ├── main.lua
│   └── zero-project - 01 - Celtic dream.ogg
├── Minefield/
│   ├── conf.lua
│   ├── main.lua
│   └── menu.lua
├── Obey/
│   ├── B.lua
│   ├── Char.lua
│   ├── E.lua
│   ├── O.lua
│   ├── README.md
│   ├── Y.lua
│   ├── class.lua
│   └── main.lua
├── README.md
├── SidescrollerCollision/
│   ├── README.md
│   └── main.lua
├── SpriteSheet/
│   ├── README.md
│   ├── SpriteSheet.lua
│   └── main.lua
├── TexturedPolygon/
│   ├── README.md
│   └── main.lua
└── VerbNounParser/
    ├── Console.lua
    ├── Door.lua
    ├── Key.lua
    ├── Parser.lua
    ├── README.md
    ├── Window.lua
    └── main.lua
Condensed preview — 47 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (71K chars).
[
  {
    "path": "CodeCapture/CodeCapture.lua",
    "chars": 893,
    "preview": "local M={}\nM.KONAMI={'up','up','down','down','left','right','left','right','b','a'}\n\nlocal STATES={}\nlocal CURRSTATE\n\nlo"
  },
  {
    "path": "CodeCapture/README.md",
    "chars": 767,
    "preview": "CodeCapture\n===========\n\nThis sample is inspired by the [KonamiCode] thread.\n\nThis is a simple library, which can be use"
  },
  {
    "path": "CodeCapture/main.lua",
    "chars": 749,
    "preview": "local CodeCapture=require 'CodeCapture'\n\nfunction love.load()\n  CodeCapture.setCode(\"qwerty\", function() MODE='ONE' end)"
  },
  {
    "path": "CollisionExample/README.md",
    "chars": 995,
    "preview": "Collision example\n===========\n\nThis sample is inspired by the [RestrictRectangleMovement] thread.\n\nThe sample illustrate"
  },
  {
    "path": "CollisionExample/main.lua",
    "chars": 1764,
    "preview": "local lg=love.graphics\nfunction love.load()\n  W, H=lg.getWidth(), lg.getHeight()\n  local w,h=40,40\n  Obstacles={}\n  for "
  },
  {
    "path": "Fireworks/Firework.lua",
    "chars": 2196,
    "preview": "require 'class'\nlocal Vector=require 'Vector'\nlocal Particle=require 'Particle'\nSTATE={ROCKET=1, EXPLODE=2, LIVE=3, DEAD"
  },
  {
    "path": "Fireworks/FireworkEngine.lua",
    "chars": 568,
    "preview": "require 'class'\nFirework=require 'Firework'\n\nlocal M=class(function(self)\n  self.Fireworks={}\nend)\n\nfunction M:update(dt"
  },
  {
    "path": "Fireworks/Particle.lua",
    "chars": 958,
    "preview": "require 'class'\nlocal Vector=require 'Vector'\nlocal lg=love.graphics\n\nlocal M=class(function(self, x, y, R, G, B, v)\n  s"
  },
  {
    "path": "Fireworks/README.md",
    "chars": 328,
    "preview": "Fireworks example\n==============\n\nThis is an example of fireworks, inspired by the [facepunch] thread, which is mentione"
  },
  {
    "path": "Fireworks/Vector.lua",
    "chars": 785,
    "preview": "require 'class'\n\nlocal M=class(function(self, x, y)\n  self.x=x or 0\n  self.y=y or 0\nend)\n\nfunction M:isVector()\n  return"
  },
  {
    "path": "Fireworks/class.lua",
    "chars": 1246,
    "preview": "--[[\n-- $Id: class.lua 10 2008-07-01 22:18:32Z basique $\n-- Simple class implementation\n-- Taken from http://lua-users.o"
  },
  {
    "path": "Fireworks/main.lua",
    "chars": 396,
    "preview": "FireworkEngine=require 'FireworkEngine'\nfunction love.load()\n  FE=FireworkEngine()\n  love.graphics.setBlendMode('additiv"
  },
  {
    "path": "GameOfLife/Readme.md",
    "chars": 631,
    "preview": "Game of Life\n============\n\nGame of Life inspired by [this thread](http://love2d.org/forums/viewtopic.php?f=4&t=2858)\n\nCo"
  },
  {
    "path": "GameOfLife/main.lua",
    "chars": 4784,
    "preview": "-- Game of Life by miko\n-- Controls:\n-- 0, 1, 2 - set cell border width\n-- left,right - decrease/increase no of columns\n"
  },
  {
    "path": "LICENSE",
    "chars": 1405,
    "preview": "All the code within this repository is licensed under the terms of the MIT license reproduced below. So it is free to us"
  },
  {
    "path": "MikoIntroScreen/Intro.lua",
    "chars": 8857,
    "preview": "require 'class'\n\n--love=love or {graphics={}} -- plain lua compatibility\nlocal lg=love.graphics\nif not lg.newFramebuffer"
  },
  {
    "path": "MikoIntroScreen/README.md",
    "chars": 475,
    "preview": "LOVEJam Intro Screen\n===========\n\nThis sample is inspired by the [LOVEJam] site.\n\nThis is a splash screen intro, and als"
  },
  {
    "path": "MikoIntroScreen/class.lua",
    "chars": 1246,
    "preview": "--[[\n-- $Id: class.lua 10 2008-07-01 22:18:32Z basique $\n-- Simple class implementation\n-- Taken from http://lua-users.o"
  },
  {
    "path": "MikoIntroScreen/conf.lua",
    "chars": 151,
    "preview": "function love.conf(t)\r\n\tt.title = \"miko lovejam intro\"\r\n\tt.author = \"miko\"\r\n\tt.identity = \"mario\"\r\n\tt.screen.width = 800"
  },
  {
    "path": "MikoIntroScreen/main.lua",
    "chars": 727,
    "preview": "local Intro=require 'Intro'\nfunction love.load()\n  I=Intro()\n  local t1=I:addText('LoveJam Test Jam entry!'):setPosition"
  },
  {
    "path": "Minefield/conf.lua",
    "chars": 465,
    "preview": "function love.conf(t)\n\tt.modules.joystick = false\n\tt.modules.audio = false\n\tt.modules.keyboard = true\n\tt.modules.event ="
  },
  {
    "path": "Minefield/main.lua",
    "chars": 5691,
    "preview": "local lg=love.graphics\nORGWIDTH, ORGHEIGHT=lg.getWidth(), lg.getHeight()\nlocal Menu=require 'menu'\n\nfunction love.load()"
  },
  {
    "path": "Minefield/menu.lua",
    "chars": 2838,
    "preview": "local lg=love.graphics\nlocal Options={\n  {name='play', title='Play the game!'},\n  {name='help', title='Help'},\n  {name='"
  },
  {
    "path": "Obey/B.lua",
    "chars": 677,
    "preview": "local Char=require('Char')\nlocal lg=love.graphics\n\nlocal M=class(Char, function(self, W, H)\n  Char.init(self, 'B', W, H)"
  },
  {
    "path": "Obey/Char.lua",
    "chars": 2588,
    "preview": "require 'class'\nlocal lg=love.graphics\n\nlocal M=class(function(self, name, W, H)\n  self.W, self.H=W, H\n  self.position={"
  },
  {
    "path": "Obey/E.lua",
    "chars": 397,
    "preview": "local Char=require('Char')\nlocal lg=love.graphics\n\nlocal M=class(Char, function(self, W, H)\n  Char.init(self, 'E', W, H)"
  },
  {
    "path": "Obey/O.lua",
    "chars": 478,
    "preview": "local Char=require('Char')\nlocal lg=love.graphics\n\nlocal M=class(Char, function(self, W, H)\n  Char.init(self, 'O', W, H)"
  },
  {
    "path": "Obey/README.md",
    "chars": 264,
    "preview": "Obeying avatar\n===========\n\nThis sample is inspired by the [AngryLovers] thread.\n\nIt creates an avatar animation. The ke"
  },
  {
    "path": "Obey/Y.lua",
    "chars": 361,
    "preview": "local Char=require('Char')\nlocal lg=love.graphics\n\nlocal M=class(Char, function(self, W, H)\n  Char.init(self, 'Y', W, H)"
  },
  {
    "path": "Obey/class.lua",
    "chars": 1246,
    "preview": "--[[\n-- $Id: class.lua 10 2008-07-01 22:18:32Z basique $\n-- Simple class implementation\n-- Taken from http://lua-users.o"
  },
  {
    "path": "Obey/main.lua",
    "chars": 1223,
    "preview": "if type(love._version)~='string' then\n  error('love 0.8+ required!')\nend\n\nlocal lg=love.graphics\n--W,H=512, 512\nW,H=90,9"
  },
  {
    "path": "README.md",
    "chars": 263,
    "preview": "Love2d samples\n==============\n\nThis is a repository for sample games and applications which I am playing with while lear"
  },
  {
    "path": "SidescrollerCollision/README.md",
    "chars": 1196,
    "preview": "Sidescroller Collision example\n===========\n\nThis sample is a follow-up to my earlier [CollisionExample]. This time this "
  },
  {
    "path": "SidescrollerCollision/main.lua",
    "chars": 3873,
    "preview": "function love.load()\n  CELLSIZE=32\n  PLAYERSIZE=16\n\n  Player={x=92, y=100, G=-100, S=100, jumping=false, falling=false, "
  },
  {
    "path": "SpriteSheet/README.md",
    "chars": 254,
    "preview": "SpriteSheet\n===========\n\nThis sample is inspired by the [spritesheet] thread.\n\nThis is a simple library, which can be us"
  },
  {
    "path": "SpriteSheet/SpriteSheet.lua",
    "chars": 1736,
    "preview": "local lg=love.graphics\n\nlocal Animation={}\nAnimation.__index=Animation\n\nfunction Animation.new(spritesheet)\n  local obj="
  },
  {
    "path": "SpriteSheet/main.lua",
    "chars": 1768,
    "preview": "local SpriteSheet=require 'SpriteSheet'\n\nfunction love.load()\n  local img='spritesheet.png'\n  framewidth=32\n  frameheigh"
  },
  {
    "path": "TexturedPolygon/README.md",
    "chars": 377,
    "preview": "Textured Polygon\n===========\n\nThis sample is inspired by the [TexturedPolygon] thread.\n\nGiven the texture image, it plac"
  },
  {
    "path": "TexturedPolygon/main.lua",
    "chars": 1981,
    "preview": "\n-- Parameters:\n--  target - framebuffer with black/white pixels\n--  texture - file name or imageData\n-- Returns:\n--  Im"
  },
  {
    "path": "VerbNounParser/Console.lua",
    "chars": 1958,
    "preview": "local M={}\nlocal MT={}\nMT.__index=M\n\nfunction M.new(P)\n  local o=setmetatable({}, MT)\n  o:initialize(P)\n  return o\nend\n\n"
  },
  {
    "path": "VerbNounParser/Door.lua",
    "chars": 1585,
    "preview": "local M={}\nlocal MT={}\nMT.__index=M\n\nfunction M.new(P)\n  local o=setmetatable({}, MT)\n  o:initialize(P)\n  return o\nend\n\n"
  },
  {
    "path": "VerbNounParser/Key.lua",
    "chars": 812,
    "preview": "local M={}\nlocal MT={}\nMT.__index=M\n\nfunction M.new(P)\n  local o=setmetatable({}, MT)\n  o:initialize(P)\n  return o\nend\n\n"
  },
  {
    "path": "VerbNounParser/Parser.lua",
    "chars": 1357,
    "preview": "local P={}\nlocal MT={}\nMT.__index=P\n\nfunction P.new(...)\n  local o=setmetatable({}, MT)\n  o:initialize(...)\n  return o\ne"
  },
  {
    "path": "VerbNounParser/README.md",
    "chars": 1003,
    "preview": "VerbNounParser\n===========\n\nThis sample is inspired by the [verb-noun parser] thread.\n\nThe idea is to register a sef of "
  },
  {
    "path": "VerbNounParser/Window.lua",
    "chars": 841,
    "preview": "local M={}\nlocal MT={}\nMT.__index=M\n\nfunction M.new(P)\n  local o=setmetatable({}, MT)\n  o:initialize(P)\n  return o\nend\n\n"
  },
  {
    "path": "VerbNounParser/main.lua",
    "chars": 1052,
    "preview": "local Parser=require 'Parser'\nlocal Door=require 'Door'\nlocal Window=require 'Window'\nlocal Key=require 'Key'\nlocal Cons"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the miko/Love2d-samples GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 47 files (64.7 KB), approximately 21.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!