Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F622674
RecordPlayback.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None
RecordPlayback.cpp
View Options
/*
* Copyright (C) 2019 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include
"RecordPlayback.h"
#include
"TreeStorageNode.h"
#include
"POASerializer.h"
#include
"InputManager.h"
#include
"Functions.h"
#include
"Render.h"
#include
<fstream>
#include
<iostream>
#include
<sstream>
#include
<vector>
#include
<map>
#include
<algorithm>
#include
<assert.h>
#include
<stdio.h>
#include
<string.h>
#include
<SDL_ttf_fontfallback.h>
#include
"libs/tinyformat/tinyformat.h"
const
int
MAX_MOUSE_IDLE_TIME
=
1
*
40
;
using
namespace
std
;
RecordPlayback
::
RecordPlayback
(
SDL_Renderer
&
renderer
,
ImageManager
&
imageManager
)
:
Game
(
renderer
,
imageManager
)
,
lastMouseX
(
-1
),
lastMouseY
(
-1
),
mouseIdleTime
(
-
MAX_MOUSE_IDLE_TIME
)
,
replaySpeed
(
0x10
),
replayIdleTime
(
0
),
replayPaused
(
false
)
{
guiTexture
=
imageManager
.
loadTexture
(
getDataPath
()
+
"gfx/gui.png"
,
renderer
);
// We always show the cursor since Game hides it first.
SDL_ShowCursor
(
SDL_ENABLE
);
}
RecordPlayback
::~
RecordPlayback
()
{
}
enum
RecordPlaybackButtons
{
BTN_RESTART
,
BTN_REWIND
,
BTN_PREV_FRAME
,
BTN_PLAY
,
BTN_NEXT_FRAME
,
BTN_FAST_FORWARD
,
BTN_SLOWER
,
BTN_FASTER
,
};
void
RecordPlayback::handleEvents
(
ImageManager
&
imageManager
,
SDL_Renderer
&
renderer
)
{
// First let Game process events.
Game
::
handleEvents
(
imageManager
,
renderer
);
int
clickedButton
=
-1
;
const
InputManagerKeys
keys
[
8
]
=
{
INPUTMGR_RESTART
,
INPUTMGR_LEFT
,
INPUTMGR_PREVIOUS
,
INPUTMGR_SPACE
,
INPUTMGR_NEXT
,
INPUTMGR_RIGHT
,
INPUTMGR_UP
,
INPUTMGR_DOWN
,
};
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
if
(
inputMgr
.
isKeyDownEvent
(
keys
[
i
]))
{
clickedButton
=
i
;
break
;
}
}
if
(
event
.
type
==
SDL_MOUSEBUTTONDOWN
)
{
const
SDL_Rect
r
=
{
100
,
SCREEN_HEIGHT
-
144
,
SCREEN_WIDTH
-
200
,
72
};
const
SDL_Point
p
=
{
event
.
button
.
x
,
event
.
button
.
y
};
if
(
mouseIdleTime
<
0
&&
SDL_PointInRect
(
&
p
,
&
r
))
{
if
(
p
.
y
<
r
.
y
+
24
)
{
}
else
if
(
p
.
y
<
r
.
y
+
40
)
{
// TODO: clicked the slider
}
else
if
(
p
.
y
<
r
.
y
+
64
)
{
if
(
p
.
x
>=
r
.
x
+
8
&&
p
.
x
<
r
.
x
+
152
)
{
clickedButton
=
(
p
.
x
-
r
.
x
-
8
)
/
24
;
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
104
)
{
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
80
)
{
clickedButton
=
BTN_SLOWER
;
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
32
)
{
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
8
)
{
clickedButton
=
BTN_FASTER
;
}
}
}
else
{
clickedButton
=
BTN_PLAY
;
}
}
switch
(
clickedButton
)
{
case
BTN_PLAY
:
replayPaused
=
!
replayPaused
;
mouseIdleTime
=
-
MAX_MOUSE_IDLE_TIME
;
break
;
case
BTN_SLOWER
:
if
(
replaySpeed
>
0x4
)
{
replaySpeed
>>=
1
;
mouseIdleTime
=
-
MAX_MOUSE_IDLE_TIME
;
}
break
;
case
BTN_FASTER
:
if
(
replaySpeed
<
0x40
)
{
replaySpeed
<<=
1
;
mouseIdleTime
=
-
MAX_MOUSE_IDLE_TIME
;
}
break
;
}
}
void
RecordPlayback::logic
(
ImageManager
&
imageManager
,
SDL_Renderer
&
renderer
)
{
// Determine the number of ticks to advance.
int
m
=
0
;
if
(
won
||
replayPaused
)
{
replayIdleTime
=
0
;
}
else
if
(
replaySpeed
>=
0x10
)
{
m
=
replaySpeed
>>
4
;
replayIdleTime
=
0
;
}
else
{
replayIdleTime
+=
replaySpeed
;
if
(
replayIdleTime
>=
0x10
)
{
m
=
1
;
replayIdleTime
=
0
;
}
}
// Let Game process logic.
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
if
(
won
)
break
;
Game
::
logic
(
imageManager
,
renderer
);
}
}
void
RecordPlayback::render
(
ImageManager
&
imageManager
,
SDL_Renderer
&
renderer
)
{
// First let Game render.
Game
::
render
(
imageManager
,
renderer
);
const
SDL_Rect
r
=
{
100
,
SCREEN_HEIGHT
-
144
,
SCREEN_WIDTH
-
200
,
72
};
SDL_Point
p
;
// Check if mouse moves (FIXME: logic in render function)
SDL_GetMouseState
(
&
p
.
x
,
&
p
.
y
);
if
(
lastMouseX
!=
p
.
x
||
lastMouseY
!=
p
.
y
||
SDL_PointInRect
(
&
p
,
&
r
))
{
lastMouseX
=
p
.
x
;
lastMouseY
=
p
.
y
;
mouseIdleTime
=
-
MAX_MOUSE_IDLE_TIME
;
}
// Now render the playback control.
if
(
mouseIdleTime
<
0
)
{
std
::
string
newToolTip
;
SDL_Rect
toolTipRect
=
{};
const
SDL_Color
fg
=
objThemes
.
getTextColor
(
true
);
const
int
alpha
=
std
::
max
(
mouseIdleTime
,
-15
)
*
(
-17
);
const
int
alpha2
=
std
::
max
(
mouseIdleTime
,
-15
)
*
(
-10
);
drawGUIBox
(
r
.
x
,
r
.
y
,
r
.
w
,
r
.
h
,
renderer
,
0xFFFFFF00
|
alpha2
,
true
);
int
y
=
r
.
y
+
8
;
int
maxTime
=
player
.
getRecord
()
->
size
();
int
tmp
=
time
^
(
maxTime
<<
16
)
^
42
;
// Draw time text. FIXME: here we screwed up Game::timeTexture.
if
(
timeTexture
.
needsUpdate
(
tmp
))
{
timeTexture
.
update
(
tmp
,
textureUniqueFromSurface
(
renderer
,
SurfacePtr
(
TTF_RenderUTF8_Blended
(
fontMono
,
tfm
::
format
(
"%02d:%05.2f / %02d:%05.2f"
,
time
/
2400
,
(
time
%
2400
)
/
40.0
,
maxTime
/
2400
,
(
maxTime
%
2400
)
/
40.0
).
c_str
(),
fg
))));
}
SDL_SetTextureAlphaMod
(
timeTexture
.
get
(),
(
Uint8
)
alpha
);
applyTexture
(
r
.
x
+
8
,
y
,
*
timeTexture
.
get
(),
renderer
);
y
+=
16
;
// Get the tool tip text of slider if mouse is over
if
(
p
.
y
>=
y
&&
p
.
y
<
y
+
24
&&
p
.
x
>=
r
.
x
+
8
&&
p
.
x
<
r
.
x
+
r
.
w
-
8
)
{
int
x
=
p
.
x
-
r
.
x
-
12
;
if
(
x
<
0
)
x
=
0
;
if
(
x
>
r
.
w
-
24
)
x
=
r
.
w
-
24
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
x
+
8
,
y
,
8
,
-1
};
int
t
=
int
(
float
(
x
)
*
float
(
maxTime
)
/
float
(
r
.
w
-
24
)
+
0.5f
);
newToolTip
=
tfm
::
format
(
"%02d:%05.2f"
,
t
/
2400
,
(
t
%
2400
)
/
40.0
);
}
// Draw slider.
int
pos
=
maxTime
>
0
?
int
(
float
(
r
.
w
-
24
)
*
float
(
std
::
min
(
time
,
maxTime
))
/
float
(
maxTime
)
+
0.5f
)
:
0
;
drawGUIBox
(
r
.
x
+
8
,
y
+
6
,
pos
+
2
,
4
,
renderer
,
0x80808000
|
alpha
,
true
);
drawGUIBox
(
r
.
x
+
pos
+
14
,
y
+
6
,
r
.
w
-
pos
-
22
,
4
,
renderer
,
0xFFFFFF00
|
alpha
,
true
);
drawGUIBox
(
r
.
x
+
pos
+
8
,
y
,
8
,
16
,
renderer
,
0xFFFFFF00
|
alpha
,
true
);
y
+=
16
;
// Get the tool tip text of buttons if mouse is over
if
(
p
.
y
>=
y
&&
p
.
y
<
y
+
24
)
{
if
(
p
.
x
<
r
.
x
+
8
){
}
else
if
(
p
.
x
<
r
.
x
+
32
)
{
newToolTip
=
_
(
"Restart"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_RESTART
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_RESTART
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
8
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
56
)
{
newToolTip
=
_
(
"Rewind"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_LEFT
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_LEFT
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
32
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
80
)
{
newToolTip
=
_
(
"Step back"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_PREVIOUS
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_PREVIOUS
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
56
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
104
)
{
newToolTip
=
replayPaused
?
_
(
"Play"
)
:
_
(
"Pause"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_SPACE
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_SPACE
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
80
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
128
)
{
newToolTip
=
_
(
"Step forward"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_NEXT
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_NEXT
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
104
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
152
)
{
newToolTip
=
_
(
"Fast forward"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_RIGHT
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_RIGHT
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
128
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
104
)
{
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
80
)
{
newToolTip
=
_
(
"Slower"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_UP
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_UP
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
r
.
w
-
104
,
y
,
24
,
24
};
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
32
)
{
}
else
if
(
p
.
x
<
r
.
x
+
r
.
w
-
8
)
{
newToolTip
=
_
(
"Faster"
);
newToolTip
+=
" ("
+
InputManagerKeyCode
::
describeTwo
(
inputMgr
.
getKeyCode
(
INPUTMGR_DOWN
,
false
),
inputMgr
.
getKeyCode
(
INPUTMGR_DOWN
,
true
))
+
")"
;
toolTipRect
=
SDL_Rect
{
r
.
x
+
r
.
w
-
32
,
y
,
24
,
24
};
}
if
(
toolTipRect
.
h
>
0
)
{
drawGUIBox
(
toolTipRect
.
x
,
toolTipRect
.
y
,
toolTipRect
.
w
,
toolTipRect
.
h
,
renderer
,
0xFFFFFF00
|
alpha
,
true
);
}
}
// Set the alpha of gui texture
SDL_SetTextureAlphaMod
(
guiTexture
.
get
(),
(
Uint8
)
alpha
);
// Draw buttons.
SDL_Rect
srcrect
=
{
32
,
80
,
16
,
16
};
SDL_Rect
dstrect
=
{
r
.
x
+
12
,
y
+
4
,
16
,
16
};
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// restart
srcrect
.
x
+=
16
;
dstrect
.
x
+=
24
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// rewind
srcrect
.
x
+=
16
;
dstrect
.
x
+=
24
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// previous frame
srcrect
.
x
=
replayPaused
?
96
:
112
;
srcrect
.
y
=
64
;
dstrect
.
x
+=
24
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// play/pause
srcrect
.
x
=
80
;
srcrect
.
y
=
80
;
dstrect
.
x
+=
24
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// next frame
srcrect
.
x
+=
16
;
dstrect
.
x
+=
24
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// fast forward
srcrect
.
x
=
48
;
srcrect
.
y
=
80
;
dstrect
.
x
=
r
.
x
+
r
.
w
-
100
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// slower
srcrect
.
x
=
96
;
dstrect
.
x
+=
72
;
SDL_RenderCopy
(
&
renderer
,
guiTexture
.
get
(),
&
srcrect
,
&
dstrect
);
// faster
// Draw replay speed.
if
(
replaySpeedTexture
.
needsUpdate
(
replaySpeed
))
{
replaySpeedTexture
.
update
(
replaySpeed
,
textureUniqueFromSurface
(
renderer
,
SurfacePtr
(
TTF_RenderUTF8_Blended
(
fontMono
,
tfm
::
format
(
"%gx"
,
float
(
replaySpeed
)
/
16.0f
).
c_str
(),
fg
))));
}
SDL_Rect
r1
=
rectFromTexture
(
replaySpeedTexture
);
SDL_SetTextureAlphaMod
(
replaySpeedTexture
.
get
(),
(
Uint8
)
alpha
);
applyTexture
(
r
.
x
+
r
.
w
-
80
+
(
48
-
r1
.
w
)
/
2
,
y
+
(
24
-
r1
.
h
)
/
2
,
*
replaySpeedTexture
.
get
(),
renderer
);
// Reset alpha of gui texture since it is global
SDL_SetTextureAlphaMod
(
guiTexture
.
get
(),
255
);
y
+=
24
;
// Show tool tip if necessary.
if
(
!
newToolTip
.
empty
())
{
if
(
toolTipTexture
.
needsUpdate
(
newToolTip
))
{
toolTipTexture
.
update
(
newToolTip
,
textureUniqueFromSurface
(
renderer
,
SurfacePtr
(
TTF_RenderUTF8_Blended
(
fontText
,
newToolTip
.
c_str
(),
fg
))));
}
SDL_Rect
r1
=
rectFromTexture
(
toolTipTexture
);
toolTipRect
.
y
=
toolTipRect
.
y
-
r1
.
h
-
6
;
toolTipRect
.
w
=
r1
.
w
+
4
;
toolTipRect
.
h
=
r1
.
h
+
4
;
if
(
toolTipRect
.
x
+
toolTipRect
.
w
>
SCREEN_WIDTH
-
2
)
toolTipRect
.
x
=
SCREEN_WIDTH
-
2
-
toolTipRect
.
w
;
drawGUIBox
(
toolTipRect
.
x
,
toolTipRect
.
y
,
toolTipRect
.
w
,
toolTipRect
.
h
,
renderer
,
0xFFFFFF00
|
alpha
,
true
);
SDL_SetTextureAlphaMod
(
toolTipTexture
.
get
(),
(
Uint8
)
alpha
);
applyTexture
(
toolTipRect
.
x
+
2
,
toolTipRect
.
y
+
2
,
*
toolTipTexture
.
get
(),
renderer
);
}
}
// Advance the mouse idle time. (FIXME: logic in render function)
mouseIdleTime
++
;
// Render the replay finished tooltip.
if
(
won
)
{
// FIXME: here we screwed up Game::bmTipsRestartCheckpoint.
// This shouldn't cause bugs since when playing from record, the save functionality is disabled.
if
(
bmTipsRestartCheckpoint
==
NULL
){
//Draw string
bmTipsRestartCheckpoint
=
textureFromText
(
renderer
,
*
fontText
,
_
(
"Game replay is done."
),
objThemes
.
getTextColor
(
true
));
}
SDL_Texture
*
bm
=
bmTipsRestartCheckpoint
.
get
();
//Draw the tip.
if
(
bm
!=
NULL
){
const
SDL_Rect
textureSize
=
rectFromTexture
(
*
bm
);
int
x
=
(
SCREEN_WIDTH
-
textureSize
.
w
)
/
2
;
int
y
=
32
;
drawGUIBox
(
x
-
8
,
y
-
8
,
textureSize
.
w
+
16
,
textureSize
.
h
+
14
,
renderer
,
0xFFFFFFFF
);
applyTexture
(
x
,
y
,
*
bm
,
renderer
);
}
}
}
void
RecordPlayback::loadRecord
(
ImageManager
&
imageManager
,
SDL_Renderer
&
renderer
,
const
char
*
fileName
,
const
char
*
levelFileName
)
{
//Create a TreeStorageNode that will hold the loaded data.
TreeStorageNode
obj
;
{
POASerializer
objSerializer
;
//Parse the file.
if
(
!
objSerializer
.
loadNodeFromFile
(
fileName
,
&
obj
,
true
)){
cerr
<<
"ERROR: Can't load record file "
<<
fileName
<<
endl
;
return
;
}
}
//Load the seed of psuedo-random number generator.
prngSeed
.
clear
();
{
auto
it
=
obj
.
attributes
.
find
(
"seed"
);
if
(
it
!=
obj
.
attributes
.
end
()
&&
!
it
->
second
.
empty
())
{
prngSeed
=
it
->
second
[
0
];
}
}
bool
loaded
=
false
;
//substitute the level if the level file name is specified.
if
(
levelFileName
)
{
TreeStorageNode
*
obj
=
new
TreeStorageNode
();
if
(
!
POASerializer
().
loadNodeFromFile
(
levelFileName
,
obj
,
true
))
{
cerr
<<
"ERROR: Can't load level file "
<<
levelFileName
<<
endl
;
delete
obj
;
}
else
{
//also replace the script by the external one.
std
::
string
s
=
levelFileName
;
size_t
lp
=
s
.
find_last_of
(
'.'
);
if
(
lp
!=
std
::
string
::
npos
)
{
s
=
s
.
substr
(
0
,
lp
);
}
s
+=
".lua"
;
loadLevelFromNode
(
imageManager
,
renderer
,
obj
,
"?record?"
,
s
);
loaded
=
true
;
}
}
else
{
//find the node named 'map'.
for
(
unsigned
int
i
=
0
;
i
<
obj
.
subNodes
.
size
();
i
++
)
{
if
(
obj
.
subNodes
[
i
]
->
name
==
"map"
)
{
//load the script from record file.
std
::
string
s
;
auto
it
=
obj
.
attributes
.
find
(
"script"
);
if
(
it
!=
obj
.
attributes
.
end
()
&&
!
it
->
second
.
empty
())
{
s
=
"?"
+
it
->
second
[
0
];
}
//load the level. (fileName=???)
loadLevelFromNode
(
imageManager
,
renderer
,
obj
.
subNodes
[
i
],
"?record?"
,
s
);
//remove this node to prevent delete it.
obj
.
subNodes
[
i
]
=
NULL
;
//over
loaded
=
true
;
break
;
}
}
}
if
(
!
loaded
){
cerr
<<
"ERROR: Can't find subnode named 'map' from record file"
<<
endl
;
return
;
}
//load the record.
{
vector
<
int
>
*
record
=
player
.
getRecord
();
record
->
clear
();
vector
<
string
>
&
v
=
obj
.
attributes
[
"record"
];
for
(
unsigned
int
i
=
0
;
i
<
v
.
size
();
i
++
){
string
&
s
=
v
[
i
];
string
::
size_type
pos
=
s
.
find_first_of
(
'*'
);
if
(
pos
==
string
::
npos
){
//1 item only.
int
i
=
atoi
(
s
.
c_str
());
record
->
push_back
(
i
);
}
else
{
//contains many items.
int
i
=
atoi
(
s
.
substr
(
0
,
pos
).
c_str
());
int
j
=
atoi
(
s
.
substr
(
pos
+
1
).
c_str
());
for
(;
j
>
0
;
j
--
){
record
->
push_back
(
i
);
}
}
}
}
#ifdef RECORD_FILE_DEBUG
//load the debug data
{
vector
<
string
>
&
v
=
obj
.
attributes
[
"recordPlayerPosition"
];
vector
<
SDL_Rect
>
&
playerPosition
=
player
.
playerPosition
();
playerPosition
.
clear
();
if
(
!
v
.
empty
()){
if
(
!
v
[
0
].
empty
()){
stringstream
st
(
v
[
0
]);
int
m
;
st
>>
m
;
for
(
int
i
=
0
;
i
<
m
;
i
++
){
SDL_Rect
r
;
st
>>
r
.
x
>>
r
.
y
;
r
.
w
=
0
;
r
.
h
=
0
;
playerPosition
.
push_back
(
r
);
}
}
}
}
#endif
//play the record.
player
.
playRecord
();
shadow
.
playRecord
();
//???
// We always show the cursor since Game hides it first.
SDL_ShowCursor
(
SDL_ENABLE
);
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sat, Nov 14, 8:25 PM (1 d, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
122077
Default Alt Text
RecordPlayback.cpp (14 KB)
Attached To
Mode
R79 meandmyshadow
Attached
Detach File
Event Timeline