From 0cd7052df70dd9296f35380e21ba088a90a35803 Mon Sep 17 00:00:00 2001 From: stdgregwar Date: Sun, 4 Jun 2017 20:08:52 +0200 Subject: [PATCH 1/3] SFML pong example --- examples/CMakeLists.txt | 10 ++- examples/src/Sfml.cpp | 157 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 examples/src/Sfml.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 940479ae..96ee35bf 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -17,7 +17,7 @@ target_link_libraries(Example_BasicObservers CppReact) ### Example_BasicReactors find_package(Boost 1.55 COMPONENTS coroutine context system) if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) + include_directories(${Boost_INCLUDE_DIRS}) add_executable(Example_BasicReactors src/BasicReactors.cpp) target_link_libraries(Example_BasicReactors CppReact ${Boost_LIBRARIES}) else() @@ -37,3 +37,11 @@ target_link_libraries(Example_BasicSynchronization CppReact) ### Example_Sandbox add_executable(Example_Sandbox src/Main.cpp) target_link_libraries(Example_Sandbox CppReact) + +### Example SFML +find_package(SFML 2 REQUIRED system window graphics network audio) +if(SFML_FOUND) + include_directories(${SFML_INCLUDE_DIR}) + add_executable(Example_SFML src/Sfml.cpp) + target_link_libraries(Example_SFML ${SFML_LIBRARIES} CppReact) +endif() diff --git a/examples/src/Sfml.cpp b/examples/src/Sfml.cpp new file mode 100644 index 00000000..d72c817e --- /dev/null +++ b/examples/src/Sfml.cpp @@ -0,0 +1,157 @@ +#include + +using namespace std; + +#include +#include "react/Domain.h" +#include "react/Signal.h" +#include "react/Event.h" +#include "react/Algorithm.h" +#include + +namespace pong { + + constexpr int winWidth = 1280; + constexpr int winHeight = 720; + using KeyMap = unordered_map; + template + auto getOrElse(const unordered_map& m,const K& key, const V& def) -> const V& { + auto it = m.find(key); + if(it != m.end()) return it->second; + return def; + } + + struct MovableState{ + sf::Vector2f pos; + sf::Vector2f speed; + bool operator==(const MovableState& other) const { + return tie(pos,speed) == tie(other.pos,other.speed); + } + }; + + constexpr float bounce = -1.2f; + + template + void clamp(V& v, const W& min, const X& max) { + v = v < min ? min : v > max ? max : v; + } + + auto foldBallState(float dt, MovableState prev, const sf::FloatRect& lbar, const sf::FloatRect& rbar) -> MovableState { + if(prev.pos.y > winHeight || prev.pos.y < 0) { + prev.speed.y *= bounce; + clamp(prev.pos.y,0,winHeight); + } + if(prev.pos.x > winWidth || prev.pos.x < 0) { + //TODO count points + prev.speed.x*= bounce; + clamp(prev.pos.x,0,winWidth); + } + if(lbar.contains(prev.pos)) prev.speed.x *= bounce; + if(rbar.contains(prev.pos)) prev.speed.x *= bounce; + prev.pos += dt* prev.speed; + return prev; + } + + auto keysToDir(const KeyMap& m, const sf::Event& e) -> sf::Vector2f { + float val = e.type == sf::Event::KeyPressed ? 1 : -1; + return getOrElse(m,e.key.code,{0,0})*val; + } + + constexpr float speedFac = 100; + + auto dirToSpeed(const sf::Vector2f& dir, sf::Vector2f speed) -> sf::Vector2f { + return speed += dir*speedFac; + } + + auto foldBarPos(float dt, sf::Vector2f pos, const sf::Vector2f& speed) -> sf::Vector2f { + auto newPos = pos+dt*speed; + return newPos; + } + + const sf::Vector2f barsSize(10,200); + + auto barPosToRect(const sf::Vector2f& pos) -> sf::FloatRect { + return sf::FloatRect(pos,barsSize); + } + + //Player 1 keymap + KeyMap p1map = {{sf::Keyboard::Up,{0,-1}},{sf::Keyboard::Down,{0,1}}, + {sf::Keyboard::Left,{-1,0}},{sf::Keyboard::Right,{1,0}}}; + KeyMap p2map = {{sf::Keyboard::W,{0,-1}},{sf::Keyboard::S,{0,1}}, + {sf::Keyboard::A,{-1,0}},{sf::Keyboard::D,{1,0}}}; + + + using namespace react; + REACTIVE_DOMAIN(D,sequential) + USING_REACTIVE_DOMAIN(D) + + sf::RenderWindow window(sf::VideoMode(winWidth,winHeight),"ReactPong"); + sf::RectangleShape lbar(barsSize); + sf::RectangleShape rbar(barsSize); + sf::RectangleShape ball({10,10}); + + EventSourceT eventStream = MakeEventSource(); + EventSourceT frameEvent = MakeEventSource(); //dt of frames + + EventsT keysOnly = Filter(eventStream,[](const sf::Event& e){return e.type == sf::Event::KeyPressed || e.type == sf::Event::KeyReleased;}); + + using namespace std::placeholders; + EventsT rmoveDirs = Transform(keysOnly,bind(keysToDir,p1map,_1)); + EventsT lmoveDirs = Transform(keysOnly,bind(keysToDir,p2map,_1)); + + SignalT rbarSpeed = Iterate(rmoveDirs, sf::Vector2f{0,0}, dirToSpeed); + SignalT rbarPos = Iterate(frameEvent, sf::Vector2f{winWidth-20,winHeight/2},With(rbarSpeed), foldBarPos); + SignalT rbarRect = MakeSignal(rbarPos,barPosToRect); + + SignalT lbarSpeed = Iterate(lmoveDirs, sf::Vector2f{0,0}, dirToSpeed); + SignalT lbarPos = Iterate(frameEvent, sf::Vector2f{20,winHeight/2},With(lbarSpeed), foldBarPos); + SignalT lbarRect = MakeSignal(lbarPos,barPosToRect); + + SignalT ballState = Iterate( + frameEvent, + MovableState{{winWidth/2,winHeight/2},{130,130}}, + With(lbarRect,rbarRect), + foldBallState + ); + + void run() { + //Close window on sysevent close + Observe(eventStream,[](const sf::Event& e) { + if(e.type == sf::Event::Closed) window.close(); + }); + + Observe(ballState,[](const MovableState& bs) { + ball.setPosition(bs.pos); + }); + + Observe(rbarPos,[](const sf::Vector2f& pos) { + rbar.setPosition(pos); + }); + Observe(lbarPos,[](const sf::Vector2f& pos) { + lbar.setPosition(pos); + }); + + + window.setKeyRepeatEnabled(false); + window.setFramerateLimit(60); + //Event loop + while(window.isOpen()) { + sf::Event event; + while (window.pollEvent(event)) { + eventStream << event; + } + window.clear(); + frameEvent << 1.f/60; //Fixed time delta + window.draw(ball); + window.draw(lbar); + window.draw(rbar); + window.display(); + } + } +} + +int main(void) { + + pong::run(); + return 0; +} From b90b79ea2d163cbf4284768169ec128882329cab Mon Sep 17 00:00:00 2001 From: stdgregwar Date: Sun, 4 Jun 2017 22:29:30 +0200 Subject: [PATCH 2/3] Switched pong example to SDL --- examples/CMakeLists.txt | 10 +-- examples/src/Pong.cpp | 192 ++++++++++++++++++++++++++++++++++++++++ examples/src/Sfml.cpp | 157 -------------------------------- 3 files changed, 197 insertions(+), 162 deletions(-) create mode 100644 examples/src/Pong.cpp delete mode 100644 examples/src/Sfml.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 96ee35bf..da87d4ef 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -39,9 +39,9 @@ add_executable(Example_Sandbox src/Main.cpp) target_link_libraries(Example_Sandbox CppReact) ### Example SFML -find_package(SFML 2 REQUIRED system window graphics network audio) -if(SFML_FOUND) - include_directories(${SFML_INCLUDE_DIR}) - add_executable(Example_SFML src/Sfml.cpp) - target_link_libraries(Example_SFML ${SFML_LIBRARIES} CppReact) +find_package(SDL) +if(SDL_FOUND) + include_directories(${SDL_INCLUDE_DIR}) + add_executable(Example_Pong src/Pong.cpp) + target_link_libraries(Example_Pong ${SDL_LIBRARY} CppReact) endif() diff --git a/examples/src/Pong.cpp b/examples/src/Pong.cpp new file mode 100644 index 00000000..8655acbd --- /dev/null +++ b/examples/src/Pong.cpp @@ -0,0 +1,192 @@ +#include + +using namespace std; + +#include +#include "react/Domain.h" +#include "react/Signal.h" +#include "react/Event.h" +#include "react/Algorithm.h" +#include + +namespace pong { + struct vec2 { + float x,y; + vec2 operator*(float s) const {return vec2{x*s,y*s};} + vec2 operator+(const vec2& o) const {return vec2{o.x+x,o.y+y};} + vec2& operator+=(const vec2& o) { + x+=o.x; + y+=o.y; + return *this; + } + bool operator==(const vec2& o) const {return o.x == x and o.y == y;} + }; + + struct rect { + vec2 pos,size; + bool contains(const vec2& v) const { + return pos.x < v.x && pos.x+size.x > v.x && pos.y < v.y && pos.y+size.y > v.y; + } + operator SDL_Rect() const { + return SDL_Rect{pos.x,pos.y,size.x,size.y}; + } + bool operator==(const rect& o) const { + return tie(pos,size) == tie(o.pos,o.size); + } + }; + + constexpr int winWidth = 480; + constexpr int winHeight = 272; + using KeyMap = unordered_map; + template + auto getOrElse(const unordered_map& m,const K& key, const V& def) -> const V& { + auto it = m.find(key); + if(it != m.end()) return it->second; + return def; + } + + template + void clamp(V& v, const W& min, const X& max) { + v = v < min ? min : v > max ? max : v; + } + + struct MovableState{ + vec2 pos; + vec2 speed; + bool operator==(const MovableState& other) const { + return tie(pos,speed) == tie(other.pos,other.speed); + } + }; + + constexpr float bounce = -1.05f; + + auto foldBallState(float dt, MovableState prev, const rect& lbar, const rect& rbar) -> MovableState { + if(prev.pos.y > winHeight || prev.pos.y < 0) { + prev.speed.y *= bounce; + clamp(prev.pos.y,0,winHeight); + } + if(prev.pos.x > winWidth || prev.pos.x < 0) { + //TODO count points + prev.speed.x*= bounce; + clamp(prev.pos.x,0,winWidth); + } + if(lbar.contains(prev.pos)) prev.speed.x *= bounce; + if(rbar.contains(prev.pos)) prev.speed.x *= bounce; + prev.pos += prev.speed*dt; + return prev; + } + + auto keysToDir(const KeyMap& m, const SDL_Event& e) -> vec2 { + float val = e.type == SDL_KEYDOWN ? 1 : -1; + return getOrElse(m,e.key.keysym.sym,{0,0})*val; + } + + constexpr float speedFac = 500; + + auto dirToSpeed(const vec2& dir, vec2 speed) -> vec2 { + return speed += dir*speedFac; + } + + auto foldBarPos(float dt, vec2 pos, const vec2& speed) -> vec2 { + auto newPos = pos+speed*dt; + return newPos; + } + + const vec2 barsSize{5,40}; + + auto posToRect(const vec2& size, const vec2& pos) -> rect { + return rect{pos,size}; + } + + //Player 1 keymap + KeyMap p1map = {{SDLK_UP,{0,-1}},{SDLK_DOWN,{0,1}}, + {SDLK_LEFT,{-1,0}},{SDLK_RIGHT,{1,0}}}; + KeyMap p2map = {{SDLK_w,{0,-1}},{SDLK_s,{0,1}}, + {SDLK_a,{-1,0}},{SDLK_d,{1,0}}}; + + + using namespace react; + REACTIVE_DOMAIN(D,sequential) + USING_REACTIVE_DOMAIN(D) + + //sf::RenderWindow window(sf::VideoMode(winWidth,winHeight),"ReactPong"); + + EventSourceT eventStream = MakeEventSource(); + EventSourceT frameEvent = MakeEventSource(); //dt of frames + + EventsT keysOnly = Filter(eventStream,[](const SDL_Event& e){return e.type == SDL_KEYDOWN || e.type == SDL_KEYUP;}); + + using namespace std::placeholders; + EventsT rmoveDirs = Transform(keysOnly,bind(keysToDir,p1map,_1)); + EventsT lmoveDirs = Transform(keysOnly,bind(keysToDir,p2map,_1)); + + SignalT rbarSpeed = Iterate(rmoveDirs, vec2{0,0}, dirToSpeed); + SignalT rbarPos = Iterate(frameEvent, vec2{winWidth-20,winHeight/2},With(rbarSpeed), foldBarPos); + SignalT rbarRect = MakeSignal(rbarPos,bind(posToRect,barsSize,_1)); + + SignalT lbarSpeed = Iterate(lmoveDirs, vec2{0,0}, dirToSpeed); + SignalT lbarPos = Iterate(frameEvent, vec2{20,winHeight/2},With(lbarSpeed), foldBarPos); + SignalT lbarRect = MakeSignal(lbarPos,bind(posToRect,barsSize,_1)); + + SignalT ballState = Iterate( + frameEvent, + MovableState{{winWidth/2,winHeight/2},{130,130}}, + With(lbarRect,rbarRect), + foldBallState + ); + + SignalT ballRect = MakeSignal(MakeSignal(ballState,[](const MovableState& s)->vec2{return s.pos;}), + bind(posToRect,vec2{5,5},_1)); + + void run() { + //Close window on sysevent close + bool quit = false; + SDL_Rect ball; + SDL_Rect lbar; + SDL_Rect rbar; + Observe(eventStream,[&](const SDL_Event& e) { + if(e.type == SDL_QUIT) quit = true; + }); + + Observe(ballRect,[&](const rect& r) { + ball = r; + }); + + Observe(rbarRect,[&](const rect& r) { + rbar = r; + }); + Observe(lbarRect,[&](const rect& r) { + lbar = r; + }); + + SDL_Surface* screen; + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTTHREAD); + screen = SDL_SetVideoMode(winWidth,winHeight,16,SDL_SWSURFACE); + + Uint32 color = SDL_MapRGB(screen->format,255,255,255); + //Event loop + while(!quit) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + eventStream << event; + } + //window.clear(); + SDL_FillRect(screen, NULL, 0x000000); + frameEvent << 1.f/60; //Fixed time delta + SDL_FillRect(screen,&ball,color); + SDL_FillRect(screen,&lbar,color); + SDL_FillRect(screen,&rbar,color); + if(SDL_Flip(screen) == -1) break; + SDL_Delay(1000/60); + } + + SDL_FreeSurface(screen); + SDL_Quit(); + } +} + +int main(void) { + + pong::run(); + return 0; +} diff --git a/examples/src/Sfml.cpp b/examples/src/Sfml.cpp deleted file mode 100644 index d72c817e..00000000 --- a/examples/src/Sfml.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include - -using namespace std; - -#include -#include "react/Domain.h" -#include "react/Signal.h" -#include "react/Event.h" -#include "react/Algorithm.h" -#include - -namespace pong { - - constexpr int winWidth = 1280; - constexpr int winHeight = 720; - using KeyMap = unordered_map; - template - auto getOrElse(const unordered_map& m,const K& key, const V& def) -> const V& { - auto it = m.find(key); - if(it != m.end()) return it->second; - return def; - } - - struct MovableState{ - sf::Vector2f pos; - sf::Vector2f speed; - bool operator==(const MovableState& other) const { - return tie(pos,speed) == tie(other.pos,other.speed); - } - }; - - constexpr float bounce = -1.2f; - - template - void clamp(V& v, const W& min, const X& max) { - v = v < min ? min : v > max ? max : v; - } - - auto foldBallState(float dt, MovableState prev, const sf::FloatRect& lbar, const sf::FloatRect& rbar) -> MovableState { - if(prev.pos.y > winHeight || prev.pos.y < 0) { - prev.speed.y *= bounce; - clamp(prev.pos.y,0,winHeight); - } - if(prev.pos.x > winWidth || prev.pos.x < 0) { - //TODO count points - prev.speed.x*= bounce; - clamp(prev.pos.x,0,winWidth); - } - if(lbar.contains(prev.pos)) prev.speed.x *= bounce; - if(rbar.contains(prev.pos)) prev.speed.x *= bounce; - prev.pos += dt* prev.speed; - return prev; - } - - auto keysToDir(const KeyMap& m, const sf::Event& e) -> sf::Vector2f { - float val = e.type == sf::Event::KeyPressed ? 1 : -1; - return getOrElse(m,e.key.code,{0,0})*val; - } - - constexpr float speedFac = 100; - - auto dirToSpeed(const sf::Vector2f& dir, sf::Vector2f speed) -> sf::Vector2f { - return speed += dir*speedFac; - } - - auto foldBarPos(float dt, sf::Vector2f pos, const sf::Vector2f& speed) -> sf::Vector2f { - auto newPos = pos+dt*speed; - return newPos; - } - - const sf::Vector2f barsSize(10,200); - - auto barPosToRect(const sf::Vector2f& pos) -> sf::FloatRect { - return sf::FloatRect(pos,barsSize); - } - - //Player 1 keymap - KeyMap p1map = {{sf::Keyboard::Up,{0,-1}},{sf::Keyboard::Down,{0,1}}, - {sf::Keyboard::Left,{-1,0}},{sf::Keyboard::Right,{1,0}}}; - KeyMap p2map = {{sf::Keyboard::W,{0,-1}},{sf::Keyboard::S,{0,1}}, - {sf::Keyboard::A,{-1,0}},{sf::Keyboard::D,{1,0}}}; - - - using namespace react; - REACTIVE_DOMAIN(D,sequential) - USING_REACTIVE_DOMAIN(D) - - sf::RenderWindow window(sf::VideoMode(winWidth,winHeight),"ReactPong"); - sf::RectangleShape lbar(barsSize); - sf::RectangleShape rbar(barsSize); - sf::RectangleShape ball({10,10}); - - EventSourceT eventStream = MakeEventSource(); - EventSourceT frameEvent = MakeEventSource(); //dt of frames - - EventsT keysOnly = Filter(eventStream,[](const sf::Event& e){return e.type == sf::Event::KeyPressed || e.type == sf::Event::KeyReleased;}); - - using namespace std::placeholders; - EventsT rmoveDirs = Transform(keysOnly,bind(keysToDir,p1map,_1)); - EventsT lmoveDirs = Transform(keysOnly,bind(keysToDir,p2map,_1)); - - SignalT rbarSpeed = Iterate(rmoveDirs, sf::Vector2f{0,0}, dirToSpeed); - SignalT rbarPos = Iterate(frameEvent, sf::Vector2f{winWidth-20,winHeight/2},With(rbarSpeed), foldBarPos); - SignalT rbarRect = MakeSignal(rbarPos,barPosToRect); - - SignalT lbarSpeed = Iterate(lmoveDirs, sf::Vector2f{0,0}, dirToSpeed); - SignalT lbarPos = Iterate(frameEvent, sf::Vector2f{20,winHeight/2},With(lbarSpeed), foldBarPos); - SignalT lbarRect = MakeSignal(lbarPos,barPosToRect); - - SignalT ballState = Iterate( - frameEvent, - MovableState{{winWidth/2,winHeight/2},{130,130}}, - With(lbarRect,rbarRect), - foldBallState - ); - - void run() { - //Close window on sysevent close - Observe(eventStream,[](const sf::Event& e) { - if(e.type == sf::Event::Closed) window.close(); - }); - - Observe(ballState,[](const MovableState& bs) { - ball.setPosition(bs.pos); - }); - - Observe(rbarPos,[](const sf::Vector2f& pos) { - rbar.setPosition(pos); - }); - Observe(lbarPos,[](const sf::Vector2f& pos) { - lbar.setPosition(pos); - }); - - - window.setKeyRepeatEnabled(false); - window.setFramerateLimit(60); - //Event loop - while(window.isOpen()) { - sf::Event event; - while (window.pollEvent(event)) { - eventStream << event; - } - window.clear(); - frameEvent << 1.f/60; //Fixed time delta - window.draw(ball); - window.draw(lbar); - window.draw(rbar); - window.display(); - } - } -} - -int main(void) { - - pong::run(); - return 0; -} From 145765cf3ff626d8b1d6c0ea77f59ab3138e761a Mon Sep 17 00:00:00 2001 From: stdgregwar Date: Mon, 5 Jun 2017 22:11:22 +0200 Subject: [PATCH 3/3] some constants --- examples/src/Pong.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/src/Pong.cpp b/examples/src/Pong.cpp index 8655acbd..85394ba5 100644 --- a/examples/src/Pong.cpp +++ b/examples/src/Pong.cpp @@ -37,7 +37,14 @@ namespace pong { constexpr int winWidth = 480; constexpr int winHeight = 272; + constexpr float bounce = -1.05f; + const vec2 barsSize{5,40}; + constexpr float speedFac = 500; + constexpr float ballRadius = 5; + const vec2 ballStartSpeed{130,130}; + using KeyMap = unordered_map; + template auto getOrElse(const unordered_map& m,const K& key, const V& def) -> const V& { auto it = m.find(key); @@ -58,7 +65,6 @@ namespace pong { } }; - constexpr float bounce = -1.05f; auto foldBallState(float dt, MovableState prev, const rect& lbar, const rect& rbar) -> MovableState { if(prev.pos.y > winHeight || prev.pos.y < 0) { @@ -81,7 +87,6 @@ namespace pong { return getOrElse(m,e.key.keysym.sym,{0,0})*val; } - constexpr float speedFac = 500; auto dirToSpeed(const vec2& dir, vec2 speed) -> vec2 { return speed += dir*speedFac; @@ -92,7 +97,6 @@ namespace pong { return newPos; } - const vec2 barsSize{5,40}; auto posToRect(const vec2& size, const vec2& pos) -> rect { return rect{pos,size}; @@ -130,13 +134,13 @@ namespace pong { SignalT ballState = Iterate( frameEvent, - MovableState{{winWidth/2,winHeight/2},{130,130}}, + MovableState{{winWidth/2,winHeight/2},ballStartSpeed}, With(lbarRect,rbarRect), foldBallState ); SignalT ballRect = MakeSignal(MakeSignal(ballState,[](const MovableState& s)->vec2{return s.pos;}), - bind(posToRect,vec2{5,5},_1)); + bind(posToRect,vec2{ballRadius,ballRadius},_1)); void run() { //Close window on sysevent close