13
13
stand = { frames = { 1 }, fps = 1 },
14
14
walk = { frames = { 2, 3 }, fps = 5 },
15
jump = { frames = { 4 }, fps = 1 },
16
climbLeft = { frames = { 5, 6 }, fps = 5 },
17
climbRight = { frames = { 7, 8 }, fps = 5 }
15
jump = { frames = { 4 }, fps = 1 }
21
17
onNew = function (self)
22
18
self.velocity.y = 0
23
19
self.maxVelocity.y = 400
25
doPhysics = function (self, dir, elapsed)
26
local vel = self.velocity
27
local acc = self.acceleration
28
local drag = self.drag
29
local minVel = self.minVelocity
30
local maxVel = self.maxVelocity
32
-- check existence of properties
35
assert(vel, 'active sprite has no velocity property')
36
assert(acc, 'active sprite has no acceleration property')
37
assert(drag, 'active sprite has no drag property')
38
assert(minVel, 'active sprite has no minVelocity property')
39
assert(maxVel, 'active sprite has no maxVelocity property')
40
assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
45
vel.rotation = vel.rotation or 0
49
if acc[dir] and acc[dir] ~= 0 then
50
vel[dir] = vel[dir] + acc[dir] * elapsed
54
vel[dir] = vel[dir] - drag[dir] * elapsed
55
if vel[dir] < 0 then vel[dir] = 0 end
56
elseif vel[dir] < 0 then
57
vel[dir] = vel[dir] + drag[dir] * elapsed
58
if vel[dir] > 0 then vel[dir] = 0 end
63
if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
64
if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
66
if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
68
21
onStartFrame = function (self)
69
22
-- this is all in startframe so it happens before
70
23
-- physics calc at beginning of update
74
27
if self.falling then self.jumping = false end
75
28
--print(self.jumping, self.falling)
77
if (not self.onGround) and (not self.onWall) then
30
if not self.onGround then
81
35
self.acceleration.y = 800
84
self.acceleration.y = 0
86
if self.onWall == 'right' then
87
self:play('climbRight')
88
elseif self.onWall == 'left' then
89
self:play('climbLeft')
92
if the.keys:pressed('up') then
93
self.velocity.y = -200
94
elseif the.keys:pressed('down') then
98
self:freeze(self.sequences[self.currentName].frames[1])
102
37
if the.keys:pressed('left') then
103
38
self.velocity.x = -200
104
39
if self.onGround then self:play('walk') end
105
if self.onWall == 'right' then self.onWall = false end
106
40
elseif the.keys:pressed('right') then
107
41
self.velocity.x = 200
108
42
if self.onGround then self:play('walk') end
109
if self.onWall == 'left' then self.onWall = false end
111
if not self.onWall then
112
if self.onGround then self:play('stand') end
44
if self.onGround then self:play('stand') end
117
47
if the.keys:justPressed('up') and self.onGround then
119
49
self.jumping = true
122
update = function (self, elapsed)
123
-- NOTE: this is an override, not a callback
125
self:doPhysics('x', elapsed)
126
self:collide(the.view.map)
128
-- handle X collisions
130
for _, col in ipairs(self.collisions) do
131
col.other:displaceDir(self, 'x')
132
if self.velocity.x > 0 then
133
self.onWall = 'right'
134
elseif self.velocity.x < 0 then
141
self.onGround = false -- right before Y collision callbacks
142
self:doPhysics('y', elapsed)
143
self:collide(the.view.map)
145
-- handle Y collisions
146
for _, col in ipairs(self.collisions) do
147
if self.velocity.y > 0 then
151
col.other:displaceDir(self, 'y')
156
Animation.update(self, elapsed)
158
collide = function (self, ...)
160
Animation.collide(self, ...)
161
-- I could return a true/false value here if I wanted to...
52
onUpdate = function (self)
53
-- needs to happen right before collision
163
56
onCollide = function (self, other, xOverlap, yOverlap)
57
-- seriously, why does this even fire?
164
58
if other == the.view.map then return end
166
table.insert(self.collisions, {other = other,
168
yOverlap = yOverlap })
60
--print(string.format('col s{x=%i y=%i w=%i h=%i} %s', self.x, self.y, self.width, self.height, tostring(other)))
61
--print('vel.x:'..self.velocity.x.." vel.y:"..self.velocity.y)
63
-- assumption: any other collision is with a solid map tile
64
if yOverlap > xOverlap then
66
elseif xOverlap > yOverlap then
67
-- check if we've moved since collisions were generated
68
local xov, yov = self:overlap(other.x, other.y,
69
other.width, other.height)
70
if xov ~= 0 and yov ~= 0 then
71
--print('y collision')
72
if self.velocity.y > 0 then
172
function Sprite:displaceDir(other, dir)
173
if not self.solid or self == other or not other.solid then return end
174
if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
176
if other.sprites then
179
for _, spr in pairs(other.sprites) do
180
self:displace(spr, dir)
187
elseif dir == 'y' then
193
local negMove = (other[dir] - self[dir]) + other[dim]
194
local posMove = (self[dir] + self[dim]) - other[dir]
196
-- TODO: re-add hinting?
197
if negMove < posMove then
204
other[dir] = other[dir] + chg
207
87
GameView = View:extend {
208
88
onNew = function (self)
209
89
self:loadLayers('data/map.lua')
221
100
the.app = App:new {
222
101
onRun = function (self)
223
102
self.view = GameView:new()
103
--print(inspect(_(the.app):keys()))
224
104
self.console:watch('onGround', 'the.player.onGround')
225
self.console:watch('onWall', 'the.player.onWall')
227
106
onUpdate = function (self, dt)
228
107
if the.keys:justPressed('escape') and
229
108
not self.console.visible then
b'\\ No newline at end of file'