/ld27

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

« back to all changes in this revision

Viewing changes to zoetrope/utils/recorder.lua

  • Committer: Josh C
  • Date: 2013-08-24 03:11:38 UTC
  • Revision ID: josh@9ix.org-20130824031138-j4ta4ome0upsxcv5
zoetrope 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
-- Class: Recorder
 
2
-- This records the user's inputs for playback at a later time,
 
3
-- or saving to a file. You must start recording *after* all input
 
4
-- objects are set up, and you should only run one recorder at a time.
 
5
--
 
6
-- Extends:
 
7
--              <Sprite>
 
8
 
 
9
Recorder = Sprite:extend{
 
10
        -- private property: elapsed
 
11
        -- either time elapsed while recording or playing back, in seconds
 
12
        _elapsed = 0,
 
13
 
 
14
        -- private property: mousePosTimer
 
15
        -- used to make sure mouse motions are recorded even if no other event occurs
 
16
        _mousePosTimer = 0,
 
17
 
 
18
        -- Constant: IDLE
 
19
        -- The recorder is currently doing nothing.
 
20
        IDLE = 'idle',
 
21
 
 
22
        -- Constant: RECORDING
 
23
        -- The recorder is currently recording user input.
 
24
        RECORDING = 'recording',
 
25
 
 
26
        -- Constant: PLAYING
 
27
        -- The recorder is currently playing back user input.
 
28
        PLAYING = 'playing',
 
29
 
 
30
        -- Property: mousePosInterval
 
31
        -- How often, in seconds, we should capture the mouse position.
 
32
        -- This records the mouse position when other events occur, too, so
 
33
        -- it's possible the interval will be even higher in reality.
 
34
        -- Setting this number lower will burn memory.
 
35
        mousePosInterval = 0.05,
 
36
 
 
37
        -- Property: state
 
38
        -- One of the state constants, indicates what the recorder is currently doing.
 
39
 
 
40
        -- Property: record
 
41
        -- A table of inputs with timing information.
 
42
 
 
43
        new = function (self, obj)
 
44
                obj = self:extend(obj)
 
45
                obj.state = Recorder.IDLE
 
46
 
 
47
                Sprite.new(obj)
 
48
                return obj
 
49
        end,
 
50
 
 
51
        -- Method: startRecording
 
52
        -- Begins recording user inputs. If the recorder is already recording,
 
53
        -- this has no effect.
 
54
        --
 
55
        -- Arguments:
 
56
        --              record - Record to use. Any existing data is appended to.
 
57
        --                               If omitted, the current record is used. If the current
 
58
        --                               record is unset, this creates a new record.
 
59
        --
 
60
        -- Returns:
 
61
        --              nothing
 
62
 
 
63
        startRecording = function (self, record)
 
64
                if self.state ~= Recorder.IDLE then return end
 
65
 
 
66
                -- set up properties
 
67
                self.record = record or self.record or {}
 
68
                self.state = Recorder.RECORDING
 
69
                self._elapsed = 0
 
70
                self._mousePosTimer = 0
 
71
 
 
72
                -- insert ourselves into event handlers
 
73
                self:stealInputs()
 
74
        end,
 
75
 
 
76
        -- Method: stopRecording
 
77
        -- Stops recording user inputs. If the recorder wasn't recording anyway,
 
78
        -- this does nothing.
 
79
        -- 
 
80
        -- Arguments:
 
81
        --              none
 
82
        -- 
 
83
        -- Returns:
 
84
        --              nothing
 
85
 
 
86
        stopRecording = function (self)
 
87
                if self.state ~= Recorder.RECORDING then return end
 
88
 
 
89
                self.state = Recorder.IDLE
 
90
                self:restoreInputs()
 
91
                love.keypressed = self.origKeyPressed
 
92
                love.keyreleased = self.origKeyReleased
 
93
        end,
 
94
 
 
95
        -- Method: startPlaying
 
96
        -- Starts playing back user inputs. If this is already playing
 
97
        -- a recording, this restarts it.
 
98
        --
 
99
        -- Arguments:
 
100
        --              record - Record to play back. If omitted, this uses
 
101
        --                               the recorder's record property.
 
102
        --
 
103
        -- Returns:
 
104
        --              nothing
 
105
 
 
106
        startPlaying = function (self, record)
 
107
                record = record or self.record
 
108
 
 
109
                -- if we are currently recording, ignore the request
 
110
 
 
111
                if self.state == Recorder.RECORDING then return end
 
112
 
 
113
                -- restart if needed
 
114
 
 
115
                if self.state == Recorder.PLAYING then
 
116
                        self:stopPlaying()      
 
117
                end
 
118
 
 
119
                self.state = Recorder.PLAYING 
 
120
 
 
121
                self._elapsed = 0
 
122
                self.playbackIndex = 1
 
123
                self:stealInputs()
 
124
        end,
 
125
 
 
126
        -- Method: stopPlaying
 
127
        -- Stops playing back user inputs.
 
128
        --
 
129
        -- Arguments:
 
130
        --              none
 
131
        --
 
132
        -- Returns:
 
133
        --              nothing
 
134
 
 
135
        stopPlaying = function (self)
 
136
                if not self.state == Recorder.PLAYING then return end
 
137
                self.state = Recorder.IDLE
 
138
                self:restoreInputs()
 
139
        end,
 
140
 
 
141
        stealInputs = function (self)
 
142
                local this = self
 
143
 
 
144
                self.origKeyPressed = love.keypressed
 
145
                love.keypressed = function (key, code) this:recordKeyPress(key, code) end
 
146
                self.origKeyReleased = love.keyreleased
 
147
                love.keyreleased = function (key, code) this:recordKeyRelease(key, code) end
 
148
                self.origMousePressed = love.mousepressed
 
149
                love.mousepressed = function (x, y, button) this:recordMousePress(x, y, button) end
 
150
                self.origMouseReleased = love.mousereleased
 
151
                love.mousereleased = function (x, y, button) this:recordMouseRelease(x, y, button) end
 
152
        end,
 
153
 
 
154
        restoreInputs = function (self)
 
155
                love.keypressed = self.origKeyPressed
 
156
                love.keyreleased = self.origKeyReleased
 
157
                love.mousepressed = self.origMousePressed
 
158
                love.mousereleased = self.origMouseReleased
 
159
        end,
 
160
        
 
161
        recordKeyPress = function (self, key, unicode)
 
162
                table.insert(self.record, { self._elapsed, the.mouse.x, the.mouse.y, 'keypress', key, unicode })
 
163
                self._mousePosTimer = 0
 
164
 
 
165
                if self.origKeyPressed then
 
166
                        self.origKeyPressed(key, unicode)
 
167
                end
 
168
        end,
 
169
 
 
170
        recordKeyRelease = function (self, key, unicode)
 
171
                table.insert(self.record, { self._elapsed, the.mouse.x, the.mouse.y, 'keyrelease', key, unicode })
 
172
                self._mousePosTimer = 0
 
173
 
 
174
                if self.origKeyReleased then
 
175
                        self.origKeyReleased(key, unicode)
 
176
                end
 
177
        end,
 
178
 
 
179
        recordMousePress = function (self, x, y, button)
 
180
                table.insert(self.record, { self._elapsed, x, y, 'mousepress', button })
 
181
                self._mousePosTimer = 0
 
182
 
 
183
                if self.origMousePressed then
 
184
                        self.origMousePressed(x, y, button)
 
185
                end
 
186
        end,
 
187
 
 
188
        recordMouseRelease = function (self, x, y, button)
 
189
                table.insert(self.record, { self._elapsed, x, y, 'mouserelease', button })
 
190
                self._mousePosTimer = 0
 
191
 
 
192
                if self.origMouseReleased then
 
193
                        self.origMouseReleased(x, y, button)
 
194
                end
 
195
        end,
 
196
 
 
197
        update = function (self, elapsed)
 
198
                -- increment timers
 
199
 
 
200
                if self.state ~= Recorder.IDLE then
 
201
                        self._elapsed = self._elapsed + elapsed
 
202
                end
 
203
 
 
204
                -- record mouse position if the timer has expired
 
205
 
 
206
                if self.state == Recorder.RECORDING then
 
207
                        self._mousePosTimer = self._mousePosTimer + elapsed
 
208
 
 
209
                        if self._mousePosTimer > self.mousePosInterval then
 
210
                                table.insert(self.record, { self._elapsed, the.mouse.x, the.mouse.y })
 
211
 
 
212
                                self._mousePosTimer = 0
 
213
                        end
 
214
                end
 
215
 
 
216
                -- handle playback
 
217
 
 
218
                if self.state == Recorder.PLAYING and self._elapsed >= self.record[self.playbackIndex][1] then
 
219
                        local event = self.record[self.playbackIndex]
 
220
        
 
221
                        love.mouse.setPosition(event[2], event[3])
 
222
 
 
223
                        if event[4] == 'keypress' and self.origKeyPressed then
 
224
                                self.origKeyPressed(event[5], event[6])
 
225
                        elseif event[4] == 'keyrelease' and self.origKeyReleased then
 
226
                                self.origKeyReleased(event[5], event[6])
 
227
                        elseif event[4] == 'mousepress' and self.origMousePressed then
 
228
                                self.origMousePressed(event[2], event[3], event[5])
 
229
                        elseif event[4] == 'mouserelease' and self.origMouseReleased then
 
230
                                self.origMouseReleased(event[2], event[3], event[5])
 
231
                        end
 
232
 
 
233
                        self.playbackIndex = self.playbackIndex + 1
 
234
 
 
235
                        if self.playbackIndex > #self.record then
 
236
                                self:stopPlaying()
 
237
                        end
 
238
                end
 
239
        end
 
240
}