6 Commits

Author SHA1 Message Date
17a07bc95a chasing down coordinate problem 2021-12-30 19:45:05 +01:00
e46316cff8 tracking down problem with insidebounds check 2021-12-29 23:22:17 +01:00
0aeb0139d3 clock update 2021-12-27 22:23:19 +01:00
391e2ab1b7 new clock 2021-12-27 20:43:37 +01:00
3af5bbe928 fixed level jump 2021-12-27 17:37:14 +01:00
e0ac6abaef remove debug messages 2021-12-27 17:25:07 +01:00
13 changed files with 847 additions and 284 deletions

View File

@@ -4,10 +4,10 @@ Lua game inspired by an old arcade game(Qix/Gals Panic) using LOVE2D for Linux.
## TO-DO ## TO-DO
- Stop player from creating crossed lines
- Fix creation of the lines / polygon / points - Fix creation of the lines / polygon / points
- Add more pictures (manga?) - Add more pictures (manga?)
- Fix balls sometimes attaching to the lines - Fix balls sometimes attaching to the lines
- Add spiders moving around in the board, player collision kills

View File

@@ -37,6 +37,7 @@ if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
function love.load() function love.load()
love.window.setTitle('SpiderCut') love.window.setTitle('SpiderCut')
love.graphics.setDefaultFilter('nearest', 'nearest') love.graphics.setDefaultFilter('nearest', 'nearest')
love.graphics.setLineJoin( "bevel" )
math.randomseed(os.time()) math.randomseed(os.time())
push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, { push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, {
@@ -59,7 +60,16 @@ function love.keypressed(key)
if key == 'escape' then if key == 'escape' then
love.event.quit() love.event.quit()
end end
if key == 'f' then
push:switchFullscreen()
end
if key == 'r' then
gStateStack:clear()
gStateStack:push(StartState())
end
love.keyboard.keysPressed[key] = true love.keyboard.keysPressed[key] = true
end end

View File

@@ -22,13 +22,15 @@ function Ball:reset()
end end
function Ball:update(dt,level) function Ball:update(dt,level)
local tempX = self.x + self.dx * dt local tempX = math.floor((self.x + self.dx * dt) + 0.5)
local tempY = self.y + self.dy * dt local tempY = math.floor((self.y + self.dy * dt) + 0.5)
local trailSeg = level:pointOnEdge(tempX,tempY,level.player.trailSegments) local trailSeg = level:pointOnEdge(tempX,tempY,level.player.trailSegments)
if trailSeg then if trailSeg then
self.hitPlayer = true self.hitPlayer = true
-- print("ball hits player")
gSounds['hit']:play() gSounds['hit']:play()
return
end end
local i, segment = level:getTouchingSegment(tempX,tempY) local i, segment = level:getTouchingSegment(tempX,tempY)
@@ -49,8 +51,9 @@ function Ball:update(dt,level)
gSounds['blip']:play() gSounds['blip']:play()
end 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 self.remove = true
print("ball outside or touching segment")
end end
self.x = self.x + self.dx * dt self.x = self.x + self.dx * dt
@@ -60,8 +63,9 @@ function Ball:update(dt,level)
end end
function Ball:render() 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.circle('fill', self.x, self.y, self.width/2)
love.graphics.setColor(1,1,1,1)
end end
function Ball:getCollisionDirection(segment,x,y) function Ball:getCollisionDirection(segment,x,y)

36
src/Clock.lua Normal file
View File

@@ -0,0 +1,36 @@
Clock = Class {}
function Clock:init(timelimit, direction)
self.timeLimit = timelimit
self.direction = direction
self.color = {56 / 255, 56 / 255, 56 / 255, 1}
self.currentTime = "0"
self.timer = 0
self.startTime = self:getOsTime()
end
function Clock:update(dt)
local passed = math.floor((self:getOsTime() - self.startTime) * 10 + 0.5)
if self.direction == 'down' then
self.currentTime = tostring(self.timeLimit - passed)
else
self.currentTime = tostring(passed)
end
end
function Clock:render()
if self.currentTime * 1 <= 10 then
local a = math.abs(math.cos(love.timer.getTime() * .85 % 2 * math.pi))
love.graphics.setColor(.8, .12, .12, a)
else
love.graphics.setColor(self.color[1], self.color[2], self.color[3],
self.color[4])
end
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)
end
function Clock:getOsTime() return os.clock() end

View File

@@ -10,6 +10,7 @@ Timer = require 'lib/knife.timer'
require 'src/Animation' require 'src/Animation'
require 'src/constants' require 'src/constants'
require 'src/StateMachine' require 'src/StateMachine'
require 'src/Clock'
require 'src/Util' require 'src/Util'
require 'src/Level' require 'src/Level'

View File

@@ -1,67 +1,102 @@
-- require('mobdebug').start() -- require('mobdebug').start()
Level = Class {} Level = Class {}
function Level:init(stage) function Level:init(def, stage)
self.stage = stage self.stage = stage
self.points = {} self.points = {}
self.player = {} self.player = {}
self.segments = self:createLevel() self.segments = self:createLevelFromDef(def)
self.polygon = self:createPolygon() self.polygon = self:createPolygon()
self.mesh = poly2mesh(self.points) self.mesh = poly2mesh(self.points)
self.balls = self:createBallsFromDef(def)
self.clock = Clock(def.timeLimit, "down")
end end
function Level:update(dt) function Level:update(dt)
-- print_r(self.points)
-- print(tostring(#self.points))
-- if self.mesh == nil and #self.points > 2 then
-- self.mesh = poly2mesh(self.points)
-- end
self.mesh = poly2mesh(self.points) self.mesh = poly2mesh(self.points)
-- print_r(self.mesh:getVertices()) self:updateBalls(dt)
self.clock:update(dt)
end end
function Level:render() function Level:render()
self:renderBackground() self:renderBackground()
self:renderOuterSegments() self:renderOuterSegments()
self:renderBalls()
self.clock:render()
end end
function Level:renderOuterSegments() function Level:renderOuterSegments()
for k, segment in pairs(self.segments) do segment:render() end for k, segment in pairs(self.segments) do
segment:render()
end
end end
function Level:renderBackground() function Level:renderBackground()
love.graphics.draw(gImages[(self.stage % #gImages)], LEVEL_RENDER_OFFSET, local nextImg = self.stage % (#gImages + 1)
LEVEL_RENDER_OFFSET_TOP) if nextImg == 0 then
if self.mesh:type() == "Mesh" then nextImg = 1
love.graphics.draw(self.mesh, 0, 0)
end 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.segments) do
table.insert(level, Segment(seg.p1, seg.p2, seg.width, seg.face))
end
return level
end end
function Level:createLevel() function Level:createLevel()
local level = { local level = {
[1] = Segment({LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, { [1] = Segment(
VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP},
}, .5, 'down'), {
[2] = Segment({ VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET,
VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP LEVEL_RENDER_OFFSET_TOP
}, { },
VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, .5,
VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET "down"
}, .5, 'left'), ),
[3] = Segment({ [2] = Segment(
VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, {
VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET,
}, {LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET}, .5, 'up'), LEVEL_RENDER_OFFSET_TOP
[4] = Segment({ },
LEVEL_RENDER_OFFSET, VIRTUAL_HEIGHT - LEVEL_RENDER_OFFSET {
}, {LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP}, .5, 'right') 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 = { -- local level = {
-- [1] = Segment({LEVEL_RENDER_OFFSET,LEVEL_RENDER_OFFSET_TOP},{VIRTUAL_WIDTH - LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP},.5), -- [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), -- [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), -- [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), -- [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) -- [6] = Segment({LEVEL_RENDER_OFFSET,VIRTUAL_HEIGHT / 2},{LEVEL_RENDER_OFFSET,LEVEL_RENDER_OFFSET_TOP},.5)
-- } -- }
@@ -73,8 +108,10 @@ function Level:insideBounds2(x, y)
return shape:testPoint(x, y) return shape:testPoint(x, y)
end end
function Level:insideBounds(x, y, segments) function Level:insideBounds4(x, y, segments)
if not segments then segments = self.segments end if not segments then
segments = self.segments
end
local up, down, left, right = false local up, down, left, right = false
local upSeg, downSeg, leftSeg, rightSeg = nil local upSeg, downSeg, leftSeg, rightSeg = nil
@@ -83,40 +120,40 @@ function Level:insideBounds(x, y, segments)
for i, segment in pairs(segments) do for i, segment in pairs(segments) do
-- check raycast on y axis -- check raycast on y axis
if segment.vertical then if segment.vertical then
if y <= math.max(segment.firstPointY, segment.secondPointY) and y >= if
math.min(segment.firstPointY, segment.secondPointY) then y <= math.max(segment.firstPointY, segment.secondPointY) and
y >= math.min(segment.firstPointY, segment.secondPointY)
then
if x <= segment.firstPointX then if x <= segment.firstPointX then
if not rightSeg then if not rightSeg then
rightSeg = segment rightSeg = segment
elseif math.abs(segment.firstPointX - x) < elseif math.abs(segment.firstPointX - x) < math.abs(rightSeg.firstPointX - x) then
math.abs(rightSeg.firstPointX - x) then
rightSeg = segment rightSeg = segment
end end
else else
if not leftSeg then if not leftSeg then
leftSeg = segment leftSeg = segment
elseif math.abs(segment.firstPointX - x) < elseif math.abs(segment.firstPointX - x) < math.abs(leftSeg.firstPointX - x) then
math.abs(leftSeg.firstPointX - x) then
leftSeg = segment leftSeg = segment
end end
end end
end end
end end
if segment.horizontal then if segment.horizontal then
if x <= math.max(segment.firstPointX, segment.secondPointX) and x >= if
math.min(segment.firstPointX, segment.secondPointX) then x <= math.max(segment.firstPointX, segment.secondPointX) and
x >= math.min(segment.firstPointX, segment.secondPointX)
then
if y <= segment.firstPointY then if y <= segment.firstPointY then
if not downSeg then if not downSeg then
downSeg = segment downSeg = segment
elseif math.abs(segment.firstPointY - y) < elseif math.abs(segment.firstPointY - y) < math.abs(downSeg.firstPointY - y) then
math.abs(downSeg.firstPointY - y) then
downSeg = segment downSeg = segment
end end
else else
if not upSeg then if not upSeg then
upSeg = segment upSeg = segment
elseif math.abs(segment.firstPointY - y) < elseif math.abs(segment.firstPointY - y) < math.abs(upSeg.firstPointY - y) then
math.abs(upSeg.firstPointY - y) then
upSeg = segment upSeg = segment
end end
end end
@@ -124,11 +161,15 @@ function Level:insideBounds(x, y, segments)
end end
end end
if not rightSeg or not leftSeg or not upSeg or not downSeg then 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 return false
end end
if rightSeg.face ~= 'left' or leftSeg.face ~= 'right' or upSeg.face ~=
'down' or downSeg.face ~= 'up' then return false end
return true return true
end end
@@ -139,18 +180,51 @@ function Level:insideBounds3(x, y)
local j = #self.polygon local j = #self.polygon
local polygon = self.polygon local polygon = self.polygon
for i = 1, #polygon do for i = 1, #polygon do
if (polygon[i].y < y and polygon[j].y >= y or polygon[j].y < y and if (polygon[i].y < y and polygon[j].y >= y or polygon[j].y < y and polygon[i].y >= y) then
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
if (polygon[i].x + (y - polygon[i].y) / oddNodes = not oddNodes
(polygon[j].y - polygon[i].y) * (polygon[j].x - polygon[i].x) < end
x) then oddNodes = not oddNodes end
end end
j = i j = i
end end
return oddNodes return oddNodes
end end
function Level:insideBounds(x, y, segments)
if not segments then
segments = self.segments
end
-- prepare shape
local polygon = self:getPolygonFromSegments(segments)
return PointWithinShape(polygon, x, y)
end
function Level:getPolygonFromSegments(segments)
local polygon = {}
local polygonPoints = {}
local pointlist = {}
local j = 1
for i, segment in ipairs(segments) do
polygon[i] = {}
polygon[i + 1] = {}
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
j = j + 4
i = i + 1
end
return polygon
end
function Level:createPolygon() function Level:createPolygon()
if #self.segments > 5 then
print("Level:createPolygon")
print_r(self.segments)
end
local polygon = {} local polygon = {}
local polygonPoints = {} local polygonPoints = {}
local pointlist = {} local pointlist = {}
@@ -158,16 +232,16 @@ function Level:createPolygon()
for i, segment in ipairs(self.segments) do for i, segment in ipairs(self.segments) do
polygon[i] = {} polygon[i] = {}
polygon[i + 1] = {} polygon[i + 1] = {}
polygon[i].x, polygon[i].y, polygon[i + 1].x, polygon[i + 1].y = polygon[i].x, polygon[i].y, polygon[i + 1].x, polygon[i + 1].y = segment:segmentToPoints()
segment:segmentToPoints()
polygonPoints[j] = polygon[i].x polygonPoints[j] = polygon[i].x
polygonPoints[j + 1] = polygon[i].y polygonPoints[j + 1] = polygon[i].y
polygonPoints[j + 2] = polygon[i + 1].x polygonPoints[j + 2] = polygon[i + 1].x
polygonPoints[j + 3] = polygon[i + 1].y polygonPoints[j + 3] = polygon[i + 1].y
table.insert(pointlist, polygon[i].x) if polygon[i + 1].x ~= polygon[i].x or polygon[i + 1].y ~= polygon[i].y then
table.insert(pointlist, polygon[i].y) table.insert(pointlist, polygon[i].x)
table.insert(pointlist, polygon[i].y)
end
j = j + 4 j = j + 4
i = i + 1 i = i + 1
end end
@@ -177,25 +251,30 @@ function Level:createPolygon()
end end
function Level:pointOnEdge(x, y, segments) 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 local margin = 2
for i, segment in pairs(segments) do for i, segment in pairs(segments) do
if segment.vertical then -- vertical line if segment.vertical then -- vertical line
if x >= segment.firstPointX - margin and x <= segment.firstPointX + if
margin and y <= x >= segment.firstPointX - margin and x <= segment.firstPointX + margin and
math.max(segment.firstPointY, segment.secondPointY) and y >= y <= math.max(segment.firstPointY, segment.secondPointY) and
math.min(segment.firstPointY, segment.secondPointY) then y >= math.min(segment.firstPointY, segment.secondPointY)
then
return true return true
end end
elseif segment.horizontal then -- horizontal line elseif segment.horizontal then -- horizontal line
if y >= segment.firstPointY - margin and y <= segment.firstPointY + if
margin and x <= y >= segment.firstPointY - margin and y <= segment.firstPointY + margin and
math.max(segment.firstPointX, segment.secondPointX) and x >= x <= math.max(segment.firstPointX, segment.secondPointX) and
math.min(segment.firstPointX, segment.secondPointX) then x >= math.min(segment.firstPointX, segment.secondPointX)
then
return true return true
end end
end end
end end
-- print("ball pointOnEdge is false")
return false return false
end end
@@ -203,17 +282,19 @@ function Level:getTouchingSegment(x, y)
local margin = 2 local margin = 2
for i, segment in pairs(self.segments) do for i, segment in pairs(self.segments) do
if segment.vertical then -- vertical line if segment.vertical then -- vertical line
if x >= segment.firstPointX - margin and x <= segment.firstPointX + if
margin and y <= x >= segment.firstPointX - margin and x <= segment.firstPointX + margin and
math.max(segment.firstPointY, segment.secondPointY) and y >= y <= math.max(segment.firstPointY, segment.secondPointY) and
math.min(segment.firstPointY, segment.secondPointY) then y >= math.min(segment.firstPointY, segment.secondPointY)
then
return i, segment return i, segment
end end
elseif segment.horizontal then -- horizontal line elseif segment.horizontal then -- horizontal line
if y >= segment.firstPointY - margin and y <= segment.firstPointY + if
margin and x <= y >= segment.firstPointY - margin and y <= segment.firstPointY + margin and
math.max(segment.firstPointX, segment.secondPointX) and x >= x <= math.max(segment.firstPointX, segment.secondPointX) and
math.min(segment.firstPointX, segment.secondPointX) then x >= math.min(segment.firstPointX, segment.secondPointX)
then
return i, segment return i, segment
end end
end end
@@ -222,15 +303,12 @@ function Level:getTouchingSegment(x, y)
end end
function Level:cutLevel() function Level:cutLevel()
local newSegs = self.player.trailSegments local newSegs = self.player.trailSegments
local startSegi, startSeg = self.player.trailStartSegment[1], local startSegi, startSeg = self.player.trailStartSegment[1], self.player.trailStartSegment[2]
self.player.trailStartSegment[2] local endSegi, endSeg = self.player.trailFinishSegment[1], self.player.trailFinishSegment[2]
local endSegi, endSeg = self.player.trailFinishSegment[1],
self.player.trailFinishSegment[2]
local first = 0 local first = 0
local last = 0 local last = 0
local firstFace = '' local firstFace = ""
-- check if it is same start and finish segment -- check if it is same start and finish segment
if startSegi == endSegi then if startSegi == endSegi then
@@ -258,15 +336,16 @@ function Level:cutLevel()
while k <= #self.segments do while k <= #self.segments do
-- print(" segment to be inserted "..tostring(k)) -- print(" segment to be inserted "..tostring(k))
if k == startSegi and not insertedNewSegs then if k == startSegi and not insertedNewSegs then
-- print_r(new)
-- print("-- finished inserting new segments and parts")
-- print("Reached the segment being cut") -- print("Reached the segment being cut")
-- print_r(self.segments[k]) -- print_r(self.segments[k])
-- print("split the segment") -- print("split the segment")
part1, temp, part2 = self.segments[k]:splitInThreeWithSegments( part1, temp, part2 = self.segments[k]:splitInThreeWithSegments(newSegs[1], newSegs[#newSegs])
newSegs[1], newSegs[#newSegs])
-- print("part1") -- print("part1")
part1:debug() -- part1:debug()
-- print("part2") -- print("part2")
part2:debug() -- part2:debug()
-- print("insert first part") -- print("insert first part")
new[j] = part1 new[j] = part1
@@ -284,8 +363,6 @@ function Level:cutLevel()
insertedNewSegments = true insertedNewSegments = true
new[j] = part2 new[j] = part2
j = j + 1 j = j + 1
-- print_r(new)
-- print("-- finished inserting new segments and parts")
else else
new[j] = self.segments[k]:copy() new[j] = self.segments[k]:copy()
j = j + 1 j = j + 1
@@ -317,20 +394,21 @@ function Level:cutLevel()
-- print("-----start Loop for "..tostring(k).."-----") -- print("-----start Loop for "..tostring(k).."-----")
if k == startSegi and not insertedNewSegments then if k == startSegi and not insertedNewSegments then
board2StartSegi = k board2StartSegi = k
-- print("-- this segment is the start segment and not inserted new segments yet") -- print("-- this segment is the start segment and not inserted new segments yet")
-- print("newsegs[1] is joined perpendicular to k segment:") -- print("newsegs[1] is joined perpendicular to k segment:")
newSegs[1]:debug() newSegs[1]:debug()
newSegs[1]:joinPerpendicular(self.segments[k]) newSegs[1]:joinPerpendicular(self.segments[k])
newSegs[1]:debug() newSegs[1]:debug()
-- print("newSegs[1] is joined -- finished") -- print("newSegs[1] is joined -- finished")
local startPart1, startPart2 = local startPart1, startPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[1])
self.segments[k]:splitInTwoWithSegment(newSegs[1])
-- print("-- Segment k split into 2 segments by newsegs[1]: ") -- print("-- Segment k split into 2 segments by newsegs[1]: ")
startPart1:debug() startPart1:debug()
startPart2:debug() startPart2:debug()
if self.segments[last]:endEqualsStartOf(self.segments[k]) or if
self.segments[last]:startEqualsStartOf(self.segments[k]) then -- last one is linked to the start of this one 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 -- keep first part of segment
-- print("-- keep first part of the k segment") -- print("-- keep first part of the k segment")
self.segments[k] = startPart1 self.segments[k] = startPart1
@@ -347,7 +425,7 @@ function Level:cutLevel()
-- print("-- before checking for inserted new segments - Board1") -- print("-- before checking for inserted new segments - Board1")
-- print_r(board1) -- print_r(board1)
if not insertedNewSegments then 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 last = k - 1
board2EndSegi = k board2EndSegi = k
newSegs[#newSegs]:joinPerpendicular(self.segments[k]) newSegs[#newSegs]:joinPerpendicular(self.segments[k])
@@ -359,18 +437,19 @@ function Level:cutLevel()
end end
-- print_r(board1) -- print_r(board1)
local endPart1, endPart2 = local endPart1, endPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs])
self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs])
-- print("-- proceed to insert the second split segment") -- print("-- proceed to insert the second split segment")
if self.segments[last]:endEqualsEndOf(self.segments[k]) or if
self.segments[last]:startEqualsEndOf(self.segments[k]) then -- next one is linked to the start of this one 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 self.segments[k] = endPart1
savedEnd = endPart2 savedEnd = endPart2
-- print("-- keep first part of the k segment")
else else
-- print("-- keep second part of the k segment")
self.segments[k] = endPart2 self.segments[k] = endPart2
savedEnd = endPart1 savedEnd = endPart1
-- print("-- keep second part of the k segment")
end end
board1[j] = self.segments[k]:copy() board1[j] = self.segments[k]:copy()
@@ -380,20 +459,21 @@ function Level:cutLevel()
end end
elseif k == endSegi and not insertedNewSegments then elseif k == endSegi and not insertedNewSegments then
board2StartSegi = k board2StartSegi = k
-- print("-- this segment is the end segment and not inserted new segments yet") -- print("-- this segment is the end segment and not inserted new segments yet")
-- print("newsegs[#newSegs] is joined perpendicular to k segment:") -- print("newsegs[#newSegs] is joined perpendicular to k segment:")
newSegs[#newSegs]:debug() newSegs[#newSegs]:debug()
newSegs[#newSegs]:joinPerpendicular(self.segments[k]) newSegs[#newSegs]:joinPerpendicular(self.segments[k])
newSegs[#newSegs]:debug() newSegs[#newSegs]:debug()
-- print("newSegs[#newSegs] is joined -- finished") -- print("newSegs[#newSegs] is joined -- finished")
local endPart1, endPart2 = local endPart1, endPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs])
self.segments[k]:splitInTwoWithSegment(newSegs[#newSegs])
-- print("-- Segment k split into 2 segments by newsegs[#newSegs]: ") -- print("-- Segment k split into 2 segments by newsegs[#newSegs]: ")
endPart1:debug() endPart1:debug()
endPart2:debug() endPart2:debug()
if self.segments[last]:endEqualsStartOf(self.segments[k]) or if
self.segments[last]:startEqualsStartOf(self.segments[k]) then -- last one is linked to the start of this one 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 -- keep first part of segment
self.segments[k] = endPart1 self.segments[k] = endPart1
savedEnd = endPart2 savedEnd = endPart2
@@ -406,7 +486,7 @@ function Level:cutLevel()
j = j + 1 j = j + 1
if not insertedNewSegments then 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 last = k - 1
board2EndSegi = k board2EndSegi = k
newSegs[1]:joinPerpendicular(self.segments[k]) newSegs[1]:joinPerpendicular(self.segments[k])
@@ -421,14 +501,15 @@ function Level:cutLevel()
end end
-- print_r(board1) -- print_r(board1)
local startPart1, startPart2 = local startPart1, startPart2 = self.segments[k]:splitInTwoWithSegment(newSegs[1])
self.segments[k]:splitInTwoWithSegment(newSegs[1])
-- print("-- Segment k split into 2 segments by newsegs[1]: ") -- print("-- Segment k split into 2 segments by newsegs[1]: ")
startPart1:debug() startPart1:debug()
startPart2:debug() startPart2:debug()
if self.segments[last]:endEqualsEndOf(self.segments[k]) or if
self.segments[last]:startEqualsEndOf(self.segments[k]) then -- next one is linked to the start of this one 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 self.segments[k] = startPart1
savedstart = startPart2 savedstart = startPart2
else else
@@ -441,7 +522,6 @@ function Level:cutLevel()
-- print_r(board1) -- print_r(board1)
insertedNewSegments = true insertedNewSegments = true
end end
elseif k ~= startSegi and k ~= endSegi then elseif k ~= startSegi and k ~= endSegi then
board1[j] = self.segments[k]:copy() board1[j] = self.segments[k]:copy()
j = j + 1 j = j + 1
@@ -460,6 +540,7 @@ function Level:cutLevel()
-- print('---- Create Second board from '..tostring(board2StartSegi)..' to '..tostring(board2EndSegi)) -- print('---- Create Second board from '..tostring(board2StartSegi)..' to '..tostring(board2EndSegi))
j = 1 j = 1
if board2StartSegi < board2EndSegi then if board2StartSegi < board2EndSegi then
-- print_r(board2)
board2[j] = savedStart board2[j] = savedStart
j = j + 1 j = j + 1
-- print_r(board2) -- print_r(board2)
@@ -484,9 +565,9 @@ function Level:cutLevel()
board2[j] = newseg:copy() board2[j] = newseg:copy()
j = j + 1 j = j + 1
end end
-- print_r(board2)
else 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') -- print('-- inserted first segment, proceed with skipped segments in first board, end < start')
board2[j] = savedEnd board2[j] = savedEnd
j = j + 1 j = j + 1
@@ -514,8 +595,6 @@ function Level:cutLevel()
j = j + 1 j = j + 1
i = i - 1 i = i - 1
end end
-- print('-- inserted new segments, final board2 before ordering')
-- print_r(board2)
end end
-- print("order segments in cutlevel board2") -- print("order segments in cutlevel board2")
@@ -524,17 +603,16 @@ function Level:cutLevel()
-- print("PREPARE BOARD 2 -- FINAL") -- print("PREPARE BOARD 2 -- FINAL")
-- print_r(board2) -- print_r(board2)
if self:containsBalls(board1) == 0 then local b1balls = self:containsBalls(board1)
self.segments = board2 local b2balls = self:containsBalls(board2)
elseif self:containsBalls(board2) == 0 then if b1balls > b2balls then
self.segments = board1 self.segments = board1
else else
self.segments = self:getPerimeter(board1) > self.segments = board2
self:getPerimeter(board2) and board1 or board2
end end
end end
self:createPolygon() self.polygon = self:createPolygon()
self.mesh = poly2mesh(self.points) self.mesh = poly2mesh(self.points)
end end
@@ -562,8 +640,7 @@ function Level:orderSegments(segs)
-- -- print("new[i] end equals start of ") -- -- print("new[i] end equals start of ")
-- s:debug() -- s:debug()
if new[i].vertical == s.vertical and new[i].horizontal == if new[i].vertical == s.vertical and new[i].horizontal == s.horizontal then
s.horizontal then
-- -- print("join contiguous "..tostring(i).. 'with'..tostring(j)) -- -- print("join contiguous "..tostring(i).. 'with'..tostring(j))
new[i]:joinContiguous(s) new[i]:joinContiguous(s)
table.remove(segs, j) table.remove(segs, j)
@@ -583,8 +660,7 @@ function Level:orderSegments(segs)
-- -- print("new[i] end equals end of ") -- -- print("new[i] end equals end of ")
-- s:debug() -- s:debug()
s:switchDirection() s:switchDirection()
if new[i].vertical == s.vertical and new[i].horizontal == if new[i].vertical == s.vertical and new[i].horizontal == s.horizontal then
s.horizontal then
-- -- print("join contiguous "..tostring(i).. 'with'..tostring(j)) -- -- print("join contiguous "..tostring(i).. 'with'..tostring(j))
new[i]:joinContiguous(s) new[i]:joinContiguous(s)
table.remove(segs, j) table.remove(segs, j)
@@ -607,14 +683,10 @@ function Level:orderSegments(segs)
-- -- print("search didnt yield any segment") -- -- print("search didnt yield any segment")
local margin = 2 local margin = 2
while not found and margin < 5 do while not found and margin < 5 do
fi, fs = self:findNearestSegment(new[i].secondPointX, fi, fs = self:findNearestSegment(new[i].secondPointX, new[i].secondPointY, segs, margin)
new[i].secondPointY, segs,
margin)
if not fs then if not fs then
fi, fs = self:findNearestSegment(new[i].firstPointX, fi, fs = self:findNearestSegment(new[i].firstPointX, new[i].firstPointY, segs, margin)
new[i].firstPointY, segs,
margin)
if not fs then if not fs then
margin = margin + 1 margin = margin + 1
@@ -661,60 +733,60 @@ function Level:calculateSegmentFaces(segments, firstFace)
for k, s in ipairs(segments) do for k, s in ipairs(segments) do
s.face = face s.face = face
if k + 1 <= #segments then if k + 1 <= #segments then
if face == 'up' then if face == "up" then
if s.direction == 'right' then if s.direction == "right" then
if segments[k + 1].direction == 'up' then if segments[k + 1].direction == "up" then
face = 'left' face = "left"
else else
face = 'right' face = "right"
end end
else else
if segments[k + 1].direction == 'up' then if segments[k + 1].direction == "up" then
face = 'right' face = "right"
else else
face = 'left' face = "left"
end end
end end
elseif face == 'down' then elseif face == "down" then
if s.direction == 'right' then if s.direction == "right" then
if segments[k + 1].direction == 'up' then if segments[k + 1].direction == "up" then
face = 'right' face = "right"
else else
face = 'left' face = "left"
end end
else else
if segments[k + 1].direction == 'up' then if segments[k + 1].direction == "up" then
face = 'left' face = "left"
else else
face = 'right' face = "right"
end end
end end
elseif face == 'right' then elseif face == "right" then
if s.direction == 'up' then if s.direction == "up" then
if segments[k + 1].direction == 'right' then if segments[k + 1].direction == "right" then
face = 'down' face = "down"
else else
face = 'up' face = "up"
end end
else else
if segments[k + 1].direction == 'right' then if segments[k + 1].direction == "right" then
face = 'up' face = "up"
else else
face = 'down' face = "down"
end end
end end
elseif face == 'left' then elseif face == "left" then
if s.direction == 'up' then if s.direction == "up" then
if segments[k + 1].direction == 'right' then if segments[k + 1].direction == "right" then
face = 'up' face = "up"
else else
face = 'down' face = "down"
end end
else else
if segments[k + 1].direction == 'right' then if segments[k + 1].direction == "right" then
face = 'down' face = "down"
else else
face = 'up' face = "up"
end end
end end
end end
@@ -724,28 +796,38 @@ end
function Level:getPerimeter(segments) function Level:getPerimeter(segments)
local p = 0 local p = 0
if not segments then segments = self.segments end if not segments then
for k, s in pairs(segments) do p = p + s:length() end segments = self.segments
end
for k, s in pairs(segments) do
p = p + s:length()
end
return p return p
end end
function Level:findNearestSegment(x, y, segments, margin) function Level:findNearestSegment(x, y, segments, margin)
if not segments then segments = self.segments end if not segments then
if not margin then margin = 2 end segments = self.segments
end
if not margin then
margin = 2
end
-- find a touching segment within margins -- find a touching segment within margins
for i, segment in pairs(segments) do for i, segment in pairs(segments) do
if segment.vertical then -- vertical line if segment.vertical then -- vertical line
if x >= segment.firstPointX - margin and x <= segment.firstPointX + if
margin and y <= x >= segment.firstPointX - margin and x <= segment.firstPointX + margin and
math.max(segment.firstPointY, segment.secondPointY) and y >= y <= math.max(segment.firstPointY, segment.secondPointY) and
math.min(segment.firstPointY, segment.secondPointY) then y >= math.min(segment.firstPointY, segment.secondPointY)
then
return i, segment return i, segment
end end
elseif segment.horizontal then -- horizontal line elseif segment.horizontal then -- horizontal line
if y >= segment.firstPointY - margin and y <= segment.firstPointY + if
margin and x <= y >= segment.firstPointY - margin and y <= segment.firstPointY + margin and
math.max(segment.firstPointX, segment.secondPointX) and x >= x <= math.max(segment.firstPointX, segment.secondPointX) and
math.min(segment.firstPointX, segment.secondPointX) then x >= math.min(segment.firstPointX, segment.secondPointX)
then
return i, segment return i, segment
end end
end end
@@ -754,15 +836,62 @@ function Level:findNearestSegment(x, y, segments, margin)
end end
function Level:containsBalls(segments) function Level:containsBalls(segments)
-- returns numbere of balls inside the bounds passed in or self.segments -- returns number of balls inside the bounds passed in or self.segments
if not segments then segments = self.segments end if not segments then
segments = self.segments
end
local counter = 0 local counter = 0
for k, b in pairs(self.balls) do for k, b in pairs(self.balls) do
if self:insideBounds(b.x + 4, b.y + 4, segments) or if self:insideBounds(b.x + 4, b.y + 4, segments) or self:pointOnEdge(b.x + 4, b.y + 4, seegments) then
self:pointOnEdge(b.x + 4, b.y + 4, seegments) then
counter = counter + 1 counter = counter + 1
end end
end end
return counter 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 end

View File

@@ -39,13 +39,9 @@ function Player:init(def, level )
end end
function Player:isMoveAllowed(point) function Player:isMoveAllowed(point)
print("Player:isMoveAllowed " .. tostring(point[1]) .. "," .. tostring(point[2]))
point = {point[1] + self.width/2, point[2] + self.width/2} point = {point[1] + self.width/2, point[2] + self.width/2}
print("Player:isMoveAllowed " .. tostring(point[1]) .. "," .. tostring(point[2]))
for i,segment in pairs (self.trailSegments) do for i,segment in pairs (self.trailSegments) do
if segment:pointInSegment(point) then if segment:pointInSegment(point) then
print("Player:isMoveAllowed = false")
print_r(segment)
return false return false
end end
end end
@@ -102,7 +98,6 @@ function Player:onEdge()
end end
function Player:onWalking() function Player:onWalking()
-- if position of player collides with its own trail, stop motion
if #self.trail > 1 then if #self.trail > 1 then
table.remove(self.trail) table.remove(self.trail)
table.remove(self.trailSegments) table.remove(self.trailSegments)

View File

@@ -17,12 +17,12 @@ function Segment:init(firstPoint, secondPoint, lineWidth, face, color)
end end
function Segment:render() function Segment:render()
love.graphics.setColor(self.color.r, self.color.g, self.color.b, 255) love.graphics.setColor(self.color.r, self.color.g, self.color.b, 1)
love.graphics.setLineWidth(self.lineWidth) love.graphics.setLineWidth(self.lineWidth)
love.graphics.line(self.firstPointX, self.firstPointY, self.secondPointX, love.graphics.line(self.firstPointX, self.firstPointY, self.secondPointX,
self.secondPointY) self.secondPointY)
love.graphics.setColor(255, 255, 255, 255) love.graphics.setColor(1, 1, 1, 1)
-- debug -- debug
-- love.graphics.setFont(gFonts['small']) -- love.graphics.setFont(gFonts['small'])
@@ -171,14 +171,14 @@ end
function Segment:joinPerpendicular(s) function Segment:joinPerpendicular(s)
-- changes the self, not the parameter -- changes the self, not the parameter
if s.vertical then if s.vertical and self.horizontal then
local sx = s.firstPointX local sx = s.firstPointX
if math.abs(self.firstPointX - sx) < math.abs(self.secondPointX - sx) then if math.abs(self.firstPointX - sx) < math.abs(self.secondPointX - sx) then
self.firstPointX = sx self.firstPointX = sx
else else
self.secondPointX = sx self.secondPointX = sx
end end
else elseif s.horizontal and self.vertical then
local sy = s.firstPointY local sy = s.firstPointY
if math.abs(self.firstPointY - sy) < math.abs(self.secondPointY - sy) then if math.abs(self.firstPointY - sy) < math.abs(self.secondPointY - sy) then
self.firstPointY = sy self.firstPointY = sy

View File

@@ -74,7 +74,8 @@ end
-- convert a list of points forming a polygon {x1, y1, x2, y2, ...} into a mesh -- convert a list of points forming a polygon {x1, y1, x2, y2, ...} into a mesh
function poly2mesh(points) function poly2mesh(points)
-- remove duplicates??? -- print("util - poly2mesh: ")
-- print_r(points)
if #points > 2 then if #points > 2 then
local polypts = love.math.triangulate(points) local polypts = love.math.triangulate(points)
local tlist local tlist
@@ -119,3 +120,155 @@ function poly2mesh(points)
return nil return nil
end end
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

View File

@@ -9,4 +9,6 @@ WINDOW_HEIGHT = 720
LEVEL_RENDER_OFFSET_TOP = 30 LEVEL_RENDER_OFFSET_TOP = 30
LEVEL_RENDER_OFFSET = 10 LEVEL_RENDER_OFFSET = 10
TILE_SIZE = 16 TILE_SIZE = 16
LINE_WIDTH = .5

View File

@@ -44,4 +44,238 @@ ENTITY_DEFS = {
} }
} }
} }
}
LEVELS_DEF = {
[1] = {
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 = 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,
},
} }

View File

@@ -10,8 +10,8 @@ end
function EntityWalkEdgeState:update(dt) function EntityWalkEdgeState:update(dt)
local dy = self.entity.walkingSpeed * dt local dy = math.floor(self.entity.walkingSpeed * dt + 0.5)
local dx = self.entity.walkingSpeed * dt local dx = math.floor(self.entity.walkingSpeed * dt + 0.5)
if self.entity.direction == 'left' then 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 if self.entity.level:pointOnEdge(self.entity.x - dx + TILE_SIZE / 2, self.entity.y + TILE_SIZE / 2) then

View File

@@ -1,20 +1,19 @@
-- require('mobdebug').start() -- require('mobdebug').start()
PlayState = Class{__includes = BaseState} PlayState = Class {__includes = BaseState}
function PlayState:init() function PlayState:init()
self.name = 'PlayState' self.name = "PlayState"
self.stage = 1 self.stage = 1
self.level = Level(self.stage) self.level = Level(LEVELS_DEF[1], self.stage)
self.player = Player ( ENTITY_DEFS['player'] , self.level) self.player = Player(ENTITY_DEFS["player"], self.level)
self.level.player = self.player self.level.player = self.player
self.balls = {} self.balls = self.level.balls
self:createBalls() self.clock = self.level.clock
self.level.balls = self.balls
gSounds['music']:setLooping(true)
gSounds['music']:play()
gSounds["music"]:setPitch(1)
gSounds["music"]:setLooping(true)
gSounds["music"]:play()
end end
function PlayState:enter() function PlayState:enter()
@@ -23,106 +22,106 @@ end
function PlayState:update(dt) function PlayState:update(dt)
self.level:update(dt) self.level:update(dt)
self.player:update(dt) self.player:update(dt)
self:updateBalls(dt, self.level)
self:checkEndLevel(self.level) self:checkEndLevel(self.level)
end end
function PlayState:render() function PlayState:render()
love.graphics.clear(0, 0, 0, 255/255) love.graphics.clear(0, 0, 0, 255 / 255)
love.graphics.setColor(40/255, 45/255, 52/255,255/255) love.graphics.setColor(56 / 255, 56 / 255, 56 / 255, 1)
love.graphics.setFont(gFonts['small']) love.graphics.setFont(gFonts["small"])
love.graphics.printf('Score '..tostring(self.player.score), love.graphics.printf("Score " .. tostring(self.player.score), LEVEL_RENDER_OFFSET, LEVEL_RENDER_OFFSET_TOP/2, VIRTUAL_WIDTH, "left")
0, 5, VIRTUAL_WIDTH, 'left')
love.graphics.setFont(gFonts['medium']) love.graphics.setFont(gFonts["medium"])
love.graphics.printf('Stage '..tostring(self.stage), love.graphics.printf("Stage " .. tostring(self.stage), 0, 5, VIRTUAL_WIDTH, "center")
0, 5, VIRTUAL_WIDTH, 'center')
self.level:render() self.level:render()
self.player:render() self.player:render()
self:renderBalls(dt)
end end
function PlayState:createBalls() function PlayState:checkEndLevel(level)
self.balls = {} if #self.balls <= 0 then
-- game over - reset level
for i = 1, self.stage do print("game over due to 0 balls")
table.insert(self.balls,Ball( self:gameOver()
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
end
function PlayState:updateBalls(dt, level) -- check perimeter of level, if low enough, create new level move on to the next stage
for k,ball in pairs(self.balls) do if level:getPerimeter() < 500 then
ball:update(dt,level) print("next stage due to perimeter goal reached")
self:nextStage()
end end
-- check if clock finished counting limit time
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
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
-- remove balls outside bounds -- remove balls outside bounds
for k,ball in pairs(self.balls) do for k, ball in pairs(self.balls) do
if ball.remove then if ball.remove then
table.remove(self.balls,k) table.remove(self.balls, k)
self.player.score = self.player.score - 1 self.player.score = self.player.score - 1
elseif ball.hitPlayer then elseif ball.hitPlayer then
-- check if any ball hit the player trail segments -- check if any ball hit the player trail segments
print("game over due to player hit by ball")
self:gameOver() self:gameOver()
end end
end
if #self.balls <= 0 then
-- game over - reset level
self:gameOver()
end
-- check perimeter of level, if low enough, create new level move on to the next stage
if level:getPerimeter() < 500 then
self:nextStage()
end
end
function PlayState:checkEndLevel (level)
if #self.balls <= 0 then
-- game over - reset level
self:gameOver()
end
-- check perimeter of level, if low enough, create new level move on to the next stage
if level:getPerimeter() < 500 then
self:nextStage()
end
end
function PlayState:renderBalls(dt)
for k,ball in pairs(self.balls) do
ball:render()
end end
end end
function PlayState:gameOver() function PlayState:gameOver()
gStateStack:pop() gStateStack:pop()
gSounds['music']:stop() gSounds["music"]:stop()
gStateStack:push(GameOverState(self.player.score),function() end) gStateStack:push(
GameOverState(self.player.score),
function()
end
)
end end
function PlayState:nextStage() function PlayState:nextStage()
gStateStack:push(FadeOutState({ gStateStack:push(
r = 255/255, g = 255/255, b = 255/255}, 1,function() FadeOutState(
self.stage = self.stage + 1 {
self.level = Level(self.stage) r = 255 / 255,
self.player:reset() g = 255 / 255,
self.player.score = self.player.score + self.player.multiplier * #self.balls b = 255 / 255
self.player.multiplier = self.player.multiplier + #self.balls },
self.balls = {} 1,
self:createBalls() function()
self.level.player = self.player self.stage = self.stage + 1
self.player.level = self.level local nextDef = self.stage % (#LEVELS_DEF + 1)
self.level.balls = self.balls if nextDef == 0 then nextDef = 1 end
gSounds['music']:stop() self.level = Level(LEVELS_DEF[nextDef], self.stage)
gSounds['heal']:play() self.balls = self.level.balls
gStateStack:push(FadeOutState({r = 1/255, g = 1/255, b = 1/255}, 1,function() self.clock = self.level.clock
gSounds['music']:play() self.player:reset()
end)) self.player.score = self.player.score + self.player.multiplier * #self.balls
end)) self.player.multiplier = self.player.multiplier + #self.balls
end 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