/zoeplat

To get this branch, use:
bzr branch http://9ix.org/bzr/zoeplat
2 by Josh C
basic tiles, map, player, movement
1
STRICT = true
2
DEBUG = true
3
4
require 'zoetrope'
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
5
__ = require 'underscore'
12 by Josh C
only jump when you're on the ground
6
--inspect = require 'inspect'
2 by Josh C
basic tiles, map, player, movement
7
10 by Josh C
make player an animation
8
Player = Animation:extend {
2 by Josh C
basic tiles, map, player, movement
9
   image = 'data/player.png',
10 by Josh C
make player an animation
10
   height = 32,
11
   width = 32,
12
   sequences = {
13
      stand = { frames = { 1 }, fps = 1 },
14
      walk = { frames = { 2, 3 }, fps = 5 },
22 by Josh C
climbing animation
15
      jump = { frames = { 4 }, fps = 1 },
16
      climbLeft = { frames = { 5, 6 }, fps = 5 },
17
      climbRight = { frames = { 7, 8 }, fps = 5 }
10 by Josh C
make player an animation
18
   },
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
19
   collisions = {},
20
   onWall = false,
3 by Josh C
jump
21
   onNew = function (self)
22
              self.velocity.y = 0
5 by Josh C
use built-in maxVelocity system
23
              self.maxVelocity.y = 400
3 by Josh C
jump
24
           end,
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
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
31
32
                  -- check existence of properties
33
34
                  if STRICT then
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')
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
40
                     assert(__.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
41
                  end
42
43
                  vel.x = vel.x or 0
44
                  vel.y = vel.y or 0
45
                  vel.rotation = vel.rotation or 0
46
47
                  -- physics
48
49
                  if acc[dir] and acc[dir] ~= 0 then
50
                     vel[dir] = vel[dir] + acc[dir] * elapsed
51
                  else
52
                     if drag[dir] then
53
                        if vel[dir] > 0 then
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
59
                        end
60
                     end
61
                  end
62
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
65
66
                  if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
67
               end,
4 by Josh C
fix jitter caused by focus shift happening in the wrong order. Looks
68
   onStartFrame = function (self)
69
                     -- this is all in startframe so it happens before
70
                     -- physics calc at beginning of update
3 by Josh C
jump
71
12 by Josh C
only jump when you're on the ground
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)
76
19 by Josh C
climb walls
77
                     if (not self.onGround) and (not self.onWall) then
13 by Josh C
reapply jump animation after Y collision. (there's a frame of no
78
                        self:play('jump')
79
                     end
80
6 by Josh C
whitespace cleanup
81
                     self.acceleration.y = 800
82
19 by Josh C
climb walls
83
                     if self.onWall then
84
                        self.acceleration.y = 0
85
22 by Josh C
climbing animation
86
                        if self.onWall == 'right' then
87
                           self:play('climbRight')
88
                        elseif self.onWall == 'left' then
89
                           self:play('climbLeft')
90
                        end
91
19 by Josh C
climb walls
92
                        if the.keys:pressed('up') then
93
                           self.velocity.y = -200
94
                        elseif the.keys:pressed('down') then
95
                           self.velocity.y = 200
96
                        else
97
                           self.velocity.y = 0
22 by Josh C
climbing animation
98
                           self:freeze(self.sequences[self.currentName].frames[1])
19 by Josh C
climb walls
99
                        end
100
                     end
101
6 by Josh C
whitespace cleanup
102
                     if the.keys:pressed('left') then
103
                        self.velocity.x = -200
15 by Josh C
more reliable onGround calc
104
                        if self.onGround then self:play('walk') end
19 by Josh C
climb walls
105
                        if self.onWall == 'right' then self.onWall = false end
6 by Josh C
whitespace cleanup
106
                     elseif the.keys:pressed('right') then
107
                        self.velocity.x = 200
15 by Josh C
more reliable onGround calc
108
                        if self.onGround then self:play('walk') end
19 by Josh C
climb walls
109
                        if self.onWall == 'left' then self.onWall = false end
10 by Josh C
make player an animation
110
                     else
21 by Josh C
really easy version of knowing when we reached the top of a wall.
111
                        if not self.onWall then
22 by Josh C
climbing animation
112
                           if self.onGround then self:play('stand') end
21 by Josh C
really easy version of knowing when we reached the top of a wall.
113
                           self.velocity.x = 0
114
                        end
6 by Josh C
whitespace cleanup
115
                     end
116
15 by Josh C
more reliable onGround calc
117
                     if the.keys:justPressed('up') and self.onGround then
6 by Josh C
whitespace cleanup
118
                        self.velocity.y = -400
12 by Josh C
only jump when you're on the ground
119
                        self.jumping = true
6 by Josh C
whitespace cleanup
120
                     end
121
                  end,
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
122
   update = function (self, elapsed)
123
               -- NOTE: this is an override, not a callback
124
125
               self:doPhysics('x', elapsed)
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
126
               self:collide(the.view.map)
127
128
               -- handle X collisions
21 by Josh C
really easy version of knowing when we reached the top of a wall.
129
               self.onWall = false
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
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
135
                     self.onWall = 'left'
136
                  else
137
                     print 'x ??'
138
                  end
139
               end
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
140
141
               self.onGround = false -- right before Y collision callbacks
142
               self:doPhysics('y', elapsed)
143
               self:collide(the.view.map)
18 by Josh C
call Animation.update so we actually get animations
144
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
145
               -- handle Y collisions
146
               for _, col in ipairs(self.collisions) do
147
                  if self.velocity.y > 0 then
148
                     self.onGround = true
149
                  end
150
151
                  col.other:displaceDir(self, 'y')
152
                  self.velocity.y = 0
153
                  self.jumping = false
154
               end
155
18 by Josh C
call Animation.update so we actually get animations
156
               Animation.update(self, elapsed)
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
157
            end,
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
158
   collide = function (self, ...)
159
                self.collisions = {}
160
                Animation.collide(self, ...)
161
                -- I could return a true/false value here if I wanted to...
162
             end,
8 by Josh C
some basic collision (and workarounds)
163
   onCollide = function (self, other, xOverlap, yOverlap)
164
                  if other == the.view.map then return end
165
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
166
                  table.insert(self.collisions, {other = other,
167
                                                 xOverlap = xOverlap,
168
                                                 yOverlap = yOverlap })
169
               end
2 by Josh C
basic tiles, map, player, movement
170
}
171
20 by Josh C
fairly major overhaul of collision handling to track whether we're on a
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
176
177
   if other.sprites then
178
      -- handle groups
179
180
      for _, spr in pairs(other.sprites) do
181
         self:displace(spr, dir)
182
      end
183
   else
184
      -- handle sprites
185
      local dim
186
      if dir == 'x' then
187
         dim = 'width'
188
      elseif dir == 'y' then
189
         dim = 'height'
190
      else
191
         print 'dir ??'
192
      end
193
194
      local negMove = (other[dir] - self[dir]) + other[dim]
195
      local posMove = (self[dir] + self[dim]) - other[dir]
196
197
      -- TODO: re-add hinting?
198
      if negMove < posMove then
199
         chg = - negMove
200
      else
201
         chg = posMove
202
      end
203
   end
204
205
   other[dir] = other[dir] + chg
206
end
207
2 by Josh C
basic tiles, map, player, movement
208
GameView = View:extend {
209
   onNew = function (self)
210
              self:loadLayers('data/map.lua')
211
              self.focus = the.player
212
              self:clampTo(self.map)
8 by Josh C
some basic collision (and workarounds)
213
           end,
214
   onUpdate = function (self)
215
                 --print('tick')
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
216
                 --the.player:collide(self.map)
8 by Josh C
some basic collision (and workarounds)
217
                 --self.map:collide(the.player)
218
              end
2 by Josh C
basic tiles, map, player, movement
219
}
220
221
the.app = App:new {
222
   onRun = function (self)
223
              self.view = GameView:new()
15 by Josh C
more reliable onGround calc
224
              self.console:watch('onGround', 'the.player.onGround')
16 by Josh C
try to track X collisions. break out Sprite's physics in prep for
225
              self.console:watch('onWall', 'the.player.onWall')
2 by Josh C
basic tiles, map, player, movement
226
           end,
227
   onUpdate = function (self, dt)
14 by Josh C
don't quit w/ escape if debug console is up
228
                 if the.keys:justPressed('escape') and 
229
                   not self.console.visible then
17 by Josh C
reorganize code - separate X and Y physics so we can collide in each
230
                    self.quit()
12 by Josh C
only jump when you're on the ground
231
                 end
2 by Josh C
basic tiles, map, player, movement
232
              end
233
}