diff --git a/README.md b/README.md index baa78b5..7bf4452 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ Lua game inspired by an old arcade game(Qix/Gals Panic) using LOVE2D for Linux. ## TO-DO -- Stop player from creating crossed lines - - Fix creation of the lines / polygon / points - Add more pictures (manga?) - Fix balls sometimes attaching to the lines + +- Add spiders moving around in the board, player collision kills diff --git a/main.lua b/main.lua index a47ae2c..c2f6fbe 100644 --- a/main.lua +++ b/main.lua @@ -65,6 +65,11 @@ function love.keypressed(key) push:switchFullscreen() end + if key == 'r' then + gStateStack:clear() + gStateStack:push(StartState()) + end + love.keyboard.keysPressed[key] = true end diff --git a/src/Ball.lua b/src/Ball.lua index 02d5aca..b45661f 100644 --- a/src/Ball.lua +++ b/src/Ball.lua @@ -22,13 +22,15 @@ function Ball:reset() end function Ball:update(dt,level) - local tempX = self.x + self.dx * dt - local tempY = self.y + self.dy * dt + local tempX = math.floor((self.x + self.dx * dt) + 0.5) + local tempY = math.floor((self.y + self.dy * dt) + 0.5) local trailSeg = level:pointOnEdge(tempX,tempY,level.player.trailSegments) if trailSeg then self.hitPlayer = true + -- print("ball hits player") gSounds['hit']:play() + return end local i, segment = level:getTouchingSegment(tempX,tempY) @@ -49,8 +51,9 @@ function Ball:update(dt,level) gSounds['blip']:play() end - if not (level:insideBounds(tempX,tempY) or level:pointOnEdge(tempX,tempY)) then + if not level:insideBounds(tempX,tempY) and not level:pointOnEdge(tempX,tempY) then self.remove = true + print("ball outside or touching segment") end self.x = self.x + self.dx * dt @@ -60,8 +63,9 @@ function Ball:update(dt,level) end function Ball:render() - love.graphics.setColor(255/255,1/255,1/255,255/255) + love.graphics.setColor(1,0.1,0.1,1) love.graphics.circle('fill', self.x, self.y, self.width/2) + love.graphics.setColor(1,1,1,1) end function Ball:getCollisionDirection(segment,x,y) diff --git a/src/Clock.lua b/src/Clock.lua index 117a981..9ee043c 100644 --- a/src/Clock.lua +++ b/src/Clock.lua @@ -26,8 +26,8 @@ function Clock:render() love.graphics.setColor(self.color[1], self.color[2], self.color[3], self.color[4]) end - love.graphics.setFont(gFonts['medium']) - love.graphics.printf('Time: ' .. self.currentTime, 0, 5, VIRTUAL_WIDTH, + love.graphics.setFont(gFonts['small']) + love.graphics.printf('Time: ' .. self.currentTime, 0, LEVEL_RENDER_OFFSET_TOP/2, VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, 'right') love.graphics.setFont(gFonts['small']) love.graphics.setColor(1, 1, 1, 1) diff --git a/src/Level.lua b/src/Level.lua index dc5c0f9..b5787a7 100644 --- a/src/Level.lua +++ b/src/Level.lua @@ -5,64 +5,98 @@ function Level:init(def, stage) self.stage = stage self.points = {} self.player = {} - self.segments = self:createLevelFromDef(def, stage) + self.segments = self:createLevelFromDef(def) self.polygon = self:createPolygon() self.mesh = poly2mesh(self.points) + self.balls = self:createBallsFromDef(def) + self.clock = Clock(def.timeLimit, "down") end function Level:update(dt) self.mesh = poly2mesh(self.points) + self:updateBalls(dt) + self.clock:update(dt) end function Level:render() self:renderBackground() self:renderOuterSegments() + self:renderBalls() + self.clock:render() end function Level:renderOuterSegments() - for k, segment in pairs(self.segments) do segment:render() end -end - -function Level:renderBackground() - love.graphics.draw(gImages[(self.stage % #gImages)], LEVEL_RENDER_OFFSET, - LEVEL_RENDER_OFFSET_TOP) - if self.mesh:type() == "Mesh" then - love.graphics.draw(self.mesh, 0, 0) + for k, segment in pairs(self.segments) do + segment:render() end end -function Level:createLevelFromDef(def, stage) +function Level:renderBackground() + local nextImg = self.stage % (#gImages + 1) + if nextImg == 0 then + nextImg = 1 + end + love.graphics.draw(gImages[nextImg], LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP) + if self.mesh:type() == "Mesh" then + love.graphics.draw(self.mesh, 0, 0) + end +end + +function Level:createLevelFromDef(def) local level = {} - for i, seg in pairs(def[1].segments) do - table.insert(level, Segment(seg.p1, seg.p2, seg.width, seg.face) ) + for i, seg in pairs(def.segments) do + table.insert(level, Segment(seg.p1, seg.p2, seg.width, seg.face)) end return level end function Level:createLevel() local level = { - [1] = Segment({LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, { - VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP - }, .5, 'down'), - [2] = Segment({ - VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP - }, { - VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, - VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET - }, .5, 'left'), - [3] = Segment({ - VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, - VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET - }, {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, .5, 'up'), - [4] = Segment({ - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET - }, {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, .5, 'right') + [1] = Segment( + {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + { + VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, + LEVEL_RENDER_OFFSET_TOP + }, + .5, + "down" + ), + [2] = Segment( + { + VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, + LEVEL_RENDER_OFFSET_TOP + }, + { + VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, + VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET + }, + .5, + "left" + ), + [3] = Segment( + { + VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, + VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET + }, + {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + .5, + "up" + ), + [4] = Segment( + { + LEVEL_RENDER_OFFSET, + VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET + }, + {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + .5, + "right" + ) } -- local level = { -- [1] = Segment({LEVEL_RENDER_OFFSET,LEVEL_RENDER_OFFSET_TOP},{VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP},.5), -- [2] = Segment({VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP},{VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET},.5), -- [3] = Segment({VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET},{VIRTUAL_WIDTH / 2 + 10, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET},.5), - -- [4] = Segment({VIRTUAL_WIDTH / 2 + 10, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET},{VIRTUAL_WIDTH / 2 + 10, VIRTUAL_HEIGHT / 2},.5), + -- [4] = Segment({VIRTUAL_WIDTH / 2 + 10, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET},{VIRTUAL_WIDTH / 2 + 10, VIRTUAL_HEIGHT / 2},.5), -- [5] = Segment({VIRTUAL_WIDTH / 2 + 10, VIRTUAL_HEIGHT / 2},{LEVEL_RENDER_OFFSET,VIRTUAL_HEIGHT / 2},.5), -- [6] = Segment({LEVEL_RENDER_OFFSET,VIRTUAL_HEIGHT / 2},{LEVEL_RENDER_OFFSET,LEVEL_RENDER_OFFSET_TOP},.5) -- } @@ -74,8 +108,10 @@ function Level:insideBounds2(x, y) return shape:testPoint(x, y) end -function Level:insideBounds(x, y, segments) - if not segments then segments = self.segments end +function Level:insideBounds4(x, y, segments) + if not segments then + segments = self.segments + end local up, down, left, right = false local upSeg, downSeg, leftSeg, rightSeg = nil @@ -84,40 +120,40 @@ function Level:insideBounds(x, y, segments) for i, segment in pairs(segments) do -- check raycast on y axis if segment.vertical then - if y <= math.max(segment.firstPointY, segment.secondPointY) and y >= - math.min(segment.firstPointY, segment.secondPointY) then + if + y <= math.max(segment.firstPointY, segment.secondPointY) and + y >= math.min(segment.firstPointY, segment.secondPointY) + then if x <= segment.firstPointX then if not rightSeg then rightSeg = segment - elseif math.abs(segment.firstPointX - x) < - math.abs(rightSeg.firstPointX - x) then + elseif math.abs(segment.firstPointX - x) < math.abs(rightSeg.firstPointX - x) then rightSeg = segment end else if not leftSeg then leftSeg = segment - elseif math.abs(segment.firstPointX - x) < - math.abs(leftSeg.firstPointX - x) then + elseif math.abs(segment.firstPointX - x) < math.abs(leftSeg.firstPointX - x) then leftSeg = segment end end end end if segment.horizontal then - if x <= math.max(segment.firstPointX, segment.secondPointX) and x >= - math.min(segment.firstPointX, segment.secondPointX) then + if + x <= math.max(segment.firstPointX, segment.secondPointX) and + x >= math.min(segment.firstPointX, segment.secondPointX) + then if y <= segment.firstPointY then if not downSeg then downSeg = segment - elseif math.abs(segment.firstPointY - y) < - math.abs(downSeg.firstPointY - y) then + elseif math.abs(segment.firstPointY - y) < math.abs(downSeg.firstPointY - y) then downSeg = segment end else if not upSeg then upSeg = segment - elseif math.abs(segment.firstPointY - y) < - math.abs(upSeg.firstPointY - y) then + elseif math.abs(segment.firstPointY - y) < math.abs(upSeg.firstPointY - y) then upSeg = segment end end @@ -125,11 +161,15 @@ function Level:insideBounds(x, y, segments) end end if not rightSeg or not leftSeg or not upSeg or not downSeg then + print("ball outside - seg check") + return false + end + + if rightSeg.face ~= "left" or leftSeg.face ~= "right" or upSeg.face ~= "down" or downSeg.face ~= "up" then + print("ball outside - face check") return false end - if rightSeg.face ~= 'left' or leftSeg.face ~= 'right' or upSeg.face ~= - 'down' or downSeg.face ~= 'up' then return false end return true end @@ -140,17 +180,26 @@ function Level:insideBounds3(x, y) local j = #self.polygon local polygon = self.polygon for i = 1, #polygon do - if (polygon[i].y < y and polygon[j].y >= y or polygon[j].y < y and - polygon[i].y >= y) then - if (polygon[i].x + (y - polygon[i].y) / - (polygon[j].y - polygon[i].y) * (polygon[j].x - polygon[i].x) < - x) then oddNodes = not oddNodes end + if (polygon[i].y < y and polygon[j].y >= y or polygon[j].y < y and polygon[i].y >= y) then + if (polygon[i].x + (y - polygon[i].y) / (polygon[j].y - polygon[i].y) * (polygon[j].x - polygon[i].x) < x) then + oddNodes = not oddNodes + end end j = i end return oddNodes end +function Level:insideBounds(x, y, segments) + if not segments then + segments = self.segments + end + -- prepare shape + print_r(self.polygon) + + return PointWithinShape(self.polygon, x, y) +end + function Level:createPolygon() local polygon = {} local polygonPoints = {} @@ -159,16 +208,16 @@ function Level:createPolygon() for i, segment in ipairs(self.segments) do polygon[i] = {} polygon[i + 1] = {} - polygon[i].x, polygon[i].y, polygon[i + 1].x, polygon[i + 1].y = - segment:segmentToPoints() + polygon[i].x, polygon[i].y, polygon[i + 1].x, polygon[i + 1].y = segment:segmentToPoints() polygonPoints[j] = polygon[i].x polygonPoints[j + 1] = polygon[i].y polygonPoints[j + 2] = polygon[i + 1].x polygonPoints[j + 3] = polygon[i + 1].y - table.insert(pointlist, polygon[i].x) - table.insert(pointlist, polygon[i].y) - + if polygon[i + 1].x ~= polygon[i].x or polygon[i + 1].y ~= polygon[i].y then + table.insert(pointlist, polygon[i].x) + table.insert(pointlist, polygon[i].y) + end j = j + 4 i = i + 1 end @@ -178,25 +227,30 @@ function Level:createPolygon() end function Level:pointOnEdge(x, y, segments) - if not segments then segments = self.segments end + if not segments then + segments = self.segments + end local margin = 2 for i, segment in pairs(segments) do if segment.vertical then -- vertical line - if x >= segment.firstPointX - margin and x <= segment.firstPointX + - margin and y <= - math.max(segment.firstPointY, segment.secondPointY) and y >= - math.min(segment.firstPointY, segment.secondPointY) then + if + x >= segment.firstPointX - margin and x <= segment.firstPointX + margin and + y <= math.max(segment.firstPointY, segment.secondPointY) and + y >= math.min(segment.firstPointY, segment.secondPointY) + then return true end elseif segment.horizontal then -- horizontal line - if y >= segment.firstPointY - margin and y <= segment.firstPointY + - margin and x <= - math.max(segment.firstPointX, segment.secondPointX) and x >= - math.min(segment.firstPointX, segment.secondPointX) then + if + y >= segment.firstPointY - margin and y <= segment.firstPointY + margin and + x <= math.max(segment.firstPointX, segment.secondPointX) and + x >= math.min(segment.firstPointX, segment.secondPointX) + then return true end end end + -- print("ball pointOnEdge is false") return false end @@ -204,17 +258,19 @@ function Level:getTouchingSegment(x, y) local margin = 2 for i, segment in pairs(self.segments) do if segment.vertical then -- vertical line - if x >= segment.firstPointX - margin and x <= segment.firstPointX + - margin and y <= - math.max(segment.firstPointY, segment.secondPointY) and y >= - math.min(segment.firstPointY, segment.secondPointY) then + if + x >= segment.firstPointX - margin and x <= segment.firstPointX + margin and + y <= math.max(segment.firstPointY, segment.secondPointY) and + y >= math.min(segment.firstPointY, segment.secondPointY) + then return i, segment end elseif segment.horizontal then -- horizontal line - if y >= segment.firstPointY - margin and y <= segment.firstPointY + - margin and x <= - math.max(segment.firstPointX, segment.secondPointX) and x >= - math.min(segment.firstPointX, segment.secondPointX) then + if + y >= segment.firstPointY - margin and y <= segment.firstPointY + margin and + x <= math.max(segment.firstPointX, segment.secondPointX) and + x >= math.min(segment.firstPointX, segment.secondPointX) + then return i, segment end end @@ -223,15 +279,12 @@ function Level:getTouchingSegment(x, y) end function Level:cutLevel() - local newSegs = self.player.trailSegments - local startSegi, startSeg = self.player.trailStartSegment[1], - self.player.trailStartSegment[2] - local endSegi, endSeg = self.player.trailFinishSegment[1], - self.player.trailFinishSegment[2] + local startSegi, startSeg = self.player.trailStartSegment[1], self.player.trailStartSegment[2] + local endSegi, endSeg = self.player.trailFinishSegment[1], self.player.trailFinishSegment[2] local first = 0 local last = 0 - local firstFace = '' + local firstFace = "" -- check if it is same start and finish segment if startSegi == endSegi then @@ -259,11 +312,12 @@ function Level:cutLevel() while k <= #self.segments do -- print(" segment to be inserted "..tostring(k)) if k == startSegi and not insertedNewSegs then + -- print_r(new) + -- print("-- finished inserting new segments and parts") -- print("Reached the segment being cut") -- print_r(self.segments[k]) -- print("split the segment") - part1, temp, part2 = self.segments[k]:splitInThreeWithSegments( - newSegs[1], newSegs[#newSegs]) + part1, temp, part2 = self.segments[k]:splitInThreeWithSegments(newSegs[1], newSegs[#newSegs]) -- print("part1") part1:debug() -- print("part2") @@ -285,8 +339,6 @@ function Level:cutLevel() insertedNewSegments = true new[j] = part2 j = j + 1 - -- print_r(new) - -- print("-- finished inserting new segments and parts") else new[j] = self.segments[k]:copy() j = j + 1 @@ -318,20 +370,21 @@ function Level:cutLevel() -- print("-----start Loop for "..tostring(k).."-----") if k == startSegi and not insertedNewSegments then board2StartSegi = k - -- print("-- this segment is the start segment and not inserted new segments yet") - -- print("newsegs[1] is joined perpendicular to k segment:") + -- print("-- this segment is the start segment and not inserted new segments yet") + -- print("newsegs[1] is joined perpendicular to k segment:") newSegs[1]:debug() newSegs[1]:joinPerpendicular(self.segments[k]) newSegs[1]:debug() -- print("newSegs[1] is joined -- finished") - local startPart1, startPart2 = - self.segments[k]:splitInTwoWithSegment(newSegs[1]) + local startPart1, startPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[1]) -- print("-- Segment k split into 2 segments by newsegs[1]: ") startPart1:debug() startPart2:debug() - if self.segments[last]:endEqualsStartOf(self.segments[k]) or - self.segments[last]:startEqualsStartOf(self.segments[k]) then -- last one is linked to the start of this one + if + self.segments[last]:endEqualsStartOf(self.segments[k]) or + self.segments[last]:startEqualsStartOf(self.segments[k]) + then -- last one is linked to the start of this one -- keep first part of segment -- print("-- keep first part of the k segment") self.segments[k] = startPart1 @@ -348,7 +401,7 @@ function Level:cutLevel() -- print("-- before checking for inserted new segments - Board1") -- print_r(board1) if not insertedNewSegments then - k = endSegi -- skip to last segment to cut and insert it as well + k = endSegi -- skip to last segment to cut and insert it as well last = k - 1 board2EndSegi = k newSegs[#newSegs]:joinPerpendicular(self.segments[k]) @@ -360,18 +413,19 @@ function Level:cutLevel() end -- print_r(board1) - local endPart1, endPart2 = - self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs]) + local endPart1, endPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs]) -- print("-- proceed to insert the second split segment") - if self.segments[last]:endEqualsEndOf(self.segments[k]) or - self.segments[last]:startEqualsEndOf(self.segments[k]) then -- next one is linked to the start of this one + if + self.segments[last]:endEqualsEndOf(self.segments[k]) or + self.segments[last]:startEqualsEndOf(self.segments[k]) + then -- next one is linked to the start of this one + -- print("-- keep first part of the k segment") self.segments[k] = endPart1 savedEnd = endPart2 - -- print("-- keep first part of the k segment") else + -- print("-- keep second part of the k segment") self.segments[k] = endPart2 savedEnd = endPart1 - -- print("-- keep second part of the k segment") end board1[j] = self.segments[k]:copy() @@ -381,20 +435,21 @@ function Level:cutLevel() end elseif k == endSegi and not insertedNewSegments then board2StartSegi = k - -- print("-- this segment is the end segment and not inserted new segments yet") - -- print("newsegs[#newSegs] is joined perpendicular to k segment:") + -- print("-- this segment is the end segment and not inserted new segments yet") + -- print("newsegs[#newSegs] is joined perpendicular to k segment:") newSegs[#newSegs]:debug() newSegs[#newSegs]:joinPerpendicular(self.segments[k]) newSegs[#newSegs]:debug() -- print("newSegs[#newSegs] is joined -- finished") - local endPart1, endPart2 = - self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs]) + local endPart1, endPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs]) -- print("-- Segment k split into 2 segments by newsegs[#newSegs]: ") endPart1:debug() endPart2:debug() - if self.segments[last]:endEqualsStartOf(self.segments[k]) or - self.segments[last]:startEqualsStartOf(self.segments[k]) then -- last one is linked to the start of this one + if + self.segments[last]:endEqualsStartOf(self.segments[k]) or + self.segments[last]:startEqualsStartOf(self.segments[k]) + then -- last one is linked to the start of this one -- keep first part of segment self.segments[k] = endPart1 savedEnd = endPart2 @@ -407,7 +462,7 @@ function Level:cutLevel() j = j + 1 if not insertedNewSegments then - k = startSegi -- skip to last segment to cut and insert it as well + k = startSegi -- skip to last segment to cut and insert it as well last = k - 1 board2EndSegi = k newSegs[1]:joinPerpendicular(self.segments[k]) @@ -422,14 +477,15 @@ function Level:cutLevel() end -- print_r(board1) - local startPart1, startPart2 = - self.segments[k]:splitInTwoWithSegment(newSegs[1]) + local startPart1, startPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[1]) -- print("-- Segment k split into 2 segments by newsegs[1]: ") startPart1:debug() startPart2:debug() - if self.segments[last]:endEqualsEndOf(self.segments[k]) or - self.segments[last]:startEqualsEndOf(self.segments[k]) then -- next one is linked to the start of this one + if + self.segments[last]:endEqualsEndOf(self.segments[k]) or + self.segments[last]:startEqualsEndOf(self.segments[k]) + then -- next one is linked to the start of this one self.segments[k] = startPart1 savedstart = startPart2 else @@ -442,7 +498,6 @@ function Level:cutLevel() -- print_r(board1) insertedNewSegments = true end - elseif k ~= startSegi and k ~= endSegi then board1[j] = self.segments[k]:copy() j = j + 1 @@ -461,6 +516,7 @@ function Level:cutLevel() -- print('---- Create Second board from '..tostring(board2StartSegi)..' to '..tostring(board2EndSegi)) j = 1 if board2StartSegi < board2EndSegi then + -- print_r(board2) board2[j] = savedStart j = j + 1 -- print_r(board2) @@ -485,9 +541,9 @@ function Level:cutLevel() board2[j] = newseg:copy() j = j + 1 end - -- print_r(board2) - else + -- print('-- inserted new segments, final board2 before ordering') + -- print_r(board2) -- print('-- inserted first segment, proceed with skipped segments in first board, end < start') board2[j] = savedEnd j = j + 1 @@ -515,8 +571,6 @@ function Level:cutLevel() j = j + 1 i = i - 1 end - -- print('-- inserted new segments, final board2 before ordering') - -- print_r(board2) end -- print("order segments in cutlevel board2") @@ -525,13 +579,12 @@ function Level:cutLevel() -- print("PREPARE BOARD 2 -- FINAL") -- print_r(board2) - if self:containsBalls(board1) == 0 then - self.segments = board2 - elseif self:containsBalls(board2) == 0 then + local b1balls = self:containsBalls(board1) + local b2balls = self:containsBalls(board2) + if b1balls > b2balls then self.segments = board1 else - self.segments = self:getPerimeter(board1) > - self:getPerimeter(board2) and board1 or board2 + self.segments = board2 end end @@ -563,8 +616,7 @@ function Level:orderSegments(segs) -- -- print("new[i] end equals start of ") -- s:debug() - if new[i].vertical == s.vertical and new[i].horizontal == - s.horizontal then + if new[i].vertical == s.vertical and new[i].horizontal == s.horizontal then -- -- print("join contiguous "..tostring(i).. 'with'..tostring(j)) new[i]:joinContiguous(s) table.remove(segs, j) @@ -584,8 +636,7 @@ function Level:orderSegments(segs) -- -- print("new[i] end equals end of ") -- s:debug() s:switchDirection() - if new[i].vertical == s.vertical and new[i].horizontal == - s.horizontal then + if new[i].vertical == s.vertical and new[i].horizontal == s.horizontal then -- -- print("join contiguous "..tostring(i).. 'with'..tostring(j)) new[i]:joinContiguous(s) table.remove(segs, j) @@ -608,14 +659,10 @@ function Level:orderSegments(segs) -- -- print("search didnt yield any segment") local margin = 2 while not found and margin < 5 do - fi, fs = self:findNearestSegment(new[i].secondPointX, - new[i].secondPointY, segs, - margin) + fi, fs = self:findNearestSegment(new[i].secondPointX, new[i].secondPointY, segs, margin) if not fs then - fi, fs = self:findNearestSegment(new[i].firstPointX, - new[i].firstPointY, segs, - margin) + fi, fs = self:findNearestSegment(new[i].firstPointX, new[i].firstPointY, segs, margin) if not fs then margin = margin + 1 @@ -662,60 +709,60 @@ function Level:calculateSegmentFaces(segments, firstFace) for k, s in ipairs(segments) do s.face = face if k + 1 <= #segments then - if face == 'up' then - if s.direction == 'right' then - if segments[k + 1].direction == 'up' then - face = 'left' + if face == "up" then + if s.direction == "right" then + if segments[k + 1].direction == "up" then + face = "left" else - face = 'right' + face = "right" end else - if segments[k + 1].direction == 'up' then - face = 'right' + if segments[k + 1].direction == "up" then + face = "right" else - face = 'left' + face = "left" end end - elseif face == 'down' then - if s.direction == 'right' then - if segments[k + 1].direction == 'up' then - face = 'right' + elseif face == "down" then + if s.direction == "right" then + if segments[k + 1].direction == "up" then + face = "right" else - face = 'left' + face = "left" end else - if segments[k + 1].direction == 'up' then - face = 'left' + if segments[k + 1].direction == "up" then + face = "left" else - face = 'right' + face = "right" end end - elseif face == 'right' then - if s.direction == 'up' then - if segments[k + 1].direction == 'right' then - face = 'down' + elseif face == "right" then + if s.direction == "up" then + if segments[k + 1].direction == "right" then + face = "down" else - face = 'up' + face = "up" end else - if segments[k + 1].direction == 'right' then - face = 'up' + if segments[k + 1].direction == "right" then + face = "up" else - face = 'down' + face = "down" end end - elseif face == 'left' then - if s.direction == 'up' then - if segments[k + 1].direction == 'right' then - face = 'up' + elseif face == "left" then + if s.direction == "up" then + if segments[k + 1].direction == "right" then + face = "up" else - face = 'down' + face = "down" end else - if segments[k + 1].direction == 'right' then - face = 'down' + if segments[k + 1].direction == "right" then + face = "down" else - face = 'up' + face = "up" end end end @@ -725,28 +772,38 @@ end function Level:getPerimeter(segments) local p = 0 - if not segments then segments = self.segments end - for k, s in pairs(segments) do p = p + s:length() end + if not segments then + segments = self.segments + end + for k, s in pairs(segments) do + p = p + s:length() + end return p end function Level:findNearestSegment(x, y, segments, margin) - if not segments then segments = self.segments end - if not margin then margin = 2 end + if not segments then + segments = self.segments + end + if not margin then + margin = 2 + end -- find a touching segment within margins for i, segment in pairs(segments) do if segment.vertical then -- vertical line - if x >= segment.firstPointX - margin and x <= segment.firstPointX + - margin and y <= - math.max(segment.firstPointY, segment.secondPointY) and y >= - math.min(segment.firstPointY, segment.secondPointY) then + if + x >= segment.firstPointX - margin and x <= segment.firstPointX + margin and + y <= math.max(segment.firstPointY, segment.secondPointY) and + y >= math.min(segment.firstPointY, segment.secondPointY) + then return i, segment end elseif segment.horizontal then -- horizontal line - if y >= segment.firstPointY - margin and y <= segment.firstPointY + - margin and x <= - math.max(segment.firstPointX, segment.secondPointX) and x >= - math.min(segment.firstPointX, segment.secondPointX) then + if + y >= segment.firstPointY - margin and y <= segment.firstPointY + margin and + x <= math.max(segment.firstPointX, segment.secondPointX) and + x >= math.min(segment.firstPointX, segment.secondPointX) + then return i, segment end end @@ -755,15 +812,62 @@ function Level:findNearestSegment(x, y, segments, margin) end function Level:containsBalls(segments) - -- returns numbere of balls inside the bounds passed in or self.segments - if not segments then segments = self.segments end + -- returns number of balls inside the bounds passed in or self.segments + if not segments then + segments = self.segments + end local counter = 0 for k, b in pairs(self.balls) do - if self:insideBounds(b.x + 4, b.y + 4, segments) or - self:pointOnEdge(b.x + 4, b.y + 4, seegments) then + if self:insideBounds(b.x + 4, b.y + 4, segments) or self:pointOnEdge(b.x + 4, b.y + 4, seegments) then counter = counter + 1 end end return counter + -- return #self.balls +end + +function Level:createBalls(n) + local balls = {} + + for i = 1, n do + table.insert( + balls, + Ball( + math.random(LEVEL_RENDER_OFFSET + 5, VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET - 5), --X + math.random(LEVEL_RENDER_OFFSET_TOP + 5, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET - 5), --Y + math.random(20, 90), + math.random(20, 90) -- speed + ) + ) + end + return balls +end +function Level:createBallsFromDef(def) + local balls = {} + + for i = 1, def.balls do + table.insert( + balls, + Ball( + math.random(LEVEL_RENDER_OFFSET + 5, VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET - 5), --X + math.random(LEVEL_RENDER_OFFSET_TOP + 5, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET - 5), --Y + math.random(def.ballSpeed - 10, def.ballSpeed + 10), + math.random(def.ballSpeed - 10, def.ballSpeed + 10) -- speed + ) + ) + end + return balls +end + +function Level:updateBalls(dt) + for k, ball in pairs(self.balls) do + ball:update(dt, self) + end +end + +function Level:renderBalls() + for k, ball in pairs(self.balls) do + ball:render() + end end diff --git a/src/Player.lua b/src/Player.lua index 2218858..cf2f1d1 100644 --- a/src/Player.lua +++ b/src/Player.lua @@ -98,7 +98,6 @@ function Player:onEdge() end function Player:onWalking() - -- if position of player collides with its own trail, stop motion if #self.trail > 1 then table.remove(self.trail) table.remove(self.trailSegments) diff --git a/src/Util.lua b/src/Util.lua index 9fcef84..4ddd698 100644 --- a/src/Util.lua +++ b/src/Util.lua @@ -74,7 +74,8 @@ end -- convert a list of points forming a polygon {x1, y1, x2, y2, ...} into a mesh function poly2mesh(points) - -- remove duplicates??? + -- print("util - poly2mesh: ") + -- print_r(points) if #points > 2 then local polypts = love.math.triangulate(points) local tlist @@ -119,3 +120,155 @@ function poly2mesh(points) return nil end end + +-- point in shape calculation +function PointWithinShape(shape, tx, ty) + if #shape == 0 then + return false + elseif #shape == 1 then + return shape[1].x == tx and shape[1].y == ty + elseif #shape == 2 then + return PointWithinLine(shape, tx, ty) + else + return CrossingsMultiplyTest(shape, tx, ty) + end +end + +function BoundingBox(box, tx, ty) + return (box[2].x >= tx and box[2].y >= ty) + and (box[1].x <= tx and box[1].y <= ty) + or (box[1].x >= tx and box[2].y >= ty) + and (box[2].x <= tx and box[1].y <= ty) +end + +function colinear(line, x, y, e) + e = e or 0.1 + m = (line[2].y - line[1].y) / (line[2].x - line[1].x) + local function f(x) return line[1].y + m*(x - line[1].x) end + return math.abs(y - f(x)) <= e +end + +function PointWithinLine(line, tx, ty, e) + e = e or 0.66 + if BoundingBox(line, tx, ty) then + return colinear(line, tx, ty, e) + else + return false + end +end + +------------------------------------------------------------------------- +-- The following function is based off code from +-- [ http://erich.realtimerendering.com/ptinpoly/ ] +-- +--[[ + ======= Crossings Multiply algorithm =================================== + * This version is usually somewhat faster than the original published in + * Graphics Gems IV; by turning the division for testing the X axis crossing + * into a tricky multiplication test this part of the test became faster, + * which had the additional effect of making the test for "both to left or + * both to right" a bit slower for triangles than simply computing the + * intersection each time. The main increase is in triangle testing speed, + * which was about 15% faster; all other polygon complexities were pretty much + * the same as before. On machines where division is very expensive (not the + * case on the HP 9000 series on which I tested) this test should be much + * faster overall than the old code. Your mileage may (in fact, will) vary, + * depending on the machine and the test data, but in general I believe this + * code is both shorter and faster. This test was inspired by unpublished + * Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson. + * Related work by Samosky is in: + * + * Samosky, Joseph, "SectionView: A system for interactively specifying and + * visualizing sections through three-dimensional medical image data", + * M.S. Thesis, Department of Electrical Engineering and Computer Science, + * Massachusetts Institute of Technology, 1993. + * + --]] + +--[[ Shoot a test ray along +X axis. The strategy is to compare vertex Y values + * to the testing point's Y and quickly discard edges which are entirely to one + * side of the test ray. Note that CONVEX and WINDING code can be added as + * for the CrossingsTest() code; it is left out here for clarity. + * + * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point + * _point_, returns 1 if inside, 0 if outside. + --]] +function CrossingsMultiplyTest(pgon, tx, ty) + local i, yflag0, yflag1, inside_flag + local vtx0, vtx1 + + local numverts = #pgon + + vtx0 = pgon[numverts] + vtx1 = pgon[1] + + -- get test bit for above/below X axis + yflag0 = ( vtx0.y >= ty ) + inside_flag = false + + for i=2,numverts+1 do + yflag1 = ( vtx1.y >= ty ) + + --[[ Check if endpoints straddle (are on opposite sides) of X axis + * (i.e. the Y's differ); if so, +X ray could intersect this edge. + * The old test also checked whether the endpoints are both to the + * right or to the left of the test point. However, given the faster + * intersection point computation used below, this test was found to + * be a break-even proposition for most polygons and a loser for + * triangles (where 50% or more of the edges which survive this test + * will cross quadrants and so have to have the X intersection computed + * anyway). I credit Joseph Samosky with inspiring me to try dropping + * the "both left or both right" part of my code. + --]] + if ( yflag0 ~= yflag1 ) then + --[[ Check intersection of pgon segment with +X ray. + * Note if >= point's X; if so, the ray hits it. + * The division operation is avoided for the ">=" test by checking + * the sign of the first vertex wrto the test point; idea inspired + * by Joseph Samosky's and Mark Haigh-Hutchinson's different + * polygon inclusion tests. + --]] + if ( ((vtx1.y - ty) * (vtx0.x - vtx1.x) >= (vtx1.x - tx) * (vtx0.y - vtx1.y)) == yflag1 ) then + inside_flag = not inside_flag + end + end + + -- Move to the next pair of vertices, retaining info as possible. + yflag0 = yflag1 + vtx0 = vtx1 + vtx1 = pgon[i] + end + + return inside_flag +end + +function GetIntersect( points ) + local g1 = points[1].x + local h1 = points[1].y + + local g2 = points[2].x + local h2 = points[2].y + + local i1 = points[3].x + local j1 = points[3].y + + local i2 = points[4].x + local j2 = points[4].y + + local xk = 0 + local yk = 0 + + if checkIntersect({x=g1, y=h1}, {x=g2, y=h2}, {x=i1, y=j1}, {x=i2, y=j2}) then + local a = h2-h1 + local b = (g2-g1) + local v = ((h2-h1)*g1) - ((g2-g1)*h1) + + local d = i2-i1 + local c = (j2-j1) + local w = ((j2-j1)*i1) - ((i2-i1)*j1) + + xk = (1/((a*d)-(b*c))) * ((d*v)-(b*w)) + yk = (-1/((a*d)-(b*c))) * ((a*w)-(c*v)) + end + return xk, yk +end \ No newline at end of file diff --git a/src/entity/entity_defs.lua b/src/entity/entity_defs.lua index a2e349d..481db3d 100644 --- a/src/entity/entity_defs.lua +++ b/src/entity/entity_defs.lua @@ -75,5 +75,207 @@ LEVELS_DEF = { face = 'right' }, }, + spiders = 0, + timeLimit = 300, + balls = 1, + ballSpeed = 20, + }, + [2] = { + segments = + { + { + p1 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width = LINE_WIDTH, + face = 'down' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'left' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'up' + }, + { + p1 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width= LINE_WIDTH, + face = 'right' + }, + }, + spiders = 0, + timeLimit = 35, + balls = 2, + ballSpeed = 40, + }, + [3] = { + segments = + { + { + p1 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width = LINE_WIDTH, + face = 'down' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'left' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'up' + }, + { + p1 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width= LINE_WIDTH, + face = 'right' + }, + }, + spiders = 0, + timeLimit = 45, + balls = 3, + ballSpeed = 45, + }, + [4] = { + segments = + { + { + p1 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width = LINE_WIDTH, + face = 'down' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'left' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'up' + }, + { + p1 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width= LINE_WIDTH, + face = 'right' + }, + }, + spiders = 1, + timeLimit = 60, + balls = 3, + ballSpeed = 45, + }, + [5] = { + segments = + { + { + p1 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width = LINE_WIDTH, + face = 'down' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'left' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'up' + }, + { + p1 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width= LINE_WIDTH, + face = 'right' + }, + }, + spiders = 1, + timeLimit = 65, + balls = 4, + ballSpeed = 50, + }, + [6] = { + segments = + { + { + p1 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width = LINE_WIDTH, + face = 'down' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'left' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'up' + }, + { + p1 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width= LINE_WIDTH, + face = 'right' + }, + }, + spiders = 2, + timeLimit = 75, + balls = 4, + ballSpeed = 50, + }, + [7] = { + segments = + { + { + p1 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width = LINE_WIDTH, + face = 'down' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + p2 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'left' + }, + { + p1 = {VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + width = LINE_WIDTH, + face = 'up' + }, + { + p1 = {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, + p2 = {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, + width= LINE_WIDTH, + face = 'right' + }, + }, + spiders = 2, + timeLimit = 90, + balls = 5, + ballSpeed = 60, }, } \ No newline at end of file diff --git a/src/states/entity/EntityWalkEdgeState.lua b/src/states/entity/EntityWalkEdgeState.lua index faf3761..78d4c8e 100644 --- a/src/states/entity/EntityWalkEdgeState.lua +++ b/src/states/entity/EntityWalkEdgeState.lua @@ -10,8 +10,8 @@ end function EntityWalkEdgeState:update(dt) - local dy = self.entity.walkingSpeed * dt - local dx = self.entity.walkingSpeed * dt + local dy = math.floor(self.entity.walkingSpeed * dt + 0.5) + local dx = math.floor(self.entity.walkingSpeed * dt + 0.5) if self.entity.direction == 'left' then if self.entity.level:pointOnEdge(self.entity.x - dx + TILE_SIZE / 2, self.entity.y + TILE_SIZE / 2) then diff --git a/src/states/game/PlayState.lua b/src/states/game/PlayState.lua index 1fdec92..053813f 100644 --- a/src/states/game/PlayState.lua +++ b/src/states/game/PlayState.lua @@ -1,21 +1,19 @@ -- require('mobdebug').start() -PlayState = Class{__includes = BaseState} +PlayState = Class {__includes = BaseState} function PlayState:init() - self.name = 'PlayState' + self.name = "PlayState" self.stage = 1 - self.level = Level(LEVELS_DEF, self.stage) - self.player = Player ( ENTITY_DEFS['player'] , self.level) + self.level = Level(LEVELS_DEF[1], self.stage) + self.player = Player(ENTITY_DEFS["player"], self.level) self.level.player = self.player - self.balls = {} - self:createBalls() - self.level.balls = self.balls - self.clock = Clock(30,"down") - - gSounds['music']:setLooping(true) - gSounds['music']:play() + self.balls = self.level.balls + self.clock = self.level.clock + gSounds["music"]:setPitch(1) + gSounds["music"]:setLooping(true) + gSounds["music"]:play() end function PlayState:enter() @@ -24,107 +22,106 @@ end function PlayState:update(dt) self.level:update(dt) self.player:update(dt) - self.clock:update(dt) - self:updateBalls(dt, self.level) self:checkEndLevel(self.level) end function PlayState:render() - love.graphics.clear(0, 0, 0, 255/255) - love.graphics.setColor(40/255, 45/255, 52/255,255/255) + love.graphics.clear(0, 0, 0, 255 / 255) + love.graphics.setColor(56 / 255, 56 / 255, 56 / 255, 1) - love.graphics.setFont(gFonts['small']) - love.graphics.printf('Score '..tostring(self.player.score), - 0, 5, VIRTUAL_WIDTH, 'left') + love.graphics.setFont(gFonts["small"]) + love.graphics.printf("Score " .. tostring(self.player.score), LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP/2, VIRTUAL_WIDTH, "left") - love.graphics.setFont(gFonts['medium']) - love.graphics.printf('Stage '..tostring(self.stage), - 0, 5, VIRTUAL_WIDTH, 'center') + love.graphics.setFont(gFonts["medium"]) + love.graphics.printf("Stage " .. tostring(self.stage), 0, 5, VIRTUAL_WIDTH, "center") - self.clock:render() self.level:render() self.player:render() - self:renderBalls(dt) end -function PlayState:createBalls() - self.balls = {} - - for i = 1, self.stage do - table.insert(self.balls,Ball( - math.random(LEVEL_RENDER_OFFSET + 5, VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET - 5), --X - math.random(LEVEL_RENDER_OFFSET_TOP + 5, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET - 5), --Y - math.random(20,90),math.random(20,90) -- speed - )) - end -end - -function PlayState:updateBalls(dt, level) - for k,ball in pairs(self.balls) do - ball:update(dt,level) - end - -- remove balls outside bounds - for k,ball in pairs(self.balls) do - if ball.remove then - table.remove(self.balls,k) - self.player.score = self.player.score - 1 - elseif ball.hitPlayer then - -- check if any ball hit the player trail segments - self:gameOver() - end - end - -end - -function PlayState:checkEndLevel (level) +function PlayState:checkEndLevel(level) if #self.balls <= 0 then -- game over - reset level + print("game over due to 0 balls") self:gameOver() end -- check perimeter of level, if low enough, create new level move on to the next stage if level:getPerimeter() < 500 then + print("next stage due to perimeter goal reached") self:nextStage() end -- check if clock finished counting limit time - if self.clock.direction == 'up' and self.clock.currentTime * 1 > self.clock.timeLimit then + if self.clock.direction == "up" and self.clock.currentTime * 1 > self.clock.timeLimit then + print("game over due to time limit reached") self:gameOver() - elseif self.clock.direction == 'down' and self.clock.currentTime * 1 <= 0 then + elseif self.clock.direction == "down" and self.clock.currentTime * 1 <= 0 then + print("game over due to time limit reached") self:gameOver() + elseif self.clock.direction == "up" and self.clock.currentTime * 1 > self.clock.timeLimit - 10 then + gSounds["music"]:setPitch(1.25) + elseif self.clock.direction == "down" and self.clock.currentTime * 1 <= 10 then + gSounds["music"]:setPitch(1.25) end -end -function PlayState:renderBalls(dt) - for k,ball in pairs(self.balls) do - ball:render() + -- remove balls outside bounds + for k, ball in pairs(self.balls) do + if ball.remove then + table.remove(self.balls, k) + self.player.score = self.player.score - 1 + elseif ball.hitPlayer then + -- check if any ball hit the player trail segments + print("game over due to player hit by ball") + self:gameOver() + end end end function PlayState:gameOver() gStateStack:pop() - gSounds['music']:stop() - gStateStack:push(GameOverState(self.player.score),function() end) + gSounds["music"]:stop() + gStateStack:push( + GameOverState(self.player.score), + function() + end + ) end function PlayState:nextStage() - gStateStack:push(FadeOutState({ - r = 255/255, g = 255/255, b = 255/255}, 1,function() - self.stage = self.stage + 1 - self.level = Level(LEVELS_DEF,self.stage) - self.clock = Clock(self.clock.timeLimit + 3 * #self.balls,"down") - self.player:reset() - self.player.score = self.player.score + self.player.multiplier * #self.balls - self.player.multiplier = self.player.multiplier + #self.balls - self.balls = {} - self:createBalls() - self.level.player = self.player - self.player.level = self.level - self.level.balls = self.balls - gSounds['music']:stop() - gSounds['heal']:play() - gStateStack:push(FadeOutState({r = 1/255, g = 1/255, b = 1/255}, 1,function() - gSounds['music']:play() - end)) - end)) -end \ No newline at end of file + gStateStack:push( + FadeOutState( + { + r = 255 / 255, + g = 255 / 255, + b = 255 / 255 + }, + 1, + function() + self.stage = self.stage + 1 + local nextDef = self.stage % (#LEVELS_DEF + 1) + if nextDef == 0 then nextDef = 1 end + self.level = Level(LEVELS_DEF[nextDef], self.stage) + self.balls = self.level.balls + self.clock = self.level.clock + self.player:reset() + self.player.score = self.player.score + self.player.multiplier * #self.balls + self.player.multiplier = self.player.multiplier + #self.balls + self.level.player = self.player + self.player.level = self.level + gSounds["music"]:stop() + gSounds["heal"]:play() + gStateStack:push( + FadeOutState( + {r = 1 / 255, g = 1 / 255, b = 1 / 255}, + 1, + function() + gSounds["music"]:setPitch(1) + gSounds["music"]:play() + end + ) + ) + end + ) + ) +end