summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAki <nthirtyone@gmail.com>2017-04-09 22:07:04 +0200
committerAki <nthirtyone@gmail.com>2017-04-09 22:07:04 +0200
commit0dd01913fe0eefc7ba4bc0797877f40fdedf9315 (patch)
tree8d270eb07f589d2487b3ce66d4865e5a4718042a
parent55b0cf1a22e4a7e41fe00aa693445d6c4bd0652d (diff)
parenta03c1125f10fbbad253a0efc4727072fcbd55345 (diff)
downloadroflnauts-0dd01913fe0eefc7ba4bc0797877f40fdedf9315.zip
roflnauts-0dd01913fe0eefc7ba4bc0797877f40fdedf9315.tar.gz
roflnauts-0dd01913fe0eefc7ba4bc0797877f40fdedf9315.tar.bz2
Merge branch 'com'
-rw-r--r--Makefile4
-rw-r--r--animated.lua81
-rw-r--r--cloud.lua63
-rw-r--r--config/animations/effects.lua (renamed from effects.lua)21
-rw-r--r--config/animations/hero.lua (renamed from animations.lua)0
-rw-r--r--config/maps.lua (renamed from maplist.lua)0
-rw-r--r--config/maps/aiguillon.lua (renamed from maps/aiguillon.lua)0
-rw-r--r--config/maps/alpha abyss.lua (renamed from maps/alpha abyss.lua)0
-rw-r--r--config/maps/default.lua (renamed from maps/default.lua)0
-rw-r--r--config/maps/readme.md (renamed from maps/readme.md)0
-rw-r--r--config/maps/ribbit.lua (renamed from maps/ribbit.lua)0
-rw-r--r--config/maps/rill.lua (renamed from maps/rill.lua)0
-rw-r--r--config/maps/sorona.lua (renamed from maps/sorona.lua)0
-rw-r--r--config/maps/starstorm.lua (renamed from maps/starstorm.lua)0
-rw-r--r--config/menus/credits.lua (renamed from config/menucredits.lua)6
-rw-r--r--config/menus/host.lua (renamed from config/menuhost.lua)15
-rw-r--r--config/menus/main.lua (renamed from config/menumain.lua)12
-rw-r--r--config/menus/select.lua (renamed from config/menuselect.lua)15
-rw-r--r--config/menus/settings.lua (renamed from config/menusettings.lua)8
-rw-r--r--config/nauts.lua (renamed from nautslist.lua)5
-rw-r--r--config/sounds.lua (renamed from sounds.lua)0
-rw-r--r--decoration.lua33
-rw-r--r--effect.lua68
-rw-r--r--element.lua42
-rw-r--r--iconsList.lua37
-rw-r--r--main.lua79
-rw-r--r--mapicons.lua12
-rw-r--r--music.lua27
-rw-r--r--nautsicons.lua11
-rw-r--r--not/Button.lua (renamed from button.lua)56
-rw-r--r--not/Camera.lua (renamed from camera.lua)8
-rw-r--r--not/Cloud.lua71
-rw-r--r--not/Controller.lua (renamed from controller.lua)14
-rw-r--r--not/Decoration.lua33
-rw-r--r--not/Effect.lua46
-rw-r--r--not/Element.lua50
-rw-r--r--not/Header.lua (renamed from header.lua)45
-rw-r--r--not/Hero.lua284
-rw-r--r--not/Menu.lua (renamed from menu.lua)78
-rw-r--r--not/Music.lua25
-rw-r--r--not/PhysicalBody.lua93
-rw-r--r--not/Platform.lua37
-rw-r--r--not/Player.lua159
-rw-r--r--not/Ray.lua (renamed from ray.lua)0
-rw-r--r--not/Selector.lua (renamed from selector.lua)79
-rw-r--r--not/Settings.lua (renamed from settings.lua)12
-rw-r--r--not/Sprite.lua152
-rw-r--r--not/World.lua (renamed from world.lua)179
-rw-r--r--platform.lua73
-rw-r--r--player.lua449
-rw-r--r--readme.md4
51 files changed, 1295 insertions, 1191 deletions
diff --git a/Makefile b/Makefile
index 5eee011..5f17a9c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
all:
- zip not-nautz maps/*.lua config/*.lua assets/*.png assets/sounds/*.ogg assets/platforms/*.png assets/nauts/*.png assets/music/*.ogg assets/decorations/*.png assets/backgrounds/*.png *.lua gamecontrollerdb.txt settings.default
+ zip not-nautz not/*.lua config/maps/*.lua config/menus/*.lua config/*.lua assets/*.png assets/sounds/*.ogg assets/platforms/*.png assets/nauts/*.png assets/music/*.ogg assets/decorations/*.png assets/backgrounds/*.png *.lua gamecontrollerdb.txt settings.default
mv not-nautz.zip ../not-nautz.love
clean:
- $(RM) ../not-nautz.love \ No newline at end of file
+ rm ../not-nautz.love \ No newline at end of file
diff --git a/animated.lua b/animated.lua
deleted file mode 100644
index 160ee44..0000000
--- a/animated.lua
+++ /dev/null
@@ -1,81 +0,0 @@
--- `Animated`
--- Abstract class for drawable animated entities.
-
--- Metatable
-Animated = {
- animations--[[table with animations]],
- current--[[animations.default]],
- sprite--[[love.graphics.newImage()]],
- frame = 1,
- delay = .1,
-}
-Animated.__index = Animated
-
--- Cleans up reference to sprite on deletion.
-function Animated:delete()
- self.sprite = nil
-end
-
--- Sets an Image as a sprite.
-function Animated:setSprite(image)
- self.sprite = image
-end
--- Returns current sprite Image.
-function Animated:getSprite()
- return self.sprite
-end
-
--- Sets new animations list.
-function Animated:setAnimationsList(t)
- if t then
- self.animations = t
- self:setAnimation("default")
- end
-end
-
--- Sets current animation by table key.
-function Animated:setAnimation(animation)
- self.frame = 1
- self.delay = Animated.delay -- INITIAL from metatable
- self.current = self.animations[animation]
-end
--- Returns current animation table.
-function Animated:getAnimation()
- return self.current
-end
-
--- Get frame quad for drawing.
-function Animated:getQuad()
- if self.animations and self.current then
- return self.current[self.frame]
- end
-end
-
--- Drawing self to LOVE2D buffer.
--- If there is no Quad, it will draw entire sprite.
-function Animated:draw(...)
- local s, q = self:getSprite(), self:getQuad()
- if s then
- love.graphics.setColor(255,255,255,255)
- if q then love.graphics.draw(s, q, ...)
- else love.graphics.draw(s, ...) end
- end
-end
--- Animation updating.
-function Animated:update(dt)
- if self.animations and self.current then
- self.delay = self.delay - dt
- if self.delay < 0 then
- self.delay = self.delay + Animated.delay -- INITIAL from metatable
- self:nextFrame()
- end
- end
-end
--- Moving to the next frame.
-function Animated:nextFrame()
- if self.current.repeated or not (self.frame == self.current.frames) then
- self.frame = (self.frame % self.current.frames) + 1
- else
- self:setAnimation("default")
- end
-end \ No newline at end of file
diff --git a/cloud.lua b/cloud.lua
deleted file mode 100644
index c12e236..0000000
--- a/cloud.lua
+++ /dev/null
@@ -1,63 +0,0 @@
--- `Cloud`
--- That white thing moving in the background.
-
--- WHOLE CODE HAS FLAG OF "need a cleanup"
-
--- Metatable of `Cloud`
--- nils initialized in constructor
-Cloud = {
- x = 0, -- position horizontal
- y = 0, -- position vertical
- t = 1, -- type (sprite number)
- v = 13, -- velocity
- sprite = nil,
- quads = {
- [1] = love.graphics.newQuad( 1, 1, 158,47, 478,49),
- [2] = love.graphics.newQuad(160, 1, 158,47, 478,49),
- [3] = love.graphics.newQuad(319, 1, 158,47, 478,49)
- }
-}
-
--- Constructor of `Cloud`
-function Cloud:new(x, y, t, v)
- -- Meta
- local o = {}
- setmetatable(o, self)
- self.__index = self
- -- Load spritesheet to metatable if not yet loaded
- if self.sprite == nil then
- self.sprite = love.graphics.newImage("assets/clouds.png")
- end
- -- Init
- o.x = x or self.x
- o.y = y or self.y
- o.t = t or self.t
- o.v = v or self.v
- return o
-end
-
--- Position
-function Cloud:getPosition()
- return self.x, self.y
-end
-
--- Update of `Cloud`, returns x for world to delete cloud after reaching right corner
-function Cloud:update(dt)
- self.x = self.x + self.v*dt
- return self.x
-end
-
--- Draw `Cloud`
-function Cloud:draw(offset_x, offset_y, scale)
- -- locals
- local offset_x = offset_x or 0
- local offset_y = offset_y or 0
- local scale = scale or 1
- local x, y = self:getPosition()
- -- pixel grid
- local draw_x = (math.floor(x) + offset_x) * scale
- local draw_y = (math.floor(y) + offset_y) * scale
- -- draw
- love.graphics.setColor(255,255,255,255)
- love.graphics.draw(self.sprite, self.quads[self.t], draw_x, draw_y, 0, scale, scale)
-end \ No newline at end of file
diff --git a/effects.lua b/config/animations/effects.lua
index 6946d10..dd6d55e 100644
--- a/effects.lua
+++ b/config/animations/effects.lua
@@ -16,14 +16,16 @@ local quads = {
[2] = love.graphics.newQuad( 24, 0, 24,24, 168,120),
[3] = love.graphics.newQuad( 48, 0, 24,24, 168,120),
[4] = love.graphics.newQuad( 72, 0, 24,24, 168,120),
- frames = 4
+ frames = 4,
+ repeated = false
},
doublejump = {
[1] = love.graphics.newQuad( 0, 24, 24,24, 168,120),
[2] = love.graphics.newQuad( 24, 24, 24,24, 168,120),
[3] = love.graphics.newQuad( 48, 24, 24,24, 168,120),
[4] = love.graphics.newQuad( 72, 24, 24,24, 168,120),
- frames = 4
+ frames = 4,
+ repeated = false
},
land = {
[1] = love.graphics.newQuad( 0, 48, 24,24, 168,120),
@@ -31,7 +33,8 @@ local quads = {
[3] = love.graphics.newQuad( 48, 48, 24,24, 168,120),
[4] = love.graphics.newQuad( 72, 48, 24,24, 168,120),
[5] = love.graphics.newQuad( 96, 48, 24,24, 168,120),
- frames = 5
+ frames = 5,
+ repeated = false
},
respawn = {
[1] = love.graphics.newQuad( 0, 72, 24,24, 168,120),
@@ -41,7 +44,8 @@ local quads = {
[5] = love.graphics.newQuad( 96, 72, 24,24, 168,120),
[6] = love.graphics.newQuad(120, 72, 24,24, 168,120),
[7] = love.graphics.newQuad(144, 72, 24,24, 168,120),
- frames = 7
+ frames = 7,
+ repeated = false
},
clash = {
[1] = love.graphics.newQuad( 0, 96, 24,24, 168,120),
@@ -50,20 +54,23 @@ local quads = {
[4] = love.graphics.newQuad( 72, 96, 24,24, 168,120),
[5] = love.graphics.newQuad( 96, 96, 24,24, 168,120),
[6] = love.graphics.newQuad(120, 96, 24,24, 168,120),
- frames = 6
+ frames = 6,
+ repeated = false
},
trail = {
[1] = love.graphics.newQuad(104, 0, 16,16, 168,120),
[2] = love.graphics.newQuad(120, 0, 16,16, 168,120),
[3] = love.graphics.newQuad(136, 0, 16,16, 168,120),
[4] = love.graphics.newQuad(152, 0, 16,16, 168,120),
- frames = 4
+ frames = 4,
+ repeated = false
},
hit = {
[1] = love.graphics.newQuad(106, 18, 16,16, 168,120),
[2] = love.graphics.newQuad(122, 18, 16,16, 168,120),
[3] = love.graphics.newQuad(138, 18, 16,16, 168,120),
- frames = 3
+ frames = 3,
+ repeated = false
}
}
return quads \ No newline at end of file
diff --git a/animations.lua b/config/animations/hero.lua
index 881da49..881da49 100644
--- a/animations.lua
+++ b/config/animations/hero.lua
diff --git a/maplist.lua b/config/maps.lua
index 32e89a5..32e89a5 100644
--- a/maplist.lua
+++ b/config/maps.lua
diff --git a/maps/aiguillon.lua b/config/maps/aiguillon.lua
index 40d3928..40d3928 100644
--- a/maps/aiguillon.lua
+++ b/config/maps/aiguillon.lua
diff --git a/maps/alpha abyss.lua b/config/maps/alpha abyss.lua
index 0dd2c61..0dd2c61 100644
--- a/maps/alpha abyss.lua
+++ b/config/maps/alpha abyss.lua
diff --git a/maps/default.lua b/config/maps/default.lua
index 05b8dc9..05b8dc9 100644
--- a/maps/default.lua
+++ b/config/maps/default.lua
diff --git a/maps/readme.md b/config/maps/readme.md
index dc139ad..dc139ad 100644
--- a/maps/readme.md
+++ b/config/maps/readme.md
diff --git a/maps/ribbit.lua b/config/maps/ribbit.lua
index c3f5c78..c3f5c78 100644
--- a/maps/ribbit.lua
+++ b/config/maps/ribbit.lua
diff --git a/maps/rill.lua b/config/maps/rill.lua
index 83c02f2..83c02f2 100644
--- a/maps/rill.lua
+++ b/config/maps/rill.lua
diff --git a/maps/sorona.lua b/config/maps/sorona.lua
index 8ec4727..8ec4727 100644
--- a/maps/sorona.lua
+++ b/config/maps/sorona.lua
diff --git a/maps/starstorm.lua b/config/maps/starstorm.lua
index 7f00633..7f00633 100644
--- a/maps/starstorm.lua
+++ b/config/maps/starstorm.lua
diff --git a/config/menucredits.lua b/config/menus/credits.lua
index 9d38da4..77cba62 100644
--- a/config/menucredits.lua
+++ b/config/menus/credits.lua
@@ -1,7 +1,7 @@
local menu = ...
-local button = require "button"
-local element = require "element"
+local button = require "not.Button"
+local element = require "not.Element"
local width, height = love.graphics.getWidth()/getRealScale(), love.graphics.getHeight()/getRealScale()
local bx = width/2-29
@@ -11,7 +11,7 @@ return {
:setText("Go back")
:setPosition(bx,144)
:set("active", function (self)
- self.parent:load("menumain")
+ self.parent:open("main")
end)
,
element:new(menu)
diff --git a/config/menuhost.lua b/config/menus/host.lua
index 64ce0e7..b318a5b 100644
--- a/config/menuhost.lua
+++ b/config/menus/host.lua
@@ -1,13 +1,16 @@
local menu = ...
-local button = require "button"
-local selector = require "selector"
+local button = require "not.Button"
+local selector = require "not.Selector"
local width, height = love.graphics.getWidth()/getScale(), love.graphics.getHeight()/getScale()
local bx = width/2-29
local map_selector = selector:new(menu)
+require "iconsList"
+local icons, maps = getMapsIconsList()
+
return {
map_selector
:setPosition(width/2, 40)
@@ -15,9 +18,9 @@ return {
:setMargin(0)
:set("global", true)
:set("first", true)
- :set("list", require "maplist")
+ :set("list", maps)
:set("icons_i", love.graphics.newImage("assets/maps.png"))
- :set("icons_q", require "mapicons")
+ :set("icons_q", icons)
:set("shape", "panorama")
:init()
,
@@ -29,14 +32,14 @@ return {
end)
:set("active", function (self)
MAP = map_selector:getFullSelection(true)[1][1] -- please, don't kill me for this, kek
- self.parent:load("menuselect")
+ self.parent:open("select")
end)
,
button:new(menu)
:setText("Go back")
:setPosition(bx,117)
:set("active", function (self)
- self.parent:load("menumain")
+ self.parent:open("main")
end)
,
} \ No newline at end of file
diff --git a/config/menumain.lua b/config/menus/main.lua
index 50b3d56..236c011 100644
--- a/config/menumain.lua
+++ b/config/menus/main.lua
@@ -1,8 +1,8 @@
local menu = ...
-local button = require "button"
-local header = require "header"
-local element = require "element"
+local button = require "not.Button"
+local header = require "not.Header"
+local element = require "not.Element"
local width, height = love.graphics.getWidth()/getScale(), love.graphics.getHeight()/getScale()
local bx = width/2-29
@@ -14,7 +14,7 @@ return {
:setText("Start")
:setPosition(bx, 80)
:set("active", function (self)
- self.parent:load("menuhost")
+ self.parent:open("host")
end)
,
button:new(menu)
@@ -28,14 +28,14 @@ return {
:setText("Settings")
:setPosition(bx, 112)
:set("active", function (self)
- self.parent:load("menusettings")
+ self.parent:open("settings")
end)
,
button:new(menu)
:setText("Credits")
:setPosition(bx, 128)
:set("active", function (self)
- self.parent:load("menucredits")
+ self.parent:open("credits")
end)
,
button:new(menu)
diff --git a/config/menuselect.lua b/config/menus/select.lua
index 19f46ab..804b4eb 100644
--- a/config/menuselect.lua
+++ b/config/menus/select.lua
@@ -1,8 +1,8 @@
local menu = ...
-local button = require "button"
-local selector = require "selector"
-local element = require "element"
+local button = require "not.Button"
+local selector = require "not.Selector"
+local element = require "not.Element"
local width, height = love.graphics.getWidth()/getScale(), love.graphics.getHeight()/getScale()
local bx = width/2-29
@@ -10,15 +10,18 @@ local bx = width/2-29
local naut_selector = selector:new(menu)
local start_button = button:new(menu)
+require "iconsList"
+local nautsIcons, nautsList = getNautsIconsList()
+
return {
naut_selector
:setPosition(width/2,60)
:setMargin(8)
:setSize(32, 32)
- :set("list", require "nautslist")
+ :set("list", nautsList)
:set("global", false)
:set("icons_i", love.graphics.newImage("assets/portraits.png"))
- :set("icons_q", require "nautsicons")
+ :set("icons_q", nautsIcons)
:init()
,
start_button
@@ -41,7 +44,7 @@ return {
:setText("Go back")
:setPosition(bx,150)
:set("active", function (self)
- self.parent:load("menuhost")
+ self.parent:open("host")
end)
,
element:new(menu)
diff --git a/config/menusettings.lua b/config/menus/settings.lua
index 1631e4f..ae0403d 100644
--- a/config/menusettings.lua
+++ b/config/menus/settings.lua
@@ -1,8 +1,8 @@
local menu = ...
-local button = require "button"
-local selector = require "selector"
-local element = require "element"
+local button = require "not.Button"
+local selector = require "not.Selector"
+local element = require "not.Element"
local width, height = love.graphics.getWidth()/getRealScale(), love.graphics.getHeight()/getRealScale()
local bx = width/2-29
@@ -105,7 +105,7 @@ local a = {
:setText("Go back")
:setPosition(bx,144)
:set("active", function (self)
- self.parent:load("menumain")
+ self.parent:open("main")
end)
,
dimmer
diff --git a/nautslist.lua b/config/nauts.lua
index d0c7a61..2eea71a 100644
--- a/nautslist.lua
+++ b/config/nauts.lua
@@ -32,4 +32,9 @@ return {
"biker", -- chucho
"vrooom", -- lux
"shutter", -- max
+ "disco", -- esc rocco
+ "yarr", -- ted pirate
+ "blblal", -- blabl zork
+ "kong", -- ronimo
+ "rock", -- rock
}
diff --git a/sounds.lua b/config/sounds.lua
index c30af16..c30af16 100644
--- a/sounds.lua
+++ b/config/sounds.lua
diff --git a/decoration.lua b/decoration.lua
deleted file mode 100644
index 3ca6f76..0000000
--- a/decoration.lua
+++ /dev/null
@@ -1,33 +0,0 @@
-Decoration = {
- world = nil,
- sprite = nil,
- x = 0,
- y = 0
-}
-Decoration.__index = Decoration
-setmetatable(Decoration, Animated)
-function Decoration:new(x, y, sprite)
- local o = {}
- setmetatable(o, self)
- o.sprite = love.graphics.newImage(sprite)
- o:setPosition(x,y)
- return o
-end
-function Decoration:setPosition(x, y)
- self.x, self.y = x, y
-end
-function Decoration:getPosition()
- return self.x, self.y
-end
-function Decoration:draw(offset_x, offset_y, scale)
- -- locals
- local offset_x = offset_x or 0
- local offset_y = offset_y or 0
- local scale = scale or 1
- local x, y = self:getPosition()
- -- pixel grid
- local draw_x = (math.floor(x) + offset_x) * scale
- local draw_y = (math.floor(y) + offset_y) * scale
- -- draw
- Animated.draw(self, draw_x, draw_y, 0, scale, scale)
-end \ No newline at end of file
diff --git a/effect.lua b/effect.lua
deleted file mode 100644
index 4e327a1..0000000
--- a/effect.lua
+++ /dev/null
@@ -1,68 +0,0 @@
--- `Effect`
--- Short animation with graphics that plays in various situation.
-
--- Metatable of `Effect`
--- nils initialized in constructor
-Effect = {
- x = 0,
- y = 0,
- delay = 0.06,
- initial = nil,
- frame = 1,
- animation = nil,
- sprite = nil,
- quads = require "effects"
-}
-
--- Construct of `Effect`
-function Effect:new(name, x, y)
- -- Meta
- local o = {}
- setmetatable(o, self)
- self.__index = self
- -- Load spritesheet to metatable if not yet loaded
- if self.sprite == nil then
- self.sprite = love.graphics.newImage("assets/effects.png")
- end
- -- Init
- o.initial = o.delay
- o.animation = name
- o.x = x or self.x
- o.y = y or self.y
- return o
-end
-
--- Position
-function Effect:getPosition()
- return self.x, self.y
-end
-
--- Animation and return flag for deletion after completion
--- returns true if completed and ready to delete
-function Effect:update(dt)
- self.delay = self.delay - dt
- if self.delay < 0 then
- if self.frame < self.quads[self.animation].frames then
- self.frame = self.frame + 1
- self.delay = self.delay + self.initial
- else
- return true -- delete
- end
- end
- return false
-end
-
--- Draw me with scale and offsets, senpai
-function Effect:draw(offset_x, offset_y, scale)
- -- locals
- local offset_x = offset_x or 0
- local offset_y = offset_y or 0
- local scale = scale or 1
- local x, y = self:getPosition()
- -- pixel grid
- local draw_x = (math.floor(x) + offset_x) * scale
- local draw_y = (math.floor(y) + offset_y) * scale
- -- draw
- love.graphics.setColor(255,255,255,255)
- love.graphics.draw(self.sprite, self.quads[self.animation][self.frame], draw_x, draw_y, 0, scale, scale)
-end \ No newline at end of file
diff --git a/element.lua b/element.lua
deleted file mode 100644
index f9d1c3d..0000000
--- a/element.lua
+++ /dev/null
@@ -1,42 +0,0 @@
--- `Element`
--- Empty element for `Menu` creation. Can be anything.
-Element = {
- x = 0,
- y = 0,
- parent
-}
-function Element:new(parent)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- o.parent = parent
- return o
-end
-function Element:delete() end -- deletes Element
-function Element:getPosition() return self.x, self.y end -- gives x,y of Element
-function Element:setPosition(x,y)
- self.x, self.y = x, y
- return self
-end
-function Element:set(name, func)
- if type(name) == "string" and func ~= nil then
- self[name] = func
- end
- return self
-end
-
--- Menu callbacks
-function Element:focus() -- Called when Element gains focus
- return false
-end
-function Element:blur() end -- Called when Element loses focus
-
--- LÖVE2D callbacks
-function Element:draw(scale) end
-function Element:update(dt) end
-
--- Controller callbacks
-function Element:controlpressed(set, action, key) end
-function Element:controlreleased(set, action, key) end
-
-return Element \ No newline at end of file
diff --git a/iconsList.lua b/iconsList.lua
new file mode 100644
index 0000000..4a384dc
--- /dev/null
+++ b/iconsList.lua
@@ -0,0 +1,37 @@
+-- TODO: These should be part of non-existent AssetsManager or something similar.
+local function testAvoidList (i, avoidList)
+ for key,value in pairs(avoidList) do
+ if i == value then
+ table.remove(avoidList, key)
+ return false
+ end
+ end
+ return true
+end
+
+function createIconsList (sheetWidth, sheetHeight, iconWidth, keysList, avoidList)
+ local avoidList = avoidList or {}
+ local iconsList, newKeysList = {}, {}
+ local iconsNumber = math.floor(sheetWidth / iconWidth)
+ local iconHeight = sheetHeight
+ for i=1,iconsNumber do
+ if testAvoidList(i, avoidList) then
+ iconsList[keysList[i]] = love.graphics.newQuad((i-1)*iconWidth, 0, iconWidth, iconHeight, sheetWidth, sheetHeight)
+ table.insert(newKeysList, keysList[i])
+ end
+ end
+ return iconsList, newKeysList
+end
+
+function getNautsIconsList (avoidList)
+ local avoidList = avoidList or {32,33,34,35,36}
+ local keysList = require "config.nauts"
+ local iconsList, newKeysList = createIconsList(1008, 27, 28, keysList, avoidList)
+ return iconsList, newKeysList
+end
+
+function getMapsIconsList (avoidList)
+ local keysList = require "config.maps"
+ local iconsList, newKeysList = createIconsList(532, 37, 76, keysList, avoidList)
+ return iconsList, newKeysList
+end
diff --git a/main.lua b/main.lua
index deff1a1..11e4d95 100644
--- a/main.lua
+++ b/main.lua
@@ -1,10 +1,11 @@
--- "NOTNAUTS"
--- WHOLE CODE HAS FLAG OF "need a cleanup"
+--- Roflnauts 2
+-- TODO: Any lua source file in root directory that is not `main` (this file), `conf` should be moved to a proper directory. Its name should be changed to show what it contains.
-- Pretend you didn't see this
-- This is work for scene manager
+-- TODO: Create SceneManager or similar class.
Scene = nil
-function changeScene(scene)
+function changeScene (scene)
if Scene ~= nil then
Scene:delete()
end
@@ -12,58 +13,41 @@ function changeScene(scene)
end
-- Should be moved to scene/camera
-function getScale()
+-- TODO: move following functions to `Camera`.
+function getScale ()
return math.max(1, math.floor(math.max(love.graphics.getWidth() / 320, love.graphics.getHeight() / 180)))
end
-function getRealScale()
+
+function getRealScale ()
return math.max(1, math.max(love.graphics.getWidth() / 320, love.graphics.getHeight() / 180))
end
--- Should be moved to Sprite metaclass (non-existent yet)
-function newImage(path)
- local imagedata = love.image.newImageData(path)
- local transparency = function(x, y, r, g, b, a)
- if (r == 0 and g == 128 and b == 64) or
- (r == 0 and g == 240 and b == 6) then
- a = 0
- end
- return r, g, b, a
- end
- imagedata:mapPixel(transparency)
- local image = love.graphics.newImage(imagedata)
- return image
-end
-- Require
-require "world"
-require "camera"
-require "menu"
-require "controller"
-require "music"
-require "settings"
+require "iconsList"
+require "not.World"
+require "not.Camera"
+require "not.Menu"
+require "not.Controller"
+require "not.Settings"
-- Temporary debug
debug = false
-- LÖVE2D callbacks
-function love.load()
- -- Graphics
+function love.load ()
love.graphics.setBackgroundColor(90, 90, 90)
love.graphics.setDefaultFilter("nearest", "nearest")
- -- Font
+ -- TODO: Move fonts somewhere else out of global scope.
Font = love.graphics.newImageFont("assets/font-normal.png", " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,:;-_/\\!@#$%^&*?=+~`|'\"()[]{}<>", -1)
Bold = love.graphics.newImageFont("assets/font-big.png", " 0123456789AEFILNORSTUW", -2)
Font:setLineHeight(9/16)
- love.graphics.setFont(Font)
- -- Modules
+ love.graphics.setFont(Font)
Controller.load()
Settings.load()
- -- Scene
Scene = Menu:new()
end
-function love.update(dt)
- Scene:update(dt)
-end
-function love.draw()
+
+function love.draw ()
Scene:draw()
if debug then
local scale = getScale()
@@ -74,21 +58,20 @@ function love.draw()
love.graphics.print("Current FPS: "..tostring(love.timer.getFPS()), 10, 10+9*scale, 0, scale, scale)
end
end
-function love.quit()
- Settings.save()
-end
+
+function love.update (dt) Scene:update(dt) end
+function love.quit () Settings.save() end
+
-- Pass input to Controller
-function love.gamepadaxis(joystick, axis, value) Controller.gamepadaxis(joystick, axis, value) end
-function love.gamepadpressed(joystick, key) Controller.gamepadpressed(joystick, key) end
-function love.gamepadreleased(joystick, key) Controller.gamepadreleased(joystick, key) end
-function love.keypressed(key) Controller.keypressed(key) end
-function love.keyreleased(key) Controller.keyreleased(key) end
+function love.gamepadaxis (joystick, axis, value) Controller.gamepadaxis(joystick, axis, value) end
+function love.gamepadpressed (joystick, key) Controller.gamepadpressed(joystick, key) end
+function love.gamepadreleased (joystick, key) Controller.gamepadreleased(joystick, key) end
+function love.keypressed (key) Controller.keypressed(key) end
+function love.keyreleased (key) Controller.keyreleased(key) end
-- Controller callbacks
-function Controller.controlpressed(set, action, key)
- -- pass to current Scene
+function Controller.controlpressed (set, action, key)
Scene:controlpressed(set, action, key)
- -- globals
if key == "escape" then
love.event.quit()
end
@@ -96,7 +79,7 @@ function Controller.controlpressed(set, action, key)
debug = not debug
end
end
-function Controller.controlreleased(set, action, key)
- -- pass to current Scene
+
+function Controller.controlreleased (set, action, key)
Scene:controlreleased(set, action, key)
end \ No newline at end of file
diff --git a/mapicons.lua b/mapicons.lua
deleted file mode 100644
index 4893da7..0000000
--- a/mapicons.lua
+++ /dev/null
@@ -1,12 +0,0 @@
--- Maps icons list generation file
--- REWORK NEEDED, it is so similar to `nautsicons.lua` they could be merged together into one function that returns icon quad sequences.
-local maps = require "maplist"
-local w, h = 532, 37
-local icons = {}
-
-local i = 0
-for _,map in pairs(maps) do
- icons[map] = love.graphics.newQuad(i*76, 0, 76, 37, w, h)
- i = i + 1
-end
-return icons
diff --git a/music.lua b/music.lua
deleted file mode 100644
index 1ac26bb..0000000
--- a/music.lua
+++ /dev/null
@@ -1,27 +0,0 @@
--- `Music`
--- Simple music player object that plays and loops selected track in single Scene.
-
--- WHOLE CODE HAS FLAG OF "need a cleanup"
-
--- Metatable of `Music`
--- nils initialized in constructor
-Music = {
- track = nil,
- source = nil
-}
-function Music:new(track)
- -- Meta
- local o = {}
- setmetatable(o, self)
- self.__index = self
- -- Init
- o.track = track
- o.source = love.audio.newSource("assets/music/" .. o.track)
- o.source:setLooping(true)
- o.source:setVolume(.7)
- o.source:play()
- return o
-end
-function Music:delete()
- self.source:stop()
-end \ No newline at end of file
diff --git a/nautsicons.lua b/nautsicons.lua
deleted file mode 100644
index 6c09a8f..0000000
--- a/nautsicons.lua
+++ /dev/null
@@ -1,11 +0,0 @@
--- Spritesheet for character portraits
-local nauts = require "nautslist"
-local w, h = 1008, 27
-local icons = {}
-
-local i = 0
-for _,naut in pairs(nauts) do
- icons[naut] = love.graphics.newQuad(i*28, 0, 28, 27, w, h)
- i = i + 1
-end
-return icons
diff --git a/button.lua b/not/Button.lua
index c5681b2..91aca45 100644
--- a/button.lua
+++ b/not/Button.lua
@@ -1,51 +1,48 @@
--- `Button`
--- Button used in `Menu`
-
+--- `Button`
+-- Menu element that can be activated by user.
Button = {
- text = "",
- focused = false,
+ parent = --[[not.Menu]]nil,
x = 0,
y = 0,
+ text = "",
+ focused = false,
sprite,
quads,
delay = 2,
parent,
}
-function Button:new(parent)
- local o = {}
- setmetatable(o, self)
- self.__index = self
+-- `Button` is a child of `Element`.
+require "not.Element"
+Button.__index = Button
+setmetatable(Button, Element)
+
+function Button:new (parent)
+ local o = setmetatable({}, self)
o.parent = parent
o.sprite, o.quads = parent:getSheet()
return o
end
-function Button:setText(text)
+
+function Button:setText (text)
self.text = text or ""
return self
end
-function Button:setPosition(x, y)
- self.x = x or 0
- self.y = y or 0
- return self
-end
-function Button:getPosition() return self.x,self.y end
+
function Button:focus(next)
self.focused = true
return true
end
-function Button:blur()
+function Button:blur ()
self.focused = false
end
-function Button:active() end
-function Button:isEnabled() return true end
-function Button:set(name, func)
- if type(name) == "string" and type(func) == "function" then
- self[name] = func
- end
- return self
+
+function Button:active () end
+function Button:isEnabled ()
+ return true
end
-function Button:draw(scale)
+
+function Button:draw (scale)
local x,y = self:getPosition()
local quad = self.quads
local sprite = self.sprite
@@ -62,17 +59,18 @@ function Button:draw(scale)
love.graphics.setFont(Font)
love.graphics.printf(self.text, (x+2)*scale, (y+4)*scale, 54, "center", 0, scale, scale)
end
-function Button:update(dt)
+
+function Button:update (dt)
self.delay = self.delay + dt
if self.delay > Button.delay then -- Button.delay is initial
self.delay = self.delay - Button.delay
end
end
-function Button:controlpressed(set, action, key)
+
+function Button:controlpressed (set, action, key)
if action == "attack" and self.focused and self:isEnabled() then
self:active()
end
end
-function Button:controlreleased(set, action, key) end
-return Button \ No newline at end of file
+return Button
diff --git a/camera.lua b/not/Camera.lua
index 2ae7c78..63489f3 100644
--- a/camera.lua
+++ b/not/Camera.lua
@@ -1,7 +1,5 @@
--- `Camera`
+--- `Camera`
-- Used in drawing.
-
--- Metatable of `Camera`
Camera = {
x = 0,
y = 0,
@@ -16,7 +14,7 @@ Camera = {
origin_y = 0,
shake_x = 0,
shake_y = 0,
- world = nil, -- game world
+ world = --[[not.World]]nil,
}
-- Constructor of `Camera`
@@ -62,7 +60,7 @@ function Camera:getDestination ()
end
-- Translate points
-function Camera:translatePosition(x, y)
+function Camera:translatePosition (x, y)
local x = x or 0
local y = y or 0
return (x-self.x)*self.scale, (y-self.y)*self.scale
diff --git a/not/Cloud.lua b/not/Cloud.lua
new file mode 100644
index 0000000..3bc5377
--- /dev/null
+++ b/not/Cloud.lua
@@ -0,0 +1,71 @@
+--- `Cloud`
+-- That white thing moving in the background.
+-- TODO: extends variables names to be readable.
+Cloud = {
+ t = 1, -- type (sprite number)
+ v = 13 -- velocity
+}
+
+-- TODO: allow maps to use other quads and sprites for clouds
+-- TODO: you know this isn't right, don't you?
+local animations = {
+ default = {
+ [1] = love.graphics.newQuad( 1, 1, 158,47, 478,49),
+ frames = 1,
+ repeated = true
+ },
+ default2 = {
+ [1] = love.graphics.newQuad(160, 1, 158,47, 478,49),
+ frames = 1,
+ repeated = true
+ },
+ default3 = {
+ [1] = love.graphics.newQuad(319, 1, 158,47, 478,49),
+ frames = 1,
+ repeated = true
+ }
+}
+
+-- `Cloud` is a child of `Decoration`.
+require "not.Decoration"
+Cloud.__index = Cloud
+setmetatable(Cloud, Decoration)
+
+-- Constructor of `Cloud`.
+function Cloud:new (x, y, t, v)
+ local o = setmetatable({}, self)
+ o:init(x, y, t, v)
+ -- Load spritesheet statically.
+ if self:getImage() == nil then
+ self:setImage(Sprite.newImage("assets/clouds.png"))
+ end
+ return o
+end
+
+-- Initializer of `Cloud`.
+function Cloud:init (x, y, t, v)
+ Decoration.init(self, x, y, nil)
+ self:setAnimationsList(animations)
+ self:setVelocity(v)
+ self:setType(t)
+end
+
+-- Setters for cloud type and velocity.
+function Cloud:setType (type)
+ local animation = "default"
+ if type > 1 then
+ animation = animation .. type
+ end
+ self:setAnimation(animation)
+ self.t = type
+end
+function Cloud:setVelocity (velocity)
+ self.v = velocity
+end
+
+-- Update of `Cloud`, returns x for world to delete cloud after reaching right corner.
+function Cloud:update (dt)
+ Decoration.update(self, dt)
+ self.x = self.x + self.v*dt
+ return self.x
+end
diff --git a/controller.lua b/not/Controller.lua
index f035162..8a2a863 100644
--- a/controller.lua
+++ b/not/Controller.lua
@@ -1,14 +1,12 @@
--- `Controller`
+--- `Controller`
-- Module to manage player input.
-- It uses `love.keypressed`, `love.keyreleased`, `love.gamepadreleased`, `love.gamepadpressed`, `love.joystickadded`, so be sure not to use them by yourself.
-- Rather than that use functions provided by this module: `Controller.controlpressed` and `Controller.controlreleased`.
--- For information on additional functions, look below.
-
--- Namespace
-Controller = {}
-Controller.sets = {}
-Controller.axes = {}
-Controller.deadzone = .3
+Controller = {
+ sets = {},
+ axes = {},
+ deadzone = .3
+}
-- Declared to avoid calling nil. Be sure to define yours after this line is performed.
function Controller.controlpressed(set, action, key) end
diff --git a/not/Decoration.lua b/not/Decoration.lua
new file mode 100644
index 0000000..9dc2bdd
--- /dev/null
+++ b/not/Decoration.lua
@@ -0,0 +1,33 @@
+--- `Decoration`
+-- Positioned sprite used to decorate maps with additional graphics.
+Decoration = {
+ world = --[[not.World]]nil,
+ x = 0,
+ y = 0
+}
+
+-- `Decoration` is a child of `Sprite`.
+require "not.Sprite"
+Decoration.__index = Decoration
+setmetatable(Decoration, Sprite)
+
+-- Constructor of `Decoration`.
+function Decoration:new (x, y, imagePath)
+ local o = setmetatable({}, self)
+ o:init(x, y, imagePath)
+ return o
+end
+
+-- Initializer of `Decoration`.
+function Decoration:init (x, y, imagePath)
+ Sprite.init(self, imagePath)
+ self:setPosition(x, y)
+end
+
+-- Position-related methods.
+function Decoration:getPosition ()
+ return self.x, self.y
+end
+function Decoration:setPosition (x, y)
+ self.x, self.y = x, y
+end \ No newline at end of file
diff --git a/not/Effect.lua b/not/Effect.lua
new file mode 100644
index 0000000..dd7570a
--- /dev/null
+++ b/not/Effect.lua
@@ -0,0 +1,46 @@
+--- `Effect`
+-- Short animation with graphics that plays in various situation.
+-- TODO: animation is currently slower than it used to be, check if it is ok; if not then make it possible to change it to 0.06 delay.
+Effect = {
+ finished = false,
+}
+
+-- `Effect` is a child of `Decoration`.
+require "not.Decoration"
+Effect.__index = Effect
+setmetatable(Effect, Decoration)
+
+-- Constructor of `Effect`.
+function Effect:new (name, x, y)
+ local o = setmetatable({}, self)
+ o:init(name, x, y)
+ -- Load spritesheet statically.
+ if self:getImage() == nil then
+ self:setImage(Sprite.newImage("assets/effects.png"))
+ end
+ return o
+end
+
+-- Initializer of `Effect`.
+function Effect:init (name, x, y)
+ Decoration.init(self, x, y, nil)
+ self:setAnimationsList(require("config.animations.effects"))
+ self:setAnimation(name)
+end
+
+-- Update of `Effect`.
+-- Returns true if animation is finished and effect is ready to be deleted.
+function Effect:update (dt)
+ Decoration.update(self, dt)
+ return self.finished
+end
+
+-- Overridden from `not.Sprite`.
+-- Sets finished flag if reached last frame of played animation.
+function Effect:goToNextFrame ()
+ if not (self.frame == self.current.frames) then
+ self.frame = (self.frame % self.current.frames) + 1
+ else
+ self.finished = true
+ end
+end
diff --git a/not/Element.lua b/not/Element.lua
new file mode 100644
index 0000000..e6d91da
--- /dev/null
+++ b/not/Element.lua
@@ -0,0 +1,50 @@
+--- `Element`
+-- Empty element used inside `Menu`.
+Element = {
+ parent = --[[not.Menu]]nil,
+ x = 0,
+ y = 0
+}
+
+Element.__index = Element
+
+function Element:new (parent)
+ local o = setmetatable({}, self)
+ o.parent = parent
+ return o
+end
+
+function Element:delete () end -- deletes Element
+
+function Element:getPosition ()
+ return self.x, self.y
+end
+function Element:setPosition (x, y)
+ self.x = x or 0
+ self.y = y or 0
+ return self
+end
+
+function Element:set (name, func)
+ if type(name) == "string" and func ~= nil then
+ self[name] = func
+ end
+ return self
+end
+
+-- Called when menu tries to focus on this element.
+-- If it will return false then menu will skip element and go to next in list.
+function Element:focus ()
+ return false
+end
+function Element:blur () end -- Called when Element loses focus.
+
+-- LÖVE2D callbacks
+function Element:draw (scale) end
+function Element:update (dt) end
+
+-- Controller callbacks
+function Element:controlpressed (set, action, key) end
+function Element:controlreleased (set, action, key) end
+
+return Element
diff --git a/header.lua b/not/Header.lua
index d67e582..a563ab2 100644
--- a/header.lua
+++ b/not/Header.lua
@@ -1,41 +1,36 @@
--- `Header`
--- It dances!
-
+--- `Header`
+-- Swinging title.
Header = {
+ parent = --[[not.Menu]]nil,
x = 0,
y = 0,
text = "",
- parent,
bounce = 2,
}
-function Header:new(parent)
- local o = {}
- setmetatable(o, self)
- self.__index = self
+
+-- `Header` is a child of `Element`.
+require "not.Element"
+Header.__index = Header
+setmetatable(Header, Element)
+
+function Header:new (parent)
+ local o = setmetatable({}, self)
o.parent = parent
return o
end
-function Header:setText(text)
+
+function Header:setText (text)
self.text = text or ""
return self
end
-function Header:setPosition(x, y)
- self.x = x or 0
- self.y = y or 0
- return self
-end
-function Header:getBounce(f)
+
+function Header:getBounce (f)
local f = f or 1
return math.sin(self.bounce*f*math.pi)
end
-function Header:getPosition() return self.x,self.y end -- gives x,y of Element
-function Header:focus()
- return false
-end
-function Header:blur() end -- Called when Element loses focus
-- LÖVE2D callbacks
-function Header:draw(scale)
+function Header:draw (scale)
local angle = self:getBounce(2)
local dy = self:getBounce()*4
local x,y = self:getPosition()
@@ -43,15 +38,11 @@ function Header:draw(scale)
love.graphics.setFont(Bold)
love.graphics.printf(string.upper(self.text),x*scale,(y+dy)*scale,400,"center",(angle*5)*math.pi/180,scale,scale,200,12)
end
-function Header:update(dt)
+function Header:update (dt)
self.bounce = self.bounce + dt*0.7
if self.bounce > Header.bounce then -- Header.bounce is initial
self.bounce = self.bounce - Header.bounce
end
end
--- Controller callbacks
-function Header:controlpressed(set, action, key) end
-function Header:controlreleased(set, action, key) end
-
-return Header \ No newline at end of file
+return Header
diff --git a/not/Hero.lua b/not/Hero.lua
new file mode 100644
index 0000000..feb61da
--- /dev/null
+++ b/not/Hero.lua
@@ -0,0 +1,284 @@
+--- `Hero`
+-- Hero (often referred to as: "naut") entity that exists in a game world.
+-- Collision category: [2]
+Hero = {
+ -- General and physics
+ name = "empty",
+ angle = 0,
+ facing = 1,
+ max_velocity = 105,
+ world = --[[not.World]]nil,
+ group = nil,
+ -- Combat
+ combo = 0,
+ lives = 3,
+ spawntimer = 2,
+ isAlive = true,
+ punchCooldown = 0.25,
+ punchdir = 0, -- a really bad thing
+ -- Movement
+ inAir = true,
+ salto = false,
+ isJumping = false,
+ isWalking = false,
+ jumpTimer = 0.16,
+ jumpCounter = 2,
+ -- Statics
+ portrait_sprite = nil,
+ portrait_frame = nil,
+ portrait_sheet = getNautsIconsList(),
+ portrait_box = love.graphics.newQuad( 0, 15, 32,32, 80,130),
+ sfx = require "config.sounds",
+}
+
+-- `Hero` is a child of `PhysicalBody`.
+require "not.PhysicalBody"
+Hero.__index = Hero
+setmetatable(Hero, PhysicalBody)
+
+-- Constructor of `Hero`.
+function Hero:new (game, world, x, y, name)
+ local o = setmetatable({}, self)
+ o:init(name, game, x, y)
+ -- Load portraits statically.
+ if self.portrait_sprite == nil then
+ self.portrait_sprite = love.graphics.newImage("assets/portraits.png")
+ self.portrait_frame = love.graphics.newImage("assets/menu.png")
+ end
+ return o
+end
+
+-- Initializer of `Hero`.
+function Hero:init (name, world, x, y)
+ -- Find imagePath based on hero name.
+ local fileName = name or Hero.name -- INITIAL from metatable
+ local imagePath = string.format("assets/nauts/%s.png", fileName)
+ -- `PhysicalBody` initialization.
+ PhysicalBody.init(self, world, x, y, imagePath)
+ self:setBodyType("dynamic")
+ self:setBodyFixedRotation(true)
+ self.group = -1-#world.Nauts
+ -- Main fixture initialization.
+ local fixture = self:addFixture({-5,-8, 5,-8, 5,8, -5,8}, 8)
+ fixture:setUserData(self)
+ fixture:setCategory(2)
+ fixture:setMask(2)
+ fixture:setGroupIndex(self.group)
+ -- Actual `Hero` initialization.
+ self.world = world
+ self.punchCooldown = 0
+ self.name = name
+ self:setAnimationsList(require("config.animations.hero"))
+ self:createEffect("respawn")
+end
+
+-- Update callback of `Hero`
+function Hero:update (dt)
+ PhysicalBody.update(self, dt)
+ if self.body:isDestroyed() then return end
+
+ -- Salto
+ if self.salto and (self.current == self.animations.walk or self.current == self.animations.default) then
+ self.angle = (self.angle + 17 * dt * self.facing) % 360
+ elseif self.angle ~= 0 then
+ self.angle = 0
+ end
+
+ -- Custom linear damping.
+ if not self.isWalking then
+ local face = nil
+ local x, y = self:getLinearVelocity()
+ if x < -12 then
+ face = 1
+ elseif x > 12 then
+ face = -1
+ else
+ face = 0
+ end
+ self:applyForce(40*face,0)
+ if not self.inAir then
+ self:applyForce(80*face,0)
+ end
+ end
+
+ -- Could you please die?
+ -- TODO: World/Map function for testing if Point is inside playable area.
+ local m = self.world.map
+ local x, y = self:getPosition()
+ if (x < m.center_x - m.width*1.5 or x > m.center_x + m.width*1.5 or
+ y < m.center_y - m.height*1.5 or y > m.center_y + m.height*1.5) and
+ self.isAlive
+ then
+ self:die()
+ end
+
+ -- Respawn timer.
+ if self.spawntimer > 0 then
+ self.spawntimer = self.spawntimer - dt
+ end
+ if self.spawntimer <= 0 and not self.isAlive and self.lives >= 0 then
+ self:respawn()
+ end
+
+ -- # PUNCH
+ -- Cooldown
+ self.punchCooldown = self.punchCooldown - dt
+ if not self.body:isDestroyed() then -- TODO: This is weird
+ for _,fixture in pairs(self.body:getFixtureList()) do -- TODO: getFixtures from `PhysicalBody` or similar.
+ if fixture:getUserData() ~= self then
+ fixture:setUserData({fixture:getUserData()[1] - dt, fixture:getUserData()[2]})
+ if fixture:getUserData()[1] < 0 then
+ fixture:destroy()
+ end
+ end
+ end
+ end
+
+ -- Stop vertical
+ local c,a = self.current, self.animations
+ if (c == a.attack_up or c == a.attack_down or c == a.attack) and self.frame < c.frames then
+ if self.punchdir == 0 then
+ self:setLinearVelocity(0,0)
+ else
+ self:setLinearVelocity(38*self.facing,0)
+ end
+ end
+
+ if self.punchCooldown <= 0 and self.punchdir == 1 then
+ self.punchdir = 0
+ end
+end
+
+-- TODO: comment them and place them somewhere properly
+function Hero:getAngle ()
+ return self.angle
+end
+function Hero:getHorizontalMirror ()
+ return self.facing
+end
+function Hero:getOffset ()
+ return 12,15
+end
+
+-- Draw of `Hero`
+function Hero:draw (offset_x, offset_y, scale, debug)
+ if not self.isAlive then return end
+ PhysicalBody.draw(self, offset_x, offset_y, scale, debug)
+end
+
+-- Draw HUD of `Hero`
+-- elevation: 1 bottom, 0 top
+function Hero:drawHUD (x,y,scale,elevation)
+ -- hud displays only if player is alive
+ if self.isAlive then
+ love.graphics.setColor(255,255,255,255)
+ love.graphics.draw(self.portrait_frame, self.portrait_box, (x)*scale, (y)*scale, 0, scale, scale)
+ love.graphics.draw(self.portrait_sprite, self.portrait_sheet[self.name], (x+2)*scale, (y+3)*scale, 0, scale, scale)
+ local dy = 30 * elevation
+ love.graphics.setFont(Font)
+ love.graphics.print((self.combo).."%",(x+2)*scale,(y-3+dy)*scale,0,scale,scale)
+ love.graphics.print(math.max(0, self.lives),(x+24)*scale,(y-3+dy)*scale,0,scale,scale)
+ end
+end
+
+-- Change animation of `Hero`
+-- default, walk, attack, attack_up, attack_down, damage
+function Hero:goToNextFrame ()
+ if self.current.repeated or not (self.frame == self.current.frames) then
+ self.frame = (self.frame % self.current.frames) + 1
+ elseif self.isWalking then
+ self:setAnimation("walk")
+ elseif self.current == self.animations.damage then
+ self:setAnimation("default")
+ end
+end
+
+-- Spawn `Effect` relative to `Hero`
+function Hero:createEffect (name)
+ if name == "trail" or name == "hit" then
+ -- 16px effect: -7 -7
+ self.world:createEffect(name, self.body:getX()-8, self.body:getY()-8)
+ elseif name ~= nil then
+ -- 24px effect: -12 -15
+ self.world:createEffect(name, self.body:getX()-12, self.body:getY()-15)
+ end
+end
+
+-- Creates temporary fixture for hero's body that acts as sensor.
+-- direction: ("left", "right", "up", "down")
+-- Sensor fixture is deleted after time set in UserData[1]; deleted by `not.Hero.update`.
+-- TODO: Magic numbers present in `not.Hero.punch`.
+function Hero:punch (direction)
+ self.punchCooldown = Hero.punchCooldown -- INITIAL from metatable
+ -- Choose shape based on punch direction.
+ local shape
+ if direction == "left" then shape = {-2,-6, -20,-6, -20,6, -2,6} end
+ if direction == "right" then shape = {2,-6, 20,-6, 20,6, 2,6} end
+ if direction == "up" then shape = {-8,-4, -8,-20, 8,-20, 8,-4} end
+ if direction == "down" then shape = {-8,4, -8,20, 8,20, 8,4} end
+ -- Create and set sensor fixture.
+ local fixture = self:addFixture(shape, 0)
+ fixture:setSensor(true)
+ fixture:setCategory(3)
+ fixture:setMask(1,3)
+ fixture:setGroupIndex(self.group)
+ fixture:setUserData({0.08, direction})
+ self:playSound(4)
+end
+
+-- Taking damage of `Hero` by successful hit test
+-- currently called from World's startContact
+-- TODO: attack functions needs to be renamed, because even I have problems understanding them.
+function Hero:damage (direction)
+ local horizontal, vertical = 0, 0
+ if direction == "left" then
+ horizontal = -1
+ end
+ if direction == "right" then
+ horizontal = 1
+ end
+ if direction == "up" then
+ vertical = -1
+ end
+ if direction == "down" then
+ vertical = 1
+ end
+ self:createEffect("hit")
+ local x,y = self:getLinearVelocity()
+ self:setLinearVelocity(x,0)
+ self:applyLinearImpulse((42+self.combo)*horizontal, (68+self.combo)*vertical + 15)
+ self:setAnimation("damage")
+ self.combo = math.min(999, self.combo + 10)
+ self.punchCooldown = 0.08 + self.combo*0.0006
+ self:playSound(2)
+end
+
+-- DIE
+function Hero:die ()
+ self:playSound(1)
+ self.combo = Hero.combo -- INITIAL from metatable
+ self.lives = self.lives - 1
+ self.isAlive = false
+ self.spawntimer = Hero.spawntimer -- INITIAL from metatable
+ self:setBodyActive(false)
+ self.world:onNautKilled(self)
+end
+
+-- And then respawn. Like Jon Snow.
+function Hero:respawn ()
+ self.isAlive = true
+ self:setLinearVelocity(0,0)
+ self:setPosition(self.world:getSpawnPosition()) -- TODO: I'm not convinced about getting new position like this.
+ self:setBodyActive(true)
+ self:createEffect("respawn")
+ self:playSound(7)
+end
+
+-- Sounds
+-- TODO: Possibly export to nonexistent SoundEmitter class. Can be used by World (Stage), too.
+function Hero:playSound (sfx, force)
+ if self.isAlive or force then
+ local source = love.audio.newSource(self.sfx[sfx])
+ source:play()
+ end
+end
diff --git a/menu.lua b/not/Menu.lua
index fef46df..8ef1861 100644
--- a/menu.lua
+++ b/not/Menu.lua
@@ -1,24 +1,20 @@
--- `Menu` (Scene)
+--- `Menu`
-- It creates single screen of a menu
-- I do know that model I used here and in `World` loading configuration files is not flawless but I did not want to rewrite `World`s one but wanted to keep things similar at least in project scope.
-
-require "music"
-
--- Here it begins
Menu = {
scale = getScale(),
- elements, --table
+ elements = --[[{not.Element}]]nil,
active = 1,
- music,
- sprite,
- background,
- asteroids,
- stars,
+ music = --[[not.Music]]nil,
+ sprite = --[[love.graphics.newImage]]nil,
+ background = --[[love.graphics.newImage]]nil,
+ asteroids = --[[love.graphics.newImage]]nil,
+ stars = --[[love.graphics.newImage]]nil,
asteroids_bounce = 0,
stars_frame = 1,
stars_delay = 0.8,
allowMove = true,
- quads = {
+ quads = { -- TODO: Could be moved to config file or perhaps QuadManager to manage all quads for animations etc.
button = {
normal = love.graphics.newQuad(0, 0, 58,15, 80,130),
active = love.graphics.newQuad(0, 0, 58,15, 80,130)
@@ -39,46 +35,54 @@ Menu = {
},
}
}
-function Menu:new(name)
- local o = {}
- setmetatable(o, self)
- self.__index = self
- self.sprite = love.graphics.newImage("assets/menu.png")
- self.background = love.graphics.newImage("assets/backgrounds/menu.png")
- self.asteroids = love.graphics.newImage("assets/asteroids.png")
- self.stars = love.graphics.newImage("assets/stars.png")
- o.elements = {}
- o:load(name)
- o.music = Music:new("menu.ogg")
+
+Menu.__index = Menu
+
+require "not.Music"
+
+function Menu:new (name)
+ local o = setmetatable({}, self)
+ -- Load statically.
+ if self.sprite == nil then
+ self.sprite = love.graphics.newImage("assets/menu.png")
+ self.background = love.graphics.newImage("assets/backgrounds/menu.png")
+ self.asteroids = love.graphics.newImage("assets/asteroids.png")
+ self.stars = love.graphics.newImage("assets/stars.png")
+ end
+ o:init(name)
return o
end
-function Menu:delete()
+
+function Menu:init (name)
+ self.music = Music:new("menu.ogg")
+ self:open(name)
+end
+
+function Menu:delete ()
self.music:delete()
end
--- Load menu from file
-function Menu:load(name)
- local name = "config/" .. (name or "menumain") .. ".lua"
- local menu = love.filesystem.load(name)
- self.active = 1
- self.elements = menu(self)
+function Menu:open (name)
+ local name = name or "main"
+ self.active = Menu.active --Menu.active is initial
+ self.elements = love.filesystem.load(string.format("config/menus/%s.lua", name))(self)
self.elements[self.active]:focus()
end
-- Return reference to quads table and menu sprite
-function Menu:getSheet()
+function Menu:getSheet ()
return self.sprite, self.quads
end
-- Cycle elements
-function Menu:next()
+function Menu:next ()
self.elements[self.active]:blur()
self.active = (self.active%#self.elements)+1
if not self.elements[self.active]:focus() then
self:next()
end
end
-function Menu:previous()
+function Menu:previous ()
self.elements[self.active]:blur()
if self.active == 1 then
self.active = #self.elements
@@ -91,7 +95,7 @@ function Menu:previous()
end
-- LÖVE2D callbacks
-function Menu:update(dt)
+function Menu:update (dt)
for _,element in pairs(self.elements) do
element:update(dt)
end
@@ -107,7 +111,7 @@ function Menu:update(dt)
end
end
end
-function Menu:draw()
+function Menu:draw ()
local scale = self.scale
local scaler = getRealScale()
love.graphics.draw(self.background, 0, 0, 0, scaler, scaler)
@@ -120,7 +124,7 @@ function Menu:draw()
end
-- Controller callbacks
-function Menu:controlpressed(set, action, key)
+function Menu:controlpressed (set, action, key)
if self.allowMove then
if action == "down" then
self:next()
@@ -133,7 +137,7 @@ function Menu:controlpressed(set, action, key)
element:controlpressed(set, action, key)
end
end
-function Menu:controlreleased(set, action, key)
+function Menu:controlreleased (set, action, key)
for _,element in pairs(self.elements) do
element:controlreleased(set, action, key)
end
diff --git a/not/Music.lua b/not/Music.lua
new file mode 100644
index 0000000..ee930f4
--- /dev/null
+++ b/not/Music.lua
@@ -0,0 +1,25 @@
+--- `Music`
+-- Simple music player object that plays and loops selected track in single Scene.
+Music = {
+ source = --[[love.audio.newSource]]nil
+}
+
+Music.__index = Music
+
+function Music:new (trackName)
+ local o = setmetatable({}, self)
+ o:init(trackName)
+ return o
+end
+
+-- TODO: trackName should be passed without file extension.
+function Music:init (trackName)
+ self.source = love.audio.newSource("assets/music/" .. trackName)
+ self.source:setLooping(true)
+ self.source:setVolume(.7)
+ self.source:play()
+end
+
+function Music:delete ()
+ self.source:stop()
+end \ No newline at end of file
diff --git a/not/PhysicalBody.lua b/not/PhysicalBody.lua
new file mode 100644
index 0000000..e9625fa
--- /dev/null
+++ b/not/PhysicalBody.lua
@@ -0,0 +1,93 @@
+--- `PhysicalBody`
+-- Abstract class for drawable entity existing in `not.World`.
+PhysicalBody = {
+ body =--[[love.physics.newBody]]nil,
+}
+
+-- `PhysicalBody` is a child of `Sprite`.
+require "not.Sprite"
+PhysicalBody.__index = PhysicalBody
+setmetatable(PhysicalBody, Sprite)
+
+--[[ Constructor of `PhysicalBody`.
+function PhysicalBody:new (world, x, y, imagePath)
+ local o = setmetatable({}, self)
+ o:init(world, x, y, imagePath)
+ return o
+end
+]]
+
+-- Initializer of `PhysicalBody`.
+function PhysicalBody:init (world, x, y, imagePath)
+ Sprite.init(self, imagePath)
+ self.body = love.physics.newBody(world.world, x, y)
+end
+
+-- Add new fixture to body.
+function PhysicalBody:addFixture (shape, density)
+ local shape = love.physics.newPolygonShape(shape)
+ local fixture = love.physics.newFixture(self.body, shape, density)
+ return fixture
+end
+
+-- Position-related methods.
+function PhysicalBody:getPosition ()
+ return self.body:getPosition()
+end
+function PhysicalBody:setPosition (x, y)
+ self.body:setPosition(x, y)
+end
+
+-- Velocity-related methods.
+function PhysicalBody:setLinearVelocity (x, y)
+ self.body:setLinearVelocity(x, y)
+end
+function PhysicalBody:getLinearVelocity ()
+ return self.body:getLinearVelocity()
+end
+
+-- Various setters from Body.
+-- type: BodyType ("static", "dynamic", "kinematic")
+function PhysicalBody:setBodyType (type)
+ self.body:setType(type)
+end
+function PhysicalBody:setBodyFixedRotation (bool)
+ self.body:setFixedRotation(bool)
+end
+function PhysicalBody:setBodyActive (bool)
+ self.body:setActive(bool)
+end
+
+-- Physical influence methods.
+function PhysicalBody:applyLinearImpulse (x, y)
+ self.body:applyLinearImpulse(x, y)
+end
+function PhysicalBody:applyForce (x, y)
+ self.body:applyForce(x, y)
+end
+
+-- Update of `PhysicalBody`.
+function PhysicalBody:update (dt)
+ Sprite.update(self, dt)
+end
+
+-- Draw of `PhysicalBody`.
+function PhysicalBody:draw (offset_x, offset_y, scale, debug)
+ Sprite.draw(self, offset_x, offset_y, scale)
+ if debug then
+ for _,fixture in pairs(self.body:getFixtureList()) do
+ local category = fixture:getCategory()
+ if category == 1 then
+ love.graphics.setColor(255, 69, 0, 140)
+ end
+ if category == 2 then
+ love.graphics.setColor(137, 255, 0, 120)
+ end
+ if category == 3 then
+ love.graphics.setColor(137, 0, 255, 40)
+ end
+ -- TODO: `world` is not a member of `PhysicalBody` or its instance normally.
+ love.graphics.polygon("fill", self.world.camera:translatePoints(self.body:getWorldPoints(fixture:getShape():getPoints())))
+ end
+ end
+end
diff --git a/not/Platform.lua b/not/Platform.lua
new file mode 100644
index 0000000..3748c47
--- /dev/null
+++ b/not/Platform.lua
@@ -0,0 +1,37 @@
+--- `Platform`
+-- Static platform physical object with a sprite. `Players` can walk on it.
+-- Collision category: [1]
+-- TODO: reformat code to follow new code patterns
+-- TODO: comment uncovered code parts
+Platform = {
+ world = --[[not.World]]nil,
+}
+
+-- `Platform` is a child of `PhysicalBody`.
+require "not.PhysicalBody"
+Platform.__index = Platform
+setmetatable(Platform, PhysicalBody)
+
+-- Constructor of `Platform`
+function Platform:new (animations, shape, game, x, y, sprite)
+ local o = setmetatable({}, self)
+ o:init(animations, shape, game, x, y, sprite)
+ return o
+end
+
+-- Initializer of `Platform`.
+function Platform:init (animations, shape, world, x, y, imagePath)
+ PhysicalBody.init(self, world, x, y, imagePath)
+ self:setAnimationsList(animations)
+ self.world = world
+ -- Create table of shapes if single shape is passed.
+ if type(shape[1]) == "number" then
+ shape = {shape}
+ end
+ -- Add all shapes from as fixtures to body.
+ for _,single in pairs(shape) do
+ local fixture = self:addFixture(single)
+ fixture:setCategory(1)
+ fixture:setFriction(0.2)
+ end
+end \ No newline at end of file
diff --git a/not/Player.lua b/not/Player.lua
new file mode 100644
index 0000000..2a4b2e6
--- /dev/null
+++ b/not/Player.lua
@@ -0,0 +1,159 @@
+--- `Player`
+-- Special `not.Hero` controllable by a player.
+Player = {
+ -- TODO: move functions and properties related to controls from `not.Hero`.
+ controllerSet = --[[Controller.sets.*]]nil,
+}
+
+-- `Player` is a child of `Hero`.
+require "not.Hero"
+Player.__index = Player
+setmetatable(Player, Hero)
+
+-- Constructor of `Player`.
+function Player:new (name, game, x, y)
+ local o = setmetatable({}, self)
+ o:init(name, game, x, y)
+ -- Load portraits statically to `not.Hero`.
+ -- TODO: this is heresy, put it into `load` method or something similar.
+ if Hero.portrait_sprite == nil then
+ Hero.portrait_sprite = love.graphics.newImage("assets/portraits.png")
+ Hero.portrait_frame = love.graphics.newImage("assets/menu.png")
+ end
+ return o
+end
+
+-- Initializer of `Player`.
+function Player:init (...)
+ Hero.init(self, ...)
+end
+
+-- Controller set manipulation.
+function Player:assignControllerSet (set)
+ self.controllerSet = set
+end
+function Player:getControllerSet ()
+ return self.controllerSet
+end
+
+-- Check if control of assigned controller is pressed.
+function Player:isControlDown (control)
+ return Controller.isDown(self:getControllerSet(), control)
+end
+
+-- Update of `Player`.
+function Player:update (dt)
+ Hero.update(self, dt) -- TODO: It would be probably a good idea to add return to update functions to terminate if something goes badly in parent's update.
+ if self.body:isDestroyed() then return end
+ local x, y = self:getLinearVelocity()
+ -- Jumping.
+ if self.isJumping and self.jumpTimer > 0 then
+ self:setLinearVelocity(x,-160)
+ self.jumpTimer = self.jumpTimer - dt
+ end
+
+ -- Walking.
+ if self:isControlDown("left") then
+ self.facing = -1
+ self:applyForce(-250, 0)
+ -- Controlled speed limit
+ if x < -self.max_velocity then
+ self:applyForce(250, 0)
+ end
+ end
+ if self:isControlDown("right") then
+ self.facing = 1
+ self:applyForce(250, 0)
+ -- Controlled speed limit
+ if x > self.max_velocity then
+ self:applyForce(-250, 0)
+ end
+ end
+end
+
+-- Controller callbacks.
+function Player:controlpressed (set, action, key)
+ if set ~= self:getControllerSet() then return end
+ -- Jumping
+ if action == "jump" then
+ if self.jumpCounter > 0 then
+ -- General jump logics
+ self.isJumping = true
+ --self:playSound(6)
+ -- Spawn proper effect
+ if not self.inAir then
+ self:createEffect("jump")
+ else
+ self:createEffect("doublejump")
+ end
+ -- Start salto if last jump
+ if self.jumpCounter == 1 then
+ self.salto = true
+ end
+ -- Animation clear
+ if (self.current == self.animations.attack) or
+ (self.current == self.animations.attack_up) or
+ (self.current == self.animations.attack_down) then
+ self:setAnimation("default")
+ end
+ -- Remove jump
+ self.jumpCounter = self.jumpCounter - 1
+ end
+ end
+
+ -- Walking
+ if (action == "left" or action == "right") then
+ self.isWalking = true
+ if (self.current ~= self.animations.attack) and
+ (self.current ~= self.animations.attack_up) and
+ (self.current ~= self.animations.attack_down) then
+ self:setAnimation("walk")
+ end
+ end
+
+ -- Punching
+ if action == "attack" and self.punchCooldown <= 0 then
+ local f = self.facing
+ self.salto = false
+ if self:isControlDown("up") then
+ -- Punch up
+ if self.current ~= self.animations.damage then
+ self:setAnimation("attack_up")
+ end
+ self:punch("up")
+ elseif self:isControlDown("down") then
+ -- Punch down
+ if self.current ~= self.animations.damage then
+ self:setAnimation("attack_down")
+ end
+ self:punch("down")
+ else
+ -- Punch horizontal
+ if self.current ~= self.animations.damage then
+ self:setAnimation("attack")
+ end
+ if f == 1 then
+ self:punch("right")
+ else
+ self:punch("left")
+ end
+ self.punchdir = 1
+ end
+ end
+end
+function Player:controlreleased (set, action, key)
+ if set ~= self:getControllerSet() then return end
+ -- Jumping
+ if action == "jump" then
+ self.isJumping = false
+ self.jumpTimer = Hero.jumpTimer -- take initial from metatable
+ end
+ -- Walking
+ if (action == "left" or action == "right") then
+ self.isWalking = false
+ if not (self:isControlDown("left") or self:isControlDown("right")) and
+ self.current == self.animations.walk then
+ self:setAnimation("default")
+ end
+ end
+end
diff --git a/ray.lua b/not/Ray.lua
index bbe11c1..bbe11c1 100644
--- a/ray.lua
+++ b/not/Ray.lua
diff --git a/selector.lua b/not/Selector.lua
index 61401e7..8e03457 100644
--- a/selector.lua
+++ b/not/Selector.lua
@@ -1,4 +1,4 @@
--- `Selector` (Element)
+--- `Selector`
-- Used in Menu for selecting various things from list. Works for each Controller set or globally.
--[[
How to use `Selector` in `Menu` config file?
@@ -12,9 +12,8 @@ selector:new(menu)
:set("global", false) -- true: single selector; false: selector for each controller set present
:init()
]]
-
Selector = {
- parent,
+ parent = --[[not.Menu]]nil,
x = 0,
y = 0,
width = 0,
@@ -35,53 +34,39 @@ Selector = {
icons_q
}
+-- `Selector` is a child of `Element`.
+require "not.Element"
+Selector.__index = Selector
+setmetatable(Selector, Element)
+
-- Constructor
-function Selector:new(parent)
- local o = {}
- setmetatable(o, self)
- self.__index = self
+function Selector:new (parent)
+ local o = setmetatable({}, self)
o.parent = parent
o.sprite, o.quads = parent:getSheet()
return o
end
--- Position
-function Selector:getPosition()
- return self.x, self.y
-end
-function Selector:setPosition(x,y)
- self.x, self.y = x, y
- return self
-end
-
-- Size of single block
-function Selector:getSize()
+function Selector:getSize ()
return self.width, self.height
end
-function Selector:setSize(width, height)
+function Selector:setSize (width, height)
self.width, self.height = width, height
return self
end
-- Spacing between two blocks
-function Selector:getMargin()
+function Selector:getMargin ()
return self.margin
end
-function Selector:setMargin(margin)
+function Selector:setMargin (margin)
self.margin = margin
return self
end
--- General setter for Menu configuration files
-function Selector:set(name, func)
- if type(name) == "string" and func ~= nil then
- self[name] = func
- end
- return self
-end
-
-- Initialize Selector with current settings.
-function Selector:init()
+function Selector:init ()
-- Make sure that there is list present
if self.list == nil then
self.list = {}
@@ -105,17 +90,17 @@ function Selector:init()
end
-- Cycle through list on given number
-function Selector:next(n)
+function Selector:next (n)
local current = self.selections[n]
self:setSelection(n, current + 1)
end
-function Selector:previous(n)
+function Selector:previous (n)
local current = self.selections[n]
self:setSelection(n, current - 1)
end
-- Get number associated with a given set
-function Selector:checkNumber(set)
+function Selector:checkNumber (set)
if self.global then return 1 end -- For global Selector
for n,check in pairs(self.sets) do
if check == set then return n end
@@ -123,13 +108,13 @@ function Selector:checkNumber(set)
end
-- Check if given number is locked
-function Selector:isLocked(n)
+function Selector:isLocked (n)
local n = n or 1
return self.locks[n]
end
-- Sets value of selection of given number. Returns old.
-function Selector:setSelection(n, new)
+function Selector:setSelection (n, new)
-- Functception. It sounds like fun but it isn't.
local function limit(new, total)
if new > total then
@@ -147,18 +132,18 @@ function Selector:setSelection(n, new)
end
-- Get value of selection of given number
-function Selector:getSelection(n)
+function Selector:getSelection (n)
local n = n or 1
return self.selections[n]
end
-- Get value from list by selection
-function Selector:getListValue(i)
+function Selector:getListValue (i)
return self.list[i]
end
-- Checks if selection of given number is unique within Selector scope.
-function Selector:isUnique(n)
+function Selector:isUnique (n)
local selection = self:getSelection(n)
for fn,v in pairs(self.selections) do
if fn ~= n and self:isLocked(fn) and v == selection then
@@ -169,7 +154,7 @@ function Selector:isUnique(n)
end
-- Get list of selections, checks if not locked are allowed.
-function Selector:getFullSelection(allowed)
+function Selector:getFullSelection (allowed)
local allowed = allowed
if allowed == nil then allowed = false end
local t = {}
@@ -186,7 +171,7 @@ function Selector:getFullSelection(allowed)
end
-- Rolls and returns random selection from list that is not locked.
-function Selector:rollRandom(avoids)
+function Selector:rollRandom (avoids)
-- Me: You should make it simpler.
-- Inner me: Nah, it works. Leave it.
-- Me: Ok, let's leave it as it is.
@@ -209,7 +194,7 @@ function Selector:rollRandom(avoids)
end
-- Draw single block of Selector
-function Selector:drawBlock(n, x, y, scale)
+function Selector:drawBlock (n, x, y, scale)
if self.quads == nil or self.sprite == nil then return end
local x, y = x or 0, y or 0
local name = self:getListValue(self:getSelection(n))
@@ -249,16 +234,16 @@ function Selector:drawBlock(n, x, y, scale)
end
-- Menu callbacks
-function Selector:focus() -- Called when Element gains focus
+function Selector:focus () -- Called when Element gains focus
self.focused = true
return true
end
-function Selector:blur() -- Called when Element loses focus
+function Selector:blur () -- Called when Element loses focus
self.focused = false
end
-- LÖVE2D callbacks
-function Selector:draw(scale)
+function Selector:draw (scale)
local x,y = self:getPosition()
local margin = self:getMargin()
local width = self:getSize()
@@ -267,7 +252,7 @@ function Selector:draw(scale)
self:drawBlock(n, x+(margin+width)*(n-1)+margin*n, y, scale)
end
end
-function Selector:update(dt)
+function Selector:update (dt)
self.delay = self.delay + dt
if self.delay > Selector.delay then -- Selector.delay is initial
self.delay = self.delay - Selector.delay
@@ -275,7 +260,8 @@ function Selector:update(dt)
end
-- Controller callbacks
-function Selector:controlpressed(set, action, key)
+-- TODO: Add action to perform when key is pressed and selector is locked in e.g. to move into character selection from map selection.
+function Selector:controlpressed (set, action, key)
if set and self.focused then
local n = self:checkNumber(set)
local locked = self:isLocked(n)
@@ -300,6 +286,5 @@ function Selector:controlpressed(set, action, key)
end
end
end
-function Selector:controlreleased(set, action, key) end
-return Selector \ No newline at end of file
+return Selector
diff --git a/settings.lua b/not/Settings.lua
index e73b997..e3316f9 100644
--- a/settings.lua
+++ b/not/Settings.lua
@@ -1,5 +1,9 @@
-Settings = {}
-Settings.current = {}
+--- `Settings`
+-- Stores, loads, saves and changes game settings including Controller sets.
+Settings = {
+ current = {}
+}
+
function Settings.load()
if Controller then
if not love.filesystem.exists("settings") then
@@ -27,6 +31,7 @@ function Settings.load()
end
end
end
+
function Settings.save()
local new = love.filesystem.newFile("settings")
local sets = Settings.current
@@ -51,6 +56,7 @@ function Settings.save()
new:write(string)
new:close()
end
+
function Settings.change(n, left, right, up, down, attack, jump, joystick)
local bool
if joystick then
@@ -63,4 +69,4 @@ function Settings.change(n, left, right, up, down, attack, jump, joystick)
Settings.save()
-- Load settings
Settings.load()
-end \ No newline at end of file
+end
diff --git a/not/Sprite.lua b/not/Sprite.lua
new file mode 100644
index 0000000..25d85f1
--- /dev/null
+++ b/not/Sprite.lua
@@ -0,0 +1,152 @@
+--- `Sprite`
+-- Abstract class for drawable animated entities.
+Sprite = {
+ animations =--[[table with animations]]nil,
+ current =--[[animations.default]]nil,
+ image =--[[love.graphics.newImage]]nil,
+ frame = 1,
+ delay = .1,
+}
+Sprite.__index = Sprite
+
+--[[ Constructor of `Sprite`.
+function Sprite:new (imagePath)
+ local o = setmetatable({}, self)
+ o:init(imagePath)
+ return o
+end
+]]
+
+-- Cleans up reference to image on deletion.
+function Sprite:delete ()
+ self.image = nil
+end
+
+-- Initializes new Sprite instance.
+function Sprite:init (imagePath)
+ if type(imagePath) == "string" then
+ self:setImage(Sprite.newImage(imagePath))
+ end
+end
+
+-- Creates new Image object from path. Key-colours two shades of green. Static.
+function Sprite.newImage (path)
+ local imagedata = love.image.newImageData(path)
+ local transparency = function(x, y, r, g, b, a)
+ if (r == 0 and g == 128 and b == 64) or
+ (r == 0 and g == 240 and b == 6) then
+ a = 0
+ end
+ return r, g, b, a
+ end
+ imagedata:mapPixel(transparency)
+ local image = love.graphics.newImage(imagedata)
+ return image
+end
+
+-- Sets an Image as an image.
+function Sprite:setImage (image)
+ self.image = image
+end
+-- Returns current image Image.
+function Sprite:getImage ()
+ return self.image
+end
+
+-- Sets new animations list.
+function Sprite:setAnimationsList (t)
+ if t then
+ self.animations = t
+ self:setAnimation("default")
+ end
+end
+
+-- Sets current animation by table key.
+function Sprite:setAnimation (animation)
+ self.frame = 1
+ self.delay = Sprite.delay -- INITIAL from metatable
+ self.current = self.animations[animation]
+end
+-- Returns current animation table.
+function Sprite:getAnimation ()
+ return self.current
+end
+
+-- Get frame quad for drawing.
+function Sprite:getQuad ()
+ if self.animations and self.current then
+ return self.current[self.frame]
+ end
+end
+
+-- TODO: Following five methods are stupid, do something about them!
+-- Sprite can't be moved by itself. Positioning should be handled by children's methods.
+function Sprite:getPosition ()
+ return 0,0
+end
+-- Sprite can't be rotated by itself. Rotation should be handled by children's methods.
+function Sprite:getAngle ()
+ return 0
+end
+-- Sprite can't be mirrored by itself. Mirroring should be handled by children's methods.
+function Sprite:getHorizontalMirror ()
+ return 1
+end
+function Sprite:getVerticalMirror ()
+ return 1
+end
+-- Sprite can't be offset by itself. Offsetting should be handled by children's methods.
+function Sprite:getOffset ()
+ return 0,0
+end
+
+-- Drawing self to LOVE2D buffer.
+-- If there is no Quad, it will draw entire image. It won't draw anything if there is no image.
+-- TODO: it doesn't follow same pattern as `not.Hero.draw`. It should implement so it can be called from `not.World`.
+-- TODO: change children if above changes are in effect: `not.Platform`, `not.Decoration`.
+function Sprite:draw (offset_x, offset_y, scale)
+ local offset_x = offset_x or 0
+ local offset_y = offset_y or 0
+
+ local i, q = self:getImage(), self:getQuad()
+ local x, y = self:getPosition()
+ local angle = self:getAngle()
+
+ local scaleX = self:getHorizontalMirror()*(scale or 1)
+ local scaleY = self:getVerticalMirror()*(scale or 1)
+
+ -- pixel grid ; `approx` selected to prevent floating characters on certain conditions
+ local approx = math.floor
+ if (y - math.floor(y)) > 0.5 then approx = math.ceil end
+ local draw_y = (approx(y) + offset_y) * scale
+ local draw_x = (math.floor(x) + offset_x) * scale
+
+ if i then
+ love.graphics.setColor(255,255,255,255)
+ if q then
+ love.graphics.draw(i, q, draw_x, draw_y, angle, scaleX, scaleY, self:getOffset())
+ else
+ love.graphics.draw(i, draw_x, draw_y, angle, scaleX, scaleY, self:getOffset())
+ end
+ end
+end
+
+-- Animation updating.
+function Sprite:update (dt)
+ if self.animations and self.current then
+ self.delay = self.delay - dt
+ if self.delay < 0 then
+ self.delay = self.delay + Sprite.delay -- INITIAL from metatable
+ self:goToNextFrame()
+ end
+ end
+end
+
+-- Moving to the next frame.
+function Sprite:goToNextFrame ()
+ if self.current.repeated or not (self.frame == self.current.frames) then
+ self.frame = (self.frame % self.current.frames) + 1
+ else
+ self:setAnimation("default")
+ end
+end \ No newline at end of file
diff --git a/world.lua b/not/World.lua
index 9c308b8..bbceec4 100644
--- a/world.lua
+++ b/not/World.lua
@@ -1,27 +1,15 @@
--- `World`
+--- `World`
-- Used to manage physical world and everything inside it: clouds, platforms, nauts, background etc.
-
--- WHOLE CODE HAS FLAG OF "need a cleanup"
-
-require "platform"
-require "player"
-require "cloud"
-require "effect"
-require "decoration"
-require "ray"
-
--- Metatable of `World`
--- nils initialized in constructor
+-- TODO: Possibly move common parts of `World` and `Menu` to abstract class `Scene`.
World = {
- -- inside
- world = nil,
- Nauts = nil,
- Platforms = nil,
- Clouds = nil,
- Decorations = nil,
- Effects = nil,
- Rays = nil,
- camera = nil,
+ world = --[[love.physics.newWorld]]nil,
+ Nauts = --[[{not.Hero}]]nil,
+ Platforms = --[[{not.Platform}]]nil,
+ Clouds = --[[{not.Cloud}]]nil,
+ Decorations = --[[{not.Decoration}]]nil,
+ Effects = --[[{not.Effect}]]nil,
+ Rays = --[[{not.Ray}]]nil,
+ camera = --[[not.Camera]]nil,
-- cloud generator
clouds_delay = 5,
-- Map
@@ -35,46 +23,48 @@ World = {
music = nil
}
+World.__index = World
+
+require "not.Platform"
+require "not.Player"
+require "not.Cloud"
+require "not.Effect"
+require "not.Decoration"
+require "not.Ray"
+require "not.Music"
+
-- Constructor of `World` ZA WARUDO!
-function World:new(map, nauts)
- -- Meta
- local o = {}
- setmetatable(o, self)
- self.__index = self
- -- Physical world initialization
+function World:new (map, nauts)
+ local o = setmetatable({}, self)
+ o:init(map, nauts)
+ return o
+end
+
+-- Init za warudo
+function World:init (map, nauts)
+ -- Box2D physical world.
love.physics.setMeter(64)
- o.world = love.physics.newWorld(0, 9.81*64, true)
- o.world:setCallbacks(o.beginContact, o.endContact)
- -- Empty tables for objects
- local n = {}
- o.Nauts = n
- local p = {}
- o.Platforms = {}
- local c = {}
- o.Clouds = c
- local e = {}
- o.Effects = e
- local d = {}
- o.Decorations = d
- local r = {}
- o.Rays = r
- -- Random init
+ self.world = love.physics.newWorld(0, 9.81*64, true)
+ self.world:setCallbacks(self.beginContact, self.endContact)
+ -- Tables for entities. TODO: It is still pretty bad!
+ self.Nauts = {}
+ self.Platforms = {}
+ self.Clouds = {}
+ self.Effects = {}
+ self.Decorations = {}
+ self.Rays = {}
+ -- Random init; TODO: use LOVE2D's random.
math.randomseed(os.time())
- -- Map
+ -- Map and misc.
local map = map or "default"
- o:loadMap(map)
- -- Nauts
- o:spawnNauts(nauts)
- -- Create camera
- o.camera = Camera:new(o)
- -- Play music
- o.music = Music:new(o.map.theme)
- return o
+ self:loadMap(map)
+ self:spawnNauts(nauts)
+ self.camera = Camera:new(self)
+ self.music = Music:new(self.map.theme)
end
-- The end of the world
-function World:delete()
- self.world:destroy()
+function World:delete ()
for _,platform in pairs(self.Platforms) do
platform:delete()
end
@@ -82,14 +72,14 @@ function World:delete()
naut:delete()
end
self.music:delete()
- self = nil
+ self.world:destroy()
end
-- Load map from file
-function World:loadMap(name)
+-- TODO: Change current map model to function-based one.
+function World:loadMap (name)
local name = name or "default"
- name = "maps/" .. name .. ".lua"
- local map = love.filesystem.load(name)
+ local map = love.filesystem.load(string.format("config/maps/%s.lua", name))
self.map = map()
-- Platforms
for _,platform in pairs(self.map.platforms) do
@@ -110,44 +100,49 @@ function World:loadMap(name)
end
-- Spawn all the nauts for the round
-function World:spawnNauts(nauts)
+function World:spawnNauts (nauts)
for _,naut in pairs(nauts) do
local x,y = self:getSpawnPosition()
local spawn = self:createNaut(x, y, naut[1])
- spawn:assignControlSet(naut[2])
+ spawn:assignControllerSet(naut[2])
end
end
-- Get respawn location
-function World:getSpawnPosition()
+function World:getSpawnPosition ()
local n = math.random(1, #self.map.respawns)
return self.map.respawns[n].x, self.map.respawns[n].y
end
-- Add new platform to the world
-function World:createPlatform(x, y, polygon, sprite, animations)
- table.insert(self.Platforms, Platform:new(self, self.world, x, y, polygon, sprite, animations))
+-- TODO: it would be nice if function parameters would be same as `not.Platform.new`.
+function World:createPlatform (x, y, polygon, sprite, animations)
+ table.insert(self.Platforms, Platform:new(animations, polygon, self, x, y, sprite))
end
-- Add new naut to the world
-function World:createNaut(x, y, name)
- local naut = Player:new(self, self.world, x, y, name)
+-- TODO: separate two methods for `not.Hero` and `not.Player`.
+function World:createNaut (x, y, name)
+ local naut = Player:new(name, self, x, y)
table.insert(self.Nauts, naut)
return naut
end
-- Add new decoration to the world
-function World:createDecoration(x, y, sprite)
+-- TODO: `not.World.create*` functions often have different naming for parameters. It is not ground-breaking but it makes reading code harder for no good reason.
+function World:createDecoration (x, y, sprite)
table.insert(self.Decorations, Decoration:new(x, y, sprite))
end
-- Add new cloud to the world
-function World:createCloud(x, y, t, v)
+-- TODO: extend variables names to provide better readability.
+-- TODO: follow new parameters in `not.Cloud.new` based on `not.Cloud.init`.
+function World:createCloud (x, y, t, v)
table.insert(self.Clouds, Cloud:new(x, y, t, v))
end
-- Randomize Cloud creation
-function World:randomizeCloud(outside)
+function World:randomizeCloud (outside)
if outside == nil then
outside = true
else
@@ -167,18 +162,20 @@ function World:randomizeCloud(outside)
end
-- Add an effect behind nauts
-function World:createEffect(name, x, y)
+-- TODO: follow new parameters in `not.Effect.new` based on `not.Effect.init`.
+-- TODO: along with `createRay` move this nearer reast of `create*` methods for readability.
+function World:createEffect (name, x, y)
table.insert(self.Effects, Effect:new(name, x, y))
end
-- Add a ray
-function World:createRay(naut)
+function World:createRay (naut)
table.insert(self.Rays, Ray:new(naut, self))
end
-- get Nauts functions
-- more than -1 lives
-function World:getNautsPlayable()
+function World:getNautsPlayable ()
local nauts = {}
for _,naut in pairs(self.Nauts) do
if naut.lives > -1 then
@@ -188,27 +185,27 @@ function World:getNautsPlayable()
return nauts
end
-- are alive
-function World:getNautsAlive()
+function World:getNautsAlive ()
local nauts = {}
for _,naut in self.Nauts do
- if naut.alive then
+ if naut.isAlive then
table.insert(nauts, naut)
end
end
return nauts
end
-- all of them
-function World:getNautsAll()
+function World:getNautsAll ()
return self.Nauts
end
-- get Map name
-function World:getMapName()
+function World:getMapName ()
return self.map.name
end
-- Event: when player is killed
-function World:onNautKilled(naut)
+function World:onNautKilled (naut)
self.camera:startShake()
self:createRay(naut)
local nauts = self:getNautsPlayable()
@@ -220,17 +217,15 @@ function World:onNautKilled(naut)
end
end
-function World:getBounce(f)
+function World:getBounce (f)
local f = f or 1
return math.sin(self.win_move*f*math.pi)
end
-- LÖVE2D callbacks
-- Update ZU WARUDO
-function World:update(dt)
- -- Physical world
+function World:update (dt)
self.world:update(dt)
- -- Camera
self.camera:update(dt)
-- Engine world: Nauts, Grounds (kek) and Decorations - all Animateds (top kek)
for _,naut in pairs(self.Nauts) do
@@ -279,7 +274,7 @@ function World:update(dt)
end
end
-- Draw
-function World:draw()
+function World:draw ()
-- Camera stuff
local offset_x, offset_y = self.camera:getOffsets()
local scale = self.camera.scale
@@ -288,7 +283,7 @@ function World:draw()
-- Background
love.graphics.draw(self.background, 0, 0, 0, scaler, scaler)
- -- This needs to be reworked!
+ -- TODO: this needs to be reworked!
-- Draw clouds
for _,cloud in pairs(self.Clouds) do
cloud:draw(offset_x, offset_y, scale)
@@ -370,14 +365,14 @@ end
-- Box2D callbacks
-- beginContact
-function World.beginContact(a, b, coll)
+function World.beginContact (a, b, coll)
if a:getCategory() == 1 then
local x,y = coll:getNormal()
if y < -0.6 then
- print(b:getUserData().name .. " is not in air")
- -- Move them to Player
+ -- TODO: move landing to `not.Hero`
+ -- Move them to Hero
b:getUserData().inAir = false
- b:getUserData().jumpnumber = 2
+ b:getUserData().jumpCounter = 2
b:getUserData().salto = false
b:getUserData():createEffect("land")
end
@@ -394,16 +389,16 @@ function World.beginContact(a, b, coll)
end
end
-- endContact
-function World.endContact(a, b, coll)
+function World.endContact (a, b, coll)
if a:getCategory() == 1 then
- print(b:getUserData().name .. " is in air")
- -- Move them to Player
+ -- Move them to Hero
b:getUserData().inAir = true
end
end
-- Controller callbacks
-function World:controlpressed(set, action, key)
+-- TODO: names of this methods don't follow naming patterns in this project. See `Controller` and change it.
+function World:controlpressed (set, action, key)
if key == "f6" and debug then
local map = self:getMapName()
local nauts = {}
@@ -417,7 +412,7 @@ function World:controlpressed(set, action, key)
naut:controlpressed(set, action, key)
end
end
-function World:controlreleased(set, action, key)
+function World:controlreleased (set, action, key)
for k,naut in pairs(self:getNautsAll()) do
naut:controlreleased(set, action, key)
end
diff --git a/platform.lua b/platform.lua
deleted file mode 100644
index 908cf73..0000000
--- a/platform.lua
+++ /dev/null
@@ -1,73 +0,0 @@
--- `Platform`
--- Static platform physical object with a sprite. `Players` can walk on it.
--- Collision category: [1]
-
--- WHOLE CODE HAS FLAG OF "need a cleanup"
-require "animated"
-
--- Metatable of `Platform`
--- nils initialized in constructor
-Platform = {
- body = nil,
- shape = nil,
- fixture = nil,
- world = nil,
-}
-Platform.__index = Platform
-setmetatable(Platform, Animated)
-
--- Constructor of `Platform`
-function Platform:new (game, world, x, y, shape, sprite, animations)
- local o = {}
- setmetatable(o, self)
- o.body = love.physics.newBody(world, x, y)
- -- MULTIPLE SHAPES NEED TO BE REWRITED!
- o.shape = {}
- if type(shape[1]) == "number" then
- local poly = love.physics.newPolygonShape(shape)
- table.insert(o.shape, poly)
- o.fixture = love.physics.newFixture(o.body, poly)
- o.fixture:setCategory(1)
- o.fixture:setFriction(0.2)
- else
- for i,v in pairs(shape) do
- local poly = love.physics.newPolygonShape(v)
- table.insert(o.shape, poly)
- local fixture = love.physics.newFixture(o.body, poly)
- fixture:setCategory(1)
- fixture:setFriction(0.2)
- end
- end
- -- END HERE
- o:setSprite(love.graphics.newImage(sprite))
- o:setAnimationsList(animations)
- o.world = game
- return o
-end
-
--- Position
-function Platform:getPosition()
- return self.body:getPosition()
-end
-
--- Draw of `Platform`
-function Platform:draw (offset_x, offset_y, scale, debug)
- -- locals
- local offset_x = offset_x or 0
- local offset_y = offset_y or 0
- local scale = scale or 1
- local debug = debug or false
- local x, y = self:getPosition()
- -- pixel grid
- local draw_x = (math.floor(x) + offset_x) * scale
- local draw_y = (math.floor(y) + offset_y) * scale
- -- sprite draw
- Animated.draw(self, draw_x, draw_y, 0, scale, scale)
- -- debug draw
- if debug then
- love.graphics.setColor(255, 69, 0, 140)
- for i,v in pairs(self.shape) do
- love.graphics.polygon("fill", self.world.camera:translatePoints(self.body:getWorldPoints(v:getPoints())))
- end
- end
-end \ No newline at end of file
diff --git a/player.lua b/player.lua
deleted file mode 100644
index 775dd60..0000000
--- a/player.lua
+++ /dev/null
@@ -1,449 +0,0 @@
--- `Player`
--- Entity controlled by a player. It has a physical body and a sprite. Can play animations and interact with other instances of the same class.
--- Collision category: [2]
-
--- WHOLE CODE HAS FLAG OF "need a cleanup"
-require "animated"
-
--- Metatable of `Player`
--- nils initialized in constructor
-Player = {
- -- General and physics
- name = "empty",
- body = nil,
- shape = nil,
- fixture = nil,
- sprite = nil,
- rotate = 0, -- "angle" would sound better
- facing = 1,
- max_velocity = 105,
- world = nil, -- game world
- -- Combat
- combo = 0,
- lives = 3,
- spawntimer = 2,
- alive = true,
- punchcd = 0.25,
- punchdir = 0, -- a really bad thing
- -- Movement
- inAir = true,
- salto = false,
- jumpactive = false,
- jumpdouble = true,
- jumptimer = 0.16,
- jumpnumber = 2,
- -- Keys
- controlset = nil,
- -- HUD
- portrait_sprite = nil,
- portrait_frame = nil,
- portrait_sheet = require "nautsicons",
- portrait_box = love.graphics.newQuad( 0, 15, 32,32, 80,130),
- -- Sounds
- sfx = require "sounds",
- -- Animations table
- animations = require "animations"
-}
-Player.__index = Player
-setmetatable(Player, Animated)
-
--- Constructor of `Player`
-function Player:new (game, world, x, y, name)
- -- Meta
- local o = {}
- setmetatable(o, self)
- -- Physics
- local group = -1-#game.Nauts
- o.body = love.physics.newBody(world, x, y, "dynamic")
- o.shape = love.physics.newRectangleShape(10, 16)
- o.fixture = love.physics.newFixture(o.body, o.shape, 8)
- o.fixture:setUserData(o)
- o.fixture:setCategory(2)
- o.fixture:setMask(2)
- o.fixture:setGroupIndex(group)
- o.body:setFixedRotation(true)
- -- Misc
- o.name = name or "empty"
- o:setSprite(newImage("assets/nauts/"..o.name..".png"))
- o.world = game
- o.punchcd = 0
- -- Animation
- o.current = o.animations.default
- o:createEffect("respawn")
- -- Portrait load for first object created
- if self.portrait_sprite == nil then
- self.portrait_sprite = love.graphics.newImage("assets/portraits.png")
- self.portrait_frame = love.graphics.newImage("assets/menu.png")
- end
- return o
-end
-
--- Control set managment
-function Player:assignControlSet(set)
- self.controlset = set
-end
-function Player:getControlSet()
- return self.controlset
-end
-
--- Update callback of `Player`
-function Player:update(dt)
- -- hotfix? for destroyed bodies
- if self.body:isDestroyed() then return end
- -- locals
- local x, y = self.body:getLinearVelocity()
- local isDown = Controller.isDown
- local controlset = self:getControlSet()
-
- -- # VERTICAL MOVEMENT
- -- Jumping
- if self.jumpactive and self.jumptimer > 0 then
- self.body:setLinearVelocity(x,-160)
- self.jumptimer = self.jumptimer - dt
- end
-
- -- Salto
- if self.salto and (self.current == self.animations.walk or self.current == self.animations.default) then
- self.rotate = (self.rotate + 17 * dt * self.facing) % 360
- elseif self.rotate ~= 0 then
- self.rotate = 0
- end
-
- -- # HORIZONTAL MOVEMENT
- -- Walking
- if isDown(controlset, "left") then
- self.facing = -1
- self.body:applyForce(-250, 0)
- -- Controlled speed limit
- if x < -self.max_velocity then
- self.body:applyForce(250, 0)
- end
- end
- if isDown(controlset, "right") then
- self.facing = 1
- self.body:applyForce(250, 0)
- -- Controlled speed limit
- if x > self.max_velocity then
- self.body:applyForce(-250, 0)
- end
- end
-
- -- Custom linear damping
- if not isDown(controlset, "left") and
- not isDown(controlset, "right")
- then
- local face = nil
- if x < -12 then
- face = 1
- elseif x > 12 then
- face = -1
- else
- face = 0
- end
- self.body:applyForce(40*face,0)
- if not self.inAir then
- self.body:applyForce(80*face,0)
- end
- end
-
- Animated.update(self, dt)
-
- -- # DEATH
- -- We all die in the end.
- local m = self.world.map
- if (self.body:getX() < m.center_x - m.width*1.5 or self.body:getX() > m.center_x + m.width*1.5 or
- self.body:getY() < m.center_y - m.height*1.5 or self.body:getY() > m.center_y + m.height*1.5) and
- self.alive
- then
- self:die()
- end
-
- -- respawn
- if self.spawntimer > 0 then
- self.spawntimer = self.spawntimer - dt
- end
- if self.spawntimer <= 0 and not self.alive and self.lives >= 0 then
- self:respawn()
- end
-
- -- # PUNCH
- -- Cooldown
- self.punchcd = self.punchcd - dt
- if not self.body:isDestroyed() then -- This is weird
- for _,fixture in pairs(self.body:getFixtureList()) do
- if fixture:getUserData() ~= self then
- fixture:setUserData({fixture:getUserData()[1] - dt, fixture:getUserData()[2]})
- if fixture:getUserData()[1] < 0 then
- fixture:destroy()
- end
- end
- end
- end
-
- -- Stop vertical
- local c,a = self.current, self.animations
- if (c == a.attack_up or c == a.attack_down or c == a.attack) and self.frame < c.frames then
- if self.punchdir == 0 then
- self.body:setLinearVelocity(0,0)
- else
- self.body:setLinearVelocity(38*self.facing,0)
- end
- end
-
- if self.punchcd <= 0 and self.punchdir == 1 then
- self.punchdir = 0
- end
-end
-
--- Controller callbacks
-function Player:controlpressed(set, action, key)
- if set ~= self:getControlSet() then return end
- local isDown = Controller.isDown
- local controlset = self:getControlSet()
- -- Jumping
- if action == "jump" then
- if self.jumpnumber > 0 then
- -- General jump logics
- self.jumpactive = true
- --self:playSound(6)
- -- Spawn proper effect
- if not self.inAir then
- self:createEffect("jump")
- else
- self:createEffect("doublejump")
- end
- -- Start salto if last jump
- if self.jumpnumber == 1 then
- self.salto = true
- end
- -- Animation clear
- if (self.current == self.animations.attack) or
- (self.current == self.animations.attack_up) or
- (self.current == self.animations.attack_down) then
- self:setAnimation("default")
- end
- -- Remove jump
- self.jumpnumber = self.jumpnumber - 1
- end
- end
-
- -- Walking
- if (action == "left" or action == "right") and
- (self.current ~= self.animations.attack) and
- (self.current ~= self.animations.attack_up) and
- (self.current ~= self.animations.attack_down) then
- self:setAnimation("walk")
- end
-
- -- Punching
- if action == "attack" and self.punchcd <= 0 then
- local f = self.facing
- self.salto = false
- if isDown(controlset, "up") then
- -- Punch up
- if self.current ~= self.animations.damage then
- self:setAnimation("attack_up")
- end
- self:hit("up")
- elseif isDown(controlset, "down") then
- -- Punch down
- if self.current ~= self.animations.damage then
- self:setAnimation("attack_down")
- end
- self:hit("down")
- else
- -- Punch horizontal
- if self.current ~= self.animations.damage then
- self:setAnimation("attack")
- end
- if f == 1 then
- self:hit("right")
- else
- self:hit("left")
- end
- self.punchdir = 1
- end
- end
-end
-function Player:controlreleased(set, action, key)
- if set ~= self:getControlSet() then return end
- local isDown = Controller.isDown
- local controlset = self:getControlSet()
- -- Jumping
- if action == "jump" then
- self.jumpactive = false
- self.jumptimer = Player.jumptimer -- take initial from metatable
- end
- -- Walking
- if (action == "left" or action == "right") and not
- (isDown(controlset, "left") or isDown(controlset, "right")) and
- self.current == self.animations.walk
- then
- self:setAnimation("default")
- end
-end
-
--- Draw of `Player`
-function Player:draw(offset_x, offset_y, scale, debug)
- -- draw only alive
- if not self.alive then return end
- -- locals
- local offset_x = offset_x or 0
- local offset_y = offset_y or 0
- local scale = scale or 1
- local debug = debug or false
- local x, y = self:getPosition()
- -- pixel grid ; `approx` selected to prevent floating characters on certain conditions
- local approx = math.floor
- if (y - math.floor(y)) > 0.5 then approx = math.ceil end
- local draw_y = (approx(y) + offset_y) * scale
- local draw_x = (math.floor(x) + offset_x) * scale
- -- sprite draw
- Animated.draw(self, draw_x, draw_y, self.rotate, self.facing*scale, scale, 12, 15)
- -- debug draw
- if debug then
- for _,fixture in pairs(self.body:getFixtureList()) do
- if fixture:getCategory() == 2 then
- love.graphics.setColor(137, 255, 0, 120)
- else
- love.graphics.setColor(137, 0, 255, 40)
- end
- love.graphics.polygon("fill", self.world.camera:translatePoints(self.body:getWorldPoints(fixture:getShape():getPoints())))
- end
- for _,contact in pairs(self.body:getContactList()) do
- love.graphics.setColor(255, 0, 0, 255)
- love.graphics.setPointSize(scale)
- love.graphics.points(self.world.camera:translatePoints(contact:getPositions()))
- end
- end
-end
-
--- getPosition
-function Player:getPosition()
- return self.body:getPosition()
-end
-
--- Draw HUD of `Player`
--- elevation: 1 bottom, 0 top
-function Player:drawHUD(x,y,scale,elevation)
- -- hud displays only if player is alive
- if self.alive then
- love.graphics.setColor(255,255,255,255)
- love.graphics.draw(self.portrait_frame, self.portrait_box, (x)*scale, (y)*scale, 0, scale, scale)
- love.graphics.draw(self.portrait_sprite, self.portrait_sheet[self.name], (x+2)*scale, (y+3)*scale, 0, scale, scale)
- local dy = 30 * elevation
- love.graphics.setFont(Font)
- love.graphics.print((self.combo*10).."%",(x+2)*scale,(y-3+dy)*scale,0,scale,scale)
- love.graphics.print(math.max(0, self.lives),(x+24)*scale,(y-3+dy)*scale,0,scale,scale)
- end
-end
-
--- Change animation of `Player`
--- default, walk, attack, attack_up, attack_down, damage
-function Player:nextFrame()
- local isDown = Controller.isDown
- local controlset = self:getControlSet()
- if self.current.repeated or not (self.frame == self.current.frames) then
- self.frame = (self.frame % self.current.frames) + 1
- elseif isDown(controlset, "right") or isDown(controlset, "left") then
- -- If nonrepeatable animation is finished and player is walking
- self:setAnimation("walk")
- elseif self.current == self.animations.damage then
- self:setAnimation("default")
- end
-end
-
--- Spawn `Effect` relative to `Player`
-function Player:createEffect(name)
- if name == "trail" or name == "hit" then
- -- 16px effect: -7 -7
- self.world:createEffect(name, self.body:getX()-8, self.body:getY()-8)
- elseif name ~= nil then
- -- 24px effect: -12 -15
- self.world:createEffect(name, self.body:getX()-12, self.body:getY()-15)
- end
-end
-
--- Punch of `Player`
--- direction: left, right, up, down
--- creates temporary fixture for player's body that acts as sensor; fixture is deleted after time set in UserData[1]; deleted by Player:update(dt)
-function Player:hit(direction)
- -- start cooldown
- self.punchcd = Player.punchcd -- INITIAL from metatable
- -- actual punch
- local fixture
- if direction == "left" then
- fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(-2,-6, -20,-6, -20,6, -2,6), 0)
- end
- if direction == "right" then
- fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(2,-6, 20,-6, 20,6, 2,6), 0)
- end
- if direction == "up" then
- fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(-8,-4, -8,-20, 8,-20, 8,-4), 0)
- end
- if direction == "down" then
- fixture = love.physics.newFixture(self.body, love.physics.newPolygonShape(-8,4, -8,20, 8,20, 8,4), 0)
- end
- fixture:setSensor(true)
- fixture:setCategory(3)
- fixture:setMask(1,3)
- fixture:setGroupIndex(self.fixture:getGroupIndex())
- fixture:setUserData({0.08, direction})
- -- sound
- self:playSound(4)
-end
-
--- Taking damage of `Player` by successful hit test
--- currently called from World's startContact
-function Player:damage(direction)
- local horizontal, vertical = 0, 0
- if direction == "left" then
- horizontal = -1
- end
- if direction == "right" then
- horizontal = 1
- end
- if direction == "up" then
- vertical = -1
- end
- if direction == "down" then
- vertical = 1
- end
- self:createEffect("hit")
- local x,y = self.body:getLinearVelocity()
- self.body:setLinearVelocity(x,0)
- self.body:applyLinearImpulse((42+10*self.combo)*horizontal, (68+10*self.combo)*vertical + 15)
- self:setAnimation("damage")
- self.combo = math.min(27, self.combo + 1)
- self.punchcd = 0.08 + self.combo*0.006
- self:playSound(2)
-end
-
--- DIE
-function Player:die()
- self:playSound(1)
- self.combo = Player.combo -- INITIAL from metatable
- self.lives = self.lives - 1
- self.alive = false
- self.spawntimer = Player.spawntimer -- INITIAL from metatable
- self.body:setActive(false)
- self.world:onNautKilled(self)
-end
-
--- And then respawn. Like Jon Snow.
-function Player:respawn()
- self.alive = true
- self.body:setLinearVelocity(0,0)
- self.body:setPosition(self.world:getSpawnPosition())
- self.body:setActive(true)
- self:createEffect("respawn")
- self:playSound(7)
-end
-
--- Sounds
-function Player:playSound(sfx, force)
- if self.alive or force then
- local source = love.audio.newSource(self.sfx[sfx])
- source:play()
- end
-end
diff --git a/readme.md b/readme.md
index 33ad9f7..26869fa 100644
--- a/readme.md
+++ b/readme.md
@@ -1,2 +1,2 @@
-# Notnauts
-Well, yep. \ No newline at end of file
+# Roflnauts 2
+More information available [here](https://www.awesomenauts.com/forum/viewtopic.php?f=12&t=45632).