git repos / saland

commit 148e781e

sago007 · 2018-10-28 11:51
148e781ea16aa7f11fbdb4fc18f43f6d2517beac patch · browse files
parent ee1fd5110bc336dfc1fd5d0625f7059f06348576

Add start menu

Changed files

A data/sprites/menu.sprite
A src/MenuSystem.cpp
A src/MenuSystem.h
A src/global.hpp
M src/saland.cpp before
M src/saland/globals.hpp before
diff --git a/data/sprites/menu.sprite b/data/sprites/menu.sprite new file mode 100644 index 0000000..adc68eb --- /dev/null +++ b/data/sprites/menu.sprite
@@ -0,0 +1,22 @@
+{
+
+"menu_marked" : {
+ "texture" : "menu_marked",
+ "topx" : 0,
+ "topy" : 0,
+ "height" : 60,
+ "width" : 600,
+ "number_of_frames" : 1,
+ "frame_time" : 1
+},
+"menu_unmarked" : {
+ "texture" : "menu_unmarked",
+ "topx" : 0,
+ "topy" : 0,
+ "height" : 60,
+ "width" : 600,
+ "number_of_frames" : 1,
+ "frame_time" : 1
+}
+
+}
diff --git a/src/MenuSystem.cpp b/src/MenuSystem.cpp new file mode 100644 index 0000000..b383a93 --- /dev/null +++ b/src/MenuSystem.cpp
@@ -0,0 +1,350 @@
+/*
+===========================================================================
+blockattack - Block Attack - Rise of the Blocks
+Copyright (C) 2005-2012 Poul Sander
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program. If not, see http://www.gnu.org/licenses/
+
+Source information and contacts persons can be found at
+https://blockattack.net
+===========================================================================
+*/
+
+
+#include "MenuSystem.h"
+#include "common.h"
+#include "global.hpp"
+
+static int oldmousex = 0;
+static int oldmousey = 0;
+
+const char* const menu_marked = "menu_marked";
+const char* const menu_unmarked = "menu_unmarked";
+
+ButtonGfx standardButton;
+
+void ButtonGfx::setSurfaces() {
+ this->xsize = globalData.spriteHolder->GetSprite(menu_marked).GetWidth();
+ this->ysize = globalData.spriteHolder->GetSprite(menu_marked).GetHeight();
+ if (globalData.verboseLevel) {
+ std::cout << "Surfaces set, size: " << this->xsize << " , " << this->ysize << "\n";
+ }
+}
+
+sago::SagoTextField* ButtonGfx::getLabel(const std::string& text) {
+ const auto& theLabel = labels.find(text);
+ if (theLabel != labels.end()) {
+ return labels[text].get();
+ }
+ std::shared_ptr<sago::SagoTextField> newField = std::make_shared<sago::SagoTextField>();
+ newField->SetHolder(&globalData.spriteHolder->GetDataHolder());
+ newField->SetFont("freeserif");
+ newField->SetFontSize(30);
+ newField->SetOutline(1, {64,64,64,255});
+ newField->SetText(text);
+ labels[text] = newField;
+ return labels[text].get();
+}
+
+Button::Button() {
+ label = "";
+ marked = false;
+ action = nullptr;
+ popOnRun = false;
+}
+
+Button::~Button() {
+}
+
+Button::Button(const Button& b) {
+ label = b.label;
+ marked = b.marked;
+ action = b.action;
+ popOnRun = false;
+}
+
+void Button::setLabel(const std::string& text) {
+ label = text;
+}
+
+void Button::setAction(void (*action2run)(void)) {
+ action = action2run;
+}
+
+void Button::doAction() {
+ if (action) {
+ action();
+ return;
+ }
+ std::cerr << "Warning: button \"" << label << "\" has no action assigned!";
+}
+
+void Button::setPopOnRun(bool popOnRun) {
+ this->popOnRun = popOnRun;
+}
+
+bool Button::isPopOnRun() const {
+ return popOnRun;
+}
+
+static void drawToScreen(const Button& b) {
+ if (b.marked) {
+ globalData.spriteHolder->GetSprite(menu_marked).Draw(globalData.screen, SDL_GetTicks(), b.x, b.y);
+ }
+ else {
+ globalData.spriteHolder->GetSprite(menu_unmarked).Draw(globalData.screen, SDL_GetTicks(), b.x, b.y);
+ }
+
+ standardButton.getLabel(b.label)->Draw(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2,
+ sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::center);
+ //standardButton.thefont->drawCenterAlsoHeight(globalData.screen, b.x+standardButton.xsize/2,b.y+standardButton.ysize/2, b.label);
+}
+
+
+static bool isClicked(const Button& b, int x,int y) {
+ if ( x >= b.x && y >= b.y && x<= b.x+standardButton.xsize && y <= b.y + standardButton.ysize) {
+ return true;
+ }
+ return false;
+}
+
+void Menu::drawSelf(SDL_Renderer* target) {
+ for (const Button* b : buttons) {
+ drawToScreen(*b);
+ }
+ drawToScreen(exit);
+ standardButton.getLabel(title)->Draw(target, 50, 50);
+}
+
+
+void Menu::placeButtons() {
+ int nextY = 100;
+ int X = 50;
+ for (Button* it : buttons) {
+ X = (globalData.xsize - standardButton.xsize)/2;
+ it->x = X;
+ it->y = nextY;
+ nextY += standardButton.ysize+10;
+ }
+ exit.x = X;
+ exit.y = nextY;
+}
+
+void Menu::addButton(Button* b) {
+ buttons.push_back(b);
+ b->marked = false;
+ placeButtons();
+}
+
+Menu::Menu(SDL_Renderer* screen) {
+ this->screen = screen;
+ buttons = std::vector<Button*>(10);
+ isSubmenu = true;
+ exit.setLabel( _("Back") );
+}
+
+Menu::Menu(SDL_Renderer* screen,bool submenu) {
+ this->screen = screen;
+ buttons = std::vector<Button*>(0);
+ isSubmenu = submenu;
+ if (isSubmenu) {
+ exit.setLabel( _("Back") );
+ }
+ else {
+ exit.setLabel( _("Exit") );
+ }
+}
+
+Menu::Menu(SDL_Renderer* screen, const std::string& title, bool submenu) {
+ this->screen = screen;
+ buttons = std::vector<Button*>(0);
+ isSubmenu = submenu;
+ this->title = title;
+ if (isSubmenu) {
+ exit.setLabel(_("Back") );
+ }
+ else {
+ exit.setLabel(_("Exit") );
+ }
+}
+
+bool isUpEvent(const SDL_Event& event) {
+ if ( event.type == SDL_KEYDOWN ) {
+ if (event.key.keysym.sym == SDLK_UP) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isDownEvent(const SDL_Event& event) {
+ if ( event.type == SDL_KEYDOWN ) {
+ if (event.key.keysym.sym == SDLK_DOWN) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isLeftEvent(const SDL_Event& event) {
+ if ( event.type == SDL_KEYDOWN ) {
+ if (event.key.keysym.sym == SDLK_LEFT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isRightEvent(const SDL_Event& event) {
+ if ( event.type == SDL_KEYDOWN ) {
+ if (event.key.keysym.sym == SDLK_RIGHT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isEscapeEvent(const SDL_Event& event) {
+ if ( event.type == SDL_KEYDOWN ) {
+ if ( event.key.keysym.sym == SDLK_ESCAPE ) {
+ return true;
+ }
+ }
+ if (event.type == SDL_CONTROLLERBUTTONDOWN) {
+ if (event.cbutton.button == SDL_CONTROLLER_BUTTON_Y || event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isConfirmEvent(const SDL_Event& event) {
+ if ( event.type == SDL_KEYDOWN ) {
+ if (event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER ) {
+ return true;
+ }
+ }
+ if (event.type == SDL_CONTROLLERBUTTONDOWN) {
+ if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A || event.cbutton.button == SDL_CONTROLLER_BUTTON_B ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Menu::IsActive() {
+ return running;
+}
+void Menu::Draw(SDL_Renderer* target) {
+ placeButtons();
+ drawSelf(target);
+#if DEBUG
+ static unsigned long int Frames;
+ static unsigned long int Ticks;
+ static char FPS[10];
+ static sago::SagoTextField fpsField;
+ sagoTextSetBlueFont(fpsField);
+ Frames++;
+ if (SDL_GetTicks() >= Ticks + 1000) {
+ if (Frames > 999) {
+ Frames=999;
+ }
+ snprintf(FPS, sizeof(FPS), "%lu fps", Frames);
+ Frames = 0;
+ Ticks = SDL_GetTicks();
+ }
+ fpsField.SetText(FPS);
+ fpsField.Draw(globalData.screen, 800, 4);
+#endif
+}
+void Menu::ProcessInput(const SDL_Event& event, bool& processed) {
+ if (isUpEvent(event)) {
+ marked--;
+ if (marked<0) {
+ marked = buttons.size(); //not -1, since exit is after the last element in the list
+ }
+ processed = true;
+ }
+
+ if (isDownEvent(event)) {
+ marked++;
+ if (marked> (int)buttons.size()) {
+ marked = 0;
+ }
+ processed = true;
+ }
+
+ if (isEscapeEvent(event) && isSubmenu) {
+ running = false;
+ processed = true;
+ }
+
+ if (isConfirmEvent(event)) {
+ if (marked < (int)buttons.size()) {
+ buttons.at(marked)->doAction();
+ if (buttons.at(marked)->isPopOnRun()) {
+ running = false;
+ }
+ }
+ if (marked == (int)buttons.size()) {
+ running = false;
+ }
+ processed = true;
+ }
+}
+
+void Menu::Update() {
+ for (int i=0; i<(int)buttons.size(); i++) {
+ buttons.at(i)->marked = (i == marked);
+ }
+ exit.marked = (marked == (int)buttons.size());
+ Uint8 buttonState = SDL_GetMouseState(nullptr,nullptr);
+ // If the mouse button is released, make bMouseUp equal true
+ if ( (buttonState&SDL_BUTTON(1))==0) {
+ bMouseUp=true;
+ }
+
+ if (abs(globalData.mousex-oldmousex)>5 || abs(globalData.mousey-oldmousey)>5) {
+ for (int i=0; i< (int)buttons.size(); ++i) {
+ if (isClicked(*buttons.at(i), globalData.mousex, globalData.mousey)) {
+ marked = i;
+ }
+ }
+ if (isClicked(exit, globalData.mousex, globalData.mousey)) {
+ marked = buttons.size();
+ }
+ oldmousex = globalData.mousex;
+ oldmousey = globalData.mousey;
+ }
+
+ //mouse clicked
+ if ( (buttonState&SDL_BUTTON(1) )==SDL_BUTTON(1) && bMouseUp) {
+ bMouseUp = false;
+ for (int i=0; i< (int)buttons.size(); ++i) {
+ if (isClicked(*buttons.at(i), globalData.mousex, globalData.mousey)) {
+ buttons.at(i)->doAction();
+ if (buttons.at(i)->isPopOnRun()) {
+ running = false;
+ }
+ //Quit here to ensure that we do not continue checking buttons after we have done the action.
+ return;
+ }
+ }
+ if (isClicked(exit, globalData.mousex, globalData.mousey)) {
+ running = false;
+ }
+ }
+}
+
diff --git a/src/MenuSystem.h b/src/MenuSystem.h new file mode 100644 index 0000000..cf3016f --- /dev/null +++ b/src/MenuSystem.h
@@ -0,0 +1,144 @@
+/*
+===========================================================================
+blockattack - Block Attack - Rise of the Blocks
+Copyright (C) 2005-2012 Poul Sander
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program. If not, see http://www.gnu.org/licenses/
+
+Source information and contacts persons can be found at
+http://blockattack.net
+===========================================================================
+*/
+
+
+#ifndef _MENUSYSTEM_H
+#define _MENUSYSTEM_H
+
+#include <string>
+#include "SDL.h"
+#include <map>
+#include <vector>
+#include "sago/SagoSprite.hpp"
+#include "sago/GameStateInterface.hpp"
+#include <memory>
+#include "sago/SagoTextField.hpp"
+
+//The ButtonGfx object hold common media for all buttons, so we can reskin them by only changeing one pointer
+struct ButtonGfx
+{
+ //The size of the buttons, so we don't have to ask w and h from the SDL Surfaces each time
+ int xsize = 0;
+ int ysize = 0;
+ sago::SagoTextField* getLabel(const std::string& text);
+ void setSurfaces();
+private:
+ std::map<std::string, std::shared_ptr<sago::SagoTextField> > labels;
+};
+
+extern ButtonGfx standardButton;
+
+//A button
+class Button
+{
+private:
+ //Pointer to a callback function.
+ void (*action)(void);
+
+ //If true the menu should also be closed then the button is clicked
+ bool popOnRun = false;
+
+public:
+ //The label. This is written on the button
+ std::string label;
+ //Is the button marked?
+ bool marked = false;
+ //Where is the button on the screen
+ int x = 0;
+ int y = 0;
+
+ Button();
+ Button(const Button& b);
+ virtual ~Button();
+
+
+ //Set the text to write on the button
+ void setLabel(const std::string& text);
+ //Set the action to run
+ void setAction(void (*action2run)(void));
+
+ virtual void doAction(); //Run the callback function
+ void setPopOnRun(bool popOnRun);
+ bool isPopOnRun() const;
+
+ //May hold any other information the callback might need
+ int iGeneric1 = 0;
+};
+
+
+class Menu : public sago::GameStateInterface
+{
+private:
+ std::vector<Button*> buttons; //Vector holder the buttons
+ Button exit; //The exit button is special since it does not have a callback function
+ bool isSubmenu = false; //True if the menu is a submenu
+ int marked = 0; //The index of the marked button (for keyboard up/down)
+ bool running = true; //The menu is running. The menu will terminate then this is false
+ SDL_Renderer *screen = nullptr; //Pointer to the screen to draw to
+ std::string title;
+ void drawSelf(SDL_Renderer* target); //Private function to draw the screen
+ void placeButtons(); //Rearanges the buttons to the correct place.
+ bool bMouseUp = false;
+public:
+ //numberOfItems is the expected numberOfItems for vector initialization
+ //SubMenu is true by default
+ Menu(SDL_Renderer *screen,bool isSubmenu);
+ Menu(SDL_Renderer *screen);
+ Menu(SDL_Renderer *screen, const std::string& title, bool isSubmenu);
+ virtual ~Menu() {}
+
+ //Add a button to the menu
+ void addButton(Button *b);
+
+ bool IsActive() override;
+ void Draw(SDL_Renderer* target) override;
+ void ProcessInput(const SDL_Event& event, bool &processed) override;
+ void Update() override;
+};
+
+class FileMenu
+{
+private:
+ std::string pm_path;
+ std::string pm_fileending;
+ bool pm_hidden_files = false;
+public:
+ FileMenu(const std::string& path, const std::string& fileending, bool hidden_files = false);
+
+ std::string getFile(SDL_Surface **screen);
+};
+
+bool isUpEvent(const SDL_Event& event);
+
+bool isDownEvent(const SDL_Event& event);
+
+bool isLeftEvent(const SDL_Event& event);
+
+bool isRightEvent(const SDL_Event& event);
+
+bool isEscapeEvent(const SDL_Event& event);
+
+bool isConfirmEvent(const SDL_Event& event);
+
+#endif /* _MENUSYSTEM_H */
+
diff --git a/src/global.hpp b/src/global.hpp new file mode 100644 index 0000000..b1d73d0 --- /dev/null +++ b/src/global.hpp
@@ -0,0 +1,30 @@
+/*
+===========================================================================
+ * Saland Adventures
+Copyright (C) 2014-2018 Poul Sander
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program. If not, see http://www.gnu.org/licenses/
+
+Source information and contacts persons can be found at
+https://github.com/sago007/saland
+===========================================================================
+*/
+
+#ifndef GLOBAL_HPP
+#define GLOBAL_HPP
+
+#include "saland/globals.hpp"
+
+#endif /* GLOBAL_HPP */
+
diff --git a/src/saland.cpp b/src/saland.cpp index a4ec3bd..38d7339 100644 --- a/src/saland.cpp +++ b/src/saland.cpp
@@ -45,6 +45,8 @@ https://github.com/sago007/saland
#include "sagotmx/tmx_struct.h"
#include "sago/SagoTextBox.hpp"
+#include "MenuSystem.h"
+
#include "common.h"
#include "os.hpp"
#include "version.h"
@@ -141,6 +143,11 @@ void RunGameState(sago::GameStateInterface& state ) {
}
}
+void startWorld() {
+ Game g;
+ RunGameState(g);
+}
+
void runGame() {
int posX = 100, posY = 100, width = 1024, height = 768;
SDL_Init(SDL_INIT_VIDEO);
@@ -157,8 +164,13 @@ void runGame() {
TitleScreen ts;
RunGameState(ts);
- Game g;
- RunGameState(g);
+ standardButton.setSurfaces();
+ Menu m(globalData.screen, false);
+ Button bStart;
+ bStart.setLabel("Start");
+ bStart.setAction(startWorld);
+ m.addButton(&bStart);
+ RunGameState(m);
SDL_DestroyRenderer(globalData.screen);
SDL_DestroyWindow(win);
diff --git a/src/saland/globals.hpp b/src/saland/globals.hpp index 93dafe1..6b68f96 100644 --- a/src/saland/globals.hpp +++ b/src/saland/globals.hpp
@@ -32,6 +32,10 @@ struct GlobalData {
SDL_Renderer* screen = nullptr;
std::unique_ptr<sago::SagoSpriteHolder> spriteHolder;
sago::SagoDataHolder* dataHolder;
+ int verboseLevel = 0;
+ int mousex = 0;
+ int mousey = 0;
+ int xsize = 1024;
};
extern GlobalData globalData;