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 }
19
onNew = function (self)
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
66
onStartFrame = function (self)
67
-- this is all in startframe so it happens before
68
-- physics calc at beginning of update
70
-- jumping/falling updates could go in EndFrame...
71
self.falling = self.velocity.y > 0
72
if self.falling then self.jumping = false end
73
--print(self.jumping, self.falling)
75
if (not self.onGround) and (not self.onWall) then
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
97
if the.keys:pressed('left') then
98
self.velocity.x = -200
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
102
elseif the.keys:pressed('right') then
103
self.velocity.x = 200
104
if self.onGround then self:play('walk') end
105
if self.onWall == 'left' then self.onWall = false end
107
if self.onGround then self:play('stand') end
110
if the.keys:justPressed('up') and self.onGround then
111
self.velocity.y = -400
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...
155
onCollide = function (self, other, xOverlap, yOverlap)
156
if other == the.view.map then return end
158
table.insert(self.collisions, {other = other,
160
yOverlap = yOverlap })
164
function Sprite:displaceDir(other, dir)
165
if not self.solid or self == other or not other.solid then return end
166
if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
168
if other.sprites then
171
for _, spr in pairs(other.sprites) do
172
self:displace(spr, dir)
177
18
if dir == 'x' then
179
20
elseif dir == 'y' then
185
local negMove = (other[dir] - self[dir]) + other[dim]
186
local posMove = (self[dir] + self[dim]) - other[dir]
188
-- TODO: re-add hinting?
189
if negMove < posMove then
23
if STRICT then error('dir '..dir) end
196
other[dir] = other[dir] + chg
199
28
GameView = View:extend {
200
29
onNew = function (self)
201
30
self:loadLayers('data/map.lua')
202
31
self.focus = the.player
203
32
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()
205
46
onUpdate = function (self)
47
--print('drawTook: ', the.drawTook)
207
49
--the.player:collide(self.map)
208
50
--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()
212
73
the.app = App:new {
213
75
onRun = function (self)
214
self.view = GameView:new()
215
self.console:watch('onGround', 'the.player.onGround')
216
self.console:watch('onWall', 'the.player.onWall')
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()
218
90
onUpdate = function (self, dt)
219
if the.keys:justPressed('escape') and
220
not self.console.visible then
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))
b'\\ No newline at end of file'
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'