1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
STRICT = true
DEBUG = true
require 'zoetrope'
_ = require 'underscore'
--inspect = require 'inspect'
Player = Animation:extend {
image = 'data/player.png',
height = 32,
width = 32,
sequences = {
stand = { frames = { 1 }, fps = 1 },
walk = { frames = { 2, 3 }, fps = 5 },
jump = { frames = { 4 }, fps = 1 }
},
onNew = function (self)
self.velocity.y = 0
self.maxVelocity.y = 400
end,
doPhysics = function (self, dir, elapsed)
local vel = self.velocity
local acc = self.acceleration
local drag = self.drag
local minVel = self.minVelocity
local maxVel = self.maxVelocity
-- check existence of properties
if STRICT then
assert(vel, 'active sprite has no velocity property')
assert(acc, 'active sprite has no acceleration property')
assert(drag, 'active sprite has no drag property')
assert(minVel, 'active sprite has no minVelocity property')
assert(maxVel, 'active sprite has no maxVelocity property')
assert(_.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
end
vel.x = vel.x or 0
vel.y = vel.y or 0
vel.rotation = vel.rotation or 0
-- physics
if acc[dir] and acc[dir] ~= 0 then
vel[dir] = vel[dir] + acc[dir] * elapsed
else
if drag[dir] then
if vel[dir] > 0 then
vel[dir] = vel[dir] - drag[dir] * elapsed
if vel[dir] < 0 then vel[dir] = 0 end
elseif vel[dir] < 0 then
vel[dir] = vel[dir] + drag[dir] * elapsed
if vel[dir] > 0 then vel[dir] = 0 end
end
end
end
if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
end,
onStartFrame = function (self)
-- this is all in startframe so it happens before
-- physics calc at beginning of update
-- jumping/falling updates could go in EndFrame...
self.falling = self.velocity.y > 0
if self.falling then self.jumping = false end
--print(self.jumping, self.falling)
if not self.onGround then
self:play('jump')
end
self.velocity.x = 0
self.acceleration.y = 800
if the.keys:pressed('left') then
self.velocity.x = -200
if self.onGround then self:play('walk') end
elseif the.keys:pressed('right') then
self.velocity.x = 200
if self.onGround then self:play('walk') end
else
if self.onGround then self:play('stand') end
end
if the.keys:justPressed('up') and self.onGround then
self.velocity.y = -400
self.jumping = true
end
end,
update = function (self, elapsed)
-- NOTE: this is an override, not a callback
self:doPhysics('x', elapsed)
self.onGround = false -- right before Y collision callbacks
self:doPhysics('y', elapsed)
self:collide(the.view.map)
end,
onCollide = function (self, other, xOverlap, yOverlap)
-- seriously, why does this even fire?
if other == the.view.map then return end
--print(string.format('col s{x=%i y=%i w=%i h=%i} %s', self.x, self.y, self.width, self.height, tostring(other)))
--print('vel.x:'..self.velocity.x.." vel.y:"..self.velocity.y)
-- assumption: any other collision is with a solid map tile
if yOverlap > xOverlap then
other:displace(self)
if self.velocity.x > 0 then
self.onWall = 'right'
elseif self.velocity.x < 0 then
self.onWall = 'left'
else
print 'x ??'
end
elseif xOverlap > yOverlap then
-- check if we've moved since collisions were generated
local xov, yov = self:overlap(other.x, other.y,
other.width, other.height)
if xov ~= 0 and yov ~= 0 then
--print('y collision')
if self.velocity.y > 0 then
self.onGround = true
end
self.velocity.y = 0
other:displace(self)
self.jumping = false
end
else
print('xy ??')
end
end,
}
GameView = View:extend {
onNew = function (self)
self:loadLayers('data/map.lua')
self.focus = the.player
self:clampTo(self.map)
end,
onUpdate = function (self)
--print('tick')
--the.player:collide(self.map)
--self.map:collide(the.player)
end
}
the.app = App:new {
onRun = function (self)
self.view = GameView:new()
--print(inspect(_(the.app):keys()))
self.console:watch('onGround', 'the.player.onGround')
self.console:watch('onWall', 'the.player.onWall')
end,
onUpdate = function (self, dt)
if the.keys:justPressed('escape') and
not self.console.visible then
self.quit()
end
end
}
|