summaryrefslogtreecommitdiffhomepage
path: root/not
diff options
context:
space:
mode:
authorAki <nthirtyone@gmail.com>2017-08-13 02:26:55 +0200
committerAki <nthirtyone@gmail.com>2017-08-13 02:26:55 +0200
commitb1cf14d64a2d3e28683db87190c4b2c7799c259d (patch)
treee45dac5cc6ce5265e3e3e2c914eb7cc92a820b8b /not
parent0dd01913fe0eefc7ba4bc0797877f40fdedf9315 (diff)
parented62b573417bdc85bec616f6016846b02de4c906 (diff)
downloadroflnauts-maps.zip
roflnauts-maps.tar.gz
roflnauts-maps.tar.bz2
Merge branch 'multi'maps
Diffstat (limited to 'not')
-rw-r--r--not/Button.lua29
-rw-r--r--not/Camera.lua14
-rw-r--r--not/Cloud.lua30
-rw-r--r--not/Decoration.lua29
-rw-r--r--not/Effect.lua32
-rw-r--r--not/Element.lua16
-rw-r--r--not/Entity.lua17
-rw-r--r--not/Header.lua20
-rw-r--r--not/Hero.lua239
-rw-r--r--not/Menu.lua114
-rw-r--r--not/MenuBackground.lua49
-rw-r--r--not/Music.lua25
-rw-r--r--not/MusicPlayer.lua51
-rw-r--r--not/Object.lua3
-rw-r--r--not/PhysicalBody.lua34
-rw-r--r--not/Platform.lua29
-rw-r--r--not/Player.lua49
-rw-r--r--not/Ray.lua40
-rw-r--r--not/Scene.lua38
-rw-r--r--not/SceneManager.lua62
-rw-r--r--not/Selector.lua50
-rw-r--r--not/Settings.lua90
-rw-r--r--not/Sprite.lua72
-rw-r--r--not/World.lua153
24 files changed, 698 insertions, 587 deletions
diff --git a/not/Button.lua b/not/Button.lua
index 91aca45..a2f7a19 100644
--- a/not/Button.lua
+++ b/not/Button.lua
@@ -1,27 +1,18 @@
+require "not.Element"
+
--- `Button`
-- Menu element that can be activated by user.
-Button = {
- parent = --[[not.Menu]]nil,
- x = 0,
- y = 0,
- text = "",
- focused = false,
- sprite,
- quads,
- delay = 2,
- parent,
-}
+Button = Element:extends()
--- `Button` is a child of `Element`.
-require "not.Element"
-Button.__index = Button
-setmetatable(Button, Element)
+Button.text = ""
+Button.focused = false
+Button.sprite = --[[]]nil
+Button.quads = --[[]]nil
+Button.delay = 2
function Button:new (parent)
- local o = setmetatable({}, self)
- o.parent = parent
- o.sprite, o.quads = parent:getSheet()
- return o
+ Button.__super.new(self, parent)
+ self.sprite, self.quads = parent:getSheet()
end
function Button:setText (text)
diff --git a/not/Camera.lua b/not/Camera.lua
index 63489f3..aa4df5b 100644
--- a/not/Camera.lua
+++ b/not/Camera.lua
@@ -5,8 +5,6 @@ Camera = {
y = 0,
dest_x = 0,
dest_y = 0,
- scale = getScale(),
- scaler = getRealScale(),
shake = 0,
timer = 0,
delay = 0,
@@ -45,7 +43,7 @@ function Camera:getPosition ()
end
function Camera:getPositionScaled ()
- return self.x*self.scale, self.y*self.scale
+ return self.x*getScale(), self.y*getScale()
end
-- Destination
@@ -63,7 +61,7 @@ end
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
+ return (x-self.x)*getScale(), (y-self.y)*getScale()
end
function Camera:translatePoints(...)
@@ -72,9 +70,9 @@ function Camera:translatePoints(...)
local x,y = self:getOffsets()
for k,v in pairs(a) do
if k%2 == 1 then
- table.insert(r, (v + x) * self.scale)
+ table.insert(r, (v + x) * getScale())
else
- table.insert(r, (v + y) * self.scale)
+ table.insert(r, (v + y) * getScale())
end
end
return r
@@ -120,8 +118,8 @@ function Camera:follow ()
sum_y = naut_y + sum_y
end
end
- local x = sum_x / i - love.graphics.getWidth()/self.scale/2
- local y = sum_y / i - love.graphics.getHeight()/self.scale/2 + 4*self.scale -- hotfix
+ local x = sum_x / i - love.graphics.getWidth()/getScale()/2
+ local y = sum_y / i - love.graphics.getHeight()/getScale()/2 + 4*getScale() -- hotfix
return x,y
end
diff --git a/not/Cloud.lua b/not/Cloud.lua
index 3bc5377..25169c0 100644
--- a/not/Cloud.lua
+++ b/not/Cloud.lua
@@ -1,10 +1,11 @@
+require "not.Decoration"
+
--- `Cloud`
-- That white thing moving in the background.
-- TODO: extends variables names to be readable.
-Cloud = {
- t = 1, -- type (sprite number)
- v = 13 -- velocity
-}
+Cloud = Decoration:extends()
+Cloud.t = 1 -- type (sprite number)
+Cloud.v = 13 -- velocity
-- TODO: allow maps to use other quads and sprites for clouds
-- TODO: you know this isn't right, don't you?
@@ -26,25 +27,12 @@ local animations = {
}
}
--- `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.
+function Cloud:new (x, y, t, v, world)
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)
+ Cloud.__super.new(self, x, y, world, nil)
self:setAnimationsList(animations)
self:setVelocity(v)
self:setType(t)
@@ -65,7 +53,9 @@ end
-- Update of `Cloud`, returns x for world to delete cloud after reaching right corner.
function Cloud:update (dt)
- Decoration.update(self, dt)
+ Cloud.__super.update(self, dt)
self.x = self.x + self.v*dt
return self.x
end
+
+return Cloud
diff --git a/not/Decoration.lua b/not/Decoration.lua
index 9dc2bdd..97524f5 100644
--- a/not/Decoration.lua
+++ b/not/Decoration.lua
@@ -1,26 +1,15 @@
+require "not.Entity"
+
--- `Decoration`
-- Positioned sprite used to decorate maps with additional graphics.
-Decoration = {
- world = --[[not.World]]nil,
- x = 0,
- y = 0
-}
+Decoration = Entity:extends()
--- `Decoration` is a child of `Sprite`.
-require "not.Sprite"
-Decoration.__index = Decoration
-setmetatable(Decoration, Sprite)
+Decoration.x = 0
+Decoration.y = 0
-- 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)
+function Decoration:new (x, y, world, imagePath)
+ Decoration.__super.new(self, world, imagePath)
self:setPosition(x, y)
end
@@ -30,4 +19,6 @@ function Decoration:getPosition ()
end
function Decoration:setPosition (x, y)
self.x, self.y = x, y
-end \ No newline at end of file
+end
+
+return Decoration
diff --git a/not/Effect.lua b/not/Effect.lua
index dd7570a..6c0dad0 100644
--- a/not/Effect.lua
+++ b/not/Effect.lua
@@ -1,29 +1,15 @@
--- `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)
+Effect = require "not.Decoration":extends()
-- 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"))
+function Effect:new (name, x, y, world)
+ -- TODO: Load spritesheet statically. Put it to load or somewhere else within non-existent resource manager.
+ if Effect:getImage() == nil then
+ Effect: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)
+ Effect.__super.new(self, x, y, world, nil)
+ self.finished = false
self:setAnimationsList(require("config.animations.effects"))
self:setAnimation(name)
end
@@ -31,7 +17,7 @@ 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)
+ Effect.__super.update(self, dt)
return self.finished
end
@@ -44,3 +30,5 @@ function Effect:goToNextFrame ()
self.finished = true
end
end
+
+return Effect
diff --git a/not/Element.lua b/not/Element.lua
index e6d91da..24576e6 100644
--- a/not/Element.lua
+++ b/not/Element.lua
@@ -1,17 +1,15 @@
+require "not.Object"
+
--- `Element`
-- Empty element used inside `Menu`.
-Element = {
- parent = --[[not.Menu]]nil,
- x = 0,
- y = 0
-}
+Element = Object:extends()
-Element.__index = Element
+Element.parent = --[[not.Menu]]nil
+Element.x = 0
+Element.y = 0
function Element:new (parent)
- local o = setmetatable({}, self)
- o.parent = parent
- return o
+ self.parent = parent
end
function Element:delete () end -- deletes Element
diff --git a/not/Entity.lua b/not/Entity.lua
new file mode 100644
index 0000000..0e21e48
--- /dev/null
+++ b/not/Entity.lua
@@ -0,0 +1,17 @@
+require "not.Sprite"
+
+--- `Entity`
+-- Basic, visible object to be used within World instance. Can be anything. Represented as `Sprite`.
+-- We still need to keep old, global way of using modules but there are `returns` on the end at least.
+-- It probably would be nice to move `World` dependency out of it but for now it should stay this way. Later `World` instance could be just passed to methods that need it.
+Entity = Sprite:extends()
+
+Entity.world =--[[not.World]]nil
+
+-- Simple constructor for `Entity`.
+function Entity:new (world, imagePath)
+ Entity.__super.new(self, imagePath)
+ self.world = world
+end
+
+return Entity
diff --git a/not/Header.lua b/not/Header.lua
index a563ab2..8b2ec0d 100644
--- a/not/Header.lua
+++ b/not/Header.lua
@@ -1,22 +1,14 @@
+require "not.Element"
+
--- `Header`
-- Swinging title.
-Header = {
- parent = --[[not.Menu]]nil,
- x = 0,
- y = 0,
- text = "",
- bounce = 2,
-}
+Header = Element:extends()
--- `Header` is a child of `Element`.
-require "not.Element"
-Header.__index = Header
-setmetatable(Header, Element)
+Header.text = ""
+Header.bounce = 2
function Header:new (parent)
- local o = setmetatable({}, self)
- o.parent = parent
- return o
+ Header.__super.new(self, parent)
end
function Header:setText (text)
diff --git a/not/Hero.lua b/not/Hero.lua
index feb61da..039aeb8 100644
--- a/not/Hero.lua
+++ b/not/Hero.lua
@@ -1,82 +1,81 @@
--- `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 = require "not.PhysicalBody":extends()
--- `Hero` is a child of `PhysicalBody`.
-require "not.PhysicalBody"
-Hero.__index = Hero
-setmetatable(Hero, PhysicalBody)
+-- Few are left...
+Hero.jumpTimer = 0.16
+Hero.jumpCounter = 2
+Hero.sfx = require "config.sounds"
+
+Hero.QUAD_PORTRAITS = getNautsIconsList()
+Hero.QUAD_FRAME = love.graphics.newQuad(0, 15, 32,32, 80,130)
+Hero.IMAGE_PORTRAITS = nil
+Hero.IMAGE_FRAME = nil
+Hero.MAX_VELOCITY = 105
+Hero.RESPAWN_TIME = 2
+Hero.PUNCH_COOLDOWN = 0.25
+Hero.PUNCH_FIXTURE_LIFETIME = 0.08
+Hero.PUNCH_LEFT = {-2,-6, -20,-6, -20,6, -2,6}
+Hero.PUNCH_RIGHT = {2,-6, 20,-6, 20,6, 2,6}
+Hero.PUNCH_UP = {-8,-4, -8,-20, 8,-20, 8,-4}
+Hero.PUNCH_DOWN = {-8,4, -8,20, 8,20, 8,4}
-- 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")
+function Hero:new (name, x, y, world)
+ local imagePath = string.format("assets/nauts/%s.png", name)
+ Hero.load()
+ Hero.__super.new(self, x, y, world, imagePath)
+ -- Physics
+ self.group = -1-#world.Nauts
+ self:setBodyType("dynamic")
+ self:setBodyFixedRotation(true)
+ self:newFixture()
+ -- General
+ self.world = world
+ self.name = name
+ self.angle = 0
+ self.facing = 1
+ -- Status
+ self.combo = 0
+ self.lives = 3
+ self.inAir = true
+ self.salto = false
+ self.smoke = false
+ self.isAlive = true
+ self.isWalking = false
+ self.isJumping = false
+ self.spawntimer = 2
+ self.punchCooldown = 0
+ self:setAnimationsList(require("config.animations.hero"))
+ -- Post-creation
+ self:createEffect("respawn")
+end
+
+-- TODO: This is temporarily called by constructor.
+function Hero.load ()
+ if Hero.IMAGE_PORTRAITS == nil then
+ Hero.IMAGE_PORTRAITS = love.graphics.newImage("assets/portraits.png")
+ Hero.IMAGE_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.
+--- Creates hero's fixture and adds it to physical body.
+function Hero:newFixture ()
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
-
+ Hero.__super.update(self, dt)
+ if self.body:isDestroyed() then
+ return
+ end
+ self:dampVelocity(dt)
-- 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
@@ -84,23 +83,6 @@ function Hero:update (dt)
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
@@ -120,6 +102,13 @@ function Hero:update (dt)
self:respawn()
end
+ -- Trail spawner
+ -- TODO: lower the frequency of spawning - currently it is each frame.
+ if self.smoke and self.inAir then
+ local dx, dy = love.math.random(-5, 5), love.math.random(-5, 5)
+ self:createEffect("trail", dx, dy)
+ end
+
-- # PUNCH
-- Cooldown
self.punchCooldown = self.punchCooldown - dt
@@ -135,17 +124,33 @@ function Hero:update (dt)
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)
+ local currentAnimation = self:getAnimation()
+ if self.frame < currentAnimation.frames then
+ if currentAnimation == self.animations.attack_up or currentAnimation == self.animations.attack_down then
+ self:setLinearVelocity(0, 0)
+ end
+ if currentAnimation == self.animations.attack then
+ self:setLinearVelocity(38*self.facing, 0)
end
end
+end
- if self.punchCooldown <= 0 and self.punchdir == 1 then
- self.punchdir = 0
+--- Damps linear velocity every frame by applying minor force to body.
+function Hero:dampVelocity (dt)
+ if not self.isWalking then
+ local face
+ 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
end
@@ -163,7 +168,13 @@ 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)
+ Hero.__super.draw(self, offset_x, offset_y, scale, debug)
+end
+
+function Hero:drawTag (offset_x, offset_y, scale)
+ local x,y = self:getPosition()
+ love.graphics.setFont(Font)
+ love.graphics.printf(string.format("Player %d", math.abs(self.group)), (math.floor(x)+offset_x)*scale, (math.floor(y)+offset_y-26)*scale,100,'center',0,scale,scale,50,0)
end
-- Draw HUD of `Hero`
@@ -172,8 +183,8 @@ 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)
+ love.graphics.draw(self.IMAGE_FRAME, self.QUAD_FRAME, (x)*scale, (y)*scale, 0, scale, scale)
+ love.graphics.draw(self.IMAGE_PORTRAITS, self.QUAD_PORTRAITS[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)
@@ -194,35 +205,44 @@ function Hero:goToNextFrame ()
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)
+function Hero:createEffect (name, dx, dy)
+ local x, y = self.body:getX()-12, self.body:getY()-15
+ if dx then
+ x = x + dx
end
+ if dy then
+ y = y + dy
+ end
+ self.world:createEffect(name, x, y)
+end
+
+-- Called by World when Hero starts contact with Platform (lands).
+function Hero:land ()
+ self.inAir = false
+ self.jumpCounter = 2
+ self.salto = false
+ self.smoke = false
+ self:createEffect("land")
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
+ self.punchCooldown = Hero.PUNCH_COOLDOWN
-- 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
+ if direction == "left" then shape = Hero.PUNCH_LEFT end
+ if direction == "right" then shape = Hero.PUNCH_RIGHT end
+ if direction == "up" then shape = Hero.PUNCH_UP end
+ if direction == "down" then shape = Hero.PUNCH_DOWN end
-- Create and set sensor fixture.
local fixture = self:addFixture(shape, 0)
fixture:setSensor(true)
fixture:setCategory(3)
- fixture:setMask(1,3)
+ fixture:setMask(1)
fixture:setGroupIndex(self.group)
- fixture:setUserData({0.08, direction})
+ fixture:setUserData({Hero.PUNCH_FIXTURE_LIFETIME, direction})
self:playSound(4)
end
@@ -251,15 +271,18 @@ function Hero:damage (direction)
self.combo = math.min(999, self.combo + 10)
self.punchCooldown = 0.08 + self.combo*0.0006
self:playSound(2)
+ if self.combo > 80 then
+ self.smoke = true
+ end
end
-- DIE
function Hero:die ()
self:playSound(1)
- self.combo = Hero.combo -- INITIAL from metatable
+ self.combo = 0
self.lives = self.lives - 1
self.isAlive = false
- self.spawntimer = Hero.spawntimer -- INITIAL from metatable
+ self.spawntimer = Hero.RESPAWN_TIME
self:setBodyActive(false)
self.world:onNautKilled(self)
end
@@ -267,6 +290,8 @@ end
-- And then respawn. Like Jon Snow.
function Hero:respawn ()
self.isAlive = true
+ self.salto = false
+ self.smoke = false
self:setLinearVelocity(0,0)
self:setPosition(self.world:getSpawnPosition()) -- TODO: I'm not convinced about getting new position like this.
self:setBodyActive(true)
@@ -282,3 +307,5 @@ function Hero:playSound (sfx, force)
source:play()
end
end
+
+return Hero
diff --git a/not/Menu.lua b/not/Menu.lua
index 8ef1861..f6da354 100644
--- a/not/Menu.lua
+++ b/not/Menu.lua
@@ -1,72 +1,49 @@
--- `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.
-Menu = {
- scale = getScale(),
- elements = --[[{not.Element}]]nil,
- active = 1,
- 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 = { -- 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)
- },
- portrait = {
- normal = love.graphics.newQuad( 0, 15, 32,32, 80,130),
- active = love.graphics.newQuad(32, 15, 32,32, 80,130)
- },
- panorama = {
- normal = love.graphics.newQuad(0,47, 80,42, 80,130),
- active = love.graphics.newQuad(0,88, 80,42, 80,130)
- },
- arrow_l = love.graphics.newQuad(68, 0, 6, 6, 80,130),
- arrow_r = love.graphics.newQuad(74, 0, 6, 6, 80,130),
- stars = {
- love.graphics.newQuad( 0, 0, 320, 200, 640,200),
- love.graphics.newQuad(320, 0, 320, 200, 640,200)
- },
- }
-}
-
-Menu.__index = Menu
+Menu = require "not.Scene":extends()
-require "not.Music"
+Menu.elements = --[[{not.Element}]]nil
+Menu.active = 1
+Menu.music = --[[not.Music]]nil
+Menu.sprite = --[[love.graphics.newImage]]nil
+Menu.allowMove = true
+Menu.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)
+ },
+ portrait = {
+ normal = love.graphics.newQuad( 0, 15, 32,32, 80,130),
+ active = love.graphics.newQuad(32, 15, 32,32, 80,130)
+ },
+ panorama = {
+ normal = love.graphics.newQuad(0,47, 80,42, 80,130),
+ active = love.graphics.newQuad(0,88, 80,42, 80,130)
+ },
+ arrow_l = love.graphics.newQuad(68, 0, 6, 6, 80,130),
+ arrow_r = love.graphics.newQuad(74, 0, 6, 6, 80,130),
+}
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")
+ if Menu.sprite == nil then
+ Menu.sprite = love.graphics.newImage("assets/menu.png")
end
- o:init(name)
- return o
-end
-
-function Menu:init (name)
- self.music = Music:new("menu.ogg")
+ self.elements = {}
self:open(name)
end
-function Menu:delete ()
- self.music:delete()
-end
+function Menu:delete () end
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()
+ self.elements = love.filesystem.load(string.format("config/menus/%s.lua", name))(self, self.elements[1])
+ -- Common with `next` method.
+ if not self.elements[self.active]:focus() then
+ self:next()
+ end
end
-- Return reference to quads table and menu sprite
@@ -94,29 +71,26 @@ function Menu:previous ()
end
end
+-- @Override
+function Menu:isInputDisabled ()
+ if self.inputBreakTimer then
+ return self.inputDisabled or self.inputBreakTimer > 0
+ end
+ return self.inputDisabled
+end
+
-- LÖVE2D callbacks
function Menu:update (dt)
for _,element in pairs(self.elements) do
element:update(dt)
end
- self.asteroids_bounce = self.asteroids_bounce + dt*0.1
- if self.asteroids_bounce > 2 then self.asteroids_bounce = self.asteroids_bounce - 2 end
- self.stars_delay = self.stars_delay - dt
- if self.stars_delay < 0 then
- self.stars_delay = self.stars_delay + Menu.stars_delay --Menu.stars_delay is initial
- if self.stars_frame == 2 then
- self.stars_frame = 1
- else
- self.stars_frame = 2
- end
+ if self.inputBreakTimer and self.inputBreakTimer > 0 then
+ self.inputBreakTimer = self.inputBreakTimer - dt
end
end
function Menu:draw ()
- local scale = self.scale
+ local scale = getScale()
local scaler = getRealScale()
- love.graphics.draw(self.background, 0, 0, 0, scaler, scaler)
- love.graphics.draw(self.stars, self.quads.stars[self.stars_frame], 0, 0, 0, scaler, scaler)
- love.graphics.draw(self.asteroids, 0, math.floor(64+math.sin(self.asteroids_bounce*math.pi)*4)*scaler, 0, scaler, scaler)
love.graphics.setFont(Font)
for _,element in pairs(self.elements) do
element:draw(scale)
@@ -141,4 +115,6 @@ function Menu:controlreleased (set, action, key)
for _,element in pairs(self.elements) do
element:controlreleased(set, action, key)
end
-end \ No newline at end of file
+end
+
+return Menu
diff --git a/not/MenuBackground.lua b/not/MenuBackground.lua
new file mode 100644
index 0000000..83b409c
--- /dev/null
+++ b/not/MenuBackground.lua
@@ -0,0 +1,49 @@
+--- `MenuBackground`
+-- Represented as space background with blinking stars and moving asteroids.
+-- It might be too specific, but whatever. It is still better than hardcoded background in `Menu` class.
+MenuBackground = require "not.Element":extends()
+
+MenuBackground.BASE_STARS_DELAY = .8
+MenuBackground.QUAD_STARS = {
+ love.graphics.newQuad( 0, 0, 320, 200, 640,200),
+ love.graphics.newQuad(320, 0, 320, 200, 640,200)
+}
+
+function MenuBackground:new (parent)
+ MenuBackground.__super.new(parent)
+ self.starsFrame = 1
+ self.starsDelay = self.BASE_STARS_DELAY
+ self.asteroidsBounce = 0
+ -- Load statically.
+ if MenuBackground.IMAGE_BACKGROUND == nil then
+ MenuBackground.IMAGE_BACKGROUND = love.graphics.newImage("assets/backgrounds/menu.png")
+ MenuBackground.IMAGE_ASTEROIDS = love.graphics.newImage("assets/asteroids.png")
+ MenuBackground.IMAGE_STARS = love.graphics.newImage("assets/stars.png")
+ end
+end
+
+function MenuBackground:update (dt)
+ self.asteroidsBounce = self.asteroidsBounce + dt*0.1
+ if self.asteroidsBounce > 2 then
+ self.asteroidsBounce = self.asteroidsBounce - 2
+ end
+ self.starsDelay = self.starsDelay - dt
+ if self.starsDelay < 0 then
+ self.starsDelay = self.starsDelay + self.BASE_STARS_DELAY
+ if self.starsFrame == 2 then
+ self.starsFrame = 1
+ else
+ self.starsFrame = 2
+ end
+ end
+end
+
+function MenuBackground:draw ()
+ local scale = self.scale
+ local scaler = getRealScale()
+ love.graphics.draw(self.IMAGE_BACKGROUND, 0, 0, 0, scaler, scaler)
+ love.graphics.draw(self.IMAGE_STARS, self.QUAD_STARS[self.starsFrame], 0, 0, 0, scaler, scaler)
+ love.graphics.draw(self.IMAGE_ASTEROIDS, 0, math.floor(64+math.sin(self.asteroidsBounce*math.pi)*4)*scaler, 0, scaler, scaler)
+end
+
+return MenuBackground
diff --git a/not/Music.lua b/not/Music.lua
deleted file mode 100644
index ee930f4..0000000
--- a/not/Music.lua
+++ /dev/null
@@ -1,25 +0,0 @@
---- `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/MusicPlayer.lua b/not/MusicPlayer.lua
new file mode 100644
index 0000000..4634ed9
--- /dev/null
+++ b/not/MusicPlayer.lua
@@ -0,0 +1,51 @@
+require "not.Object"
+
+--- `MusicPlayer`
+-- Simple music player object that plays and loops selected track.
+MusicPlayer = Object:extends()
+
+function MusicPlayer:new (trackName)
+ self.tracks = {}
+ if trackName then
+ self:setTrack(trackName)
+ self:play()
+ end
+end
+
+function MusicPlayer:delete ()
+ self.tracks = nil
+ self:stop()
+end
+
+function MusicPlayer:setTrack (trackName)
+ if self.source then
+ self.source:stop()
+ end
+ if self.tracks[trackName] then
+ self.source = self.tracks[trackName]
+ else
+ local source = love.audio.newSource("assets/music/" .. trackName)
+ source:setLooping(true)
+ source:setVolume(.7)
+ self.source = source
+ self.tracks[trackName] = source
+ end
+end
+
+function MusicPlayer:getCurrentTrack ()
+ for key,track in pairs(self.tracks) do
+ if self.tracks[key] == self.source then
+ return key
+ end
+ end
+end
+
+function MusicPlayer:play ()
+ self.source:play()
+end
+
+function MusicPlayer:stop ()
+ self.source:stop()
+end
+
+return MusicPlayer
diff --git a/not/Object.lua b/not/Object.lua
new file mode 100644
index 0000000..30b91b5
--- /dev/null
+++ b/not/Object.lua
@@ -0,0 +1,3 @@
+-- Wrapping library to game's hierarchy in a shameless way.
+Object = require "lib.object.Object"
+return Object
diff --git a/not/PhysicalBody.lua b/not/PhysicalBody.lua
index e9625fa..804c706 100644
--- a/not/PhysicalBody.lua
+++ b/not/PhysicalBody.lua
@@ -1,26 +1,17 @@
+require "not.Entity"
+
--- `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)
+PhysicalBody = Entity:extends()
---[[ Constructor of `PhysicalBody`.
-function PhysicalBody:new (world, x, y, imagePath)
- local o = setmetatable({}, self)
- o:init(world, x, y, imagePath)
- return o
-end
-]]
+PhysicalBody.body =--[[love.physics.newBody]]nil
--- Initializer of `PhysicalBody`.
-function PhysicalBody:init (world, x, y, imagePath)
- Sprite.init(self, imagePath)
+-- Constructor of `PhysicalBody`.
+-- `world` and `imagePath` are passed to parent's constructor (`Entity`).
+function PhysicalBody:new (x, y, world, imagePath)
+ PhysicalBody.__super.new(self, world, imagePath)
self.body = love.physics.newBody(world.world, x, y)
+ self.body:setUserData(self)
end
-- Add new fixture to body.
@@ -68,12 +59,12 @@ end
-- Update of `PhysicalBody`.
function PhysicalBody:update (dt)
- Sprite.update(self, dt)
+ PhysicalBody.__super.update(self, dt)
end
-- Draw of `PhysicalBody`.
function PhysicalBody:draw (offset_x, offset_y, scale, debug)
- Sprite.draw(self, offset_x, offset_y, scale)
+ PhysicalBody.__super.draw(self, offset_x, offset_y, scale)
if debug then
for _,fixture in pairs(self.body:getFixtureList()) do
local category = fixture:getCategory()
@@ -86,8 +77,9 @@ function PhysicalBody:draw (offset_x, offset_y, scale, debug)
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
+
+return PhysicalBody
diff --git a/not/Platform.lua b/not/Platform.lua
index 3748c47..a4b3a59 100644
--- a/not/Platform.lua
+++ b/not/Platform.lua
@@ -1,29 +1,14 @@
+require "not.PhysicalBody"
+
--- `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)
+Platform = PhysicalBody:extends()
-- 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)
+function Platform:new (animations, shape, x, y, world, imagePath)
+ Platform.__super.new(self, x, y, world, imagePath)
self:setAnimationsList(animations)
- self.world = world
-- Create table of shapes if single shape is passed.
if type(shape[1]) == "number" then
shape = {shape}
@@ -34,4 +19,6 @@ function Platform:init (animations, shape, world, x, y, imagePath)
fixture:setCategory(1)
fixture:setFriction(0.2)
end
-end \ No newline at end of file
+end
+
+return Platform
diff --git a/not/Player.lua b/not/Player.lua
index 2a4b2e6..b0dac75 100644
--- a/not/Player.lua
+++ b/not/Player.lua
@@ -1,31 +1,15 @@
+require "not.Hero"
+
--- `Player`
-- Special `not.Hero` controllable by a player.
-Player = {
- -- TODO: move functions and properties related to controls from `not.Hero`.
- controllerSet = --[[Controller.sets.*]]nil,
-}
+-- TODO: move functions and properties related to controls from `not.Hero`.
+Player = Hero:extends()
--- `Player` is a child of `Hero`.
-require "not.Hero"
-Player.__index = Player
-setmetatable(Player, Hero)
+Player.controllerSet =--[[Controller.sets.*]]nil
-- 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, ...)
+function Player:new (name, x, y, world)
+ Player.__super.new(self, name, x, y, world)
end
-- Controller set manipulation.
@@ -43,7 +27,7 @@ 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.
+ Player.__super.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.
@@ -57,7 +41,7 @@ function Player:update (dt)
self.facing = -1
self:applyForce(-250, 0)
-- Controlled speed limit
- if x < -self.max_velocity then
+ if x < -self.MAX_VELOCITY then
self:applyForce(250, 0)
end
end
@@ -65,7 +49,7 @@ function Player:update (dt)
self.facing = 1
self:applyForce(250, 0)
-- Controlled speed limit
- if x > self.max_velocity then
+ if x > self.MAX_VELOCITY then
self:applyForce(-250, 0)
end
end
@@ -74,6 +58,7 @@ end
-- Controller callbacks.
function Player:controlpressed (set, action, key)
if set ~= self:getControllerSet() then return end
+ self.smoke = false -- TODO: temporary
-- Jumping
if action == "jump" then
if self.jumpCounter > 0 then
@@ -137,7 +122,6 @@ function Player:controlpressed (set, action, key)
else
self:punch("left")
end
- self.punchdir = 1
end
end
end
@@ -150,10 +134,13 @@ function Player:controlreleased (set, action, key)
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")
+ if not (self:isControlDown("left") or self:isControlDown("right")) then
+ self.isWalking = false
+ if self.current == self.animations.walk then
+ self:setAnimation("default")
+ end
end
end
end
+
+return Player
diff --git a/not/Ray.lua b/not/Ray.lua
index bbe11c1..16a9bee 100644
--- a/not/Ray.lua
+++ b/not/Ray.lua
@@ -1,36 +1,32 @@
--- `Ray`
+require "not.Object"
+
+--- `Ray`
-- That awesome effect that blinks when player dies!
+Ray = Object:extends()
--- WHOLE CODE HAS FLAG OF "need a cleanup"
+Ray.naut =--[[not.Hero]]nil
+Ray.world =--[[not.World]]nil
+Ray.canvas =--[[love.graphics.newCanvas]]nil
+Ray.delay = 0.3
-Ray = {
- naut = nil,
- world = nil,
- canvas = nil,
- delay = 0.3
-}
-function Ray:new(naut, world)
- -- Meta
- local o = {}
- setmetatable(o, self)
- self.__index = self
- -- Init
- o.naut = naut
- o.world = world
+function Ray:new (naut, world)
+ self.naut = naut
+ self.world = world
-- Cavas, this is temporary, I believe.
- local scale = o.world.camera.scale
+ local scale = getScale()
local w, h = love.graphics.getWidth(), love.graphics.getHeight()
- o.canvas = love.graphics.newCanvas(w/scale, h/scale)
- return o
+ self.canvas = love.graphics.newCanvas(w/scale, h/scale)
end
-function Ray:update(dt)
+
+function Ray:update (dt)
self.delay = self.delay - dt
if self.delay < 0 then
return true -- delete
end
return false
end
-function Ray:draw(offset_x, offset_y, scale)
+
+function Ray:draw (offset_x, offset_y, scale)
love.graphics.setCanvas(self.canvas)
love.graphics.clear()
love.graphics.setColor(255, 247, 228, 247)
@@ -50,3 +46,5 @@ function Ray:draw(offset_x, offset_y, scale)
-- draw on screen
love.graphics.draw(self.canvas, 0, 0, 0, scale, scale)
end
+
+return Ray
diff --git a/not/Scene.lua b/not/Scene.lua
new file mode 100644
index 0000000..f0e2e34
--- /dev/null
+++ b/not/Scene.lua
@@ -0,0 +1,38 @@
+--- `Scene`
+Scene = require "not.Object":extends()
+
+function Scene:new ()
+ self.sleeping = false
+ self.hidden = false
+ self.inputDisabled = false
+end
+
+function Scene:delete () end
+function Scene:update (dt) end
+function Scene:draw () end
+function Scene:controlpressed (set, action, key) end
+function Scene:controlreleased (set, action, key) end
+
+-- Following setters and getters are a little bit too much, I think. But they do follow general coding directions.
+function Scene:setSleeping (sleeping)
+ self.sleeping = sleeping
+end
+function Scene:isSleeping ()
+ return self.sleeping
+end
+
+function Scene:setHidden (hidden)
+ self.hidden = hidden
+end
+function Scene:isHidden ()
+ return self.hidden
+end
+
+function Scene:setInputDisabled (inputDisabled)
+ self.inputDisabled = inputDisabled
+end
+function Scene:isInputDisabled ()
+ return self.inputDisabled
+end
+
+return Scene
diff --git a/not/SceneManager.lua b/not/SceneManager.lua
new file mode 100644
index 0000000..c076448
--- /dev/null
+++ b/not/SceneManager.lua
@@ -0,0 +1,62 @@
+--- `SceneManager`
+-- Used for changing single active scene.
+-- TODO: Extend functionality for more than one active scene (eg. overlay menu).
+SceneManager = require "not.Object":extends()
+
+function SceneManager:new ()
+ self.scenes = {}
+end
+
+-- This function should be removed when multiple scenes will be handled properly by SceneManager and other things.
+function SceneManager:changeScene (scene)
+ table.remove(self.scenes, #self.scenes)
+ return self:addScene(scene)
+end
+
+function SceneManager:addScene (scene)
+ table.insert(self.scenes, scene)
+ return scene
+end
+
+-- Not nice, not nice.
+function SceneManager:removeTopScene ()
+ table.remove(self.scenes, #self.scenes)
+end
+
+function SceneManager:getAllScenes ()
+ return self.scenes
+end
+
+function SceneManager:update (dt)
+ for _,scene in pairs(self:getAllScenes()) do
+ if not scene:isSleeping() then
+ scene:update(dt)
+ end
+ end
+end
+
+function SceneManager:draw ()
+ for _,scene in pairs(self:getAllScenes()) do
+ if not scene:isHidden() then
+ scene:draw()
+ end
+ end
+end
+
+function SceneManager:controlpressed (set, action, key)
+ for _,scene in pairs(self:getAllScenes()) do
+ if not scene:isInputDisabled() then
+ scene:controlpressed(set, action, key)
+ end
+ end
+end
+
+function SceneManager:controlreleased (set, action, key)
+ for _,scene in pairs(self:getAllScenes()) do
+ if not scene:isInputDisabled() then
+ scene:controlreleased(set, action, key)
+ end
+ end
+end
+
+return SceneManager
diff --git a/not/Selector.lua b/not/Selector.lua
index 8e03457..ef78778 100644
--- a/not/Selector.lua
+++ b/not/Selector.lua
@@ -1,3 +1,5 @@
+require "not.Element"
+
--- `Selector`
-- Used in Menu for selecting various things from list. Works for each Controller set or globally.
--[[
@@ -12,39 +14,29 @@ selector:new(menu)
:set("global", false) -- true: single selector; false: selector for each controller set present
:init()
]]
-Selector = {
- parent = --[[not.Menu]]nil,
- x = 0,
- y = 0,
- width = 0,
- height = 0,
- margin = 0,
- focused = false,
- global = false,
- delay = 2,
- first = false,
- list,
- sets,
- locks,
- selections,
- shape = "portrait",
- sprite,
- quads,
- icons_i,
- icons_q
-}
+Selector = Element:extends()
--- `Selector` is a child of `Element`.
-require "not.Element"
-Selector.__index = Selector
-setmetatable(Selector, Element)
+Selector.width = 0
+Selector.height = 0
+Selector.margin = 0
+Selector.focused = false
+Selector.global = false
+Selector.delay = 2
+Selector.first = false
+Selector.list = --[[]]nil
+Selector.sets = --[[]]nil
+Selector.locks = --[[]]nil
+Selector.selections = --[[]]nil
+Selector.shape = "portrait"
+Selector.sprite = --[[]]nil
+Selector.quads = --[[]]nil
+Selector.icons_i = --[[]]nil
+Selector.icons_q = --[[]]nil
-- Constructor
function Selector:new (parent)
- local o = setmetatable({}, self)
- o.parent = parent
- o.sprite, o.quads = parent:getSheet()
- return o
+ Selector.__super.new(self, parent)
+ self.sprite, self.quads = parent:getSheet()
end
-- Size of single block
diff --git a/not/Settings.lua b/not/Settings.lua
index e3316f9..ca429eb 100644
--- a/not/Settings.lua
+++ b/not/Settings.lua
@@ -4,26 +4,39 @@ Settings = {
current = {}
}
-function Settings.load()
+-- Converts from old settings format to the one after `02aba07e03465205b45c41df7aec6894d4e89909`.
+local function convertToNew (old)
+ return {sets = old, display = "fullscreen"}
+end
+
+local function filePrepare ()
+ if not love.filesystem.exists("settings") then
+ local def = love.filesystem.newFile("settings.default")
+ local new = love.filesystem.newFile("settings")
+ new:open("w") def:open("r")
+ new:write(def:read())
+ new:close() def:close()
+ end
+end
+
+local function fileLoad ()
+ local getSettings = love.filesystem.load("settings")
+ local settings = getSettings()
+ if not settings.sets then
+ settings = convertToNew(settings)
+ end
+ Settings.current = settings
+end
+
+local function controllerLoad ()
if Controller then
- if not love.filesystem.exists("settings") then
- local def = love.filesystem.newFile("settings.default")
- local new = love.filesystem.newFile("settings")
- new:open("w") def:open("r")
- new:write(def:read())
- new:close() def:close()
- end
- local getSettings = love.filesystem.load("settings")
- Settings.current = getSettings()
Controller.reset()
- local joysticksList = love.joystick.getJoysticks() -- local list for editing
- for _,set in pairs(Settings.current) do
+ local joysticksList = love.joystick.getJoysticks()
+ for _,set in pairs(Settings.current.sets) do
local isJoystick = set[7]
local joystick
if isJoystick then
- -- take and remove first joystick from list
- joystick = joysticksList[1]
- table.remove(joysticksList, 1)
+ joystick = table.remove(joysticksList, 1)
end
if not isJoystick or joystick then
Controller.registerSet(set[1], set[2], set[3], set[4], set[5], set[6], joystick)
@@ -32,12 +45,37 @@ function Settings.load()
end
end
-function Settings.save()
+local function displayLoad ()
+ local width, height, flags = love.window.getMode()
+ if Settings.current.display == "fullscreen" then
+ if not flags.fullscreen then
+ love.window.setFullscreen(true, "desktop")
+ end
+ else
+ local scale = tonumber(Settings.current.display) or 1
+ local expectedWidth, expectedHeight = 320 * scale, 180 * scale
+ if flags.fullscreen then
+ love.window.setFullscreen(false)
+ end
+ if width ~= expectedWidth or height ~= expectedHeight then
+ love.window.setMode(expectedWidth, expectedHeight)
+ end
+ end
+end
+
+function Settings.load ()
+ filePrepare()
+ fileLoad()
+ controllerLoad()
+ displayLoad()
+end
+
+function Settings.save ()
local new = love.filesystem.newFile("settings")
- local sets = Settings.current
- local string = "return {\n"
+ local sets = Settings.current.sets
+ local string = "return {\n\tsets = {\n"
for i,set in pairs(sets) do
- string = string .. "\t{"
+ string = string .. "\t\t{"
for j,word in pairs(set) do
if j ~= 7 then
string = string .. "\"" .. word .. "\", "
@@ -51,22 +89,26 @@ function Settings.save()
end
string = string .. "},\n"
end
- string = string .. "}"
+ string = string .. "\t},\n"
+ string = string .. "\tdisplay = \"" .. Settings.current.display .. "\",\n"
+ string = string .. "}\n"
new:open("w")
new:write(string)
new:close()
end
-function Settings.change(n, left, right, up, down, attack, jump, joystick)
+function Settings.change (n, left, right, up, down, attack, jump, joystick)
local bool
if joystick then
bool = true
else
bool = false
end
- -- Save current settings
- Settings.current[n] = {left, right, up, down, attack, jump, bool}
+ Settings.current.sets[n] = {left, right, up, down, attack, jump, bool}
+ Settings.reload()
+end
+
+function Settings.reload ()
Settings.save()
- -- Load settings
Settings.load()
end
diff --git a/not/Sprite.lua b/not/Sprite.lua
index 25d85f1..3951e6e 100644
--- a/not/Sprite.lua
+++ b/not/Sprite.lua
@@ -1,34 +1,27 @@
+require "not.Object"
+
--- `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`.
+Sprite = Object:extends()
+
+Sprite.animations =--[[table with animations]]nil
+Sprite.current =--[[animations.default]]nil
+Sprite.image =--[[love.graphics.newImage]]nil
+Sprite.frame = 1
+Sprite.delay = .1
+
+-- Constructor of `Sprite`.
function Sprite:new (imagePath)
- local o = setmetatable({}, self)
- o:init(imagePath)
- return o
+ if type(imagePath) == "string" then
+ self:setImage(Sprite.newImage(imagePath))
+ end
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)
@@ -64,7 +57,7 @@ end
-- Sets current animation by table key.
function Sprite:setAnimation (animation)
self.frame = 1
- self.delay = Sprite.delay -- INITIAL from metatable
+ self.delay = Sprite.delay -- INITIAL from prototype
self.current = self.animations[animation]
end
-- Returns current animation table.
@@ -79,26 +72,15 @@ function Sprite:getQuad ()
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
+-- Sprite's position. Can be overriden to add functionality.
+function Sprite:getPosition () return 0,0 end
+-- Sprite's angle. Can be overriden to add functionality.
+function Sprite:getAngle () return 0 end
+-- Sprite's horizontal and vertical mirrors. Can be overriden to add functionality.
+function Sprite:getHorizontalMirror () return 1 end
+function Sprite:getVerticalMirror () return 1 end
+-- Sprite's drawing offset from position. Can be overriden to add functionality.
+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.
@@ -136,7 +118,7 @@ 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.delay = self.delay + Sprite.delay -- INITIAL from prototype
self:goToNextFrame()
end
end
@@ -149,4 +131,6 @@ function Sprite:goToNextFrame ()
else
self:setAnimation("default")
end
-end \ No newline at end of file
+end
+
+return Sprite
diff --git a/not/World.lua b/not/World.lua
index bbceec4..c73a3da 100644
--- a/not/World.lua
+++ b/not/World.lua
@@ -1,29 +1,21 @@
--- `World`
-- Used to manage physical world and everything inside it: clouds, platforms, nauts, background etc.
-- TODO: Possibly move common parts of `World` and `Menu` to abstract class `Scene`.
-World = {
- 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
- map = nil,
- background = nil,
- -- Gameplay status
- lastNaut = false,
- -- "WINNER"
- win_move = 0,
- -- Music
- music = nil
-}
+World = require "not.Scene":extends()
-World.__index = World
+World.world =--[[love.physics.newWorld]]nil
+World.Nauts =--[[{not.Hero}]]nil
+World.Platforms =--[[{not.Platform}]]nil
+World.Clouds =--[[{not.Cloud}]]nil
+World.Decorations =--[[{not.Decoration}]]nil
+World.Effects =--[[{not.Effect}]]nil
+World.Rays =--[[{not.Ray}]]nil
+World.camera =--[[not.Camera]]nil
+World.music =--[[not.Music]]nil
+World.clouds_delay = 5
+World.map =--[[config.maps.*]]nil
+World.background =--[[image?]]nil
+World.lastNaut = false
require "not.Platform"
require "not.Player"
@@ -31,17 +23,9 @@ 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)
- 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)
self.world = love.physics.newWorld(0, 9.81*64, true)
@@ -53,14 +37,13 @@ function World:init (map, nauts)
self.Effects = {}
self.Decorations = {}
self.Rays = {}
- -- Random init; TODO: use LOVE2D's random.
- math.randomseed(os.time())
-- Map and misc.
local map = map or "default"
self:loadMap(map)
self:spawnNauts(nauts)
self.camera = Camera:new(self)
- self.music = Music:new(self.map.theme)
+ musicPlayer:setTrack(self.map.theme)
+ musicPlayer:play()
end
-- The end of the world
@@ -71,7 +54,6 @@ function World:delete ()
for _,naut in pairs(self.Nauts) do
naut:delete()
end
- self.music:delete()
self.world:destroy()
end
@@ -110,20 +92,20 @@ end
-- Get respawn location
function World:getSpawnPosition ()
- local n = math.random(1, #self.map.respawns)
+ local n = love.math.random(1, #self.map.respawns)
return self.map.respawns[n].x, self.map.respawns[n].y
end
-- Add new platform to the world
-- 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))
+ table.insert(self.Platforms, Platform(animations, polygon, x, y, self, sprite))
end
-- Add new naut to the world
-- TODO: separate two methods for `not.Hero` and `not.Player`.
function World:createNaut (x, y, name)
- local naut = Player:new(name, self, x, y)
+ local naut = Player(name, x, y, self)
table.insert(self.Nauts, naut)
return naut
end
@@ -131,14 +113,14 @@ end
-- Add new decoration to the world
-- 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))
+ table.insert(self.Decorations, Decoration(x, y, self, sprite))
end
-- Add new cloud to the world
-- 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))
+ table.insert(self.Clouds, Cloud(x, y, t, v, self))
end
-- Randomize Cloud creation
@@ -151,13 +133,13 @@ function World:randomizeCloud (outside)
local x,y,t,v
local m = self.map
if outside then
- x = m.center_x-m.width*1.2+math.random(-50,20)
+ x = m.center_x-m.width*1.2+love.math.random(-50,20)
else
- x = math.random(m.center_x-m.width/2,m.center_x+m.width/2)
+ x = love.math.random(m.center_x-m.width/2,m.center_x+m.width/2)
end
- y = math.random(m.center_y-m.height/2, m.center_y+m.height/2)
- t = math.random(1,3)
- v = math.random(8,18)
+ y = love.math.random(m.center_y-m.height/2, m.center_y+m.height/2)
+ t = love.math.random(1,3)
+ v = love.math.random(8,18)
self:createCloud(x, y, t, v)
end
@@ -165,12 +147,12 @@ end
-- 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))
+ table.insert(self.Effects, Effect(name, x, y, self))
end
-- Add a ray
function World:createRay (naut)
- table.insert(self.Rays, Ray:new(naut, self))
+ table.insert(self.Rays, Ray(naut, self))
end
-- get Nauts functions
@@ -210,18 +192,15 @@ function World:onNautKilled (naut)
self:createRay(naut)
local nauts = self:getNautsPlayable()
if self.lastNaut then
- changeScene(Menu:new())
+ sceneManager:removeTopScene()
+ sceneManager:changeScene(Menu())
elseif #nauts < 2 then
self.lastNaut = true
naut:playSound(5, true)
+ sceneManager:addScene(Menu("win"))
end
end
-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)
@@ -267,18 +246,13 @@ function World:update (dt)
table.remove(self.Rays, _)
end
end
- -- Bounce `winner`
- self.win_move = self.win_move + dt
- if self.win_move > 2 then
- self.win_move = self.win_move - 2
- end
end
-- Draw
function World:draw ()
-- Camera stuff
local offset_x, offset_y = self.camera:getOffsets()
- local scale = self.camera.scale
- local scaler = self.camera.scaler
+ local scale = getScale()
+ local scaler = getRealScale()
-- Background
love.graphics.draw(self.background, 0, 0, 0, scaler, scaler)
@@ -341,6 +315,10 @@ function World:draw ()
love.graphics.line(x1,y1,x2,y2)
end
+ for _,naut in pairs(self.Nauts) do
+ naut:drawTag(offset_x, offset_y, scale)
+ end
+
-- Draw HUDs
for _,naut in pairs(self.Nauts) do
-- I have no idea where to place them T_T
@@ -350,31 +328,20 @@ function World:draw ()
if _ < 3 then y, e = h-33, 0 end
naut:drawHUD(1+(_%2)*(w-34), y, scale, e)
end
-
- -- Draw winner
- if self.lastNaut then
- local w, h = love.graphics.getWidth()/scale, love.graphics.getHeight()/scale
- local angle = self:getBounce(2)
- local dy = self:getBounce()*3
- love.graphics.setFont(Bold)
- love.graphics.printf("WINNER",(w/2)*scale,(42+dy)*scale,336,"center",(angle*5)*math.pi/180,scale,scale,168,12)
- love.graphics.setFont(Font)
- love.graphics.printf("rofl, now kill yourself", w/2*scale, 18*scale, 160, "center", 0, scale, scale, 80, 3)
- end
end
-- Box2D callbacks
--- beginContact
+-- TODO: Rather than here, these contacts should be in `Hero` (most likely).
+-- TODO: Explode these into more functions.\
+-- TODO: Stop using magical numbers:
+-- [1] -> Platform
+-- [2] -> Hero
+-- [3] -> Punch sensor
function World.beginContact (a, b, coll)
if a:getCategory() == 1 then
local x,y = coll:getNormal()
if y < -0.6 then
- -- TODO: move landing to `not.Hero`
- -- Move them to Hero
- b:getUserData().inAir = false
- b:getUserData().jumpCounter = 2
- b:getUserData().salto = false
- b:getUserData():createEffect("land")
+ b:getUserData():land()
end
local vx, vy = b:getUserData().body:getLinearVelocity()
if math.abs(x) == 1 or (y < -0.6 and x == 0) then
@@ -382,16 +349,27 @@ function World.beginContact (a, b, coll)
end
end
if a:getCategory() == 3 then
- b:getUserData():damage(a:getUserData()[2])
+ if b:getCategory() == 2 then
+ b:getUserData():damage(a:getUserData()[2])
+ end
+ if b:getCategory() == 3 then
+ a:getBody():getUserData():damage(b:getUserData()[2])
+ b:getBody():getUserData():damage(a:getUserData()[2])
+ local x1,y1 = b:getBody():getUserData():getPosition()
+ local x2,y2 = a:getBody():getUserData():getPosition()
+ local x = (x2 - x1) / 2 + x1 - 12
+ local y = (y2 - y1) / 2 + y1 - 15
+ a:getBody():getUserData().world:createEffect("clash", x, y)
+ end
end
if b:getCategory() == 3 then
- a:getUserData():damage(b:getUserData()[2])
+ if a:getCategory() == 2 then
+ a:getUserData():damage(b:getUserData()[2])
+ end
end
end
--- endContact
function World.endContact (a, b, coll)
if a:getCategory() == 1 then
- -- Move them to Hero
b:getUserData().inAir = true
end
end
@@ -403,10 +381,15 @@ function World:controlpressed (set, action, key)
local map = self:getMapName()
local nauts = {}
for _,naut in pairs(self:getNautsAll()) do
- table.insert(nauts, {naut.name, naut:getControlSet()})
+ table.insert(nauts, {naut.name, naut:getControllerSet()})
end
- local new = World:new(map, nauts)
- changeScene(new)
+ local new = World(map, nauts)
+ sceneManager:changeScene(new)
+ end
+ if key == "escape" then
+ sceneManager:addScene(Menu("pause"))
+ self:setInputDisabled(true)
+ self:setSleeping(true)
end
for k,naut in pairs(self:getNautsAll()) do
naut:controlpressed(set, action, key)
@@ -416,4 +399,4 @@ function World:controlreleased (set, action, key)
for k,naut in pairs(self:getNautsAll()) do
naut:controlreleased(set, action, key)
end
-end \ No newline at end of file
+end