/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-03-16 19:31:02 UTC
  • Revision ID: josh@9ix.org-20130316193102-68imraus0srbj653
don't go off the edge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
STRICT = true
2
 
DEBUG = false
 
2
DEBUG = true
3
3
 
4
4
require 'zoetrope'
5
5
__ = require 'underscore'
6
6
--inspect = require 'inspect'
7
7
require 'pepperprof'
8
 
require 'getopt_alt'
9
 
 
10
 
require 'sprite'
11
 
require 'player'
12
8
 
13
9
util = {
14
10
   dim = function(dir)
17
13
      elseif dir == 'y' then
18
14
         return 'height'
19
15
      else
20
 
         if STRICT then error('dir '..dir) end
21
 
      end
22
 
   end
23
 
}
 
16
         print 'dir ??'
 
17
      end
 
18
   end
 
19
}
 
20
 
 
21
Player = Animation:extend {
 
22
   image = 'data/player.png',
 
23
   height = 32,
 
24
   width = 32,
 
25
   sequences = {
 
26
      stand = { frames = { 1 }, fps = 1 },
 
27
      walk = { frames = { 2, 3 }, fps = 5 },
 
28
      jump = { frames = { 4 }, fps = 1 },
 
29
      climbLeft = { frames = { 5, 6 }, fps = 5 },
 
30
      climbRight = { frames = { 7, 8 }, fps = 5 }
 
31
   },
 
32
   collisions = {},
 
33
   onWall = false,
 
34
   leftWallAt = 0,
 
35
   onNew = function (self)
 
36
              self.velocity.y = 0
 
37
              self.maxVelocity.y = 400
 
38
           end,
 
39
   doPhysics = function (self, dir, elapsed)
 
40
                  local vel = self.velocity
 
41
                  local acc = self.acceleration
 
42
                  local drag = self.drag
 
43
                  local minVel = self.minVelocity
 
44
                  local maxVel = self.maxVelocity
 
45
 
 
46
                  -- check existence of properties
 
47
 
 
48
                  if STRICT then
 
49
                     assert(vel, 'active sprite has no velocity property')
 
50
                     assert(acc, 'active sprite has no acceleration property')
 
51
                     assert(drag, 'active sprite has no drag property')
 
52
                     assert(minVel, 'active sprite has no minVelocity property')
 
53
                     assert(maxVel, 'active sprite has no maxVelocity property')
 
54
                     assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
 
55
                  end
 
56
 
 
57
                  vel.x = vel.x or 0
 
58
                  vel.y = vel.y or 0
 
59
                  vel.rotation = vel.rotation or 0
 
60
 
 
61
                  -- physics
 
62
 
 
63
                  if acc[dir] and acc[dir] ~= 0 then
 
64
                     vel[dir] = vel[dir] + acc[dir] * elapsed
 
65
                  else
 
66
                     if drag[dir] then
 
67
                        if vel[dir] > 0 then
 
68
                           vel[dir] = vel[dir] - drag[dir] * elapsed
 
69
                           if vel[dir] < 0 then vel[dir] = 0 end
 
70
                        elseif vel[dir] < 0 then
 
71
                           vel[dir] = vel[dir] + drag[dir] * elapsed
 
72
                           if vel[dir] > 0 then vel[dir] = 0 end
 
73
                        end
 
74
                     end
 
75
                  end
 
76
 
 
77
                  if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
 
78
                  if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end
 
79
 
 
80
                  if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
 
81
 
 
82
                  if self[dir] < 0 then self[dir] = 0 end
 
83
                  local edge = the.view.map[util.dim(dir)] -
 
84
                               the.player[util.dim(dir)]
 
85
                  -- TODO: take map position into account
 
86
                  if self[dir] > edge then self[dir] = edge end
 
87
               end,
 
88
   onStartFrame = function (self)
 
89
                     -- this is all in startframe so it happens before
 
90
                     -- physics calc at beginning of update
 
91
 
 
92
                     -- jumping/falling updates could go in EndFrame...
 
93
                     self.falling = self.velocity.y > 0
 
94
                     if self.falling then self.jumping = false end
 
95
                     --print(self.jumping, self.falling)
 
96
 
 
97
                     if (not self.onGround) and (not self.onWall) then
 
98
                        self:play('jump')
 
99
                     end
 
100
 
 
101
                     self.acceleration.y = 800
 
102
 
 
103
                     if self.onWall then
 
104
                        self.acceleration.y = 0
 
105
 
 
106
                        if self.onWall == 'right' then
 
107
                           self:play('climbRight')
 
108
                        elseif self.onWall == 'left' then
 
109
                           self:play('climbLeft')
 
110
                        end
 
111
 
 
112
                        if the.keys:pressed('up') then
 
113
                           self.velocity.y = -200
 
114
                        elseif the.keys:pressed('down') then
 
115
                           self.velocity.y = 200
 
116
                        else
 
117
                           self.velocity.y = 0
 
118
                           self:freeze(self.sequences[self.currentName].frames[1])
 
119
                        end
 
120
                     end
 
121
 
 
122
                     if the.keys:pressed('left') then
 
123
                        self.velocity.x = -200
 
124
                        if self.onGround then self:play('walk') end
 
125
                        if self.onWall == 'right' then
 
126
                           self.onWall = false
 
127
                           self.leftWallAt = love.timer.getTime()
 
128
                        end
 
129
                     elseif the.keys:pressed('right') then
 
130
                        self.velocity.x = 200
 
131
                        if self.onGround then self:play('walk') end
 
132
                        if self.onWall == 'left' then
 
133
                           self.onWall = false
 
134
                           self.leftWallAt = love.timer.getTime()
 
135
                        end
 
136
                     else
 
137
                        if not self.onWall then
 
138
                           if self.onGround then self:play('stand') end
 
139
                           self.velocity.x = 0
 
140
                        end
 
141
                     end
 
142
 
 
143
                     if the.keys:justPressed('up') and
 
144
                      (self.onGround or the.console.visible or
 
145
                       (love.timer.getTime() - self.leftWallAt < .1) ) then
 
146
                        self.velocity.y = -400
 
147
                        self.jumping = true
 
148
                     end
 
149
                  end,
 
150
   update = function (self, elapsed)
 
151
               -- NOTE: this is an override, not a callback
 
152
 
 
153
               self:doPhysics('x', elapsed)
 
154
               self:collide(the.view.map)
 
155
 
 
156
               -- handle X collisions
 
157
               self.onWall = false
 
158
               for _, col in ipairs(self.collisions) do
 
159
                  col.other:displaceDir(self, 'x')
 
160
                  if self.velocity.x > 0 then
 
161
                     self.onWall = 'right'
 
162
                  elseif self.velocity.x < 0 then
 
163
                     self.onWall = 'left'
 
164
                  else
 
165
                     print 'x ??'
 
166
                  end
 
167
               end
 
168
 
 
169
               self.onGround = false -- right before Y collision callbacks
 
170
               self:doPhysics('y', elapsed)
 
171
               self:collide(the.view.map)
 
172
 
 
173
               -- handle Y collisions
 
174
               for _, col in ipairs(self.collisions) do
 
175
                  if self.velocity.y > 0 then
 
176
                     self.onGround = true
 
177
                  end
 
178
 
 
179
                  col.other:displaceDir(self, 'y')
 
180
                  self.velocity.y = 0
 
181
                  self.jumping = false
 
182
               end
 
183
 
 
184
               Animation.update(self, elapsed)
 
185
            end,
 
186
   collide = function (self, ...)
 
187
                self.collisions = {}
 
188
                Animation.collide(self, ...)
 
189
                -- I could return a true/false value here if I wanted to...
 
190
             end,
 
191
   onCollide = function (self, other, xOverlap, yOverlap)
 
192
                  if other == the.view.map then return end
 
193
 
 
194
                  table.insert(self.collisions, {other = other,
 
195
                                                 xOverlap = xOverlap,
 
196
                                                 yOverlap = yOverlap })
 
197
               end
 
198
}
 
