diff options
Diffstat (limited to 'not/World.lua')
-rw-r--r-- | not/World.lua | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/not/World.lua b/not/World.lua new file mode 100644 index 0000000..bbceec4 --- /dev/null +++ b/not/World.lua @@ -0,0 +1,419 @@ +--- `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.__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) + 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) + 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 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) +end + +-- The end of the world +function World:delete () + for _,platform in pairs(self.Platforms) do + platform:delete() + end + for _,naut in pairs(self.Nauts) do + naut:delete() + end + self.music:delete() + self.world:destroy() +end + +-- Load map from file +-- TODO: Change current map model to function-based one. +function World:loadMap (name) + local name = name or "default" + local map = love.filesystem.load(string.format("config/maps/%s.lua", name)) + self.map = map() + -- Platforms + for _,platform in pairs(self.map.platforms) do + self:createPlatform(platform.x, platform.y, platform.shape, platform.sprite, platform.animations) + end + -- Decorations + for _,decoration in pairs(self.map.decorations) do + self:createDecoration(decoration.x, decoration.y, decoration.sprite) + end + -- Background + self.background = love.graphics.newImage(self.map.background) + -- Clouds + if self.map.clouds then + for i=1,6 do + self:randomizeCloud(false) + end + end +end + +-- Spawn all the nauts for the round +function World:spawnNauts (nauts) + for _,naut in pairs(nauts) do + local x,y = self:getSpawnPosition() + local spawn = self:createNaut(x, y, naut[1]) + spawn:assignControllerSet(naut[2]) + end +end + +-- Get respawn location +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 +-- 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 +-- 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 +-- 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 +-- 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) + if outside == nil then + outside = true + else + outside = outside + end + local x,y,t,v + local m = self.map + if outside then + x = m.center_x-m.width*1.2+math.random(-50,20) + else + x = 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) + self:createCloud(x, y, t, v) +end + +-- Add an effect behind nauts +-- 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) + table.insert(self.Rays, Ray:new(naut, self)) +end + +-- get Nauts functions +-- more than -1 lives +function World:getNautsPlayable () + local nauts = {} + for _,naut in pairs(self.Nauts) do + if naut.lives > -1 then + table.insert(nauts, naut) + end + end + return nauts +end +-- are alive +function World:getNautsAlive () + local nauts = {} + for _,naut in self.Nauts do + if naut.isAlive then + table.insert(nauts, naut) + end + end + return nauts +end +-- all of them +function World:getNautsAll () + return self.Nauts +end + +-- get Map name +function World:getMapName () + return self.map.name +end + +-- Event: when player is killed +function World:onNautKilled (naut) + self.camera:startShake() + self:createRay(naut) + local nauts = self:getNautsPlayable() + if self.lastNaut then + changeScene(Menu:new()) + elseif #nauts < 2 then + self.lastNaut = true + naut:playSound(5, true) + 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) + self.world:update(dt) + self.camera:update(dt) + -- Engine world: Nauts, Grounds (kek) and Decorations - all Animateds (top kek) + for _,naut in pairs(self.Nauts) do + naut:update(dt) + end + for _,platform in pairs(self.Platforms) do + platform:update(dt) + end + for _,decoration in pairs(self.Decorations) do + decoration:update(dt) + end + -- Clouds + if self.map.clouds then + -- generator + local n = table.getn(self.Clouds) + self.clouds_delay = self.clouds_delay - dt + if self.clouds_delay < 0 and + n < 18 + then + self:randomizeCloud() + self.clouds_delay = self.clouds_delay + World.clouds_delay -- World.clouds_delay is initial + end + -- movement + for _,cloud in pairs(self.Clouds) do + if cloud:update(dt) > 340 then + table.remove(self.Clouds, _) + end + end + end + -- Effects + for _,effect in pairs(self.Effects) do + if effect:update(dt) then + table.remove(self.Effects, _) + end + end + -- Rays + for _,ray in pairs(self.Rays) do + if ray:update(dt) then + 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 + + -- Background + love.graphics.draw(self.background, 0, 0, 0, scaler, scaler) + + -- TODO: this needs to be reworked! + -- Draw clouds + for _,cloud in pairs(self.Clouds) do + cloud:draw(offset_x, offset_y, scale) + end + + -- Draw decorations + for _,decoration in pairs(self.Decorations) do + decoration:draw(offset_x, offset_y, scale) + end + + -- Draw effects + for _,effect in pairs(self.Effects) do + effect:draw(offset_x,offset_y, scale) + end + + -- Draw player + for _,naut in pairs(self.Nauts) do + naut:draw(offset_x, offset_y, scale, debug) + end + + -- Draw ground + for _,platform in pairs(self.Platforms) do + platform:draw(offset_x, offset_y, scale, debug) + end + + -- Draw rays + for _,ray in pairs(self.Rays) do + ray:draw(offset_x, offset_y, scale) + end + + -- draw center + if debug then + local c = self.camera + local w, h = love.graphics.getWidth(), love.graphics.getHeight() + -- draw map center + love.graphics.setColor(130,130,130) + love.graphics.setLineWidth(1) + love.graphics.setLineStyle("rough") + local cx, cy = c:getPositionScaled() + local x1, y1 = c:translatePosition(self.map.center_x, cy) + local x2, y2 = c:translatePosition(self.map.center_x, cy+h) + love.graphics.line(x1,y1,x2,y2) + local x1, y1 = c:translatePosition(cx, self.map.center_y) + local x2, y2 = c:translatePosition(cx+w, self.map.center_y) + love.graphics.line(x1,y1,x2,y2) + -- draw ox, oy + love.graphics.setColor(200,200,200) + love.graphics.setLineStyle("rough") + local cx, cy = c:getPositionScaled() + local x1, y1 = c:translatePosition(0, cy) + local x2, y2 = c:translatePosition(0, cy+h) + love.graphics.line(x1,y1,x2,y2) + local x1, y1 = c:translatePosition(cx, 0) + local x2, y2 = c:translatePosition(cx+w, 0) + love.graphics.line(x1,y1,x2,y2) + end + + -- Draw HUDs + for _,naut in pairs(self.Nauts) do + -- I have no idea where to place them T_T + -- let's do: bottom-left, bottom-right, top-left, top-right + local w, h = love.graphics.getWidth()/scale, love.graphics.getHeight()/scale + local y, e = 1, 1 + 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 +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") + end + local vx, vy = b:getUserData().body:getLinearVelocity() + if math.abs(x) == 1 or (y < -0.6 and x == 0) then + b:getUserData():playSound(3) + end + end + if a:getCategory() == 3 then + b:getUserData():damage(a:getUserData()[2]) + end + if b:getCategory() == 3 then + a:getUserData():damage(b:getUserData()[2]) + end +end +-- endContact +function World.endContact (a, b, coll) + if a:getCategory() == 1 then + -- Move them to Hero + b:getUserData().inAir = true + end +end + +-- Controller callbacks +-- 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 = {} + for _,naut in pairs(self:getNautsAll()) do + table.insert(nauts, {naut.name, naut:getControlSet()}) + end + local new = World:new(map, nauts) + changeScene(new) + end + for k,naut in pairs(self:getNautsAll()) do + naut:controlpressed(set, action, key) + end +end +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 |