Async sprites loading
This commit is contained in:
parent
3dcdcadff3
commit
36d6b21613
@ -17,3 +17,4 @@ target_link_libraries(Space mingl)
|
|||||||
target_link_libraries(Space GL)
|
target_link_libraries(Space GL)
|
||||||
target_link_libraries(Space GLU)
|
target_link_libraries(Space GLU)
|
||||||
target_link_libraries(Space glut)
|
target_link_libraries(Space glut)
|
||||||
|
target_link_libraries(Space pthread)
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,6 +1,7 @@
|
|||||||
# General configuration
|
# General configuration
|
||||||
general:
|
general:
|
||||||
maxFPS: 90
|
maxFPS: 90
|
||||||
|
theme: bad
|
||||||
|
|
||||||
# Players config
|
# Players config
|
||||||
players:
|
players:
|
||||||
|
@ -25,7 +25,12 @@ typedef string configKey;
|
|||||||
* @brief this struct stores all relevant data from the configuration file
|
* @brief this struct stores all relevant data from the configuration file
|
||||||
*/
|
*/
|
||||||
struct ConfigData {
|
struct ConfigData {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief theme to use. Valid values : good,bad
|
||||||
|
*/
|
||||||
|
string theme;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief maximum framerate at which the game will run
|
* @brief maximum framerate at which the game will run
|
||||||
*/
|
*/
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#define GUARD_GAME_H
|
#define GUARD_GAME_H
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "mingl/mingl.h"
|
#include "mingl/mingl.h"
|
||||||
#include "pixelManager.h"
|
#include "pixelManager/pixelManager.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "playerDef.h"
|
#include "playerDef.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
@ -41,8 +41,9 @@ private:
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief PixelManager : Class that contains and draws all the data that will be drawn on screen
|
* @brief PixelManager : Class that contains and draws all the data that will be drawn on screen
|
||||||
|
* This is a pointer because the object is allocated at runtime, following the configuration
|
||||||
*/
|
*/
|
||||||
PixelManager pm;
|
unique_ptr<PixelManager> pm;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief ConfigData : Struct that stores all the relevant data read from the configuration file
|
* @brief ConfigData : Struct that stores all the relevant data read from the configuration file
|
||||||
@ -65,7 +66,7 @@ private:
|
|||||||
Position basePos;
|
Position basePos;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Invader posision and type matrix
|
* @brief Invader position and type matrix
|
||||||
*/
|
*/
|
||||||
InvadersGrid grid;
|
InvadersGrid grid;
|
||||||
|
|
||||||
@ -97,9 +98,9 @@ private:
|
|||||||
// invaders related variables
|
// invaders related variables
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief cooldown between two invader shot in milliseconds
|
* @brief cooldown until the invaders can shoot again
|
||||||
*/
|
*/
|
||||||
unsigned fireCooldown=120;
|
unsigned fireCooldown=0;
|
||||||
|
|
||||||
// basic methods
|
// basic methods
|
||||||
|
|
||||||
|
16
headers/mySprite.h
Normal file
16
headers/mySprite.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef GUARD_MYSPRITE_H
|
||||||
|
#define GUARD_MYSPRITE_H
|
||||||
|
|
||||||
|
#include <future>
|
||||||
|
#include "mingl/gui/sprite.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class MySprite{
|
||||||
|
public:
|
||||||
|
unique_ptr<nsGui::Sprite> ptr;
|
||||||
|
future<void> asyncLoad(const string& fname);
|
||||||
|
void mirror(MySprite& msp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
21
headers/pixelManager/goodPixelManager.h
Normal file
21
headers/pixelManager/goodPixelManager.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef GUARD_GOODPIXELMANAGER_H
|
||||||
|
#define GUARD_GOODPIXELMANAGER_H
|
||||||
|
|
||||||
|
#include "pixelManager/pixelManager.h"
|
||||||
|
|
||||||
|
class GoodPixelManager : public PixelManager{
|
||||||
|
|
||||||
|
void loadSprites(SpriteTasks& tasks) override;
|
||||||
|
|
||||||
|
MySprite player;
|
||||||
|
MySprite invaderA;
|
||||||
|
MySprite invaderB;
|
||||||
|
MySprite invaderC;
|
||||||
|
MySprite missile;
|
||||||
|
MySprite torpedo;
|
||||||
|
public:
|
||||||
|
GoodPixelManager(MinGL& win);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -24,54 +24,64 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "playMode.h"
|
#include "playMode.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
#include "mySprite.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define MIRROR(SP) mirrorData((SP).getPixelData(), (SP).getRowSize()), (SP).getRowSize()
|
|
||||||
|
|
||||||
typedef nsGui::GlutFont::GlutFonts Font;
|
typedef nsGui::GlutFont::GlutFonts Font;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @class PixelManager
|
* @class PixelManager
|
||||||
* @brief main display function, clear the window and calls sub display functions
|
* @brief main display function, clear the window and calls sub display functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's MinGL's fault. This is all I have to say
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The convention seems to just add a number to the macro name
|
||||||
|
#define ADD_TASK(X) ADD_TASK2(X, X)
|
||||||
|
#define ADD_TASK2(X, Y) tasks.push_back((X).asyncLoad("assets/"#Y".si2"));
|
||||||
|
|
||||||
|
typedef vector<future<void>> SpriteTasks;
|
||||||
|
|
||||||
|
|
||||||
class PixelManager{
|
class PixelManager{
|
||||||
public:
|
public:
|
||||||
MinGL& window;
|
MinGL& window;
|
||||||
|
|
||||||
/*
|
/*!
|
||||||
* Sprites are not const because for some reason the texture is associated with coordinates,
|
* @brief loads sprites in parallel using multiple threads
|
||||||
* and we have no way to dissociate them...
|
* @param[in] vec : We take his ownership, so
|
||||||
* So the objects are constantly updated with new coordinates as they need to be drawn
|
* @fn void loadSprites();
|
||||||
* We used {} insead of () for the constructor because the () makes the compiler think we declare methods
|
*/
|
||||||
*
|
virtual void loadSprites(SpriteTasks& tasks);
|
||||||
* (We could copy them every time, but I feel like copying image data every frame isn't great)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief sprite of the logo of the game
|
* @brief sprite of the logo of the game
|
||||||
*/
|
*/
|
||||||
nsGui::Sprite logo{"assets/logo.si2"};
|
MySprite logo;
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief sprite of the background during gameplay
|
|
||||||
*/
|
|
||||||
nsGui::Sprite gameBackground{"assets/game_background.si2"};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief sprite of the background during menu
|
* @brief sprite of the background during menu
|
||||||
*/
|
*/
|
||||||
nsGui::Sprite menuBackground{"assets/menu_background.si2"};
|
MySprite menuBackground;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief sprite of the background during gameplay
|
||||||
|
*/
|
||||||
|
MySprite gameBackground;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief sprite of the right hand of god
|
* @brief sprite of the right hand of god
|
||||||
*/
|
*/
|
||||||
nsGui::Sprite rightHand{"assets/hand_open.si2"};
|
MySprite rightHand;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief sprite of the left hand of god
|
* @brief sprite of the left hand of god
|
||||||
*/
|
*/
|
||||||
nsGui::Sprite leftHand{MIRROR(rightHand)};
|
MySprite leftHand;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief constructor the pixel manager class
|
* @brief constructor the pixel manager class
|
||||||
@ -145,11 +155,11 @@ public:
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief display a sprite on screen
|
* @brief display a sprite on screen
|
||||||
* @param[in] sprite : sprite to draw
|
* @param[in] msp : sprite to draw
|
||||||
* @param[in] pos : pixel coordinates to draw the sprite
|
* @param[in] pos : pixel coordinates to draw the sprite
|
||||||
* @fn void drawSprite(const nsGui::Sprite& sprite, const Position& pos = Position(0, 0)) const;
|
* @fn void drawSprite(const MySprite& msp, const Position& pos = Position(0, 0)) const;
|
||||||
*/
|
*/
|
||||||
void drawSprite(const nsGui::Sprite& sprite, const Position& pos = Position(0, 0)) const;
|
void drawSprite(const MySprite& msp, const Position& pos = Position(0, 0)) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief display a menu button on screen
|
* @brief display a menu button on screen
|
@ -153,6 +153,7 @@ void ConfigBuilder::readInvaderType(const configKey& baseKey, InvaderTypeDef& in
|
|||||||
|
|
||||||
void ConfigBuilder::readConfig() {
|
void ConfigBuilder::readConfig() {
|
||||||
|
|
||||||
|
collectedData.theme = getString("general.theme");
|
||||||
collectedData.maxFPS = getInt("general.maxFPS");
|
collectedData.maxFPS = getInt("general.maxFPS");
|
||||||
|
|
||||||
readGrid("grid");
|
readGrid("grid");
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* The more important stuff must be drawn last
|
* The more important stuff must be drawn last
|
||||||
*/
|
*/
|
||||||
void Game::displayAll() const {
|
void Game::displayAll() const {
|
||||||
pm.drawSprite(pm.gameBackground);
|
pm->drawSprite(pm->gameBackground);
|
||||||
for (unsigned i = 0; i < this->grid.size(); ++i){
|
for (unsigned i = 0; i < this->grid.size(); ++i){
|
||||||
for (unsigned j = 0; j < this->grid[i].size(); ++j){
|
for (unsigned j = 0; j < this->grid[i].size(); ++j){
|
||||||
Position vec(
|
Position vec(
|
||||||
@ -28,23 +28,23 @@ void Game::displayAll() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(const missile& miss : missiles){
|
for(const missile& miss : missiles){
|
||||||
pm.drawMissile(miss, confData.missilesWidth, confData.missilesColor);
|
pm->drawMissile(miss, confData.missilesWidth, confData.missilesColor);
|
||||||
}
|
}
|
||||||
for(const Torpedo& tor : torpedos){
|
for(const Torpedo& tor : torpedos){
|
||||||
pm.drawTorpedo(tor, confData.torpedosWidth, confData.torpedosColor);
|
pm->drawTorpedo(tor, confData.torpedosWidth, confData.torpedosColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
displayGod();
|
displayGod();
|
||||||
|
|
||||||
DEBUG_INSTR(
|
DEBUG_INSTR(
|
||||||
pm.drawText(Position(pm.getScreenWidth()-200, 20), "FPS : "+to_string(fps), nsGraphics::KWhite, Font::BITMAP_8_BY_13);
|
pm->drawText(Position(pm->getScreenWidth()-200, 20), "FPS : "+to_string(fps), nsGraphics::KWhite, Font::BITMAP_8_BY_13);
|
||||||
)
|
)
|
||||||
|
|
||||||
for(unsigned i=0;i<players.size();++i){
|
for(unsigned i=0;i<players.size();++i){
|
||||||
if(!players[i].isEliminated()){
|
if(!players[i].isEliminated()){
|
||||||
if(players[i].deathAnimCounter%2==0){
|
if(players[i].deathAnimCounter%2==0){
|
||||||
pm.drawPlayer(players[i].x, confData.playersWidth, confData.playerDefs[i].color);
|
pm->drawPlayer(players[i].x, confData.playersWidth, confData.playerDefs[i].color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// out of the condition, because we still need to display the falling heart
|
// out of the condition, because we still need to display the falling heart
|
||||||
@ -57,15 +57,15 @@ void Game::displayHearts(playerID pID) const {
|
|||||||
// As said before, the player loop is an illusion, 2 players max
|
// As said before, the player loop is an illusion, 2 players max
|
||||||
unsigned x;
|
unsigned x;
|
||||||
if(pID==PLAYER1)x = 0;
|
if(pID==PLAYER1)x = 0;
|
||||||
else x = pm.getScreenWidth()-HEART_LENGTH;
|
else x = pm->getScreenWidth()-HEART_LENGTH;
|
||||||
|
|
||||||
unsigned y = GOD_BENCH_SIZE+5;
|
unsigned y = GOD_BENCH_SIZE+5;
|
||||||
for(unsigned i=0;i<players[pID].lives;++i){
|
for(unsigned i=0;i<players[pID].lives;++i){
|
||||||
pm.drawHeart(Position(x, y));
|
pm->drawHeart(Position(x, y));
|
||||||
y+=HEART_LENGTH+5;
|
y+=HEART_LENGTH+5;
|
||||||
}
|
}
|
||||||
if(players[pID].hasDeathAnimation()){
|
if(players[pID].hasDeathAnimation()){
|
||||||
pm.drawHeart(Position(x, y+players[pID].deathAnimCounter*5));
|
pm->drawHeart(Position(x, y+players[pID].deathAnimCounter*5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,15 +74,15 @@ void Game::displayInvader(const Position& pos, InvaderType type) const {
|
|||||||
const InvaderTypeDef& invDef = confData.invadersDef.at(type);
|
const InvaderTypeDef& invDef = confData.invadersDef.at(type);
|
||||||
switch(type){
|
switch(type){
|
||||||
case InvaderType::TYPEA:{
|
case InvaderType::TYPEA:{
|
||||||
pm.drawInvaderA(pos, confData.invadersSize, invDef.color);
|
pm->drawInvaderA(pos, confData.invadersSize, invDef.color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case InvaderType::TYPEB:{
|
case InvaderType::TYPEB:{
|
||||||
pm.drawInvaderB(pos, confData.invadersSize, invDef.color);
|
pm->drawInvaderB(pos, confData.invadersSize, invDef.color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case InvaderType::TYPEC:{
|
case InvaderType::TYPEC:{
|
||||||
pm.drawInvaderC(pos, confData.invadersSize, invDef.color);
|
pm->drawInvaderC(pos, confData.invadersSize, invDef.color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,40 +97,40 @@ void Game::displayGod() const {
|
|||||||
case GodState::NONE:
|
case GodState::NONE:
|
||||||
return;
|
return;
|
||||||
case GodState::AWAKE: {
|
case GodState::AWAKE: {
|
||||||
pm.drawGodBench(god.counter - GOD_BENCH_SIZE);
|
pm->drawGodBench(god.counter - GOD_BENCH_SIZE);
|
||||||
|
|
||||||
Position leftHand(GOD_HAND_DISTANCE, god.counter-GOD_BENCH_SIZE);
|
Position leftHand(GOD_HAND_DISTANCE, god.counter-GOD_BENCH_SIZE);
|
||||||
Position rightHand(pm.getScreenWidth()-GOD_HAND_DISTANCE-GOD_HAND_SIZE, god.counter-GOD_BENCH_SIZE);
|
Position rightHand(pm->getScreenWidth()-GOD_HAND_DISTANCE-GOD_HAND_SIZE, god.counter-GOD_BENCH_SIZE);
|
||||||
pm.drawGodLeftHand(leftHand);
|
pm->drawGodLeftHand(leftHand);
|
||||||
pm.drawGodRightHand(rightHand);
|
pm->drawGodRightHand(rightHand);
|
||||||
pm.drawGodFace(god.counter - GOD_BENCH_SIZE);
|
pm->drawGodFace(god.counter - GOD_BENCH_SIZE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GodState::WAIT:{
|
case GodState::WAIT:{
|
||||||
pm.drawGodBench(0);
|
pm->drawGodBench(0);
|
||||||
Position leftHand(GOD_HAND_DISTANCE, 0);
|
Position leftHand(GOD_HAND_DISTANCE, 0);
|
||||||
Position rightHand(god.getRightHandPos(pm.getScreenWidth()));
|
Position rightHand(god.getRightHandPos(pm->getScreenWidth()));
|
||||||
pm.drawGodLeftHand(leftHand);
|
pm->drawGodLeftHand(leftHand);
|
||||||
pm.drawGodRightHand(rightHand);
|
pm->drawGodRightHand(rightHand);
|
||||||
pm.drawGodFace(0);
|
pm->drawGodFace(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GodState::RETRIEVE1:
|
case GodState::RETRIEVE1:
|
||||||
case GodState::RETRIEVE2:{
|
case GodState::RETRIEVE2:{
|
||||||
// Bezier curve
|
// Bezier curve
|
||||||
// counter goes [0-100]
|
// counter goes [0-100]
|
||||||
pm.drawGodBench(0);
|
pm->drawGodBench(0);
|
||||||
pm.drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
|
pm->drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
|
||||||
pm.drawGodFace(0);
|
pm->drawGodFace(0);
|
||||||
|
|
||||||
Position pos(god.getRightHandPos(pm.getScreenWidth()));
|
Position pos(god.getRightHandPos(pm->getScreenWidth()));
|
||||||
Position endPos = invIndexToPos(god.thrownInvPosX, god.thrownInvPosY);
|
Position endPos = invIndexToPos(god.thrownInvPosX, god.thrownInvPosY);
|
||||||
|
|
||||||
applyBezier(pos, god.thrownTransition, god.counter / 100.0);
|
applyBezier(pos, god.thrownTransition, god.counter / 100.0);
|
||||||
applyBezier(pos, endPos, god.counter / 100.0);
|
applyBezier(pos, endPos, god.counter / 100.0);
|
||||||
|
|
||||||
// pos is now the position we need to draw our hand to
|
// pos is now the position we need to draw our hand to
|
||||||
pm.drawGodRightHand(pos);
|
pm->drawGodRightHand(pos);
|
||||||
if(god.thrownInvType!=InvaderType::NONE){
|
if(god.thrownInvType!=InvaderType::NONE){
|
||||||
|
|
||||||
pos+=Position(GOD_HAND_SIZE/2, GOD_HAND_SIZE/2);
|
pos+=Position(GOD_HAND_SIZE/2, GOD_HAND_SIZE/2);
|
||||||
@ -140,12 +140,12 @@ void Game::displayGod() const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GodState::THROW:{
|
case GodState::THROW:{
|
||||||
pm.drawGodBench(0);
|
pm->drawGodBench(0);
|
||||||
pm.drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
|
pm->drawGodLeftHand(Position(GOD_HAND_DISTANCE, 0));
|
||||||
pm.drawGodFace(0);
|
pm->drawGodFace(0);
|
||||||
|
|
||||||
// compute start position (not sure if we should store it or compute it each time ?)
|
// compute start position (not sure if we should store it or compute it each time ?)
|
||||||
Position handPos = god.getRightHandPos(pm.getScreenWidth());
|
Position handPos = god.getRightHandPos(pm->getScreenWidth());
|
||||||
|
|
||||||
Position invaderPos = handPos;
|
Position invaderPos = handPos;
|
||||||
applyTransformation(invaderPos, GOD_HAND_SIZE, confData.invadersSize);
|
applyTransformation(invaderPos, GOD_HAND_SIZE, confData.invadersSize);
|
||||||
@ -160,7 +160,7 @@ void Game::displayGod() const {
|
|||||||
else handCounter = 30-god.counter;
|
else handCounter = 30-god.counter;
|
||||||
handPos = handPos + god.thrownVector * (handCounter / 100.0);
|
handPos = handPos + god.thrownVector * (handCounter / 100.0);
|
||||||
}
|
}
|
||||||
pm.drawGodRightHand(handPos);
|
pm->drawGodRightHand(handPos);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,42 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "playMode.h"
|
#include "playMode.h"
|
||||||
|
#include "pixelManager/goodPixelManager.h"
|
||||||
|
|
||||||
#define WININIT window("SUPER Space Invader : Turbo Apocalypse DX - VS GOD", Position(1280, 720), Position(128, 128), nsGraphics::KBlack)
|
#define WININIT window("SUPER Space Invader : Turbo Apocalypse DX - VS GOD", Position(1280, 720), Position(128, 128), nsGraphics::KBlack)
|
||||||
|
|
||||||
Game::Game() : WININIT, pm(window) {
|
Game::Game() : WININIT {
|
||||||
if(!reloadConfig()){
|
|
||||||
|
if(!reloadConfig()){ // Config
|
||||||
throw runtime_error("Initial config loading failed. Please check the error above and fix the configuration");
|
throw runtime_error("Initial config loading failed. Please check the error above and fix the configuration");
|
||||||
}
|
}
|
||||||
sm.readFile();
|
|
||||||
|
// Pixel Manager
|
||||||
|
if(confData.theme=="good"){
|
||||||
|
pm = std::make_unique<GoodPixelManager>(window);
|
||||||
|
}else if(confData.theme=="bad"){
|
||||||
|
pm = std::make_unique<PixelManager>(window);
|
||||||
|
}else throw runtime_error("Invalid theme value : "+confData.theme+
|
||||||
|
"\nValid values are : good,bad");
|
||||||
|
|
||||||
|
cout << "Loading sprites..." << endl;
|
||||||
|
SpriteTasks tasks;
|
||||||
|
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
pm->loadSprites(tasks);
|
||||||
|
for(future<void>& f : tasks)f.wait();
|
||||||
|
|
||||||
|
// We just do that for one sprite, so I didn't bother creating an 'API' for that
|
||||||
|
pm->leftHand.mirror(pm->rightHand);
|
||||||
|
|
||||||
|
chrono::high_resolution_clock::duration elapsed = chrono::high_resolution_clock::now()-start;
|
||||||
|
cout << "Done ! Time : " << chrono::duration_cast<chrono::milliseconds>(elapsed).count() << "ms" << endl;
|
||||||
|
|
||||||
|
sm.readFile(); // Score manager
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Game::areThereInvadersLeft(){
|
bool Game::areThereInvadersLeft(){
|
||||||
@ -30,7 +55,7 @@ bool Game::areThereInvadersLeft(){
|
|||||||
void Game::handleScoreSaving(){
|
void Game::handleScoreSaving(){
|
||||||
for(unsigned i=0;i<players.size();++i){
|
for(unsigned i=0;i<players.size();++i){
|
||||||
string pName;
|
string pName;
|
||||||
pm.askPlayerNameMenu(i, players[i].score, pName);
|
pm->askPlayerNameMenu(i, players[i].score, pName);
|
||||||
sm.inputScore(move(pName), players[i].score);
|
sm.inputScore(move(pName), players[i].score);
|
||||||
}
|
}
|
||||||
sm.writeFile();
|
sm.writeFile();
|
||||||
@ -42,13 +67,13 @@ void Game::managedGames() {
|
|||||||
|
|
||||||
while(playMode!=PlayMode::EXIT){
|
while(playMode!=PlayMode::EXIT){
|
||||||
if(playMode==PlayMode::NONE){
|
if(playMode==PlayMode::NONE){
|
||||||
playMode = pm.showInitialMenu();
|
playMode = pm->showInitialMenu();
|
||||||
}else{
|
}else{
|
||||||
initGame();
|
initGame();
|
||||||
enterGameLoop(); // will read the playMode
|
enterGameLoop(); // will read the playMode
|
||||||
handleScoreSaving();
|
handleScoreSaving();
|
||||||
cout << "END OF GAME" << endl;
|
cout << "END OF GAME" << endl;
|
||||||
if(!pm.showDeathMenu())playMode = PlayMode::NONE;
|
if(!pm->showDeathMenu())playMode = PlayMode::NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +94,7 @@ void Game::initGame(){
|
|||||||
}else{
|
}else{
|
||||||
players.resize(2);
|
players.resize(2);
|
||||||
// mirror the start X Position for the other
|
// mirror the start X Position for the other
|
||||||
players[1].x = pm.getScreenWidth() - confData.startXPosition - confData.playersWidth;
|
players[1].x = pm->getScreenWidth() - confData.startXPosition - confData.playersWidth;
|
||||||
}
|
}
|
||||||
players[0].x = confData.startXPosition;
|
players[0].x = confData.startXPosition;
|
||||||
|
|
||||||
@ -103,7 +128,7 @@ WinValue Game::enterGameLoop(){ // returns when game is finished
|
|||||||
fpsStartTime = startTime;
|
fpsStartTime = startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.startFrame();
|
pm->startFrame();
|
||||||
|
|
||||||
managePlayers();
|
managePlayers();
|
||||||
if(manageInvaders()) { // if they went down
|
if(manageInvaders()) { // if they went down
|
||||||
@ -126,7 +151,7 @@ WinValue Game::enterGameLoop(){ // returns when game is finished
|
|||||||
|
|
||||||
displayAll();
|
displayAll();
|
||||||
|
|
||||||
pm.endFrame();
|
pm->endFrame();
|
||||||
|
|
||||||
MyTimePoint endTime = chrono::high_resolution_clock::now();
|
MyTimePoint endTime = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ void Game::manageOnePlayer(playerID pID){
|
|||||||
else p.x -= confData.playersSpeed;
|
else p.x -= confData.playersSpeed;
|
||||||
}
|
}
|
||||||
if (ISPRESSED(pID, right)){
|
if (ISPRESSED(pID, right)){
|
||||||
if(p.x + confData.playersWidth + confData.playersSpeed >= pm.getScreenWidth()) p.x = pm.getScreenWidth() - confData.playersWidth - 1;
|
if(p.x + confData.playersWidth + confData.playersSpeed >= pm->getScreenWidth()) p.x = pm->getScreenWidth() - confData.playersWidth - 1;
|
||||||
else p.x += confData.playersSpeed;
|
else p.x += confData.playersSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ void Game::manageOnePlayer(playerID pID){
|
|||||||
|
|
||||||
if(p.fireCooldown==0) {
|
if(p.fireCooldown==0) {
|
||||||
if (ISPRESSED(pID, shoot)) {
|
if (ISPRESSED(pID, shoot)) {
|
||||||
torpedos.emplace_back(p.x + confData.playersWidth / 2, pm.getScreenHeight() - PLAYER_HEIGHT, pID);
|
torpedos.emplace_back(p.x + confData.playersWidth / 2, pm->getScreenHeight() - PLAYER_HEIGHT, pID);
|
||||||
p.fireCooldown = confData.playersFireCooldown;
|
p.fireCooldown = confData.playersFireCooldown;
|
||||||
}
|
}
|
||||||
}else --p.fireCooldown;
|
}else --p.fireCooldown;
|
||||||
@ -69,7 +69,7 @@ bool Game::manageInvaders(){
|
|||||||
|
|
||||||
// you got the end position of the invader crowd !
|
// you got the end position of the invader crowd !
|
||||||
|
|
||||||
if(end + confData.invadersSpeed < pm.getScreenWidth()){
|
if(end + confData.invadersSpeed < pm->getScreenWidth()){
|
||||||
basePos.setX(basePos.getX() + confData.invadersSpeed);
|
basePos.setX(basePos.getX() + confData.invadersSpeed);
|
||||||
}else{
|
}else{
|
||||||
basePos.setY(basePos.getY() + confData.invadersSize + confData.invadersDistance);
|
basePos.setY(basePos.getY() + confData.invadersSize + confData.invadersDistance);
|
||||||
@ -121,7 +121,7 @@ void Game::remCollidingProjectiles(){
|
|||||||
void Game::moveMissiles() {
|
void Game::moveMissiles() {
|
||||||
auto miss = missiles.begin();
|
auto miss = missiles.begin();
|
||||||
while (miss != missiles.end()) {
|
while (miss != missiles.end()) {
|
||||||
if (miss->getY() >= pm.getScreenHeight())missiles.erase(miss);
|
if (miss->getY() >= pm->getScreenHeight())missiles.erase(miss);
|
||||||
else {
|
else {
|
||||||
miss->setY(miss->getY()+confData.missilesSpeed);
|
miss->setY(miss->getY()+confData.missilesSpeed);
|
||||||
++miss;
|
++miss;
|
||||||
@ -144,7 +144,7 @@ void Game::checkMissilesAndPlayers() {
|
|||||||
auto miss_ite = missiles.begin();
|
auto miss_ite = missiles.begin();
|
||||||
while(miss_ite!=missiles.end()){
|
while(miss_ite!=missiles.end()){
|
||||||
bool wasColliding = false;
|
bool wasColliding = false;
|
||||||
if(miss_ite->getY()>=pm.getScreenHeight()-PLAYER_HEIGHT){ // check collision on Y
|
if(miss_ite->getY()>=pm->getScreenHeight()-PLAYER_HEIGHT){ // check collision on Y
|
||||||
// now check collision on X (with both players)
|
// now check collision on X (with both players)
|
||||||
for(Player& p : players){
|
for(Player& p : players){
|
||||||
if(p.isPlaying()){
|
if(p.isPlaying()){
|
||||||
@ -206,6 +206,6 @@ bool Game::invadersTouchPlayer() const {
|
|||||||
unsigned outter = line.getOutterInvader();
|
unsigned outter = line.getOutterInvader();
|
||||||
return this->basePos.getY()+confData.invadersSize*(outter+1)
|
return this->basePos.getY()+confData.invadersSize*(outter+1)
|
||||||
+confData.invadersDistance*outter
|
+confData.invadersDistance*outter
|
||||||
>= pm.getScreenHeight() - PLAYER_HEIGHT;
|
>= pm->getScreenHeight() - PLAYER_HEIGHT;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ bool Game::manageGod() {
|
|||||||
god.thrownInvPosY = grid[god.thrownInvPosX].randomValidInv();
|
god.thrownInvPosY = grid[god.thrownInvPosX].randomValidInv();
|
||||||
god.thrownInvType = InvaderType::NONE;
|
god.thrownInvType = InvaderType::NONE;
|
||||||
|
|
||||||
god.thrownTransition.setX(pm.getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE);
|
god.thrownTransition.setX(pm->getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE);
|
||||||
god.thrownTransition.setY(basePos.getY() + INV_GET_POS(god.thrownInvPosY));
|
god.thrownTransition.setY(basePos.getY() + INV_GET_POS(god.thrownInvPosY));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ bool Game::manageGod() {
|
|||||||
|
|
||||||
// compute the launch vector
|
// compute the launch vector
|
||||||
|
|
||||||
Position invaderMiddlePos(pm.getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE / 2,
|
Position invaderMiddlePos(pm->getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE / 2,
|
||||||
GOD_HAND_SIZE / 2);
|
GOD_HAND_SIZE / 2);
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ bool Game::manageGod() {
|
|||||||
* honestly at this point I want to re-code the whole game engine to allow a better handling of cases like this...*/
|
* honestly at this point I want to re-code the whole game engine to allow a better handling of cases like this...*/
|
||||||
|
|
||||||
Position playerMiddlePos(players[target].x + confData.playersWidth / 2,
|
Position playerMiddlePos(players[target].x + confData.playersWidth / 2,
|
||||||
pm.getScreenHeight() - PLAYER_HEIGHT / 2);
|
pm->getScreenHeight() - PLAYER_HEIGHT / 2);
|
||||||
|
|
||||||
god.thrownVector = playerMiddlePos - invaderMiddlePos;
|
god.thrownVector = playerMiddlePos - invaderMiddlePos;
|
||||||
god.thrownVector = god.thrownVector / (god.thrownVector.computeMagnitude() / 1000.0);
|
god.thrownVector = god.thrownVector / (god.thrownVector.computeMagnitude() / 1000.0);
|
||||||
@ -101,7 +101,7 @@ bool Game::manageGod() {
|
|||||||
case GodState::THROW: {
|
case GodState::THROW: {
|
||||||
++god.counter;
|
++god.counter;
|
||||||
|
|
||||||
Position invaderPos = god.getRightHandPos(pm.getScreenWidth());
|
Position invaderPos = god.getRightHandPos(pm->getScreenWidth());
|
||||||
applyTransformation(invaderPos, GOD_HAND_SIZE, confData.invadersSize);
|
applyTransformation(invaderPos, GOD_HAND_SIZE, confData.invadersSize);
|
||||||
Position a = god.thrownVector * (god.counter / 100.0);
|
Position a = god.thrownVector * (god.counter / 100.0);
|
||||||
invaderPos = invaderPos + a;
|
invaderPos = invaderPos + a;
|
||||||
@ -109,8 +109,8 @@ bool Game::manageGod() {
|
|||||||
bool touched = false;
|
bool touched = false;
|
||||||
|
|
||||||
// check if OOB (Out Of Bounds)
|
// check if OOB (Out Of Bounds)
|
||||||
if (invaderPos.getY() + confData.invadersSize >= pm.getScreenWidth() ||
|
if (invaderPos.getY() + confData.invadersSize >= pm->getScreenWidth() ||
|
||||||
(invaderPos.getX() < 0 || invaderPos.getX() + confData.invadersSize >= pm.getScreenWidth())) {
|
(invaderPos.getX() < 0 || invaderPos.getX() + confData.invadersSize >= pm->getScreenWidth())) {
|
||||||
touched = true;
|
touched = true;
|
||||||
|
|
||||||
/* there are no invaders in the grid anymore, and the one thrown just went out of bound
|
/* there are no invaders in the grid anymore, and the one thrown just went out of bound
|
||||||
@ -118,7 +118,7 @@ bool Game::manageGod() {
|
|||||||
if(!areThereInvadersLeft())return true;
|
if(!areThereInvadersLeft())return true;
|
||||||
|
|
||||||
// check player collision
|
// check player collision
|
||||||
} else if (invaderPos.getY() + confData.invadersSize >= pm.getScreenHeight() - PLAYER_HEIGHT) {
|
} else if (invaderPos.getY() + confData.invadersSize >= pm->getScreenHeight() - PLAYER_HEIGHT) {
|
||||||
for (Player &p: players) {
|
for (Player &p: players) {
|
||||||
if(p.isPlaying()){
|
if(p.isPlaying()){
|
||||||
if (areLinesColliding(
|
if (areLinesColliding(
|
||||||
|
26
src/mySprite.cpp
Normal file
26
src/mySprite.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
#include "mySprite.h"
|
||||||
|
|
||||||
|
future<void> MySprite::asyncLoad(const string& fname){
|
||||||
|
return std::async(std::launch::async, [fname, this]() -> void {
|
||||||
|
ptr = std::make_unique<nsGui::Sprite>(fname);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySprite::mirror(MySprite& msp) {
|
||||||
|
const vector<RGBAcolor>& inPixels = msp.ptr->getPixelData();
|
||||||
|
unsigned rowSize = msp.ptr->getRowSize();
|
||||||
|
|
||||||
|
vector<RGBAcolor> outPixels;
|
||||||
|
// we reserve size so the vector doesn't dynamically grows
|
||||||
|
outPixels.reserve(inPixels.size());
|
||||||
|
//for each line of pixel
|
||||||
|
for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){
|
||||||
|
// for each pixel of that line
|
||||||
|
for(unsigned j=0;j<rowSize;++j) {
|
||||||
|
// push back the pixel opposed to this one (still in the same line)
|
||||||
|
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr = std::make_unique<nsGui::Sprite>(outPixels, rowSize);
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mingl/gui/text.h"
|
#include "mingl/gui/text.h"
|
||||||
#include "pixelManager.h"
|
#include "pixelManager/pixelManager.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "god.h"
|
#include "god.h"
|
||||||
|
|
||||||
@ -76,26 +76,10 @@ void PixelManager::drawTorpedo(const Position& baseVector, unsigned width, const
|
|||||||
window << Rectangle(baseVector, baseVector + Position(width, width * PROJ_LENGTH_FACTOR), color);
|
window << Rectangle(baseVector, baseVector + Position(width, width * PROJ_LENGTH_FACTOR), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PixelManager::drawSprite(const Sprite& sprite, const Position& pos) const {
|
void PixelManager::drawSprite(const MySprite& msp, const Position& pos) const {
|
||||||
// see pixelManager.h for the explanation of this hack
|
// The sprite is associated with a Vec2D for whatever reason, so yeah, we modify it each time we draw it
|
||||||
const_cast<Sprite&>(sprite).setPosition(pos);
|
msp.ptr->setPosition(pos);
|
||||||
sprite.draw(window);
|
msp.ptr->draw(window);
|
||||||
}
|
|
||||||
|
|
||||||
unsigned PixelManager::getScreenHeight() const {
|
|
||||||
return window.getWindowSize().getY();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned PixelManager::getScreenWidth() const {
|
|
||||||
return window.getWindowSize().getX();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelManager::startFrame() const {
|
|
||||||
window.clearScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelManager::endFrame() const {
|
|
||||||
window.finishFrame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PixelManager::drawGodBench(int y) const {
|
void PixelManager::drawGodBench(int y) const {
|
||||||
@ -128,19 +112,3 @@ void PixelManager::drawGodFace(int y, bool angry) const {
|
|||||||
void PixelManager::drawText(const Position& pos, const string& text, const nsGraphics::RGBAcolor& color, Font font) const {
|
void PixelManager::drawText(const Position& pos, const string& text, const nsGraphics::RGBAcolor& color, Font font) const {
|
||||||
window << Text(pos, text, color, font);
|
window << Text(pos, text, color, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<RGBAcolor>
|
|
||||||
PixelManager::mirrorData(const vector<nsGraphics::RGBAcolor>& inPixels, unsigned rowSize) {
|
|
||||||
vector<RGBAcolor> outPixels;
|
|
||||||
// we reserve size so the vector doesn't dynamically grows
|
|
||||||
outPixels.reserve(inPixels.size());
|
|
||||||
//for each line of pixel
|
|
||||||
for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){
|
|
||||||
// for each pixel of that line
|
|
||||||
for(unsigned j=0;j<rowSize;++j) {
|
|
||||||
// push back the pixel opposed to this one (still in the same line)
|
|
||||||
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::move(outPixels);
|
|
||||||
}
|
|
@ -13,13 +13,13 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "mingl/shape/rectangle.h"
|
#include "mingl/shape/rectangle.h"
|
||||||
#include "playMode.h"
|
#include "playMode.h"
|
||||||
#include "pixelManager.h"
|
#include "pixelManager/pixelManager.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
using namespace nsShape;
|
using namespace nsShape;
|
||||||
using namespace nsGraphics;
|
using namespace nsGraphics;
|
||||||
|
|
||||||
void PixelManager::displayButton(const Position& baseVector,const string& text,nsGraphics::RGBAcolor& color){
|
void PixelManager::displayButton(const Position& baseVector, const string& text, nsGraphics::RGBAcolor& color){
|
||||||
window << Rectangle(baseVector, Position(180, 40)+baseVector, KGray);
|
window << Rectangle(baseVector, Position(180, 40)+baseVector, KGray);
|
||||||
window << Rectangle(baseVector+Position(2,2), Position(178, 38)+baseVector, KBlack);
|
window << Rectangle(baseVector+Position(2,2), Position(178, 38)+baseVector, KBlack);
|
||||||
window << nsGui::Text(baseVector+Position(10,22), text, color);
|
window << nsGui::Text(baseVector+Position(10,22), text, color);
|
15
src/pixelManager/goodPixelManager.cpp
Normal file
15
src/pixelManager/goodPixelManager.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "pixelManager/goodPixelManager.h"
|
||||||
|
|
||||||
|
void GoodPixelManager::loadSprites(SpriteTasks& tasks) {
|
||||||
|
PixelManager::loadSprites(tasks);
|
||||||
|
ADD_TASK(player)
|
||||||
|
ADD_TASK(invaderA)
|
||||||
|
ADD_TASK(invaderB)
|
||||||
|
ADD_TASK(invaderC)
|
||||||
|
ADD_TASK(missile)
|
||||||
|
ADD_TASK(torpedo)
|
||||||
|
}
|
||||||
|
|
||||||
|
GoodPixelManager::GoodPixelManager(MinGL& win) : PixelManager(win) {
|
||||||
|
|
||||||
|
}
|
41
src/pixelManager/pixelManager.cpp
Normal file
41
src/pixelManager/pixelManager.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "pixelManager/pixelManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
void PixelManager::loadSprites(SpriteTasks& tasks){
|
||||||
|
ADD_TASK(logo)
|
||||||
|
ADD_TASK(menuBackground)
|
||||||
|
ADD_TASK(gameBackground)
|
||||||
|
ADD_TASK2(rightHand, hand)
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelManager::startFrame() const {
|
||||||
|
window.clearScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixelManager::endFrame() const {
|
||||||
|
window.finishFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PixelManager::getScreenHeight() const {
|
||||||
|
return window.getWindowSize().getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned PixelManager::getScreenWidth() const {
|
||||||
|
return window.getWindowSize().getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<RGBAcolor>
|
||||||
|
PixelManager::mirrorData(const vector<nsGraphics::RGBAcolor>& inPixels, unsigned rowSize) {
|
||||||
|
vector<RGBAcolor> outPixels;
|
||||||
|
// we reserve size so the vector doesn't dynamically grows
|
||||||
|
outPixels.reserve(inPixels.size());
|
||||||
|
//for each line of pixel
|
||||||
|
for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){
|
||||||
|
// for each pixel of that line
|
||||||
|
for(unsigned j=0;j<rowSize;++j) {
|
||||||
|
// push back the pixel opposed to this one (still in the same line)
|
||||||
|
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(outPixels);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user