Getting closer to a solution... Still need to figure out the desyncs.

master
sigonasr2 2 years ago
parent 49ac2695e1
commit b103a9209c
  1. 194
      olcPGEX_Replay/olcPGEX_Replay.h
  2. 103
      olcPGEX_Replay/replay_test.cpp
  3. 2
      olcPGEX_Replay/test.replay

@ -5,6 +5,7 @@
namespace olc namespace olc
{ {
enum class InputType{ enum class InputType{
NONE,
KEY, KEY,
MOUSE, MOUSE,
MOUSE_MOVE, MOUSE_MOVE,
@ -18,10 +19,14 @@ namespace olc
float delay; float delay;
vi2d mousePos; vi2d mousePos;
public:
Input(int32_t key,bool press,InputType type,float delay); Input(int32_t key,bool press,InputType type,float delay);
Input(int32_t key,bool press,InputType type,float delay,vi2d mousePos); //MOUSE_MOVE Input(int32_t key,bool press,InputType type,float delay,vi2d mousePos); //MOUSE_MOVE
friend std::ostream&operator<<(std::ostream&os,const Input&rhs){os<<"Input(Key="<<rhs.key<<",Press="<<rhs.press<<",Type="<<int(rhs.type)<<",Delay="<<rhs.delay<<",MousePos="<<rhs.mousePos;return os;}; friend std::ostream&operator<<(std::ostream&os,const Input&rhs){os<<"Input(Key="<<rhs.key<<",Press="<<rhs.press<<",Type="<<int(rhs.type)<<",Delay="<<rhs.delay<<",MousePos="<<rhs.mousePos;return os;};
public:
Input(Key k);
Input(int mouseButton);
Input(InputType type);
}; };
class Recording{ class Recording{
@ -30,14 +35,16 @@ namespace olc
std::vector<Input>inputs; std::vector<Input>inputs;
float lastKeyTime; float lastKeyTime;
vi2d prevMousePos; vi2d prevMousePos;
float waitTime;
}; };
class ReplayFile{ class ReplayFile{
friend class Replay; friend class Replay;
std::string filename; std::string filename;
std::vector<Input>inputs; std::vector<Input>inputs;
float accTime; double accTime;
float nextKeyTime; double nextKeyTime;
size_t currentKeyInd;
}; };
class Replay : public olc::PGEX class Replay : public olc::PGEX
@ -46,6 +53,13 @@ namespace olc
bool isReplaying=false; bool isReplaying=false;
Recording currentRecording; Recording currentRecording;
ReplayFile currentReplay; ReplayFile currentReplay;
std::vector<Input>ignoredInputs;
HWButton pKeyboardState[256] = { 0 };
HWButton pMouseState[nMouseButtons] = { 0 };
vi2d vMousePos = {0,0};
int32_t nMouseWheelDelta = 0;
void ResetStates();
public: public:
Replay(); Replay();
@ -55,6 +69,14 @@ namespace olc
void StartReplay(const std::string filename); void StartReplay(const std::string filename);
void StopReplay(); void StopReplay();
bool RecordingIsActive();
bool ReplayIsActive();
HWButton GetKey(Key k);
HWButton GetMouse(uint32_t button);
const vi2d& GetMousePos();
int32_t GetMouseWheel();
protected: protected:
virtual void OnAfterUserCreate() override; virtual void OnAfterUserCreate() override;
virtual bool OnBeforeUserUpdate(float& fElapsedTime) override; virtual bool OnBeforeUserUpdate(float& fElapsedTime) override;
@ -75,45 +97,162 @@ namespace olc{
} }
bool Replay::RecordingIsActive(){
return isRecording;
}
bool Replay::ReplayIsActive(){
return isReplaying;
}
HWButton Replay::GetKey(Key k){
return ReplayIsActive()?pKeyboardState[k]:pge->GetKey(k);
}
HWButton Replay::GetMouse(uint32_t button){
return ReplayIsActive()?pMouseState[button]:pge->GetMouse(button);
}
const vi2d& Replay::GetMousePos(){
return ReplayIsActive()?vMousePos:pge->GetMousePos();
}
int32_t Replay::GetMouseWheel(){
return ReplayIsActive()?nMouseWheelDelta:pge->GetMouseWheel();
}
bool Replay::OnBeforeUserUpdate(float& fElapsedTime){ bool Replay::OnBeforeUserUpdate(float& fElapsedTime){
if (isRecording){ if (RecordingIsActive()){
bool keyChanged=false; bool keyChanged=false;
for (int i=0;i<256;i++){ for (int i=0;i<256;i++){
if (pge->GetKey(Key(i)).bPressed){ bool found=false;
for (Input&input:ignoredInputs){
if (input.type==InputType::KEY&&input.key==i){
found=true;
break;
}
}
if (found) continue;
if (GetKey(Key(i)).bPressed){
currentRecording.inputs.push_back({i,true,InputType::KEY,currentRecording.lastKeyTime}); currentRecording.inputs.push_back({i,true,InputType::KEY,currentRecording.lastKeyTime});
currentRecording.lastKeyTime=0;
keyChanged=true; keyChanged=true;
} }
if (pge->GetKey(Key(i)).bReleased){ if (GetKey(Key(i)).bReleased){
currentRecording.inputs.push_back({i,false,InputType::KEY,currentRecording.lastKeyTime}); currentRecording.inputs.push_back({i,false,InputType::KEY,currentRecording.lastKeyTime});
currentRecording.lastKeyTime=0;
keyChanged=true; keyChanged=true;
} }
} }
for (int i=0;i<5;i++){ for (int i=0;i<5;i++){
if (pge->GetMouse(i).bPressed){ bool found=false;
for (Input&input:ignoredInputs){
if (input.type==InputType::MOUSE&&input.key==i){
found=true;
break;
}
}
if (found) continue;
if (GetMouse(i).bPressed){
currentRecording.inputs.push_back({i,true,InputType::MOUSE,currentRecording.lastKeyTime}); currentRecording.inputs.push_back({i,true,InputType::MOUSE,currentRecording.lastKeyTime});
currentRecording.lastKeyTime=0;
keyChanged=true; keyChanged=true;
} }
if (pge->GetMouse(i).bReleased){ if (GetMouse(i).bReleased){
currentRecording.inputs.push_back({i,false,InputType::MOUSE,currentRecording.lastKeyTime}); currentRecording.inputs.push_back({i,false,InputType::MOUSE,currentRecording.lastKeyTime});
currentRecording.lastKeyTime=0;
keyChanged=true; keyChanged=true;
} }
} }
if (pge->GetMousePos()!=currentRecording.prevMousePos){ if (GetMousePos()!=currentRecording.prevMousePos){
currentRecording.prevMousePos=pge->GetMousePos(); bool found=false;
currentRecording.inputs.push_back({0,false,InputType::MOUSE_MOVE,currentRecording.lastKeyTime,pge->GetMousePos()}); for (Input&input:ignoredInputs){
if (input.type==InputType::MOUSE_MOVE){
found=true;
break;
}
}
if (found) goto mouseWheelCheck;
//GetWindowSize() = vWindowSize
//GetScreenSize() = vScreenSize
vi2d vScreenSize=pge->GetScreenSize();
vi2d vPixelSize=pge->GetPixelSize();
vi2d vWindowSize=pge->GetWindowSize();
int32_t ww = vScreenSize.x * vPixelSize.x;
int32_t wh = vScreenSize.y * vPixelSize.y;
float wasp = (float)ww / (float)wh;
vi2d vViewSize={0,0};
vViewSize.x=vWindowSize.x;
vViewSize.y=(int32_t)((float)vViewSize.x/wasp);
if (vViewSize.y>vWindowSize.y){
vViewSize.y = vWindowSize.y;
vViewSize.x=(int32_t)((float)vViewSize.y*wasp);
}
vi2d vViewPos=(vWindowSize-vViewSize)/2;
vi2d vMousePos=GetMousePos();
vMousePos.x+=vViewPos.x;
vMousePos.y+=vViewPos.y;
//currentRecording.prevMousePos=;
currentRecording.inputs.push_back({0,false,InputType::MOUSE_MOVE,currentRecording.lastKeyTime,GetMousePos()});
currentRecording.lastKeyTime=0;
keyChanged=true; keyChanged=true;
} }
if (pge->GetMouseWheel()!=0){ mouseWheelCheck:
currentRecording.inputs.push_back({pge->GetMouseWheel(),false,InputType::MOUSE_WHEEL,currentRecording.lastKeyTime}); if (GetMouseWheel()!=0){
bool found=false;
for (Input&input:ignoredInputs){
if (input.type==InputType::MOUSE_WHEEL){
found=true;
break;
}
}
if (found) goto keyTimeUpdate;
currentRecording.inputs.push_back({GetMouseWheel(),false,InputType::MOUSE_WHEEL,currentRecording.lastKeyTime});
currentRecording.lastKeyTime=0;
keyChanged=true; keyChanged=true;
} }
keyTimeUpdate:
if (!keyChanged){ if (!keyChanged){
currentRecording.lastKeyTime+=fElapsedTime; currentRecording.lastKeyTime+=fElapsedTime;
} else { } else {
currentRecording.lastKeyTime=fElapsedTime; currentRecording.lastKeyTime=fElapsedTime;
} }
} else { } else
if (ReplayIsActive()){
if (currentReplay.accTime+fElapsedTime>=currentReplay.nextKeyTime){
fElapsedTime=currentReplay.nextKeyTime-currentReplay.accTime;
Input&currentInput=currentReplay.inputs[currentReplay.currentKeyInd];
switch(currentInput.type){
case InputType::KEY:{
if (currentInput.press){
pKeyboardState[currentInput.key].bPressed=pKeyboardState[currentInput.key].bHeld=true;
} else {
pKeyboardState[currentInput.key].bReleased=true;
pKeyboardState[currentInput.key].bHeld=false;
}
}break;
case InputType::MOUSE:{
if (currentInput.press){
pMouseState[currentInput.key].bPressed=pMouseState[currentInput.key].bHeld=true;
} else {
pMouseState[currentInput.key].bReleased=true;
pMouseState[currentInput.key].bHeld=false;
}
}break;
case InputType::MOUSE_MOVE:{
vMousePos={currentInput.mousePos.x,currentInput.mousePos.y};
}break;
case InputType::MOUSE_WHEEL:{
nMouseWheelDelta=currentInput.key;
}break;
}
currentReplay.currentKeyInd++;
if (currentReplay.inputs.size()==currentReplay.currentKeyInd){
isReplaying=false;
std::cout<<"Replay finished"<<std::endl;
} else {
currentReplay.nextKeyTime=currentReplay.inputs[currentReplay.currentKeyInd].delay;
}
currentReplay.accTime=0;
} else {
currentReplay.accTime+=fElapsedTime;
}
} }
return false; return false;
} }
@ -129,6 +268,7 @@ namespace olc{
currentRecording.lastKeyTime=0; currentRecording.lastKeyTime=0;
currentRecording.prevMousePos=pge->GetMousePos(); currentRecording.prevMousePos=pge->GetMousePos();
isRecording=true; isRecording=true;
ResetStates();
} }
void Replay::StopRecording(){ void Replay::StopRecording(){
@ -143,6 +283,7 @@ namespace olc{
file.close(); file.close();
isRecording=false; isRecording=false;
std::cout<<"Recording has stopped. Recording saved to "<<currentRecording.filename<<"."<<std::endl; std::cout<<"Recording has stopped. Recording saved to "<<currentRecording.filename<<"."<<std::endl;
ResetStates();
} }
void Replay::StartReplay(const std::string filename){ void Replay::StartReplay(const std::string filename){
@ -151,11 +292,15 @@ namespace olc{
currentReplay.inputs.clear(); currentReplay.inputs.clear();
currentReplay.accTime=0; currentReplay.accTime=0;
currentReplay.nextKeyTime=0; currentReplay.nextKeyTime=0;
currentReplay.currentKeyInd=0;
while (file.good()){ while (file.good()){
Input newInput(0,false,InputType::KEY,0); Input newInput(0,false,InputType::NONE,0);
int type; int type;
file >> newInput.key; file >> newInput.key;
file >> newInput.delay; file >> newInput.delay;
if (currentReplay.nextKeyTime==0){
currentReplay.nextKeyTime=newInput.delay;
}
file >> type; file >> type;
newInput.type = InputType(type); newInput.type = InputType(type);
file >> newInput.press; file >> newInput.press;
@ -170,14 +315,31 @@ namespace olc{
} }
std::cout<<"Read "<<currentReplay.inputs.size()<<" inputs from "<<filename<<"."<<std::endl; std::cout<<"Read "<<currentReplay.inputs.size()<<" inputs from "<<filename<<"."<<std::endl;
isReplaying=true; isReplaying=true;
ResetStates();
} }
void Replay::StopReplay(){ void Replay::StopReplay(){
isReplaying=false; isReplaying=false;
std::cout<<"Replay has halted."<<std::endl; std::cout<<"Replay has halted."<<std::endl;
ResetStates();
}
void Replay::ResetStates(){
for (int i=0;i<256;i++){
pKeyboardState[i]={false,false,false};
}
for (int i=0;i<nMouseButtons;i++){
pMouseState[i]={false,false,false};
}
vMousePos={0,0};
nMouseWheelDelta=0;
} }
Input::Input(int32_t key,bool press,InputType type,float delay):key(key),type(type),delay(delay),press(press){}; Input::Input(int32_t key,bool press,InputType type,float delay):key(key),type(type),delay(delay),press(press){};
Input::Input(int32_t key,bool press,InputType type,float delay,vi2d mousePos):key(key),type(type),delay(delay),press(press),mousePos(mousePos){}; Input::Input(int32_t key,bool press,InputType type,float delay,vi2d mousePos):key(key),type(type),delay(delay),press(press),mousePos(mousePos){};
Input::Input(Key k):key(int(k)),type(InputType::KEY){};
Input::Input(int mouseButton):key(mouseButton),type(InputType::MOUSE){};
Input::Input(InputType type):type(type){};
} }
#endif #endif

@ -11,34 +11,115 @@ public:
sAppName = "Example"; sAppName = "Example";
} }
struct GameCube{
olc::vf2d pos;
olc::vf2d size;
};
public: public:
olc::Replay replaySystem; olc::Replay rp;
float upMovement=0;
float rightMovement=0;
float downMovement=0;
float leftMovement=0;
GameCube player;
std::vector<GameCube>cubes;
float moveSpd=50;
float gameTime=0;
bool OnUserCreate() override bool OnUserCreate() override
{ {
// Called once at the start, so create things here // Called once at the start, so create things here
for (int i=0;i<5;i++){
cubes.push_back({});
}
ResetGame();
return true; return true;
} }
void ResetGame(){
player={{0,0},{16,16}};
for (int i=0;i<cubes.size();i++){
cubes[i]={olc::vf2d{float(i*24+32),float(i*16+12)}, olc::vf2d{8,8}};
}
}
void PushBoxes(GameCube&original,float x,float y){
for (GameCube&cube:cubes){
if (&cube==&original)continue;
//https://github.com/OneLoneCoder/olcPixelGameEngine/blob/53fe347f26003f9b75e638b23b71d739527da931/utilities/olcUTIL_Geometry2D.h#L702 // Check if rectangle overlaps rectangle
if (cube.pos.x<original.pos.x+original.size.x&&cube.pos.x+cube.size.x>original.pos.x&&
cube.pos.y<original.pos.y+original.size.y&&cube.pos.y+cube.size.y>original.pos.y){
if (x) cube.pos.x+=x>0?std::max(0.1f,x):std::min(-0.1f,x);
if (y) cube.pos.y+=y>0?std::max(0.1f,y):std::min(-0.1f,y);
PushBoxes(cube,x,y);
}
}
}
bool OnUserUpdate(float fElapsedTime) override bool OnUserUpdate(float fElapsedTime) override
{ {
if (GetKey(olc::F1).bPressed){ gameTime+=fElapsedTime;
replaySystem.StartRecording("test.replay");
//Replay controls
if (GetKey(olc::F1).bReleased){
ResetGame();
rp.StartRecording("test.replay");
} }
if (GetKey(olc::F2).bPressed){ if (GetKey(olc::F2).bPressed){
replaySystem.StopRecording(); rp.StopRecording();
} }
if (GetKey(olc::F3).bPressed){ if (GetKey(olc::F3).bPressed){
replaySystem.StartReplay("test.replay"); ResetGame();
rp.StartReplay("test.replay");
} }
if (GetKey(olc::F4).bPressed){ if (GetKey(olc::F4).bPressed){
replaySystem.StopReplay(); rp.StopReplay();
}
if (GetKey(olc::F5).bPressed){
std::cout<<GetKey(olc::F5).bHeld<<std::endl;
}
//Game Controls
float moveAmt = fElapsedTime*moveSpd;
if (rp.GetKey(olc::W).bHeld){
player.pos.y-=moveAmt;
PushBoxes(player,0,-moveAmt);
}
if (rp.GetKey(olc::A).bHeld){
player.pos.x-=moveAmt;
PushBoxes(player,-moveAmt,0);
}
if (rp.GetKey(olc::S).bHeld){
player.pos.y+=moveAmt;
PushBoxes(player,0,moveAmt);
}
if (rp.GetKey(olc::D).bHeld){
player.pos.x+=moveAmt;
PushBoxes(player,moveAmt,0);
}
//Render Game
Clear(olc::BLACK);
if (rp.RecordingIsActive()){
if (std::sinf(8*gameTime)>0){
FillCircle({10,ScreenHeight()-10},3,olc::RED);
}
DrawStringDecal({18,float(ScreenHeight()-13)},"RECORDING",olc::RED);
}
if (rp.ReplayIsActive()){
if (std::sinf(8*gameTime)>0){
DrawStringDecal({18,float(ScreenHeight()-13)},"REPLAYING",olc::YELLOW);
}
}
FillCircle(rp.GetMousePos(),5,olc::BLUE);
FillRectDecal(player.pos,player.size,olc::YELLOW);
for (GameCube&cube:cubes){
FillRectDecal(cube.pos,cube.size,olc::DARK_GREEN);
} }
// called once per frame
for (int x = 0; x < ScreenWidth(); x++)
for (int y = 0; y < ScreenHeight(); y++)
Draw(x, y, olc::Pixel(rand() % 255, rand() % 255, rand()% 255));
return true; return true;
} }
}; };
@ -47,7 +128,7 @@ public:
int main() int main()
{ {
Example demo; Example demo;
if (demo.Construct(256, 240, 4, 4)) if (demo.Construct(256, 240, 4, 4,false,true))
demo.Start(); demo.Start();
return 0; return 0;

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save