[Added] Tutorial Screen, Start of the Game Screen

This commit is contained in:
Ninjaws
2024-12-08 22:03:56 +01:00
parent 83d1d622ee
commit 76dd80d3a3
23 changed files with 396 additions and 65 deletions
+6
View File
@@ -7,6 +7,7 @@
#include <unordered_map> #include <unordered_map>
#include "EFont.h" #include "EFont.h"
#include "EMusic.h" #include "EMusic.h"
#include "EBackground.h"
#include "Service.h" #include "Service.h"
class AssetService: public Service<AssetService> class AssetService: public Service<AssetService>
@@ -19,6 +20,7 @@ private:
std::unordered_map<EFont, std::string> fonts; std::unordered_map<EFont, std::string> fonts;
std::vector<Sound> sounds; std::vector<Sound> sounds;
std::unordered_map<EMusic, Music> music; std::unordered_map<EMusic, Music> music;
std::unordered_map<EBackground, Texture2D> backgrounds;
void setAssets(); void setAssets();
@@ -35,6 +37,10 @@ public:
Music getMusic(EMusic music) { Music getMusic(EMusic music) {
return this->music[music]; return this->music[music];
} }
Texture2D getBackground(EBackground background){
return this->backgrounds[background];
}
Texture2D loadTexture(std::string filename);
}; };
#endif #endif
+1 -4
View File
@@ -9,13 +9,10 @@
class AudioService : public Service<AudioService> class AudioService : public Service<AudioService>
{ {
private: private:
/** Friend to allow access to the destructor */
// friend class Service<AudioService>;
std::optional<Music> music; std::optional<Music> music;
EMusic currentTrack; EMusic currentTrack = EMusic::NONE;
protected: protected:
// ~AudioService();
public: public:
void setMusic(EMusic music); void setMusic(EMusic music);
+24
View File
@@ -0,0 +1,24 @@
#ifndef BACKGROUND_H
#define BACKGROUND_H
#include "raylib.h"
#include "EBackground.h"
#include <vector>
class Background {
private:
Vector2 position;
std::vector<Texture2D> textures;
protected:
public:
Background(EBackground background);
Background(std::vector<EBackground> backgrounds);
~Background(){}
Vector2 getPosition();
void updatePosition(Vector2 deltaPos);
void setPosition(Vector2 position);
void draw();
};
#endif
+13
View File
@@ -0,0 +1,13 @@
#ifndef EBACKGROUND_H
#define EBACKGROUND_H
enum class EBackground {
TUTORIAL,
GAME1,
GAME2,
GAME3,
VICTORY
};
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef GAME_SCREEN_H
#define GAME_SCREEN_H
#include "Screen.h"
class GameScreen: public Screen {
private:
protected:
public:
GameScreen();
void logic() override;
};
#endif
+1 -3
View File
@@ -2,8 +2,6 @@
#define MAIN_SCREEN_H #define MAIN_SCREEN_H
#include "Screen.h" #include "Screen.h"
#include "raylib.h"
#include <string>
class MainScreen : public Screen { class MainScreen : public Screen {
private: private:
@@ -11,10 +9,10 @@ private:
void mouseLogic(); void mouseLogic();
void keyboardLogic(); void keyboardLogic();
void clickLogic();
public: public:
MainScreen(); MainScreen();
~MainScreen();
void logic() override; void logic() override;
}; };
+33
View File
@@ -0,0 +1,33 @@
#ifndef MAP_H
#define MAP_H
#include <vector>
#include "raylib.h"
/**
* Holds the collision and texture maps for the game world
*/
class Map
{
public:
Map();
~Map() {}
void draw();
private:
/** Holds the number for every single tile, which refers to a certain sprite in the tileset */
std::vector<std::vector<Vector2>> map;
/** Holds 1s (collision) and 0s (no collision) for every tile */
std::vector<std::vector<int>> colMap;
float tileSize = 32;
Texture2D tileset;
void loadMap();
void loadColMap(){}
void loadTileset();
};
#endif
+9 -1
View File
@@ -3,15 +3,23 @@
#include <vector> #include <vector>
#include "Text.h" #include "Text.h"
#include "raylib.h"
#include <optional>
#include "Background.h"
#include "Map.h"
class Screen { class Screen {
private: private:
protected: protected:
// std::optional<Map> map;
std::optional<Camera2D> camera;
std::optional<Map> map;
std::optional<Background> background;
std::vector<Text> text; std::vector<Text> text;
public: public:
Screen(){} Screen();
~Screen(){} ~Screen(){}
/** /**
+11 -1
View File
@@ -11,6 +11,9 @@
#include <emscripten/emscripten.h> #include <emscripten/emscripten.h>
#endif #endif
/**
* Handles switching between screens
*/
class StateService : public Service<StateService> class StateService : public Service<StateService>
{ {
private: private:
@@ -18,6 +21,8 @@ private:
bool gameRunning = true; bool gameRunning = true;
Vector2 screenSize;
/** /**
* One step of the gameloop * One step of the gameloop
*/ */
@@ -26,7 +31,12 @@ private:
void handleMusic(); void handleMusic();
public: public:
Vector2 getScreenSize(){
return screenSize;
}
void setScreenSize(Vector2 screenSize) {
this->screenSize = screenSize;
}
void setScreen(EScreen screen); void setScreen(EScreen screen);
Screen *getScreen(); Screen *getScreen();
/** /**
+1 -2
View File
@@ -18,7 +18,7 @@ class Text {
public: public:
Text(std::string text, EFont font, int fontSize = 30, int spacing = 0, Color color = WHITE, Vector2 position = {100,100}); Text(std::string text, EFont font, int fontSize = 30, int spacing = 0, Color color = WHITE, Vector2 position = {100,100});
~Text(); ~Text(){}
Vector2 getDimensions(); Vector2 getDimensions();
@@ -42,7 +42,6 @@ class Text {
return this->text; return this->text;
} }
void draw(); void draw();
}; };
-7
View File
@@ -3,22 +3,15 @@
#include "Screen.h" #include "Screen.h"
#include "raylib.h" #include "raylib.h"
#include "Text.h"
#include <string>
#include <vector>
class TitleScreen : public Screen { class TitleScreen : public Screen {
private: private:
Music bg; Music bg;
// std::vector<Text> text;
public: public:
TitleScreen(); TitleScreen();
~TitleScreen();
// void step() override;
void logic() override; void logic() override;
// void draw() override;
}; };
#endif #endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef TUTORIAL_SCREEN_H
#define TUTORIAL_SCREEN_H
#include "Screen.h"
class TutorialScreen : public Screen {
private:
protected:
public:
TutorialScreen();
void logic() override;
};
#endif
+39
View File
@@ -0,0 +1,39 @@
#include "Background.h"
#include "AssetService.h"
Background::Background(EBackground background)
{
this->textures.push_back(AssetService::getInstance().getBackground(background));
this->position = {0,0};
}
Background::Background(std::vector<EBackground> backgrounds)
{
for(int i = 0; i < backgrounds.size(); i++) {
this->textures.push_back(AssetService::getInstance().getBackground(backgrounds[i]));
this->position = {0,0};
}
}
Vector2 Background::getPosition()
{
return this->position;
}
void Background::updatePosition(Vector2 deltaPos)
{
this->position = {this->position.x+deltaPos.x, this->position.y+deltaPos.y};
}
void Background::setPosition(Vector2 position)
{
this->position = position;
}
void Background::draw()
{
for(int i = 0; i < textures.size(); i++) {
DrawTexture(textures[i], position.x+ (i != 0 ? i*textures[i-1].width : 0), position.y, WHITE);
}
}
+103
View File
@@ -0,0 +1,103 @@
#include "Map.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include "AssetService.h"
Map::Map()
{
loadTileset();
loadMap();
}
void Map::loadMap()
{
std::vector<Vector2> tempMap;
std::ifstream openfile("assets/Maps/map1.txt");
map.clear();
if (openfile.is_open())
{
std::string tileLocation;
openfile >> tileLocation;
// tileTexture.loadFromFile(tileLocation);
// tileSprites.setTexture(tileTexture);
while (!openfile.eof())
{
std::string str, value;
std::getline(openfile, str);
std::stringstream stream(str);
while (std::getline(stream, value, ' '))
{
if (value.length() > 0)
{
std::string xx = value.substr(0, value.find(','));
std::string yy = value.substr(value.find(',') + 1);
int x = 0, y = 0, i, j;
// Look at all characters before the ','
for (i = 0; i < xx.length(); i++)
{
// if one of them is not a number, break
if (!isdigit(xx[i]))
break;
}
for (j = 0; j < yy.length(); j++)
{
if (!isdigit(yy[j]))
break;
}
// If all characters are numbers, convert string to int (the number that the sprite has in the sheet ( in this case, on the x axis)
if (i == xx.length())
x = atoi(xx.c_str());
else
x = -1;
// Otherwise, return -1 (aka no sprite)
if (j == yy.length())
y = atoi(yy.c_str());
else
y = -1;
// Hold both the x and y positions of the sprite
Vector2 vec2 = {(float)x, (float)y};
tempMap.push_back(vec2);
}
}
if (tempMap.size() > 0)
{
map.push_back(tempMap);
tempMap.clear();
}
}
}
}
void Map::loadTileset()
{
this->tileset = AssetService::getInstance().loadTexture("Textures/tileset.png");
}
void Map::draw()
{
for (int i = 0; i < map.size(); i++)
{
for (int j = 0; j < map[i].size(); j++)
{
if (map[i][j].x != -1 && map[i][j].y != -1)
{
// Rectangle source = {0,0,32,32};
Rectangle sourceRect = {map[i][j].x * tileSize, map[i][j].y * tileSize, tileSize, tileSize};
DrawTextureRec(tileset, sourceRect, {j * tileSize, i * tileSize}, WHITE);
// tileSprites.setPosition(j * tileSize, i * tileSize);
// tileSprites.setTextureRect(sf::IntRect(map[i][j].x * tileSize, map[i][j].y * tileSize, tileSize, tileSize));
// GetWindow().draw(tileSprites);
}
}
}
}
-6
View File
@@ -12,12 +12,6 @@ Text::Text(std::string text, EFont font, int fontSize, int spacing, Color color,
this->position = position; this->position = position;
} }
Text::~Text()
{
// Causes double free for some reason
// UnloadFont(this->font);
}
Vector2 Text::getDimensions() Vector2 Text::getDimensions()
{ {
return MeasureTextEx(font, text.c_str(), (float)fontSize, (float)spacing); return MeasureTextEx(font, text.c_str(), (float)fontSize, (float)spacing);
+1
View File
@@ -8,6 +8,7 @@
int main(void) int main(void)
{ {
StateService& stateService = StateService::getInstance(); StateService& stateService = StateService::getInstance();
stateService.setScreenSize({640,544});
stateService.startGame(); stateService.startGame();
// std::cout << "StateService instance: " << service << std::endl; // std::cout << "StateService instance: " << service << std::endl;
+27
View File
@@ -0,0 +1,27 @@
#include "GameScreen.h"
#include "Map.h"
#include "StateService.h"
GameScreen::GameScreen()
{
std::vector<EBackground> bgs;
bgs.push_back(EBackground::GAME1);
bgs.push_back(EBackground::GAME2);
bgs.push_back(EBackground::GAME3);
this->background = Background(bgs);
this->map = Map();
Vector2 screenSize = StateService::getInstance().getScreenSize();
Camera2D camera = { 0 };
camera.offset = (Vector2){ screenSize.x / 2.0f, screenSize.y / 2.0f }; // Set offset to center
camera.target = (Vector2){ screenSize.x /2.0f, screenSize.y / 2.0f }; // Initially at the center of the world
camera.rotation = 0.0f;
camera.zoom = 1.0f;
this->camera = camera;
}
void GameScreen::logic()
{
// this->background.value().updatePosition({-2.5f,0});
this->camera.value().target.x += 1.0f;
}
+23 -21
View File
@@ -1,8 +1,7 @@
#include "MainScreen.h" #include "MainScreen.h"
#include "AssetService.h"
#include "AudioService.h" #include "AudioService.h"
#include <iostream>
#include "StateService.h" #include "StateService.h"
#include "raylib.h"
MainScreen::MainScreen() MainScreen::MainScreen()
{ {
@@ -17,7 +16,6 @@ MainScreen::MainScreen()
Text txt = Text("new game", EFont::GTEK, 30, 0, WHITE); Text txt = Text("new game", EFont::GTEK, 30, 0, WHITE);
text.push_back(txt); text.push_back(txt);
} }
text[0].setColor(RED); text[0].setColor(RED);
text[1].setText("load game"); text[1].setText("load game");
text[2].setText("tutorial"); text[2].setText("tutorial");
@@ -29,12 +27,12 @@ MainScreen::MainScreen()
} }
/** Will be ignored if already active (like when coming from the TitleScreen) */ /** Will be ignored if already active (like when coming from the TitleScreen) */
AudioService::getInstance().setMusic(EMusic::MAIN); EMusic track = AudioService::getInstance().getCurrentTrack();
AudioService::getInstance().playMusic(); if (track != EMusic::MAIN)
} {
AudioService::getInstance().setMusic(EMusic::MAIN);
MainScreen::~MainScreen() AudioService::getInstance().playMusic();
{ }
} }
void MainScreen::logic() void MainScreen::logic()
@@ -43,10 +41,12 @@ void MainScreen::logic()
// std::cout << mouseD.y <<std::endl; // std::cout << mouseD.y <<std::endl;
// if (mouseD.x != 0.0f && mouseD.y != 0.0f) // if (mouseD.x != 0.0f && mouseD.y != 0.0f)
// { // {
// mouseLogic(); mouseLogic();
// } // }
keyboardLogic(); keyboardLogic();
clickLogic();
} }
void MainScreen::mouseLogic() void MainScreen::mouseLogic()
@@ -57,13 +57,15 @@ void MainScreen::mouseLogic()
if (hoveredButton == i) if (hoveredButton == i)
continue; continue;
/** Pixels around the text that also count towards that button, to make the hover feel better */
int textPadding = 20;
Vector2 dim = text[i].getDimensions(); Vector2 dim = text[i].getDimensions();
Vector2 pos = text[i].getPosition(); Vector2 pos = text[i].getPosition();
Rectangle rect = {pos.x, pos.y, dim.x, dim.y}; Rectangle rect = {pos.x, pos.y, dim.x, dim.y};
Vector2 mousePos = GetMousePosition(); Vector2 mousePos = GetMousePosition();
// mousePos.x >= rect.x && mousePos.x <= (rect.x+rect.width) && // mousePos.x >= rect.x && mousePos.x <= (rect.x+rect.width) &&
if (mousePos.x >= rect.x && mousePos.x <= (rect.x+rect.width) && mousePos.y >= rect.y && mousePos.y <= (rect.y + rect.height)) if ((mousePos.x + textPadding) >= rect.x && mousePos.x <= (rect.x + rect.width + textPadding) && (mousePos.y + textPadding) >= rect.y && mousePos.y <= (rect.y + rect.height + textPadding))
{ {
text[hoveredButton].setColor(WHITE); text[hoveredButton].setColor(WHITE);
hoveredButton = i; hoveredButton = i;
@@ -82,22 +84,22 @@ void MainScreen::keyboardLogic()
hoveredButton = ((hoveredButton - (IsKeyPressed(KEY_DOWN) ? -1 : 1)) + 4) % 4; hoveredButton = ((hoveredButton - (IsKeyPressed(KEY_DOWN) ? -1 : 1)) + 4) % 4;
text[hoveredButton].setColor(RED); text[hoveredButton].setColor(RED);
} }
}
void MainScreen::clickLogic()
{
if (IsKeyPressed(KEY_ENTER) || IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) if (IsKeyPressed(KEY_ENTER) || IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
{ {
std::cout << text[hoveredButton].getText() << std::endl;
std::string selectedButton = text[hoveredButton].getText(); std::string selectedButton = text[hoveredButton].getText();
if (selectedButton == "new game")
if(selectedButton == "new game") { StateService::getInstance().setScreen(EScreen::GAME);
else if (selectedButton == "load game")
{
} }
else if(selectedButton == "load game") { else if (selectedButton == "tutorial")
}
else if(selectedButton == "tutorial") {
StateService::getInstance().setScreen(EScreen::TUTORIAL); StateService::getInstance().setScreen(EScreen::TUTORIAL);
} else if (selectedButton == "quit")
else if(selectedButton == "quit") {
StateService::getInstance().setScreen(EScreen::CLOSE); StateService::getInstance().setScreen(EScreen::CLOSE);
}
} }
} }
+18 -1
View File
@@ -2,10 +2,24 @@
#include "AudioService.h" #include "AudioService.h"
#include <optional> #include <optional>
Screen::Screen()
{
}
void Screen::draw() void Screen::draw()
{ {
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK);
if (camera.has_value())
BeginMode2D(this->camera.value());
if (!background.has_value())
ClearBackground(BLACK);
else
this->background.value().draw();
if (map.has_value())
this->map.value().draw();
if (text.size() > 0) if (text.size() > 0)
{ {
@@ -14,5 +28,8 @@ void Screen::draw()
text[t].draw(); text[t].draw();
} }
} }
if (camera.has_value())
EndMode2D();
EndDrawing(); EndDrawing();
} }
+5 -14
View File
@@ -27,20 +27,11 @@ TitleScreen::TitleScreen()
text.push_back(textCenter); text.push_back(textCenter);
text.push_back(testSub); text.push_back(testSub);
EMusic track = AudioService::getInstance().getCurrentTrack();
AudioService::getInstance().setMusic(EMusic::MAIN); if (track != EMusic::MAIN) {
AudioService::getInstance().playMusic(); AudioService::getInstance().setMusic(EMusic::MAIN);
AudioService::getInstance().playMusic();
// bg = LoadMusicStream("assets/Audio/Music/Crash_WarpRoomTheme.ogg"); }
// bg.looping = true;
// SetMasterVolume(1.0f);
// SetMusicVolume(bg, 1.0f);
// PlayMusicStream(bg);
}
TitleScreen::~TitleScreen()
{
// UnloadMusicStream(bg);
} }
void TitleScreen::logic() void TitleScreen::logic()
+23
View File
@@ -0,0 +1,23 @@
#include "TutorialScreen.h"
#include "StateService.h"
#include "EFont.h"
#include "EScreen.h"
TutorialScreen::TutorialScreen()
{
Text textBack = Text("Press Enter to go back", EFont::SANSATION, 30, 0, RED);
textBack.setPosition({(float)(GetScreenWidth() - textBack.getDimensions().x) / 1.3f,
(float)(GetScreenHeight() - textBack.getDimensions().y) / 1.15f});
this->text.push_back(textBack);
this->background = Background(EBackground::TUTORIAL);
}
void TutorialScreen::logic()
{
if (IsKeyPressed(KEY_ENTER) || IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
{
StateService::getInstance().setScreen(EScreen::MAIN);
}
}
+13 -1
View File
@@ -1,5 +1,4 @@
#include "AssetService.h" #include "AssetService.h"
#include <iostream>
AssetService::AssetService() AssetService::AssetService()
{ {
@@ -19,6 +18,13 @@ void AssetService::setAssets()
music[EMusic::MAIN] = loadMusic("Audio/Music/Crash_WarpRoomTheme.ogg", true); music[EMusic::MAIN] = loadMusic("Audio/Music/Crash_WarpRoomTheme.ogg", true);
music[EMusic::GAME] = loadMusic("Audio/Music/GameTheme_2.ogg", true); music[EMusic::GAME] = loadMusic("Audio/Music/GameTheme_2.ogg", true);
music[EMusic::GAME_OVER] = loadMusic("Audio/Music/gameOverTheme.ogg", false); music[EMusic::GAME_OVER] = loadMusic("Audio/Music/gameOverTheme.ogg", false);
/** Todo: set volume */
backgrounds[EBackground::TUTORIAL] = loadTexture("Textures/TutorialBackground2.png");
backgrounds[EBackground::GAME1] = loadTexture("Textures/GameBackground_1.png");
backgrounds[EBackground::GAME2] = loadTexture("Textures/GameBackground_2.jpg");
backgrounds[EBackground::GAME3] = loadTexture("Textures/GameBackground_3.png");
backgrounds[EBackground::VICTORY] = loadTexture("Textures/VictoryScreenBackground.png");
} }
Font AssetService::getFont(EFont font, int fontSize) Font AssetService::getFont(EFont font, int fontSize)
@@ -29,6 +35,12 @@ Font AssetService::getFont(EFont font, int fontSize)
return fnt; return fnt;
} }
Texture2D AssetService::loadTexture(std::string filename)
{
Texture2D texture = LoadTexture((assetDir + filename).c_str());
return texture;
}
std::string AssetService::getFontUrl(EFont font) std::string AssetService::getFontUrl(EFont font)
{ {
return assetDir + fonts[font]; return assetDir + fonts[font];
+12 -4
View File
@@ -2,6 +2,8 @@
#include "raylib.h" #include "raylib.h"
#include "TitleScreen.h" #include "TitleScreen.h"
#include "MainScreen.h" #include "MainScreen.h"
#include "TutorialScreen.h"
#include "GameScreen.h"
#include <optional> #include <optional>
#include "AudioService.h" #include "AudioService.h"
@@ -15,6 +17,12 @@ void StateService::setScreen(EScreen state)
case EScreen::MAIN: case EScreen::MAIN:
currentScreen = std::make_unique<MainScreen>(); currentScreen = std::make_unique<MainScreen>();
break; break;
case EScreen::TUTORIAL:
currentScreen = std::make_unique<TutorialScreen>();
break;
case EScreen::GAME:
currentScreen = std::make_unique<GameScreen>();
break;
case EScreen::CLOSE: case EScreen::CLOSE:
gameRunning = false; gameRunning = false;
break; break;
@@ -31,7 +39,7 @@ Screen *StateService::getScreen()
void StateService::startGame() void StateService::startGame()
{ {
InitAudioDevice(); InitAudioDevice();
InitWindow(640, 544, "Jelly Rescue"); InitWindow(screenSize.x, screenSize.y, "Jelly Rescue");
SetTargetFPS(60); SetTargetFPS(60);
setScreen(EScreen::TITLE); setScreen(EScreen::TITLE);
@@ -53,8 +61,9 @@ void StateService::startGame()
void StateService::handleMusic() void StateService::handleMusic()
{ {
std::optional<Music> music = AudioService::getInstance().getMusic(); std::optional<Music> music = AudioService::getInstance().getMusic();
if(music.has_value()) { if (music.has_value())
UpdateMusicStream(music.value()); {
UpdateMusicStream(music.value());
} }
} }
@@ -64,4 +73,3 @@ void StateService::step()
currentScreen->draw(); currentScreen->draw();
currentScreen->logic(); currentScreen->logic();
} }