199
 
 
200
-- displace on a specific axis (monkey patch Sprite)
 
201
function Sprite:displaceDir(other, dir)
 
202
   if not self.solid or self == other or not other.solid then return end
 
203
   if STRICT then assert(other:instanceOf(Sprite), 'asked to displace a non-sprite') end
 
204
 
 
205
   if other.sprites then
 
206
      -- handle groups
 
207
 
 
208
      for _, spr in pairs(other.sprites) do
 
209
         self:displace(spr, dir)
 
210
      end
 
211
   else
 
212
      -- handle sprites
 
213
      local dim = util.dim(dir)
 
214
 
 
215
      local negMove = (other[dir] - self[dir]) + other[dim]
 
216
      local posMove = (self[dir] + self[dim]) - other[dir]
 
217
 
 
218
      -- TODO: re-add hinting?
 
219
      if negMove < posMove then
 
220
         chg = - negMove
 
221
      else
 
222
         chg = posMove
 
223
      end
 
224
   end
 
225
 
 
226
   other[dir] = other[dir] + chg
 
227
end
24
228
 
25
229
GameView = View:extend {
26
230
   onNew = function (self)
27
231
              self:loadLayers('data/map.lua')
28
232
              self.focus = the.player
29
233
              self:clampTo(self.map)
30
 
 
31
 
              the.recorder = Recorder:new{mousePosInterval = 9999}
32
 
              the.app.meta:add(the.recorder)
33
 
              if the.app.record then
34
 
                 the.recorder:startRecording()
35
 
              elseif the.app.playback then
36
 
                 local storage = Storage:new{filename = 'record.lua'}
37
 
                 storage:load()
38
 
                 --print(inspect(storage.data))
39
 
                 the.recorder.record = storage.data
40
 
                 the.recorder:startPlaying()
41
 
              end
42
234
           end,
43
235
   onUpdate = function (self)
44
 
                 --print('drawTook: ', the.drawTook)
45
236
                 --print('tick')
46
237
                 --the.player:collide(self.map)
47
238
                 --self.map:collide(the.player)
48
 
              end,
49
 
   -- draw = function (self, x, y)
50
 
   --           View.draw(self, x, y)
51
 
 
52
 
   --           love.graphics.print('FPS:' .. love.timer.getFPS(), 20, 20)
53
 
   --        end
 
239
              end
54
240
}
55
241
 
