14
14
walk = { frames = { 2, 3 }, fps = 5 },
15
15
jump = { frames = { 4 }, fps = 1 }
17
19
onNew = function (self)
18
20
self.velocity.y = 0
19
21
self.maxVelocity.y = 400
23
doPhysics = function (self, dir, elapsed)
24
local vel = self.velocity
25
local acc = self.acceleration
26
local drag = self.drag
27
local minVel = self.minVelocity
28
local maxVel = self.maxVelocity
30
-- check existence of properties
33
assert(vel, 'active sprite has no velocity property')
34
assert(acc, 'active sprite has no acceleration property')
35
assert(drag, 'active sprite has no drag property')
36
assert(minVel, 'active sprite has no minVelocity property')
37
assert(maxVel, 'active sprite has no maxVelocity property')
38
assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
43
vel.rotation = vel.rotation or 0
47
if acc[dir] and acc[dir] ~= 0 then
48
vel[dir] = vel[dir] + acc[dir] * elapsed
52
vel[dir] = vel[dir] - drag[dir] * elapsed
53
if vel[dir] < 0 then vel[dir] = 0 end
54
elseif vel[dir] < 0 then
55
vel[dir] = vel[dir] + drag[dir] * elapsed
56
if vel[dir] > 0 then vel[dir] = 0 end
61
if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
62
if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
64
if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
21
66
onStartFrame = function (self)
22
67
-- this is all in startframe so it happens before
23
68
-- physics calc at beginning of update
27
72
if self.falling then self.jumping = false end
28
73
--print(self.jumping, self.falling)
75
if (not self.onGround) and (not self.onWall) then
30
79
self.velocity.x = 0
31
80
self.acceleration.y = 800
83
self.acceleration.y = 0
85
if the.keys:pressed('up') then
86
self.velocity.y = -200
88
elseif the.keys:pressed('down') then
33
97
if the.keys:pressed('left') then
34
98
self.velocity.x = -200
35
if self:onGround() then self:play('walk') end
99
if self.onGround then self:play('walk') end
100
if self.onWall == 'right' then self.onWall = false end
101
if self.onWall == 'right' then self.onWall = false end
36
102
elseif the.keys:pressed('right') then
37
103
self.velocity.x = 200
38
if self:onGround() then self:play('walk') end
104
if self.onGround then self:play('walk') end
105
if self.onWall == 'left' then self.onWall = false end
40
if self:onGround() then self:play('stand') end
107
if self.onGround then self:play('stand') end
43
if the.keys:justPressed('up') and self:onGround() then
110
if the.keys:justPressed('up') and self.onGround then
44
111
self.velocity.y = -400
45
112
self.jumping = true
49
onEndFrame = function (self)
50
--print(self.velocity.y)
115
update = function (self, elapsed)
116
-- NOTE: this is an override, not a callback
118
self:doPhysics('x', elapsed)
119
self:collide(the.view.map)
121
-- handle X collisions
122
for _, col in ipairs(self.collisions) do
123
col.other:displaceDir(self, 'x')
124
if self.velocity.x > 0 then
125
self.onWall = 'right'
126
elseif self.velocity.x < 0 then
133
self.onGround = false -- right before Y collision callbacks
134
self:doPhysics('y', elapsed)
135
self:collide(the.view.map)
137
-- handle Y collisions
138
for _, col in ipairs(self.collisions) do
139
if self.velocity.y > 0 then
143
col.other:displaceDir(self, 'y')
148
Animation.update(self, elapsed)
150
collide = function (self, ...)
152
Animation.collide(self, ...)
153
-- I could return a true/false value here if I wanted to...
52
155
onCollide = function (self, other, xOverlap, yOverlap)
53
-- seriously, why does this even fire?
54
156
if other == the.view.map then return end
56
--print(string.format('col s{x=%i y=%i w=%i h=%i} %s', self.x, self.y, self.width, self.height, tostring(other)))
57
--print('vel.x:'..self.velocity.x.." vel.y:"..self.velocity.y)
59
-- assumption: any other collision is with a solid map tile
60
if yOverlap > xOverlap then
62
elseif xOverlap > yOverlap then
63
-- check if we've moved since collisions were generated
64
local xov, yov = self:overlap(other.x, other.y,
65
other.width, other.height)
66
if xov ~= 0 and yov ~= 0 then
76
onGround = function (self)
77
return (not self.jumping) and (not self.falling)
158
table.insert(self.collisions, {other = other,
160
yOverlap = yOverlap })
164
-- displace on a specific axis (monkey patch Sprite)
165
function Sprite:displaceDir(other, dir)
166
if not self.solid or self == other or not other.solid then return end
167
if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
169
if other.sprites then
172
for _, spr in pairs(other.sprites) do
173
self:displace(spr, dir)
180
elseif dir == 'y' then
186
local negMove = (other[dir] - self[dir]) + other[dim]
187
local posMove = (self[dir] + self[dim]) - other[dir]
189
-- TODO: re-add hinting?
190
if negMove < posMove then
197
other[dir] = other[dir] + chg
81
200
GameView = View:extend {
82
201
onNew = function (self)
83
202
self:loadLayers('data/map.lua')