diff --git a/README.md b/README.md index 3c01c001..9c542961 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![Logo](https://github.com/MichaelMoroz/MarbleMarcher/blob/master/doc/LOGO.PNG) -This is the community edition of Marble Marcher, a procedurally rendered fractal physics marble game in which you must get to the flag in each level as fast as you can. With 24 levels to unlock and an active [speedrunning community](https://www.speedrun.com/marblemarcher), along with a rudimentary level editor, there's always new features being developed. If you complete all levels, you can use cheats to create and enhance a more exploratory experience. +This is the community edition of Marble Marcher, a procedurally rendered fractal physics marble game in which you must get to the flag in each level as fast as you can. With 24 levels to unlock and an active [speedrunning community](https://www.speedrun.com/marblemarcher), along with a fully-featured level editor, there's always new features being developed. If you complete all levels, you can use cheats to create and enhance a more exploratory experience. Because version 1.1.0 was the last feature update of Marble Marcher, we (the Marble Marcher Community) opted to create a community edition to keep the community around the game alive and continuously improve the experience. Currently this is maintained mainly by members of the [Marble Marcher Community on Discord](https://discord.gg/r3XrJxH), in addition to the members of the [subreddit](https://www.reddit.com/r/marblemarcher) and anyone else who has contributed. diff --git a/src/Gamemodes.cpp b/src/Gamemodes.cpp index 9a859b7a..616000ba 100644 --- a/src/Gamemodes.cpp +++ b/src/Gamemodes.cpp @@ -307,13 +307,29 @@ void OpenControlMenu(Scene * scene, Overlays * overlays) controls.AddObject(&Box(800, 0), Object::Allign::CENTER); - - Text cntrl(LOCAL["DetailControls"], LOCAL("default"), 50, sf::Color::White); - cntrl.SetBorderColor(sf::Color::Black); - cntrl.SetBorderWidth(4); - controls.AddObject(&cntrl, Object::Allign::LEFT); - - + controls.AddObject(&Text(LOCAL["Keyboard Controls"], LOCAL("default"), 50), Object::Allign::LEFT); + controls.AddObject(&Box(800, 0), Object::Allign::CENTER); + controls.AddObject(&KeyMapper(LOCAL["UP"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[UP], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["DOWN"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[DOWN], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["LEFT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[LEFT], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["RIGHT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[RIGHT], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["VIEWUP"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[VIEWUP], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["VIEWDOWN"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[VIEWDOWN], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["VIEWLEFT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[VIEWLEFT], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["VIEWRIGHT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[VIEWRIGHT], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["PAUSE"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[PAUSE], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["RESTART"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[RESTART], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["SCREENSHOT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[SCREENSHOT], 1200.f, 50.f, KeyMapper::MapperType::KEYBOARD), Object::Allign::LEFT); + controls.AddObject(&Box(800, 0), Object::Allign::CENTER); + controls.AddObject(&Text(LOCAL["Gamepad Controls"], LOCAL("default"), 50), Object::Allign::LEFT); + controls.AddObject(&Box(800, 0), Object::Allign::CENTER); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_MOVE_AXIS_X"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_MOVE_AXIS_X], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_AXIS), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_MOVE_AXIS_Y"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_MOVE_AXIS_Y], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_AXIS), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_VIEW_AXIS_X"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_VIEW_AXIS_X], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_AXIS), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_VIEW_AXIS_Y"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_VIEW_AXIS_Y], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_AXIS), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_EXIT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_EXIT], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_KEYS), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_SCREENSHOT"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_SCREENSHOT], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_KEYS), Object::Allign::LEFT); + controls.AddObject(&KeyMapper(LOCAL["JOYSTICK_RESTART"], LOCAL["Waiting for input"], &SETTINGS.stg.control_mapping[JOYSTICK_RESTART], 1200.f, 50.f, KeyMapper::MapperType::JOYSTICK_KEYS), Object::Allign::LEFT); AddGlobalObject(controls); } diff --git a/src/Interface.cpp b/src/Interface.cpp index b1fe5a0c..86bd1590 100644 --- a/src/Interface.cpp +++ b/src/Interface.cpp @@ -153,6 +153,43 @@ void Add2DeleteQueue(int id) } } +std::string key_name(sf::Keyboard::Key & key) +{ + //yeah, I dont like this code either +#define ITEM(x) case sf::Keyboard:: ## x : return #x; + switch (key) + { + ITEM(A); ITEM(B); ITEM(C); + ITEM(D); ITEM(E); ITEM(F); ITEM(G); + ITEM(H); ITEM(I); ITEM(J); ITEM(K); + ITEM(L); ITEM(M); ITEM(N); ITEM(O); + ITEM(P); ITEM(Q); ITEM(R); ITEM(S); + ITEM(T); ITEM(U); ITEM(V); ITEM(W); + ITEM(X); ITEM(Y); ITEM(Z); ITEM(Num0); + ITEM(Num1); ITEM(Num2); ITEM(Num3); ITEM(Num4); + ITEM(Num5); ITEM(Num6); ITEM(Num7); ITEM(Num8); + ITEM(Num9); ITEM(Escape); ITEM(LControl); ITEM(LShift); + ITEM(LAlt); ITEM(LSystem); ITEM(RControl); ITEM(RShift); + ITEM(RAlt); ITEM(RSystem); ITEM(Menu); ITEM(LBracket); + ITEM(RBracket); ITEM(Semicolon); ITEM(Comma); ITEM(Period); + ITEM(Quote); ITEM(Slash); ITEM(Backslash); ITEM(Tilde); + ITEM(Equal); ITEM(Hyphen); ITEM(Space); ITEM(Enter); + ITEM(Backspace); ITEM(Tab); ITEM(PageUp); ITEM(PageDown); + ITEM(End); ITEM(Home); ITEM(Insert); ITEM(Delete); + ITEM(Add); ITEM(Subtract); ITEM(Multiply); ITEM(Divide); + ITEM(Left); ITEM(Right); ITEM(Up); ITEM(Down); + ITEM(Numpad0); ITEM(Numpad1); ITEM(Numpad2); ITEM(Numpad3); + ITEM(Numpad4); ITEM(Numpad5); ITEM(Numpad6); ITEM(Numpad7); + ITEM(Numpad8); ITEM(Numpad9); ITEM(F1); ITEM(F2); + ITEM(F3); ITEM(F4); ITEM(F5); ITEM(F6); + ITEM(F7); ITEM(F8); ITEM(F9); ITEM(F10); + ITEM(F11); ITEM(F12); ITEM(F13); ITEM(F14); + ITEM(F15); ITEM(Pause); + default: + return "UNKNOWN"; + } +} + void UpdateAllObjects(sf::RenderWindow * window, InputState& state) { for (auto &id : del) @@ -1185,3 +1222,96 @@ Object * Image::GetCopy() Image::~Image() { } + +KeyMapper::KeyMapper(KeyMapper & A) +{ + *this = A; +} + +KeyMapper::KeyMapper(KeyMapper && A) +{ + *this = A; +} + +void KeyMapper::operator=(KeyMapper & A) +{ + Box::operator=(A); + this_type = A.this_type; + key_ptr = A.key_ptr; + CreateCallbacks(); +} + +void KeyMapper::operator=(KeyMapper && A) +{ + Box::operator=(A); + std::swap(this_type, A.this_type); + std::swap(key_ptr, A.key_ptr); + CreateCallbacks(); +} + +void KeyMapper::CreateCallbacks() +{ + /*//use lambda funtion + this->objects[1].get()->objects[0].get()->SetMainCallbackFunction([parent = this](sf::RenderWindow * window, InputState & state) + { + float inside_size = parent->objects[0].get()->defaultstate.inside_size; + float height_1 = parent->objects[1].get()->defaultstate.size.y - 2 * parent->objects[1].get()->defaultstate.margin; + float height_2 = parent->objects[1].get()->objects[0].get()->defaultstate.size.y; + float max_slide_scroll = height_1 - height_2; + //relative scroll coefficient + float rel_coef = (inside_size - height_1) / max_slide_scroll; + parent->ScrollBy(state.mouse_speed.y*rel_coef); + }, false); + + this->SetMainHoverFunction([parent = this](sf::RenderWindow * window, InputState & state) + { + //wheel scroll + if (state.wheel != 0.f) + { + float ds = 20.f; + parent->ScrollBy(-state.wheel*ds); + } + }); + + this->SetMainDefaultFunction([parent = this](sf::RenderWindow * window, InputState & state) + { + bool A = false; + + if (state.keys[sf::Keyboard::Up]) + { + parent->Cursor(-1); + A = 1; + } + + if (state.keys[sf::Keyboard::Down]) + { + parent->Cursor(1); + A = 1; + } + + if (state.keys[sf::Keyboard::Enter]) + { + //run the callback function of the chosen object + A = parent->objects[0].get()->objects[parent->cursor_id].get()->RunCallback(window, state); + } + + if (A) parent->action_time = action_dt; + + A = false; + + if (state.key_press[sf::Keyboard::Up]) + { + parent->action_time = action_dt / 4; + } + + if (state.key_press[sf::Keyboard::Down]) + { + parent->action_time = action_dt / 4; + } + });*/ +} + +Object * KeyMapper::GetCopy() +{ + return static_cast(new KeyMapper(*this)); +} diff --git a/src/Interface.h b/src/Interface.h index 69fe220c..e84f9906 100644 --- a/src/Interface.h +++ b/src/Interface.h @@ -387,5 +387,48 @@ inline Button::Button(T text, float w, float h, std::functionAddObject(&button_text, Object::Allign::CENTER); + this->AddObject(&button_text,Object::Allign::CENTER); +} + +std::string key_name(sf::Keyboard::Key& key); + +//basic object for control mapping +class KeyMapper : public Box +{ +public: + enum MapperType { + KEYBOARD, JOYSTICK_AXIS, JOYSTICK_KEYS + }; + + template + KeyMapper(T label, T act_label, int* key, float w, float h, MapperType type, sf::Color color_active = sf::Color::Blue, sf::Color color_hover = default_hover_main_color, sf::Color color_main = default_main_color); + + KeyMapper(KeyMapper& A); + KeyMapper(KeyMapper&& A); + + void operator=(KeyMapper& A); + void operator=(KeyMapper&& A); + + void CreateCallbacks(); + + virtual Object* GetCopy(); + + MapperType this_type; + int *key_ptr; +}; + +template +inline KeyMapper::KeyMapper(T label, T act_label, int * key, float w, float h, MapperType type, sf::Color color_active, sf::Color color_hover, sf::Color color_main) +{ + SetSize(w, h); + this_type = type; + SetBackgroundColor(color_main); + Box LeftBox(0, 0, float(w * 0.5f), h-defaultstate.margin*2.f, sf::Color(0, 100, 200, 0)), + RightBox(0, 0, float(w * 0.33f), h - defaultstate.margin * 2.f, sf::Color(0, 100, 200, 128)); + LeftBox.AddObject(&Text(label, LOCAL("default"), h*0.7f, sf::Color::White), Allign::LEFT); + RightBox.AddObject(&Text(act_label, LOCAL("default"), h*0.7f, sf::Color::White), Allign::RIGHT); + RightBox.activestate.color_main = color_active; + hoverstate.color_main = color_hover; + this->AddObject(&LeftBox,Allign::LEFT); + this->AddObject(&RightBox, Allign::RIGHT); } diff --git a/src/Main.cpp b/src/Main.cpp index 9181fa78..44f21801 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -136,8 +136,6 @@ int main(int argc, char *argv[]) { OpenMainMenu(&scene, &overlays); } - DisplayError("Empty error"); - #define n_touch 5 sf::Vector2i touch_xy[n_touch]; sf::Vector2i touch_pxy[n_touch]; diff --git a/src/Settings.h b/src/Settings.h index 20bce42c..ee140d99 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -23,10 +23,12 @@ #include namespace fs = std::filesystem; -const int num_of_keys = 14; +const int num_of_keys = 18; enum KEYS { UP, DOWN, LEFT, RIGHT, VIEWUP, VIEWDOWN, VIEWLEFT, VIEWRIGHT, - JOYSTICK_MOVE_AXIS_X, JOYSTICK_MOVE_AXIS_Y, JOYSTICK_VIEW_AXIS_X, JOYSTICK_VIEW_AXIS_Y, JOYSTICK_EXIT, JOYSTICK_SCREENSHOT + PAUSE, RESTART, SCREENSHOT, + JOYSTICK_MOVE_AXIS_X, JOYSTICK_MOVE_AXIS_Y, JOYSTICK_VIEW_AXIS_X, JOYSTICK_VIEW_AXIS_Y, + JOYSTICK_EXIT, JOYSTICK_SCREENSHOT, JOYSTICK_RESTART }; struct MainSettings @@ -81,9 +83,11 @@ struct MainSettings }; extern TwEnumVal resolutions[]; -static const std::array default_control_mapping = { sf::Keyboard::W, sf::Keyboard::S, sf::Keyboard::A, sf::Keyboard::D, - sf::Keyboard::Up, sf::Keyboard::Down, sf::Keyboard::Left, sf::Keyboard::Right, - 1, 2, 3, 4, 1, 2}; +static const std::array default_control_mapping = +{ sf::Keyboard::W, sf::Keyboard::S, sf::Keyboard::A, sf::Keyboard::D, + sf::Keyboard::P, sf::Keyboard::R, sf::Keyboard::F5, + sf::Keyboard::Up, sf::Keyboard::Down, sf::Keyboard::Left, sf::Keyboard::Right, + 1, 2, 3, 4, 1, 2, 3}; //an incomprehensible wall of default parameters static const MainSettings default_settings = {