13
26
stand = { frames = { 1 }, fps = 1 },
14
27
walk = { frames = { 2, 3 }, fps = 5 },
15
jump = { frames = { 4 }, fps = 1 }
28
jump = { frames = { 4 }, fps = 1 },
29
climbLeft = { frames = { 5, 6 }, fps = 5 },
30
climbRight = { frames = { 7, 8 }, fps = 5 }
17
35
onNew = function (self)
18
36
self.velocity.y = 0
19
37
self.maxVelocity.y = 400
33
51
assert(drag, 'active sprite has no drag property')
34
52
assert(minVel, 'active sprite has no minVelocity property')
35
53
assert(maxVel, 'active sprite has no maxVelocity property')
36
assert(_.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
54
assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
59
77
if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
60
78
if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
80
-- ugly hack for falling through floor on really slow frames
81
if math.abs(vel[dir] * elapsed) > 32 then
62
86
if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
88
if self[dir] < 0 then self[dir] = 0 end
89
local edge = the.view.map[util.dim(dir)] -
90
the.player[util.dim(dir)]
91
-- TODO: take map position into account
92
if self[dir] > edge then self[dir] = edge end
64
94
onStartFrame = function (self)
65
95
-- this is all in startframe so it happens before
78
107
self.acceleration.y = 800
80
109
if self.onWall then
81
110
self.acceleration.y = 0
112
if self.onWall == 'right' then
113
self:play('climbRight')
114
elseif self.onWall == 'left' then
115
self:play('climbLeft')
83
118
if the.keys:pressed('up') then
84
119
self.velocity.y = -200
86
120
elseif the.keys:pressed('down') then
87
121
self.velocity.y = 200
90
123
self.velocity.y = 0
124
self:freeze(self.sequences[self.currentName].frames[1])
95
128
if the.keys:pressed('left') then
96
129
self.velocity.x = -200
97
130
if self.onGround then self:play('walk') end
98
if self.onWall == 'right' then self.onWall = false end
99
if self.onWall == 'right' then self.onWall = false end
131
if self.onWall == 'right' then
133
self.leftWallAt = love.timer.getTime()
100
135
elseif the.keys:pressed('right') then
101
136
self.velocity.x = 200
102
137
if self.onGround then self:play('walk') end
103
if self.onWall == 'left' then self.onWall = false end
138
if self.onWall == 'left' then
140
self.leftWallAt = love.timer.getTime()
105
if self.onGround then self:play('stand') end
143
if not self.onWall then
144
if self.onGround then self:play('stand') end
108
if the.keys:justPressed('up') and self.onGround then
149
if the.keys:justPressed('up') and
150
(self.onGround or the.console.visible or
151
(love.timer.getTime() - self.leftWallAt < .1) ) then
109
152
self.velocity.y = -400
110
153
self.jumping = true
114
157
-- NOTE: this is an override, not a callback
116
159
self:doPhysics('x', elapsed)
160
self:collide(the.view.map)
162
-- handle X collisions
164
for _, col in ipairs(self.collisions) do
165
col.other:displaceDir(self, 'x')
166
if self.velocity.x > 0 then
167
self.onWall = 'right'
168
elseif self.velocity.x < 0 then
118
175
self.onGround = false -- right before Y collision callbacks
119
176
self:doPhysics('y', elapsed)
121
177
self:collide(the.view.map)
179
-- handle Y collisions
180
for _, col in ipairs(self.collisions) do
181
if self.velocity.y > 0 then
185
col.other:displaceDir(self, 'y')
123
190
Animation.update(self, elapsed)
192
collide = function (self, ...)
194
Animation.collide(self, ...)
195
-- I could return a true/false value here if I wanted to...
125
197
onCollide = function (self, other, xOverlap, yOverlap)
126
-- seriously, why does this even fire?
127
198
if other == the.view.map then return end
129
--print(string.format('col s{x=%i y=%i w=%i h=%i} %s', self.x, self.y, self.width, self.height, tostring(other)))
130
--print('vel.x:'..self.velocity.x.." vel.y:"..self.velocity.y)
132
-- assumption: any other collision is with a solid map tile
133
if yOverlap > xOverlap then
136
if self.velocity.x > 0 then
137
self.onWall = 'right'
138
elseif self.velocity.x < 0 then
143
elseif xOverlap > yOverlap then
144
-- check if we've moved since collisions were generated
145
local xov, yov = self:overlap(other.x, other.y,
146
other.width, other.height)
147
if xov ~= 0 and yov ~= 0 then
148
--print('y collision')
149
if self.velocity.y > 0 then
200
table.insert(self.collisions, {other = other,
202
yOverlap = yOverlap })
206
-- displace on a specific axis (monkey patch Sprite)
207
function Sprite:displaceDir(other, dir)
208
if not self.solid or self == other or not other.solid then return end
209
if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
211
if other.sprites then
214
for _, spr in pairs(other.sprites) do
215
self:displace(spr, dir)
219
local dim = util.dim(dir)
221
local negMove = (other[dir] - self[dir]) + other[dim]
222
local posMove = (self[dir] + self[dim]) - other[dir]
224
-- TODO: re-add hinting?
225
if negMove < posMove then
232
other[dir] = other[dir] + chg
235
-- don't use zoetrope physics
236
function Sprite:update (elapsed)
237
if self.onUpdate then self:onUpdate(elapsed) end
164
240
GameView = View:extend {
165
241
onNew = function (self)
166
242
self:loadLayers('data/map.lua')
168
244
self:clampTo(self.map)
170
246
onUpdate = function (self)
247
--print('drawTook: ', the.drawTook)
172
249
--the.player:collide(self.map)
173
250
--self.map:collide(the.player)
252
draw = function (self, x, y)
253
View.draw(self, x, y)
255
love.graphics.print('FPS:' .. love.timer.getFPS(), 20, 20)
177
259
the.app = App:new {
178
260
onRun = function (self)
179
261
self.view = GameView:new()
180
--print(inspect(_(the.app):keys()))
181
262
self.console:watch('onGround', 'the.player.onGround')
182
263
self.console:watch('onWall', 'the.player.onWall')
264
self.console:watch('updateTook', 'the.updateTook')
265
self.console:watch('drawTook', 'the.drawTook')
267
--the.profiler = newProfiler('time', 2000)
268
--the.profiler = newProfiler()
269
--the.profiler:start()
184
271
onUpdate = function (self, dt)
185
if the.keys:justPressed('escape') and
186
not self.console.visible then
272
if the.keys:justPressed('escape') then
275
local outfile = io.open( "profile.txt", "w+" )
276
the.profiler:report( outfile )
b'\\ No newline at end of file'
283
update = function (self, dt)
284
the.updateStart = love.timer.getMicroTime()
286
if the.updateStart then
287
the.updateTook = love.timer.getMicroTime() - the.updateStart