/src/serpent.lua
https://code.google.com/p/area-serpentis/ · Lua · 240 lines · 209 code · 30 blank · 1 comment · 65 complexity · eb29d035a198c523cd0c32b806664b78 MD5 · raw file
- Serpent = {}
- Serpent_mt = { __index = Serpent }
- function Serpent.create(args)
- local self = {}
- setmetatable(self, Serpent_mt)
- self.x = args.x
- self.y = args.y
- self.dx = args.dx
- self.dy = args.dy
- self.speed = 200
- self.color = args.color
- self.text = args.text
- self.keys = args.keys
- self.ownedPoints = 0
- self.captureSound = args.captureSound
- self.slowedSound = args.slowedSound
- self:resetSegments()
- self.intCoords = { }
- self.areaTable = { }
- self.lastAreaTable = { }
- return self
- end
- function Serpent:resetSegments()
- self.segments = { Segment.create(self) }
- self.length = 0
- self.lenLimit = 300
- self.lenLimitDelta = 0
- end
- AREA_MAX_AGE = 60
- function Serpent:update(dt)
- local newSegment = false
- local distance = self.speed * dt
- self.segments[1]:elongate(distance)
- self.x = self.x + self.dx * distance
- self.y = self.y + self.dy * distance
- if love.keyboard.isDown(self.keys.up) and self.dy ~= 1 and self.dy ~= -1 then
- self.dx = 0
- self.dy = -1
- newSegment = true
- end
- if love.keyboard.isDown(self.keys.down) and self.dy ~= -1 and self.dy ~= 1 then
- self.dx = 0
- self.dy = 1
- newSegment = true
- end
- if love.keyboard.isDown(self.keys.left) and self.dx ~= 1 and self.dx ~= -1 then
- self.dx = -1
- self.dy = 0
- newSegment = true
- end
- if love.keyboard.isDown(self.keys.right) and self.dx ~= -1 and self.dx ~= 1 then
- self.dx = 1
- self.dy = 0
- newSegment = true
- end
- if newSegment then
- table.insert(self.segments, 1, Segment.create(self))
- sounds.turn:stop()
- sounds.turn:setPitch(0.8 + math.random() * 0.4)
- sounds.turn:play()
- end
- local endPos = table.maxn(self.segments)
- self.length = self.length + distance
- self.lenLimit = self.lenLimit + self.lenLimitDelta
- if self.length > self.lenLimit then
- distance = self.length - self.lenLimit
- self.length = self.lenLimit
- while distance > self.segments[endPos].length do
- distance = distance - self.segments[endPos].length
- table.remove(self.segments, endPos)
- endPos = endPos - 1
- end
- self.segments[endPos]:shorten(distance)
- end
- self:areaIntersection()
- if self:isOutOfBounds() then
- self:crashAndRespawn()
- elseif self:haveLoop() then
- self:splitSerpent()
- self:capturePoints()
- self:resetSegments()
- end
- for index, areaSegment in pairs(self.areaTable) do
- areaSegment.time = areaSegment.time + dt
- if areaSegment:getTimeRemaining() < 0 then
- table.remove(self.areaTable, index)
- end
- end
- end
- function Serpent:areaIntersection()
- local intCoords = {x, y, segment1, t, s }
- local breakLoop = false
- for index0, selfSegment in pairs(self.segments) do
- for index1, otherSerpent in pairs(snakes) do
- for index2, otherSegment in pairs(otherSerpent.areaTable) do
- if otherSerpent ~= self then
- intCoords = selfSegment:isIntersecting(otherSegment)
- if intCoords.x ~= -1 and intCoords.y ~= -1 then
- self.speed = 50
- self.slowedSound:stop()
- breakLoop = true
- break
- else
- self.speed = 200
- if self.slowedSound:isStopped() then
- self.slowedSound:play()
- end
- end
- end
- end
- if breakLoop then
- break
- end
- end
- if breakLoop then
- break
- end
- end
- end
- function Serpent:splitSerpent()
- local vector1X
- local vector1Y
- self.lastAreaTable = {}
- for index, segment in ipairs(self.segments) do
- if index <= self.intCoords.segment1 then
- if index == 1 then
- segment.length = self.intCoords.s
- vector1X = segment.x + segment.dx * segment.length
- vector1Y = segment.y + segment.dy * segment.length
- elseif index == self.intCoords.segment1 then
- segment:shorten(self.intCoords.t)
- end
- table.insert(self.areaTable, 1, segment)
- table.insert(self.lastAreaTable, segment)
- table.remove(self.segments, index)
- table.insert(self.segments, 1, Segment.create(self))
- end
- end
- end
- function Serpent:capturePoints()
- local capturedPoints = 0
- for index, point in ipairs(points) do
- if point:isInsideSegmentLoop(self.lastAreaTable) then
- point:setOwner(self)
- capturedPoints = capturedPoints + 1
- end
- end
- if capturedPoints > 0 then
- self.captureSound:stop()
- self.captureSound:play()
- end
- sounds.createLoop:stop()
- sounds.createLoop:play()
- end
- function Serpent:haveLoop()
- for index, segment in ipairs(self.segments) do
- intCoords = self.segments[1]:isIntersecting(segment)
- if index >= 4 and intCoords.x ~= -1 and intCoords.y ~= -1 then
- intCoords.segment1 = index
- self.intCoords = intCoords
- return true
- end
- end
- return false
- end
- function Serpent:isOutOfBounds()
- return (self.x < 0 or self.x > WIDTH or self.y < 0 or self.y > HEIGHT)
- end
- Serpent.headSize = 3
- Serpent.bodyWidth = 2
- function Serpent:crashAndRespawn()
- if self.x < 0 then self.x = 0 end
- if self.x > WIDTH then self.x = WIDTH end
- if self.y < 0 then self.y = 0 end
- if self.y > HEIGHT then self.y = HEIGHT end
- self.dx = -self.dx
- self.dy = -self.dy
- self:resetSegments()
- sounds.crash:stop()
- sounds.crash:play()
- end
- function Serpent:draw()
- love.graphics.setColor(self.color[1], self.color[2], self.color[3], 255)
- for index, segment in ipairs(self.segments) do
- love.graphics.setLineWidth(self.bodyWidth)
- love.graphics.line(segment.x, segment.y, segment:getEndX(), segment:getEndY())
- end
- for index, segment in ipairs(self.areaTable) do
- love.graphics.setLineWidth(1)
- local time = segment:getTimeRemaining()
- if (time < 5 and math.fmod(time, 1) > 0.5) then
- love.graphics.setColor(self.color[1], self.color[2], self.color[3], 128)
- else
- love.graphics.setColor(self.color[1], self.color[2], self.color[3], 255)
- end
- love.graphics.line(segment.x, segment.y, segment:getEndX(), segment:getEndY())
- end
- love.graphics.setColor(self.color[1], self.color[2], self.color[3], 255)
- love.graphics.circle("fill", self.x, self.y, self.headSize)
- love.graphics.setFont(fonts.serpentFont)
- love.graphics.print(self.text, self.x + self.headSize, self.y + self.headSize)
- end
- function Serpent:changeOwnedPoints(delta)
- self.ownedPoints = self.ownedPoints + delta
- --Debug:log(self.text .. ": " .. self.ownedPoints .. " points")
- end
- WINNING_POINTS_FRACTION = 0.2
- function Serpent:isWinner()
- return self.ownedPoints > table.maxn(points) * WINNING_POINTS_FRACTION
- end