5
__ = require 'underscore'
6
--inspect = require 'inspect'
9
Player = Animation:extend {
10
9
image = 'data/player.png',
14
stand = { frames = { 1 }, fps = 1 },
15
walk = { frames = { 2, 3 }, fps = 5 },
16
jump = { frames = { 4 }, fps = 1 },
17
climbLeft = { frames = { 5, 6 }, fps = 5 },
18
climbRight = { frames = { 7, 8 }, fps = 5 }
23
10
onNew = function (self)
24
11
self.velocity.y = 0
25
self.maxVelocity.y = 400
27
doPhysics = function (self, dir, elapsed)
28
local vel = self.velocity
29
local acc = self.acceleration
30
local drag = self.drag
31
local minVel = self.minVelocity
32
local maxVel = self.maxVelocity
34
-- check existence of properties
37
assert(vel, 'active sprite has no velocity property')
38
assert(acc, 'active sprite has no acceleration property')
39
assert(drag, 'active sprite has no drag property')
40
assert(minVel, 'active sprite has no minVelocity property')
41
assert(maxVel, 'active sprite has no maxVelocity property')
42
assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
47
vel.rotation = vel.rotation or 0
51
if acc[dir] and acc[dir] ~= 0 then
52
vel[dir] = vel[dir] + acc[dir] * elapsed
56
vel[dir] = vel[dir] - drag[dir] * elapsed
57
if vel[dir] < 0 then vel[dir] = 0 end
58
elseif vel[dir] < 0 then
59
vel[dir] = vel[dir] + drag[dir] * elapsed
60
if vel[dir] > 0 then vel[dir] = 0 end
65
if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
66
if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
68
if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
70
13
onStartFrame = function (self)
71
14
-- this is all in startframe so it happens before
72
15
-- physics calc at beginning of update
74
-- jumping/falling updates could go in EndFrame...
75
self.falling = self.velocity.y > 0
76
if self.falling then self.jumping = false end
77
--print(self.jumping, self.falling)
79
if (not self.onGround) and (not self.onWall) then
83
self.acceleration.y = 800
86
self.acceleration.y = 0
88
if self.onWall == 'right' then
89
self:play('climbRight')
90
elseif self.onWall == 'left' then
91
self:play('climbLeft')
94
if the.keys:pressed('up') then
95
self.velocity.y = -200
96
elseif the.keys:pressed('down') then
100
self:freeze(self.sequences[self.currentName].frames[1])
104
if the.keys:pressed('left') then
105
self.velocity.x = -200
106
if self.onGround then self:play('walk') end
107
if self.onWall == 'right' then
109
self.leftWallAt = love.timer.getTime()
111
elseif the.keys:pressed('right') then
112
self.velocity.x = 200
113
if self.onGround then self:play('walk') end
114
if self.onWall == 'left' then
116
self.leftWallAt = love.timer.getTime()
119
if not self.onWall then
120
if self.onGround then self:play('stand') end
125
if the.keys:justPressed('up') and
126
(self.onGround or the.console.visible or
127
(love.timer.getTime() - self.leftWallAt < .1) ) then
128
self.velocity.y = -400
132
update = function (self, elapsed)
133
-- NOTE: this is an override, not a callback
135
self:doPhysics('x', elapsed)
136
self:collide(the.view.map)
138
-- handle X collisions
140
for _, col in ipairs(self.collisions) do
141
col.other:displaceDir(self, 'x')
142
if self.velocity.x > 0 then
143
self.onWall = 'right'
144
elseif self.velocity.x < 0 then
151
self.onGround = false -- right before Y collision callbacks
152
self:doPhysics('y', elapsed)
153
self:collide(the.view.map)
155
-- handle Y collisions
156
for _, col in ipairs(self.collisions) do
157
if self.velocity.y > 0 then
161
col.other:displaceDir(self, 'y')
166
Animation.update(self, elapsed)
168
collide = function (self, ...)
170
Animation.collide(self, ...)
171
-- I could return a true/false value here if I wanted to...
173
onCollide = function (self, other, xOverlap, yOverlap)
174
if other == the.view.map then return end
176
table.insert(self.collisions, {other = other,
178
yOverlap = yOverlap })
18
-- TODO: this can be replaced with sprite.maxVel.y
19
if self.velocity.y >= TERM_VEL then
20
self.velocity.y = TERM_VEL
21
self.acceleration.y = 0
23
self.acceleration.y = 800
26
if the.keys:pressed('left') then
27
self.velocity.x = -200
28
elseif the.keys:pressed('right') then
32
if the.keys:justPressed('up') then
33
self.velocity.y = -400
36
onUpdate = function (self)
37
-- this is called after physics, so this makes sense here
38
the.view.map:subdisplace(self)
182
function Sprite:displaceDir(other, dir)
183
if not self.solid or self == other or not other.solid then return end
184
if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
186
if other.sprites then
189
for _, spr in pairs(other.sprites) do
190
self:displace(spr, dir)
197
elseif dir == 'y' then
203
local negMove = (other[dir] - self[dir]) + other[dim]
204
local posMove = (self[dir] + self[dim]) - other[dir]
206
-- TODO: re-add hinting?
207
if negMove < posMove then
214
other[dir] = other[dir] + chg
217
42
GameView = View:extend {
218
43
onNew = function (self)
219
44
self:loadLayers('data/map.lua')
220
45
self.focus = the.player
221
46
self:clampTo(self.map)
223
onUpdate = function (self)
225
--the.player:collide(self.map)
226
--self.map:collide(the.player)
230
50
the.app = App:new {
231
51
onRun = function (self)
232
52
self.view = GameView:new()
233
self.console:watch('onGround', 'the.player.onGround')
234
self.console:watch('onWall', 'the.player.onWall')
235
self.console:watch('updateTook', 'the.updateTook')
236
self.console:watch('drawTook', 'the.drawTook')
238
--the.profiler = newProfiler('time', 2000)
239
--the.profiler = newProfiler()
240
--the.profiler:start()
242
54
onUpdate = function (self, dt)
243
55
if the.keys:justPressed('escape') then
246
local outfile = io.open( "profile.txt", "w+" )
247
the.profiler:report( outfile )
254
update = function (self, dt)
255
the.updateStart = love.timer.getMicroTime()
257
if the.updateStart then
258
the.updateTook = love.timer.getMicroTime() - the.updateStart
b'\\ No newline at end of file'