PageRenderTime 35ms CodeModel.GetById 22ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/src/serpent.lua

https://code.google.com/p/area-serpentis/
Lua | 240 lines | 209 code | 30 blank | 1 comment | 35 complexity | eb29d035a198c523cd0c32b806664b78 MD5 | raw file
  1Serpent = {}
  2Serpent_mt = { __index = Serpent }
  3function Serpent.create(args)
  4   local self = {}
  5   setmetatable(self, Serpent_mt)
  6
  7   self.x = args.x
  8   self.y = args.y
  9   self.dx = args.dx
 10   self.dy = args.dy
 11   self.speed = 200
 12   self.color = args.color
 13   self.text = args.text
 14   self.keys = args.keys
 15   self.ownedPoints = 0
 16   self.captureSound = args.captureSound
 17   self.slowedSound = args.slowedSound
 18   self:resetSegments()
 19
 20
 21   self.intCoords = { }
 22
 23   self.areaTable = { }
 24   self.lastAreaTable = { }
 25
 26   return self
 27end
 28
 29function Serpent:resetSegments()
 30   self.segments = { Segment.create(self) }
 31   self.length = 0
 32   self.lenLimit = 300
 33   self.lenLimitDelta = 0
 34end
 35
 36AREA_MAX_AGE = 60
 37
 38function Serpent:update(dt)
 39	local newSegment = false
 40    local distance = self.speed * dt
 41	self.segments[1]:elongate(distance)
 42	self.x = self.x + self.dx * distance
 43	self.y = self.y + self.dy * distance
 44
 45
 46   if love.keyboard.isDown(self.keys.up) and self.dy ~= 1 and self.dy ~= -1 then
 47      self.dx = 0
 48	  self.dy = -1
 49	  newSegment = true
 50   end
 51   if love.keyboard.isDown(self.keys.down) and self.dy ~= -1 and self.dy ~= 1 then
 52      self.dx = 0
 53	  self.dy = 1
 54	  newSegment = true
 55   end
 56   if love.keyboard.isDown(self.keys.left) and self.dx ~= 1 and self.dx ~= -1 then
 57      self.dx = -1
 58	  self.dy = 0
 59	  newSegment = true
 60   end
 61   if love.keyboard.isDown(self.keys.right) and self.dx ~= -1 and self.dx ~= 1 then
 62      self.dx = 1
 63	  self.dy = 0
 64	  newSegment = true
 65   end
 66
 67	if newSegment then
 68		table.insert(self.segments, 1, Segment.create(self))
 69                sounds.turn:stop()
 70                sounds.turn:setPitch(0.8 + math.random() * 0.4)
 71                sounds.turn:play()
 72	end
 73
 74    local endPos = table.maxn(self.segments)
 75
 76    self.length = self.length + distance
 77    self.lenLimit = self.lenLimit + self.lenLimitDelta
 78
 79    if self.length > self.lenLimit then
 80        distance = self.length - self.lenLimit
 81        self.length = self.lenLimit
 82        while distance > self.segments[endPos].length do
 83            distance = distance - self.segments[endPos].length
 84            table.remove(self.segments, endPos)
 85            endPos = endPos - 1
 86        end
 87        self.segments[endPos]:shorten(distance)
 88    end
 89
 90	self:areaIntersection()
 91
 92	if self:isOutOfBounds() then
 93		self:crashAndRespawn()
 94	elseif self:haveLoop() then
 95		self:splitSerpent()
 96                self:capturePoints()
 97		self:resetSegments()
 98	end
 99