56
242
the.app = App:new {
57
 
   record = true,
58
243
   onRun = function (self)
59
244
              self.view = GameView:new()
60
 
              if DEBUG then
61
 
                 self.console:watch('onGround', 'the.player.onGround')
62
 
                 self.console:watch('onWall', 'the.player.onWall')
63
 
                 self.console:watch('updateTook', 'the.updateTook')
64
 
                 self.console:watch('drawTook', 'the.drawTook')
65
 
                 self.console:watch('recorder state', 'the.recorder.state')
66
 
              end
 
245
              self.console:watch('onGround', 'the.player.onGround')
 
246
              self.console:watch('onWall', 'the.player.onWall')
 
247
              self.console:watch('updateTook', 'the.updateTook')
 
248
              self.console:watch('drawTook', 'the.drawTook')
67
249
 
68
250
              --the.profiler = newProfiler('time', 2000)
69
251
              --the.profiler = newProfiler()
78
260
                       outfile:close()
79
261
                    end
80
262
 
81
 
                    if self.record then
82
 
                       if not love.filesystem.remove('record.lua') then
83
 
                          print('could not remove record.lua')
84
 
                       end
85
 
                       local storage = Storage:new{
86
 
                          data = the.recorder.record,
87
 
                          filename = 'record.lua'
88
 
                       }
89
 
                       storage:save(false)
90
 
                       --print(inspect(the.recorder.record))
91
 
                    end
92
 
 
93
263
                    self.quit()
94
264
                 end
95
265
              end,
101
271
               end
102
272
            end
103
273
}
104
 
 
105
 
function love.load (arg)
106
 
   opts = getopt(arg, '')
107
 
   if opts['p'] then
108
 
      the.app.playback = true
109
 
      the.app.record = false
110
 
   elseif opts['r'] then
111
 
      the.app.record = true
112
 
   end
113
 
 
114
 
   the.app:run()
115
 
end
 
 
b'\\ No newline at end of file'