5
5
__ = require 'underscore'
6
6
--inspect = require 'inspect'
8
Player = Animation:extend {
9
image = 'data/player.png',
13
stand = { frames = { 1 }, fps = 1 },
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 }
21
onNew = function (self)
23
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
onStartFrame = function (self)
69
-- this is all in startframe so it happens before
70
-- physics calc at beginning of update
72
-- jumping/falling updates could go in EndFrame...
73
self.falling = self.velocity.y > 0
74
if self.falling then self.jumping = false end
75
--print(self.jumping, self.falling)
77
if (not self.onGround) and (not self.onWall) then
81
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
if the.keys:pressed('left') then
103
self.velocity.x = -200
104
if self.onGround then self:play('walk') end
105
if self.onWall == 'right' then self.onWall = false end
106
elseif the.keys:pressed('right') then
107
self.velocity.x = 200
108
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
117
if the.keys:justPressed('up') and self.onGround then
118
self.velocity.y = -400
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...
163
onCollide = function (self, other, xOverlap, yOverlap)
164
if other == the.view.map then return end
166
table.insert(self.collisions, {other = other,
168
yOverlap = yOverlap })
172
-- displace on a specific axis (monkey patch Sprite)
173
function Sprite:displaceDir(other, dir)
174
if not self.solid or self == other or not other.solid then return end
175
if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
177
if other.sprites then
180
for _, spr in pairs(other.sprites) do
181
self:displace(spr, dir)
18
186
if dir == 'x' then
20
188
elseif dir == 'y' then
23
if STRICT then error('dir '..dir) end
194
local negMove = (other[dir] - self[dir]) + other[dim]
195
local posMove = (self[dir] + self[dim]) - other[dir]
197
-- TODO: re-add hinting?
198
if negMove < posMove then
205
other[dir] = other[dir] + chg
28
208
GameView = View:extend {
29
209
onNew = function (self)
30
210
self:loadLayers('data/map.lua')
31
211
self.focus = the.player
32
212
self:clampTo(self.map)
34
the.recorder = Recorder:new{mousePosInterval = 9999}
35
the.app.meta:add(the.recorder)
36
if the.app.record then
37
the.recorder:startRecording()
38
elseif the.app.playback then
39
local storage = Storage:new{filename = 'record.lua'}
41
--print(inspect(storage.data))
42
the.recorder.record = storage.data
43
the.recorder:startPlaying()
46
214
onUpdate = function (self)
47
--print('drawTook: ', the.drawTook)
49
216
--the.player:collide(self.map)
50
217
--self.map:collide(the.player)
52
-- draw = function (self, x, y)
53
-- View.draw(self, x, y)
55
-- love.graphics.print('FPS:' .. love.timer.getFPS(), 20, 20)
59
MenuScreen = View:extend {
60
--title = Text:new{text = "Test Platform Game", font = 48, wordWrap = false},
61
title = Tile:new{image = 'data/title.png', x = 0, y = 0},
62
onNew = function(self)
64
--self.title:centerAround(400, 200)
66
onUpdate = function(self, elapsed)
67
if the.keys:allJustPressed() then
68
the.app.view = GameView:new()
73
221
the.app = App:new {
75
222
onRun = function (self)
76
self.view = MenuScreen:new()
78
self.console:watch('VERSION', 'VERSION')
79
self.console:watch('onGround', 'the.player.onGround')
80
self.console:watch('onWall', 'the.player.onWall')
81
self.console:watch('updateTook', 'the.updateTook')
82
self.console:watch('drawTook', 'the.drawTook')
83
self.console:watch('recorder state', 'the.recorder.state')
86
--the.profiler = newProfiler('time', 2000)
87
--the.profiler = newProfiler()
88
--the.profiler:start()
223
self.view = GameView:new()
224
self.console:watch('onGround', 'the.player.onGround')
225
self.console:watch('onWall', 'the.player.onWall')
90
227
onUpdate = function (self, dt)
91
if the.keys:justPressed('escape') then
94
local outfile = io.open( "profile.txt", "w+" )
95
the.profiler:report( outfile )
99
if self.record and the.recorder then
100
if not love.filesystem.remove('record.lua') then
101
print('could not remove record.lua')
103
local storage = Storage:new{
104
data = the.recorder.record,
105
filename = 'record.lua'
108
--print(inspect(the.recorder.record))
228
if the.keys:justPressed('escape') and
229
not self.console.visible then
114
update = function (self, dt)
115
the.updateStart = love.timer.getMicroTime()
117
if the.updateStart then
118
the.updateTook = love.timer.getMicroTime() - the.updateStart
123
function love.load (arg)
124
opts = getopt(arg, '')
126
the.app.playback = true
127
the.app.record = false
128
elseif opts['r'] then
129
the.app.record = true
b'\\ No newline at end of file'
b'\\ No newline at end of file'