/zoeplat

To get this branch, use:
bzr branch http://9ix.org/bzr/zoeplat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
STRICT = true
DEBUG = true

require 'zoetrope'
_ = require 'underscore'
--inspect = require 'inspect'

Player = Animation:extend {
   image = 'data/player.png',
   height = 32,
   width = 32,
   sequences = {
      stand = { frames = { 1 }, fps = 1 },
      walk = { frames = { 2, 3 }, fps = 5 },
      jump = { frames = { 4 }, fps = 1 }
   },
   onNew = function (self)
              self.velocity.y = 0
              self.maxVelocity.y = 400
           end,
   doPhysics = function (self, dir, elapsed)
                  local vel = self.velocity
                  local acc = self.acceleration
                  local drag = self.drag
                  local minVel = self.minVelocity
                  local maxVel = self.maxVelocity

                  -- check existence of properties

                  if STRICT then
                     assert(vel, 'active sprite has no velocity property')
                     assert(acc, 'active sprite has no acceleration property')
                     assert(drag, 'active sprite has no drag property')
                     assert(minVel, 'active sprite has no minVelocity property')
                     assert(maxVel, 'active sprite has no maxVelocity property')
                     assert(_.include({'x','y','rotation'}, dir), 'direction should be x, y, or rotation')
                  end

                  vel.x = vel.x or 0
                  vel.y = vel.y or 0
                  vel.rotation = vel.rotation or 0

                  -- physics

                  if acc[dir] and acc[dir] ~= 0 then
                     vel[dir] = vel[dir] + acc[dir] * elapsed
                  else
                     if drag[dir] then
                        if vel[dir] > 0 then
                           vel[dir] = vel[dir] - drag[dir] * elapsed
                           if vel[dir] < 0 then vel[dir] = 0 end
                        elseif vel[dir] < 0 then
                           vel[dir] = vel[dir] + drag[dir] * elapsed
                           if vel[dir] > 0 then vel[dir] = 0 end
                        end
                     end
                  end

                  if minVel[dir] and vel[dir] < minVel[dir] then vel[dir] = minVel[dir] end
                  if maxVel[dir] and vel[dir] > maxVel[dir] then vel[dir] = maxVel[dir] end

                  if vel[dir] ~= 0 then self[dir] = self[dir] + vel[dir] * elapsed end
               end,
   onStartFrame = function (self)
                     -- this is all in startframe so it happens before
                     -- physics calc at beginning of update

                     -- jumping/falling updates could go in EndFrame...
                     self.falling = self.velocity.y > 0
                     if self.falling then self.jumping = false end
                     --print(self.jumping, self.falling)

                     if not self.onGround then
                        self:play('jump')
                     end

                     self.velocity.x = 0
                     self.acceleration.y = 800

                     if the.keys:pressed('left') then
                        self.velocity.x = -200
                        if self.onGround then self:play('walk') end
                     elseif the.keys:pressed('right') then
                        self.velocity.x = 200
                        if self.onGround then self:play('walk') end
                     else
                        if self.onGround then self:play('stand') end
                     end

                     if the.keys:justPressed('up') and self.onGround then
                        self.velocity.y = -400
                        self.jumping = true
                     end
                  end,
   update = function (self, elapsed)
               -- NOTE: this is an override, not a callback

               self:doPhysics('x', elapsed)

               self.onGround = false -- right before Y collision callbacks
               self:doPhysics('y', elapsed)

               self:collide(the.view.map)
            end,
   onCollide = function (self, other, xOverlap, yOverlap)
                  -- seriously, why does this even fire?
                  if other == the.view.map then return end

                  --print(string.format('col s{x=%i y=%i w=%i h=%i} %s', self.x, self.y, self.width, self.height, tostring(other)))
                  --print('vel.x:'..self.velocity.x.." vel.y:"..self.velocity.y)

                  -- assumption: any other collision is with a solid map tile
                  if yOverlap > xOverlap then
                     other:displace(self)

                     if self.velocity.x > 0 then
                        self.onWall = 'right'
                     elseif self.velocity.x < 0 then
                        self.onWall = 'left'
                     else
                        print 'x ??'
                     end
                  elseif xOverlap > yOverlap then
                     -- check if we've moved since collisions were generated
                     local xov, yov = self:overlap(other.x, other.y,
                                                   other.width, other.height)
                     if xov ~= 0 and yov ~= 0 then
                        --print('y collision')
                        if self.velocity.y > 0 then
                           self.onGround = true
                        end

                        self.velocity.y = 0
                        other:displace(self)
                        self.jumping = false
                     end
                  else
                     print('xy ??')
                  end

               end,
}

GameView = View:extend {
   onNew = function (self)
              self:loadLayers('data/map.lua')
              self.focus = the.player
              self:clampTo(self.map)
           end,
   onUpdate = function (self)
                 --print('tick')
                 --the.player:collide(self.map)
                 --self.map:collide(the.player)
              end
}

the.app = App:new {
   onRun = function (self)
              self.view = GameView:new()
              --print(inspect(_(the.app):keys()))
              self.console:watch('onGround', 'the.player.onGround')
              self.console:watch('onWall', 'the.player.onWall')
           end,
   onUpdate = function (self, dt)
                 if the.keys:justPressed('escape') and 
                   not self.console.visible then
                    self.quit()
                 end
              end
}