100	for index, areaSegment in pairs(self.areaTable) do
101		areaSegment.time = areaSegment.time + dt
102		if areaSegment:getTimeRemaining() < 0 then
103			table.remove(self.areaTable, index)
104		end
105	end
106end
107
108function Serpent:areaIntersection()
109	local intCoords = {x, y, segment1, t, s }
110	local breakLoop = false
111	for index0, selfSegment in pairs(self.segments) do
112		for index1, otherSerpent in pairs(snakes) do
113			for index2, otherSegment in pairs(otherSerpent.areaTable) do
114				if otherSerpent ~= self then
115					intCoords = selfSegment:isIntersecting(otherSegment)
116					if intCoords.x ~= -1 and intCoords.y ~= -1 then
117						self.speed = 50
118                                                self.slowedSound:stop()
119						breakLoop = true
120						break
121					else
122						self.speed = 200
123                                                if self.slowedSound:isStopped() then
124                                                    self.slowedSound:play()
125                                                end
126					end
127				end
128			end
129			if breakLoop then
130				break
131			end
132		end
133		if breakLoop then
134			break
135		end
136	end
137end
138
139function Serpent:splitSerpent()
140	local vector1X
141	local vector1Y
142        self.lastAreaTable = {}
143	for index, segment in ipairs(self.segments) do
144		if index <= self.intCoords.segment1 then
145			if index == 1  then
146				segment.length =  self.intCoords.s
147			vector1X = segment.x + segment.dx * segment.length
148				vector1Y = segment.y + segment.dy * segment.length
149			elseif index == self.intCoords.segment1 then
150				segment:shorten(self.intCoords.t)
151			end
152			table.insert(self.areaTable, 1, segment)
153                        table.insert(self.lastAreaTable, segment)
154			table.remove(self.segments, index)
155			table.insert(self.segments, 1, Segment.create(self))
156		end
157	end
158end
159
160function Serpent:capturePoints()
161    local capturedPoints = 0
162    for index, point in ipairs(points) do
163        if point:isInsideSegmentLoop(self.lastAreaTable) then
164            point:setOwner(self)
165            capturedPoints = capturedPoints + 1
166        end
167    end
168    if capturedPoints > 0 then
169        self.captureSound:stop()
170        self.captureSound:play()
171    end
172    sounds.createLoop:stop()
173    sounds.createLoop:play()
174end
175
176function Serpent:haveLoop()
177	for index, segment in ipairs(self.segments) do
178		intCoords = self.segments[1]:isIntersecting(segment)
179		if index >= 4 and intCoords.x ~= -1 and intCoords.y ~= -1 then
180			intCoords.segment1 = index
181			self.intCoords = intCoords
182			return true
183		end
184	end
185	return false
186end
187
188function Serpent:isOutOfBounds()
189	return (self.x < 0 or self.x > WIDTH or self.y < 0 or self.y > HEIGHT)
190end
191
192Serpent.headSize = 3
193Serpent.bodyWidth = 2
194function Serpent:crashAndRespawn()
195	if self.x < 0 then self.x = 0 end
196	if self.x > WIDTH then self.x = WIDTH end
197	if self.y < 0 then self.y = 0 end
198	if self.y > HEIGHT then self.y = HEIGHT end
199	self.dx = -self.dx
200	self.dy = -self.dy
201
202	self:resetSegments()
203        sounds.crash:stop()
204        sounds.crash:play()
205end
206
207function Serpent:draw()
208	love.graphics.setColor(self.color[1], self.color[2], self.color[3], 255)
209	for index, segment in ipairs(self.segments) do
210            love.graphics.setLineWidth(self.bodyWidth)
211            love.graphics.line(segment.x, segment.y, segment:getEndX(), segment:getEndY())
212	end
213
214	for index, segment in ipairs(self.areaTable) do
215            love.graphics.setLineWidth(1)
216            local time = segment:getTimeRemaining()
217            if (time < 5 and math.fmod(time, 1) > 0.5) then
218                love.graphics.setColor(self.color[1], self.color[2], self.color[3], 128)
219            else
220                love.graphics.setColor(self.color[1], self.color[2], self.color[3], 255)
221            end
222            love.graphics.line(segment.x, segment.y, segment:getEndX(), segment:getEndY())
223	end
224
225	love.graphics.setColor(self.color[1], self.color[2], self.color[3], 255)
226        love.graphics.circle("fill", self.x, self.y, self.headSize)
227        love.graphics.setFont(fonts.serpentFont)
228	love.graphics.print(self.text, self.x + self.headSize, self.y + self.headSize)
229end
230
231function Serpent:changeOwnedPoints(delta)
232    self.ownedPoints = self.ownedPoints + delta
233    --Debug:log(self.text .. ": " .. self.ownedPoints .. " points")
234end
235
236WINNING_POINTS_FRACTION = 0.2
237
238function Serpent:isWinner()
239    return self.ownedPoints > table.maxn(points) * WINNING_POINTS_FRACTION
240end