/zoeplat

To get this branch, use:
bzr branch http://9ix.org/bzr/zoeplat

« back to all changes in this revision

Viewing changes to main.lua

  • Committer: Josh C
  • Date: 2013-04-10 01:23:00 UTC
  • Revision ID: josh@9ix.org-20130410012300-wdgpz4k37ws1waj7
conf file for saving recording

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
DEBUG = true
3
3
 
4
4
require 'zoetrope'
5
 
 
6
 
Player = Tile:extend {
 
5
__ = require 'underscore'
 
6
--inspect = require 'inspect'
 
7
require 'pepperprof'
 
8
require 'getopt_alt'
 
9
 
 
10
util = {
 
11
   dim = function(dir)
 
12
      if dir == 'x' then
 
13
         return 'width'
 
14
      elseif dir == 'y' then
 
15
         return 'height'
 
16
      else
 
17
         if STRICT then error('dir '..dir) end
 
18
      end
 
19
   end
 
20
}
 
21
 
 
22
Player = Animation:extend {
7
23
   image = 'data/player.png',
 
24
   height = 32,
 
25
   width = 32,
 
26
   sequences = {
 
27
      stand = { frames = { 1 }, fps = 1 },
 
28
      walk = { frames = { 2, 3 }, fps = 5 },
 
29
      jump = { frames = { 4 }, fps = 1 },
 
30
      climbLeft = { frames = { 5, 6 }, fps = 5 },
 
31
      climbRight = { frames = { 7, 8 }, fps = 5 }
 
32
   },
 
33
   collisions = {},
 
34
   onWall = false,
 
35
   leftWallAt = 0,
8
36
   onNew = function (self)
9
37
              self.velocity.y = 0
10
38
              self.maxVelocity.y = 400
11
39
           end,
 
40
   doPhysics = function (self, dir, elapsed)
 
41
                  local vel = self.velocity
 
42
                  local acc = self.acceleration
 
43
                  local drag = self.drag
 
44
                  local minVel = self.minVelocity
 
45
                  local maxVel = self.maxVelocity
 
46
 
 
47
                  -- check existence of properties
 
48
 
 
49
                  if STRICT then
 
50
                     assert(vel, 'active sprite has no velocity property')
 
51
                     assert(acc, 'active sprite has no acceleration property')
 
52
                     assert(drag, 'active sprite has no drag property')
 
53
                     assert(minVel, 'active sprite has no minVelocity property')
 
54
                     assert(maxVel, 'active sprite has no maxVelocity property')
 
55
                     assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
 
56
                  end
 
57
 
 
58
                  vel.x = vel.x or 0
 
59
                  vel.y = vel.y or 0
 
60
                  vel.rotation = vel.rotation or 0
 
61
 
 
62
                  -- physics
 
63
 
 
64
                  if acc[dir] and acc[dir] ~= 0 then
 
65
                     vel[dir] = vel[dir] + acc[dir] * elapsed
 
66
                  else
 
67
                     if drag[dir] then
 
68
                        if vel[dir] > 0 then
 
69
                           vel[dir] = vel[dir] - drag[dir] * elapsed
 
70
                           if vel[dir] < 0 then vel[dir] = 0 end
 
71
                        elseif vel[dir] < 0 then
 
72
                           vel[dir] = vel[dir] + drag[dir] * elapsed
 
73
                           if vel[dir] > 0 then vel[dir] = 0 end
 
74
                        end
 
75
                     end
 
76
                  end
 
77
 
 
78
                  if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
 
79
                  if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
 
80
 
 
81
                  -- ugly hack for falling through floor on really slow frames
 
82
                  if math.abs(vel[dir] * elapsed) > 32 then
 
83
                     print('skip')
 
84
                     return
 
85
                  end
 
86
 
 
87
                  if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
 
88
 
 
89
                  if self[dir] < 0 then self[dir] = 0 end
 
90
                  local edge = the.view.map[util.dim(dir)] -
 
91
                               the.player[util.dim(dir)]
 
92
                  -- TODO: take map position into account
 
93
                  if self[dir] > edge then self[dir] = edge end
 
94
               end,
12
95
   onStartFrame = function (self)
13
96
                     -- this is all in startframe so it happens before
14
97
                     -- physics calc at beginning of update
15
98
 
16
 
                     self.velocity.x = 0
 
99
                     -- jumping/falling updates could go in EndFrame...
 
100
                     self.falling = self.velocity.y > 0
 
101
                     if self.falling then self.jumping = false end
 
102
                     --print(self.jumping, self.falling)
 
103
 
 
104
                     if (not self.onGround) and (not self.onWall) then
 
105
                        self:play('jump')
 
106
                     end
 
107
 
17
108
                     self.acceleration.y = 800
18
109
 
 
110
                     if self.onWall then
 
111
                        self.acceleration.y = 0
 
112
 
 
113
                        if self.onWall == 'right' then
 
114
                           self:play('climbRight')
 
115
                        elseif self.onWall == 'left' then
 
116
                           self:play('climbLeft')
 
117
                        end
 
118
 
 
119
                        if the.keys:pressed('up') then
 
120
                           self.velocity.y = -200
 
121
                        elseif the.keys:pressed('down') then
 
122
                           self.velocity.y = 200
 
123
                        else
 
124
                           self.velocity.y = 0
 
125
                           self:freeze(self.sequences[self.currentName].frames[1])
 
126
                        end
 
127
                     end
 
128
 
19
129
                     if the.keys:pressed('left') then
20
130
                        self.velocity.x = -200
 
131
                        if self.onGround then self:play('walk') end
 
132
                        if self.onWall == 'right' then
 
133
                           self.onWall = false
 
134
                           self.leftWallAt = love.timer.getTime()
 
135
                        end
21
136
                     elseif the.keys:pressed('right') then
22
137
                        self.velocity.x = 200
 
138
                        if self.onGround then self:play('walk') end
 
139
                        if self.onWall == 'left' then
 
140
                           self.onWall = false
 
141
                           self.leftWallAt = love.timer.getTime()
 
142
                        end
 
143
                     else
 
144
                        if not self.onWall then
 
145
                           if self.onGround then self:play('stand') end
 
146
                           self.velocity.x = 0
 
147
                        end
23
148
                     end
24
149
 
25
 
                     if the.keys:justPressed('up') then
 
150
                     if the.keys:justPressed('up') and
 
151
                      (self.onGround or the.console.visible or
 
152
                       (love.timer.getTime() - self.leftWallAt < .1) ) then
26
153
                        self.velocity.y = -400
 
154
                        self.jumping = true
27
155
                     end
28
156
                  end,
 
157
   update = function (self, elapsed)
 
158
               -- NOTE: this is an override, not a callback
 
159
 
 
160
               self:doPhysics('x', elapsed)
 
161
               self:collide(the.view.map)
 
162
 
 
163
               -- handle X collisions
 
164
               self.onWall = false
 
165
               for _, col in ipairs(self.collisions) do
 
166
                  col.other:displaceDir(self, 'x')
 
167
                  if self.velocity.x > 0 then
 
168
                     self.onWall = 'right'
 
169
                  elseif self.velocity.x < 0 then
 
170
                     self.onWall = 'left'
 
171
                  else
 
172
                     print 'x ??'
 
173
                  end
 
174
               end
 
175
 
 
176
               self.onGround = false -- right before Y collision callbacks
 
177
               self:doPhysics('y', elapsed)
 
178
               self:collide(the.view.map)
 
179
 
 
180
               -- handle Y collisions
 
181
               for _, col in ipairs(self.collisions) do
 
182
                  if self.velocity.y > 0 then
 
183
                     self.onGround = true
 
184
                  end
 
185
 
 
186
                  col.other:displaceDir(self, 'y')
 
187
                  self.velocity.y = 0
 
188
                  self.jumping = false
 
189
               end
 
190
 
 
191
               -- text blob
 
192
               if not self.text then
 
193
                  self.text = Text:new{wordWrap = true, width = 50, tint = {0,0,0}}
 
194
                  self.textfill = Fill:new{width = 54, border = {0,0,255}}
 
195
                  --the.view:add(self.textfill)
 
196
                  --the.view:add(self.text)
 
197
               end
 
198
               self.text.text = "Blah blah big text etc etc wrapping"
 
199
               self.text:centerAround(self.x+16, self.y+16, 'horizontal')
 
200
               _, texth = self.text:getSize()
 
201
               self.text.y = self.y - texth - 4
 
202
               self.textfill.x = self.text.x - 2
 
203
               self.textfill.y = self.text.y - 2
 
204
               self.textfill.height = texth + 4
 
205
 
 
206
               Animation.update(self, elapsed)
 
207
            end,
 
208
   collide = function (self, ...)
 
209
                self.collisions = {}
 
210
                Animation.collide(self, ...)
 
211
                -- I could return a true/false value here if I wanted to...
 
212
             end,
29
213
   onCollide = function (self, other, xOverlap, yOverlap)
30
 
                  -- seriously, why does this even fire?
31
214
                  if other == the.view.map then return end
32
215
 
33
 
                  --print(string.format('col s{x=%i y=%i w=%i h=%i} %s', self.x, self.y, self.width, self.height, tostring(other)))
34
 
                  --print('vel.x:'..self.velocity.x.." vel.y:"..self.velocity.y)
35
 
 
36
 
                  -- assumption: any other collision is with a solid map tile
37
 
                  if yOverlap > xOverlap then
38
 
                     other:displace(self)
39
 
                  elseif xOverlap > yOverlap then
40
 
                     -- check if we've moved since collisions were generated
41
 
                     local xov, yov = self:overlap(other.x, other.y,
42
 
                                                   other.width, other.height)
43
 
                     if xov ~= 0 and yov ~= 0 then
44
 
                        self.velocity.y = 0
45
 
                        other:displace(self)
46
 
                     end
47
 
                  else
48
 
                     print('??')
49
 
                  end
50
 
 
 
216
                  table.insert(self.collisions, {other = other,
 
217
                                                 xOverlap = xOverlap,
 
218
                                                 yOverlap = yOverlap })
51
219
               end
52
220
}
53
221
 
 
222
-- displace on a specific axis (monkey patch Sprite)
 
223
function Sprite:displaceDir(other, dir)
 
224
   if not self.solid or self == other or not other.solid then return end
 
225
   if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
 
226
 
 
227
   if other.sprites then
 
228
      -- handle groups
 
229
 
 
230
      for _, spr in pairs(other.sprites) do
 
231
         self:displace(spr, dir)
 
232
      end
 
233
   else
 
234
      -- handle sprites
 
235
      local dim = util.dim(dir)
 
236
 
 
237
      local negMove = (other[dir] - self[dir]) + other[dim]
 
238
      local posMove = (self[dir] + self[dim]) - other[dir]
 
239
 
 
240
      -- TODO: re-add hinting?
 
241
      if negMove < posMove then
 
242
         chg = - negMove
 
243
      else
 
244
         chg = posMove
 
245
      end
 
246
   end
 
247
 
 
248
   other[dir] = other[dir] + chg
 
249
end
 
250
 
 
251
-- don't use zoetrope physics
 
252
function Sprite:update (elapsed)
 
253
   if self.onUpdate then self:onUpdate(elapsed) end
 
254
end
 
255
 
54
256
GameView = View:extend {
55
257
   onNew = function (self)
56
258
              self:loadLayers('data/map.lua')
57
259
              self.focus = the.player
58
260
              self:clampTo(self.map)
 
261
 
 
262
              the.recorder = Recorder:new{mousePosInterval = 9999}
 
263
              the.app.meta:add(the.recorder)
 
264
              if the.app.record then
 
265
                 the.recorder:startRecording()
 
266
              elseif the.app.playback then
 
267
                 local storage = Storage:new{filename = 'record.lua'}
 
268
                 storage:load()
 
269
                 --print(inspect(storage.data))
 
270
                 the.recorder.record = storage.data
 
271
                 the.recorder:startPlaying()
 
272
              end
59
273
           end,
60
274
   onUpdate = function (self)
 
275
                 --print('drawTook: ', the.drawTook)
61
276
                 --print('tick')
62
 
                 the.player:collide(self.map)
 
277
                 --the.player:collide(self.map)
63
278
                 --self.map:collide(the.player)
64
 
              end
 
279
              end,
 
280
   -- draw = function (self, x, y)
 
281
   --           View.draw(self, x, y)
 
282
 
 
283
   --           love.graphics.print('FPS:' .. love.timer.getFPS(), 20, 20)
 
284
   --        end
65
285
}
66
286
 
67
287
the.app = App:new {
 
288
   record = true,
68
289
   onRun = function (self)
69
290
              self.view = GameView:new()
 
291
              self.console:watch('onGround', 'the.player.onGround')
 
292
              self.console:watch('onWall', 'the.player.onWall')
 
293
              self.console:watch('updateTook', 'the.updateTook')
 
294
              self.console:watch('drawTook', 'the.drawTook')
 
295
              self.console:watch('recorder state', 'the.recorder.state')
 
296
 
 
297
              --the.profiler = newProfiler('time', 2000)
 
298
              --the.profiler = newProfiler()
 
299
              --the.profiler:start()
70
300
           end,
71
301
   onUpdate = function (self, dt)
72
 
                 -- apparently I can do this w/ C-A-q if DEBUG is on
73
 
                 -- if the.keys:justPressed('escape') then
74
 
                 --    love.event.quit()
75
 
                 -- end
76
 
              end
77
 
}
 
 
b'\\ No newline at end of file'
 
302
                 if the.keys:justPressed('escape') then
 
303
                    if the.profiler then
 
304
                       the.profiler:stop()
 
305
                       local outfile = io.open( "profile.txt", "w+" )
 
306
                       the.profiler:report( outfile )
 
307
                       outfile:close()
 
308
                    end
 
309
 
 
310
                    if self.record then
 
311
                       if not love.filesystem.remove('record.lua') then
 
312
                          print('could not remove record.lua')
 
313
                       end
 
314
                       local storage = Storage:new{
 
315
                          data = the.recorder.record,
 
316
                          filename = 'record.lua'
 
317
                       }
 
318
                       storage:save(false)
 
319
                       --print(inspect(the.recorder.record))
 
320
                    end
 
321
 
 
322
                    self.quit()
 
323
                 end
 
324
              end,
 
325
   update = function (self, dt)
 
326
               the.updateStart = love.timer.getMicroTime()
 
327
               App.update(self, dt)
 
328
               if the.updateStart then
 
329
                  the.updateTook = love.timer.getMicroTime() - the.updateStart
 
330
               end
 
331
            end
 
332
}
 
333
 
 
334
function love.load (arg)
 
335
   opts = getopt(arg, '')
 
336
   if opts['p'] then
 
337
      the.app.playback = true
 
338
      the.app.record = false
 
339
   elseif opts['r'] then
 
340
      the.app.record = true
 
341
   end
 
342
 
 
343
   the.app:run()
 
344
end
 
 
b'\\ No newline at end of file'