cakefoot/src/Cakefoot.hpp

208 lines
6.2 KiB
C++

/* >> Cakefoot << */
#pragma once
/* Needed for functions in glm/gtx/ */
#define GLM_ENABLE_EXPERIMENTAL
/* Standard library includes */
#include <stdlib.h>
#include <string>
#include <iostream>
#include <iomanip>
#include <map>
#include <memory>
#include <functional>
#include <malloc.h>
/* Include Game.hpp before any other SDL-related headers because it defines SDL_MAIN_HANDLED */
#include "Game.hpp"
/* SPACEBOX external libraries included in source package */
#include "sdl2-gfx/SDL2_gfxPrimitives.h"
#include "json/json.hpp"
#include "glm/glm.hpp"
#include "glm/gtx/matrix_decompose.hpp"
#include "glm/gtc/matrix_access.hpp"
/* SPACEBOX classes and functions */
#include "Color.hpp"
#include "extension.hpp"
#include "filesystem.hpp"
#include "Animation.hpp"
#include "Texture.hpp"
#include "GLObject.hpp"
#include "Log.hpp"
#include "Attributes.hpp"
#include "VBO.hpp"
#include "Model.hpp"
#include "Box.hpp"
#include "Switch.hpp"
#include "Selection.hpp"
#include "math.hpp"
#include "Configuration.hpp"
#include "Timer.hpp"
#include "Text.hpp"
#include "Segment.hpp"
#include "Input.hpp"
/* Project classes */
#include "Character.hpp"
#include "Sprite.hpp"
#include "Pad.hpp"
#include "Curve.hpp"
#include "Enemy.hpp"
/*!
* The main game object. There is currently only support for one of these to exist at a time.
*
* Note: the conversion for pixel distance from the original 864x468 coordinate system to this program's NDC coordinate system is
*
* f(distance) = distance / 486.0 * 2
*
* Note: the conversion for pixel speed values from the original Python version's per-frame, fixed 25fps, 864x468 coordinate system to
* this program's per-second, adjustable framerate, NDC coordinate system is below. This gives the speed in amount of NDC to travel per
* second. For non-pixel values, just multiply by 25.
*
* f(speed) = speed / 486.0 * 25 * 2
*/
class Cakefoot : public sb::Game
{
private:
/* Convention for calling parent class in a consistent way across classes */
typedef sb::Game super;
/* Static members */
inline static std::string reset_command_name = "reset";
const inline static std::string progress_file_path = "storage/cakefoot_progress.json";
/* Member vars */
std::shared_ptr<SDL_Cursor> poke, grab;
int previous_frames_per_second = 0, curve_index = 0, curve_byte_count = 0, level_index = 0, level_select_index = 1, profile_index = 0;
std::map<std::string, GLuint> uniform;
GLuint shader_program;
glm::mat4 view {1.0f}, projection {1.0f};
sb::VAO vao;
sb::VBO vbo;
std::map<std::string, sb::Pad<>> button = {
{"start", sb::Pad<>()},
{"resume", sb::Pad<>()},
{"reset", sb::Pad<>()},
{"level increment", sb::Pad<>()},
{"level decrement", sb::Pad<>()},
{"pause", sb::Pad<>()},
{"profile increment", sb::Pad<>()},
{"profile decrement", sb::Pad<>()},
{"volume", sb::Pad<>()}
};
std::map<std::string, sb::Text> label = {
{"fps", sb::Text(font())},
{"clock", sb::Text(font())},
{"level", sb::Text(font())},
{"level select", sb::Text(font())},
{"profile", sb::Text(font())}
};
sb::Sprite playing_field, checkpoint_on, checkpoint_off, coin {"resource/coin/coin-0.png", glm::vec2{12.0f / 486.0f}};
sb::Timer on_timer, run_timer, unpaused_timer;
glm::vec3 camera_position {0.0f, 0.0f, 2.0f}, subject_position {0.0f, 0.0f, 0.0f};
float zoom = 0.0f;
glm::vec2 rotation = {0.0f, 0.0f};
std::vector<Curve> curves;
std::vector<std::shared_ptr<Enemy>> enemies;
glm::vec4 world_color {0.2f, 0.2f, 0.2f, 1.0f};
std::map<std::string, std::shared_ptr<TTF_Font>> fonts;
std::map<std::string, sb::audio::Chunk> audio;
Character character {_configuration, audio};
/*!
* Load sound effects and music into objects that can be used by the SDL mixer library. Use chunk objects for background music instead of
* music objects so background music tracks can fade into each other.
*/
void load_audio();
/*!
* Open configuration and load curve data into the object.
*/
void load_curves();
/*!
* Create GL context via super class and load vertices, UV data, and shaders.
*/
void load_gl_context();
/*!
* Create button objects and assign them to the entries in the button map. This can be re-run to apply changes made in the configuration or
* to refresh label content.
*/
void set_up_buttons();
/*!
* Style the HUD elements based on the configuration settings. This can be re-run to apply changes made in the configuration.
*/
void set_up_hud();
/*!
* Generate, bind, and fill a vertex buffer object with the game's vertex data.
*/
void load_vbo();
/*!
* @return the currently active curve
*/
Curve& curve();
/*!
* Change the level to the given index. Load enemies, update the curve index.
*
* @param index index of the level to load
*/
void load_level(int index);
/*!
* Save the JSON in the `progress` field of Game::configuration to storage at Cakefoot::progress_file_path.
*
* For PC builds, the folder `storage/` will be created in the current working directory if it doesn't exist already. The user must have
* permission to create folders in the directory. The file `progress.json` will also be created if necessary.
*
* For web builds, Emscripten is used to abstract this function so that writing to a browser's Indexed DB is done automatically. The folder
* `storage/` must have been mounted already using Emscripten's FS module.
*/
void write_progress();
public:
/*!
* Initialize a Cakefoot instance
*/
Cakefoot();
/*!
* Respond to command events
*/
void respond(SDL_Event&);
/*!
* Start timers, enable auto refresh, and run the super class's run function, which starts the game's update loop.
*
* @see Game::run()
*/
void run();
/*!
* Update parameters and draw the screen.
*
* @param timestamp seconds since the start of the program
*/
void update(float timestamp);
};
/*!
* Create a Cakewalk instance and launch its mainloop.
*
* @return Always returns 0
*/
int main();