diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..c492c00 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "macFrameworkPath": [ + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/usr/bin/clang", + "intelliSenseMode": "macos-clang-x64", + "cStandard": "c11", + "cppStandard": "c++11" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a65266f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "g++ - Build and debug", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/coffee_crisis_macos_debug", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/bin", + "environment": [], + "externalConsole": false, + "MIMode": "lldb", + "preLaunchTask": "C/C++: g++ build" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0801ee1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "files.associations": { + "cstddef": "cpp", + "__tuple": "cpp", + "array": "cpp", + "algorithm": "cpp", + "__bit_reference": "cpp", + "__hash_table": "cpp", + "__split_buffer": "cpp", + "initializer_list": "cpp", + "iterator": "cpp", + "string": "cpp", + "string_view": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "iosfwd": "cpp", + "stdexcept": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..f74ab57 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,31 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + "label": "C/C++: g++ build", + "command": "/usr/bin/g++", + "args": [ + "-g", + "${workspaceFolder}/source/*.cpp", + "-std=c++11", + "-Wall", + "-O2", + "-lSDL2", + "-o", + "${workspaceFolder}/bin/coffee_crisis_macos_debug" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "compiler: /usr/bin/g++" + } + ] +} \ No newline at end of file diff --git a/media/.DS_Store b/media/.DS_Store index 3b4105f..913ab0a 100644 Binary files a/media/.DS_Store and b/media/.DS_Store differ diff --git a/media/gfx/font_black_x2.png b/media/gfx/font_black_x2.png new file mode 100644 index 0000000..6f73652 Binary files /dev/null and b/media/gfx/font_black_x2.png differ diff --git a/media/gfx/font_white_x2.png b/media/gfx/font_white_x2.png new file mode 100644 index 0000000..c4c3051 Binary files /dev/null and b/media/gfx/font_white_x2.png differ diff --git a/media/gfx/game_bg.png b/media/gfx/game_bg.png index 83fe965..691bd54 100644 Binary files a/media/gfx/game_bg.png and b/media/gfx/game_bg.png differ diff --git a/media/sound/credits.txt b/media/sound/credits.txt index 01e9d6e..1df8d70 100644 --- a/media/sound/credits.txt +++ b/media/sound/credits.txt @@ -39,8 +39,7 @@ kenney_digitalaudio/lowDown.ogg www.kenney.nl stage_change.wav -kenney_digitalaudio/phaserUp2.ogg -www.kenney.nl +JailDoctor menu_cancel.wav kenney_digitalaudio/lowRandom.ogg diff --git a/media/sound/stage_change.wav b/media/sound/stage_change.wav index 95834dc..007d4be 100644 Binary files a/media/sound/stage_change.wav and b/media/sound/stage_change.wav differ diff --git a/source/balloon.cpp b/source/balloon.cpp index e9da6e5..01a3e2e 100644 --- a/source/balloon.cpp +++ b/source/balloon.cpp @@ -5,7 +5,7 @@ Balloon::Balloon() { mSprite = new AnimatedSprite(); - init(0, 0, NO_KIND, BALLON_VELX_POSITIVE, 0, nullptr, nullptr); + init(0, 0, NO_KIND, BALLOON_VELX_POSITIVE, 0, nullptr, nullptr); } // Destructor @@ -227,13 +227,21 @@ void Balloon::init(float x, int y, Uint8 kind, float velx, Uint16 creationtimer, // Inicializa variables mStopped = true; - mStoppedTimer = 0; + mStoppedCounter = 0; mBlinking = false; mVisible = true; mInvulnerable = false; mBeingCreated = true; - mCreationTimer = creationtimer; + mCreationCounter = creationtimer; + mCreationCounterIni = creationtimer; mPopping = false; + mBouncing.enabled = false; + mBouncing.counter = 0; + mBouncing.speed = 2; + mBouncing.zoomW = 1; + mBouncing.zoomH = 1; + mBouncing.despX = 0; + mBouncing.despY = 0; // Tipo mKind = kind; @@ -288,7 +296,24 @@ void Balloon::render() { if (mVisible) { - mSprite->render(); + if (mBouncing.enabled) + { + mSprite->setPosX(getPosX() + mBouncing.despX); + mSprite->setPosY(getPosY() + mBouncing.despY); + mSprite->render(); + mSprite->setPosX(getPosX() - mBouncing.despX); + mSprite->setPosY(getPosY() - mBouncing.despY); + } + else if (isBeingCreated()) + { + mSprite->getTexture()->setAlpha(255 - (int)((float)mCreationCounter * (255.0f/(float)mCreationCounterIni))); + mSprite->render(); + mSprite->getTexture()->setAlpha(255); + } + else + { + mSprite->render(); + } } } @@ -328,10 +353,13 @@ void Balloon::move() if (mPosY + mHeight > PLAY_AREA_BOTTOM) { // Corregimos - mPosY -= int(mVelY); + //mPosY -= int(mVelY); + mPosY = PLAY_AREA_BOTTOM - mHeight; // Invertimos colocando una velocidad por defecto mVelY = -mDefaultVelY; + + bounceStart(); } // Aplica gravedad al objeto, sin pasarse de un limite establecido @@ -357,10 +385,10 @@ void Balloon::move() setInvulnerable(true); // Todavia tiene tiempo en el contador - if (mCreationTimer > 0) + if (mCreationCounter > 0) { // Desplaza lentamente el globo hacia abajo y hacia un lado - if (mCreationTimer % 10 == 0) + if (mCreationCounter % 10 == 0) { ++mPosY; mPosX += mVelX; @@ -374,16 +402,16 @@ void Balloon::move() } // Hace visible el globo de forma intermitente - if (mCreationTimer > 100) + if (mCreationCounter > 100) { - setVisible(mCreationTimer / 10 % 2 == 0); + setVisible(mCreationCounter / 10 % 2 == 0); } else { - setVisible(mCreationTimer / 5 % 2 == 0); + setVisible(mCreationCounter / 5 % 2 == 0); } - --mCreationTimer; + --mCreationCounter; } // El contador ha llegado a cero else @@ -398,9 +426,9 @@ void Balloon::move() else if (isStopped() == true) { // Si todavía está detenido, reduce el contador - if (mStoppedTimer > 0) + if (mStoppedCounter > 0) { - --mStoppedTimer; + --mStoppedCounter; } // Si el contador ha llegado a cero, ya no está detenido else { @@ -433,6 +461,7 @@ void Balloon::update() move(); setAnimation(); shiftColliders(); + bounceUpdate(); if (isPopping()) { setInvulnerable(true); @@ -608,13 +637,13 @@ Uint16 Balloon::getTimeToLive() // Establece el valor de la variable void Balloon::setStoppedTimer(Uint16 time) { - mStoppedTimer = time; + mStoppedCounter = time; } // Obtiene del valor de la variable Uint16 Balloon::getStoppedTimer() { - return mStoppedTimer; + return mStoppedCounter; } // Obtiene del valor de la variable @@ -641,4 +670,41 @@ void Balloon::shiftColliders() Uint8 Balloon::getMenace() { return mMenace; +} + +void Balloon::bounceStart() +{ + mBouncing.enabled = true; + mBouncing.zoomW = 1; + mBouncing.zoomH = 1; + mSprite->setZoomW(mBouncing.zoomW); + mSprite->setZoomH(mBouncing.zoomH); + mBouncing.despX = 0; + mBouncing.despY = 0; +} +void Balloon::bounceStop() +{ + mBouncing.enabled = false; + mBouncing.counter = 0; + mBouncing.zoomW = 1; + mBouncing.zoomH = 1; + mSprite->setZoomW(mBouncing.zoomW); + mSprite->setZoomH(mBouncing.zoomH); + mBouncing.despX = 0; + mBouncing.despY = 0; +} +void Balloon::bounceUpdate() +{ + if (mBouncing.enabled) + { + mBouncing.zoomW = mBouncing.w[mBouncing.counter / mBouncing.speed]; + mBouncing.zoomH = mBouncing.h[mBouncing.counter / mBouncing.speed]; + mSprite->setZoomW(mBouncing.zoomW); + mSprite->setZoomH(mBouncing.zoomH); + mBouncing.despX = (mSprite->getSpriteClip().w - (mSprite->getSpriteClip().w * mBouncing.zoomW)); + mBouncing.despY = (mSprite->getSpriteClip().h - (mSprite->getSpriteClip().h * mBouncing.zoomH)); + mBouncing.counter++; + if ((mBouncing.counter / mBouncing.speed) > (MAX_BOUNCE - 1)) + bounceStop(); + } } \ No newline at end of file diff --git a/source/balloon.h b/source/balloon.h index bd3f8e0..b46531d 100644 --- a/source/balloon.h +++ b/source/balloon.h @@ -1,13 +1,66 @@ #pragma once -#include "struct.h" +#include "utils.h" #include "animatedsprite.h" #ifndef BALLOON_H #define BALLOON_H +#define MAX_BOUNCE 10 + // Clase globo class Balloon { +private: + float mPosX; // Posición en el eje X + int mPosY; // Posición en el eje Y + + Uint8 mWidth; // Ancho + Uint8 mHeight; // Alto + + float mVelX; // Velocidad en el eje X. Cantidad de pixeles a desplazarse + float mVelY; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse + float mGravity; // Aceleración en el eje Y. Modifica la velocidad + float mDefaultVelY; // Velocidad inicial que tienen al rebotar contra el suelo + int mMaxVelY; // Máxima velocidad que puede alcanzar el objeto en el eje Y + + AnimatedSprite *mSprite; // Sprite del objeto globo + bool mBeingCreated; // Indica si el globo se está creando + bool mBlinking; // Indica si el globo está intermitente + bool mInvulnerable; // Indica si el globo es invulnerable + bool mPopping; // Indica si el globo está explotando + bool mStopped; // Indica si el globo está parado + bool mVisible; // Indica si el globo es visible + Circle mCollider; // Circulo de colisión del objeto + Uint16 mCreationCounter; // Temporizador para controlar el estado "creandose" + Uint16 mCreationCounterIni; // Valor inicial para el temporizador para controlar el estado "creandose" + Uint16 mScore; // Puntos que da el globo al ser destruido + Uint16 mStoppedCounter; // Contador para controlar el estado "parado" + Uint16 mTimeToLive; // Indica el tiempo de vida que le queda al globo + Uint8 mKind; // Tipo de globo + Uint8 mMenace; // Cantidad de amenaza que genera el globo + + struct bouncing // Estructura para las variables para el efecto de los rebotes + { + bool enabled; // Si el efecto está activo + Uint8 counter; // Countador para el efecto + Uint8 speed; // Velocidad a la que transcurre el efecto + float zoomW; // Zoom aplicado a la anchura + float zoomH; // Zoom aplicado a la altura + float despX; // Desplazamiento de pixeles en el eje X antes de pintar el objeto con zoom + float despY; // idem + + // Vector con los valores de zoom para el ancho y alto del globo + float w[MAX_BOUNCE] = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f}; + float h[MAX_BOUNCE] = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f}; + }; + + bouncing mBouncing; + + void shiftColliders(); // Alinea el circulo de colisión con la posición del objeto globo + void bounceStart(); // Activa el efecto + void bounceStop(); // Detiene el efecto + void bounceUpdate(); // Aplica el efecto + public: // Constructor Balloon(); @@ -16,7 +69,7 @@ public: ~Balloon(); // Inicializador - void init(float x, int y, Uint8 kind, float velx, Uint16 creationtimer, LTexture* texture, SDL_Renderer *renderer); + void init(float x, int y, Uint8 kind, float velx, Uint16 creationtimer, LTexture *texture, SDL_Renderer *renderer); // Centra el globo en la posición X void allignTo(int x); @@ -119,67 +172,6 @@ public: // Obtiene le valor de la variable Uint8 getMenace(); - -private: - // Posición X,Y del objeto globo - float mPosX; - int mPosY; - - // Alto y ancho del objeto globo - Uint8 mWidth; - Uint8 mHeight; - - // Variables para controlar la velocidad del globo - float mVelX; - float mVelY; - float mGravity; - float mDefaultVelY; - int mMaxVelY; - - // Puntos que da el globo al ser destruido - Uint16 mScore; - - // Nivel de amenaza del globo - Uint8 mMenace; - - // Indica si el globo está parado - bool mStopped; - - // Temporizador para controlar el estado "parado" - Uint16 mStoppedTimer; - - // Indica si el globo está intermitente - bool mBlinking; - - // Indica si el globo es visible - bool mVisible; - - // Indica si el globo es invulnerable - bool mInvulnerable; - - // Indica si el globo se está creando - bool mBeingCreated; - - // Indica si el globo está explotando - bool mPopping; - - // Indica el tiempo de vida que le queda al globo - Uint16 mTimeToLive; - - // Temporizador para controlar el estado "creandose" - Uint16 mCreationTimer; - - // Tipo de globo - Uint8 mKind; - - // Sprite del objeto globo - AnimatedSprite *mSprite; - - // Circulo de colisión del objeto - Circle mCollider; - - // Alinea el circulo de colisión con la posición del objeto globo - void shiftColliders(); }; #endif diff --git a/source/bullet.h b/source/bullet.h index 48d744d..26c5d24 100644 --- a/source/bullet.h +++ b/source/bullet.h @@ -1,5 +1,5 @@ #pragma once -#include "struct.h" +#include "utils.h" #include "sprite.h" #ifndef BULLET_H diff --git a/source/coffeedrop.cpp b/source/coffeedrop.cpp new file mode 100644 index 0000000..0211825 --- /dev/null +++ b/source/coffeedrop.cpp @@ -0,0 +1,89 @@ +#include "const.h" +#include "coffeedrop.h" + +#ifndef UNUSED + +// Constructor +CoffeeDrop::CoffeeDrop() +{ + mPosX = 0; + mPosY = 0; + mWidth = 8; + mHeight = 8; + mVelX = 0; + mVelY = 0; + mGravity = 0.1f; + mFloor = 0; + mEnabled = false; + mSprite = new Sprite(); + mAlpha = 128; +} + +// Destructor +CoffeeDrop::~CoffeeDrop() +{ + delete mSprite; +} + +// Inicializador +void CoffeeDrop::init(LTexture *texture, SDL_Renderer *renderer, float x, float y, float velX, float velY, int floor) +{ + mEnabled = true; + mPosX = x; + mPosY = y; + mVelX = velX; + mVelY = velY; + mFloor = floor; + + mSprite->setRenderer(renderer); + mSprite->setTexture(texture); + mSprite->setSpriteClip(256, 97, mWidth, mHeight); + mSprite->setPosX(x); + mSprite->setPosY(y); +} + +// Actualiza las variables del objeto +void CoffeeDrop::update() +{ + if (mEnabled) + { + mVelY += mGravity; + mPosX += mVelX; + mPosY += mVelY; + + mSprite->setPosX((int)mPosX); + mSprite->setPosY((int)mPosY); + + if ((mPosY > mFloor) || (mPosX > PLAY_AREA_RIGHT) || ((mPosX - mWidth) < PLAY_AREA_LEFT)) + mEnabled = false; + + mAlpha -= 2; + if (mAlpha == 0) + mEnabled = false; + } +} + +// Pinta el objeto +void CoffeeDrop::render() +{ + if (mEnabled) + { + mSprite->getTexture()->setAlpha(mAlpha); + mSprite->render(); + mSprite->getTexture()->setAlpha(255); + } +} + +// Deshabilita el objeto +void CoffeeDrop::disable() +{ + mEnabled = false; +} + +// Comprueba si està habilitado +bool CoffeeDrop::isEnabled() +{ + return mEnabled; +} + +#endif \ No newline at end of file diff --git a/source/coffeedrop.h b/source/coffeedrop.h new file mode 100644 index 0000000..0bf9c7a --- /dev/null +++ b/source/coffeedrop.h @@ -0,0 +1,50 @@ +#pragma once +#include "sprite.h" + +#ifndef COFFEEDROP_H +#define COFFEEDROP_H + +#ifndef UNUSED + +// Clase CoffeeDrop. Gotas de café que aparecen al explotar un globo +class CoffeeDrop +{ +private: + float mPosX; // Posicion en el eje X del objeto + float mPosY; // Posicion en el eje Y del objeto + Uint8 mWidth; // Ancho del sprite + Uint8 mHeight; // Alto del sprite + float mVelX; // Velocidad en el eje X + float mVelY; // Velocidad en el eje Y + float mGravity; // Aceleración en el eje Y + int mFloor; // Punto donde se encuentra el suelo y desaparecen + bool mEnabled; // Si esta habilitado. Sirve para saber si se pinta, se actualiza o se puede usar + Sprite *mSprite; // Puntero al sprite con los graficos + Uint8 mAlpha; + +public: + // Constructor + CoffeeDrop(); + + // Destructor + ~CoffeeDrop(); + + // Inicializador + void init(LTexture *texture, SDL_Renderer *renderer, float x, float y, float velX, float velY, int floor); + + // Actualiza las variables del objeto + void update(); + + // Pinta el objeto + void render(); + + // Deshabilita el objeto + void disable(); + + // Comprueba si està habilitado + bool isEnabled(); +}; + +#endif + +#endif diff --git a/source/const.h b/source/const.h index c64146a..c547b54 100644 --- a/source/const.h +++ b/source/const.h @@ -7,73 +7,75 @@ // Textos #define WINDOW_CAPTION "Coffee Crisis" -#define TEXT_COPYRIGHT "@2020,2021 JAILDESIGNER (V1.3*)" +#define TEXT_COPYRIGHT "@2020,2021 JAILDESIGNER (V1.4)" // Recursos -const Uint8 BINFILE_SCORE = 0; -const Uint8 BINFILE_DEMO = 1; -const Uint8 BINFILE_CONFIG = 2; +#define BINFILE_SCORE 0 +#define BINFILE_DEMO 1 +#define BINFILE_CONFIG 2 -const Uint8 TOTAL_BINFILE = 3; +#define TOTAL_BINFILE 3 -const Uint8 MUSIC_INTRO = 0; -const Uint8 MUSIC_PLAYING = 1; -const Uint8 MUSIC_TITLE = 2; +#define MUSIC_INTRO 0 +#define MUSIC_PLAYING 1 +#define MUSIC_TITLE 2 -const Uint8 TOTAL_MUSIC = 3; +#define TOTAL_MUSIC 3 -const Uint8 SOUND_BALLON = 0; -const Uint8 SOUND_BULLET = 1; -const Uint8 SOUND_MENU_SELECT = 2; -const Uint8 SOUND_MENU_CANCEL = 3; -const Uint8 SOUND_MENU_MOVE = 4; -const Uint8 SOUND_TITLE = 5; -const Uint8 SOUND_PLAYER_COLLISION = 6; -const Uint8 SOUND_HISCORE = 7; -const Uint8 SOUND_ITEM_DROP = 8; -const Uint8 SOUND_ITEM_PICKUP = 9; -const Uint8 SOUND_COFFEE_OUT = 10; -const Uint8 SOUND_STAGE_CHANGE = 11; -const Uint8 SOUND_BUBBLE1 = 12; -const Uint8 SOUND_BUBBLE2 = 13; -const Uint8 SOUND_BUBBLE3 = 14; -const Uint8 SOUND_BUBBLE4 = 15; +#define SOUND_BALLOON 0 +#define SOUND_BUBBLE1 1 +#define SOUND_BUBBLE2 2 +#define SOUND_BUBBLE3 3 +#define SOUND_BUBBLE4 4 +#define SOUND_BULLET 5 +#define SOUND_COFFEE_OUT 6 +#define SOUND_HISCORE 7 +#define SOUND_ITEM_DROP 8 +#define SOUND_ITEM_PICKUP 9 +#define SOUND_MENU_CANCEL 10 +#define SOUND_MENU_MOVE 11 +#define SOUND_MENU_SELECT 12 +#define SOUND_PLAYER_COLLISION 13 +#define SOUND_STAGE_CHANGE 14 +#define SOUND_TITLE 15 -const Uint8 TOTAL_SOUND = 16; +#define TOTAL_SOUND 16 -const Uint8 TEXTURE_BALLOON = 0; -const Uint8 TEXTURE_BULLET = 1; -const Uint8 TEXTURE_FONT_BLACK = 2; -const Uint8 TEXTURE_FONT_NOKIA = 3; -const Uint8 TEXTURE_FONT_WHITE = 4; -const Uint8 TEXTURE_GAME_BG = 5; -const Uint8 TEXTURE_GAME_TEXT = 6; -const Uint8 TEXTURE_INTRO = 7; -const Uint8 TEXTURE_ITEMS = 8; -const Uint8 TEXTURE_LOGO = 9; -const Uint8 TEXTURE_MENU = 10; -const Uint8 TEXTURE_PLAYER_BODY = 11; -const Uint8 TEXTURE_PLAYER_LEGS = 12; -const Uint8 TEXTURE_PLAYER_DEATH = 13; -const Uint8 TEXTURE_TITLE = 14; +#define TEXTURE_BALLOON 0 +#define TEXTURE_BULLET 1 +#define TEXTURE_FONT_BLACK 2 +#define TEXTURE_FONT_BLACK_X2 3 +#define TEXTURE_FONT_NOKIA 4 +#define TEXTURE_FONT_WHITE 5 +#define TEXTURE_FONT_WHITE_X2 6 +#define TEXTURE_GAME_BG 7 +#define TEXTURE_GAME_TEXT 8 +#define TEXTURE_INTRO 9 +#define TEXTURE_ITEMS 10 +#define TEXTURE_LOGO 11 +#define TEXTURE_MENU 12 +#define TEXTURE_PLAYER_BODY 13 +#define TEXTURE_PLAYER_DEATH 14 +#define TEXTURE_PLAYER_LEGS 15 +#define TEXTURE_TITLE 16 -const Uint8 TOTAL_TEXTURE = 15; +#define TOTAL_TEXTURE 17 // Tamaño de bloque -const Uint8 BLOCK = 8; -const Uint8 HALF_BLOCK = BLOCK / 2; +#define BLOCK 8 +#define HALF_BLOCK BLOCK / 2 // Tamaño de la pantalla real -const int SCREEN_WIDTH = 256; -const int SCREEN_HEIGHT = SCREEN_WIDTH * 3 / 4; // 192 +#define SCREEN_WIDTH 256 +const int SCREEN_HEIGHT = SCREEN_WIDTH * 3 / 4; // Tamaño de la pantalla que se muestra -const int VIEW_WIDTH = SCREEN_WIDTH * 3; // 768 -const int VIEW_HEIGHT = SCREEN_HEIGHT * 3; // 576 +const int VIEW_WIDTH = SCREEN_WIDTH * 3; +const int VIEW_HEIGHT = SCREEN_HEIGHT * 3; // Cantidad de enteros a escribir en los ficheros de datos -const Uint8 TOTAL_SCORE_DATA = 3; -const Uint16 TOTAL_DEMO_DATA = 2000; +#define TOTAL_SCORE_DATA 3 +#define TOTAL_DEMO_DATA 2000 // Zona de juego const int PLAY_AREA_TOP = (0 * BLOCK); @@ -82,7 +84,7 @@ const int PLAY_AREA_LEFT = (0 * BLOCK); const int PLAY_AREA_RIGHT = SCREEN_WIDTH - (0 * BLOCK); const int PLAY_AREA_WIDTH = PLAY_AREA_RIGHT - PLAY_AREA_LEFT; const int PLAY_AREA_HEIGHT = PLAY_AREA_BOTTOM - PLAY_AREA_TOP; -const int PLAY_AREA_CENTER_X = PLAY_AREA_LEFT + (PLAY_AREA_WIDTH / 2); +const int PLAY_AREA_CENTER_X = PLAY_AREA_LEFT + (PLAY_AREA_WIDTH / 2); const int PLAY_AREA_CENTER_Y = PLAY_AREA_TOP + (PLAY_AREA_HEIGHT / 2); const int PLAY_AREA_FIRST_QUARTER_Y = PLAY_AREA_HEIGHT / 4; const int PLAY_AREA_THIRD_QUARTER_Y = (PLAY_AREA_HEIGHT / 4) * 3; @@ -95,95 +97,92 @@ const int SCREEN_CENTER_Y = SCREEN_HEIGHT / 2; const int SCREEN_FIRST_QUARTER_Y = SCREEN_HEIGHT / 4; const int SCREEN_THIRD_QUARTER_Y = (SCREEN_HEIGHT / 4) * 3; -// Color transparente para los sprites -const Uint8 COLOR_KEY_R = 0xff; -const Uint8 COLOR_KEY_G = 0x00; -const Uint8 COLOR_KEY_B = 0xff; - // Opciones de menu -const int MENU_NO_OPTION = -1; -const int MENU_OPTION_START = 0; -const int MENU_OPTION_QUIT = 1; -const int MENU_OPTION_TOTAL = 2; - -// Selector de menu -const int MENU_SELECTOR_BLACK = (BLOCK * 0); -const int MENU_SELECTOR_WHITE = (BLOCK * 1); +#define MENU_NO_OPTION -1 +#define MENU_OPTION_START 0 +#define MENU_OPTION_QUIT 1 +#define MENU_OPTION_TOTAL 2 // Tipos de fondos para el menu -const int MENU_BACKGROUND_TRANSPARENT = 0; -const int MENU_BACKGROUND_SOLID = 1; +#define MENU_BACKGROUND_TRANSPARENT 0 +#define MENU_BACKGROUND_SOLID 1 // Estados del jugador -const Uint8 PLAYER_STATUS_WALKING_LEFT = 0; -const Uint8 PLAYER_STATUS_WALKING_RIGHT = 1; -const Uint8 PLAYER_STATUS_WALKING_STOP = 2; +#define PLAYER_STATUS_WALKING_LEFT 0 +#define PLAYER_STATUS_WALKING_RIGHT 1 +#define PLAYER_STATUS_WALKING_STOP 2 -const Uint8 PLAYER_STATUS_FIRING_UP = 0; -const Uint8 PLAYER_STATUS_FIRING_LEFT = 1; -const Uint8 PLAYER_STATUS_FIRING_RIGHT = 2; -const Uint8 PLAYER_STATUS_FIRING_NO = 3; +#define PLAYER_STATUS_FIRING_UP 0 +#define PLAYER_STATUS_FIRING_LEFT 1 +#define PLAYER_STATUS_FIRING_RIGHT 2 +#define PLAYER_STATUS_FIRING_NO 3 -const Uint8 PLAYER_ANIMATION_LEGS_WALKING_LEFT = 0; -const Uint8 PLAYER_ANIMATION_LEGS_WALKING_RIGHT = 1; -const Uint8 PLAYER_ANIMATION_LEGS_WALKING_STOP = 2; +#define PLAYER_ANIMATION_LEGS_WALKING_LEFT 0 +#define PLAYER_ANIMATION_LEGS_WALKING_RIGHT 1 +#define PLAYER_ANIMATION_LEGS_WALKING_STOP 2 -const Uint8 PLAYER_ANIMATION_BODY_WALKING_LEFT = 0; -const Uint8 PLAYER_ANIMATION_BODY_FIRING_LEFT = 1; -const Uint8 PLAYER_ANIMATION_BODY_WALKING_RIGHT = 2; -const Uint8 PLAYER_ANIMATION_BODY_FIRING_RIGHT = 3; -const Uint8 PLAYER_ANIMATION_BODY_WALKING_STOP = 4; -const Uint8 PLAYER_ANIMATION_BODY_FIRING_UP = 5; -const Uint8 PLAYER_ANIMATION_BODY_WALKING_LEFT_EXTRA_HIT = 6; -const Uint8 PLAYER_ANIMATION_BODY_FIRING_LEFT_EXTRA_HIT = 7; -const Uint8 PLAYER_ANIMATION_BODY_WALKING_RIGHT_EXTRA_HIT = 8; -const Uint8 PLAYER_ANIMATION_BODY_FIRING_RIGHT_EXTRA_HIT = 9; -const Uint8 PLAYER_ANIMATION_BODY_WALKING_STOP_EXTRA_HIT = 10; -const Uint8 PLAYER_ANIMATION_BODY_FIRING_UP_EXTRA_HIT = 11; +#define PLAYER_ANIMATION_BODY_WALKING_LEFT 0 +#define PLAYER_ANIMATION_BODY_FIRING_LEFT 1 +#define PLAYER_ANIMATION_BODY_WALKING_RIGHT 2 +#define PLAYER_ANIMATION_BODY_FIRING_RIGHT 3 +#define PLAYER_ANIMATION_BODY_WALKING_STOP 4 +#define PLAYER_ANIMATION_BODY_FIRING_UP 5 +#define PLAYER_ANIMATION_BODY_WALKING_LEFT_EXTRA_HIT 6 +#define PLAYER_ANIMATION_BODY_FIRING_LEFT_EXTRA_HIT 7 +#define PLAYER_ANIMATION_BODY_WALKING_RIGHT_EXTRA_HIT 8 +#define PLAYER_ANIMATION_BODY_FIRING_RIGHT_EXTRA_HIT 9 +#define PLAYER_ANIMATION_BODY_WALKING_STOP_EXTRA_HIT 10 +#define PLAYER_ANIMATION_BODY_FIRING_UP_EXTRA_HIT 11 // Variables del jugador -const Uint16 PLAYER_INVULNERABLE_TIMER = 200; +#define PLAYER_INVULNERABLE_COUNTER 200 -// Estados del juego -const Uint8 GAME_STATE_TITLE = 0; -const Uint8 GAME_STATE_PLAYING = 1; -const Uint8 GAME_STATE_QUIT = 2; -const Uint8 GAME_STATE_GAME_OVER_SCREEN = 3; -const Uint8 GAME_STATE_INTRO = 4; -const Uint8 GAME_STATE_DEMO = 5; -const Uint8 GAME_STATE_INSTRUCTIONS = 6; -const Uint8 GAME_STATE_LOGO = 7; -const Uint8 GAME_STATE_INIT = 8; +// Secciones del programa +#define PROG_SECTION_LOGO 0 +#define PROG_SECTION_INTRO 1 +#define PROG_SECTION_TITLE 2 +#define PROG_SECTION_GAME 3 + +// Secciones del juego +#define GAME_SECTION_PLAY 0 +#define GAME_SECTION_PAUSE 1 +#define GAME_SECTION_GAMEOVER 2 + +// Secciones del titulo +#define TITLE_SECTION_1 0 +#define TITLE_SECTION_2 1 +#define TITLE_SECTION_3 2 +#define TITLE_SECTION_INSTRUCTIONS 3 // Estados de cada elemento que pertenece a un evento -const Uint8 EVENT_WAITING = 1; -const Uint8 EVENT_RUNNING = 2; -const Uint8 EVENT_COMPLETED = 3; +#define EVENT_WAITING 1 +#define EVENT_RUNNING 2 +#define EVENT_COMPLETED 3 // Cantidad de eventos de la intro -const Uint8 INTRO_TOTAL_BITMAPS = 6; -const Uint8 INTRO_TOTAL_TEXTS = 9; -const Uint8 INTRO_TOTAL_EVENTS = INTRO_TOTAL_BITMAPS + INTRO_TOTAL_TEXTS; +#define INTRO_TOTAL_BITMAPS 6 +#define INTRO_TOTAL_TEXTS 9 +const int INTRO_TOTAL_EVENTS = INTRO_TOTAL_BITMAPS + INTRO_TOTAL_TEXTS; // Cantidad de eventos de la pantalla de titulo -const Uint8 TITLE_TOTAL_EVENTS = 2; +#define TITLE_TOTAL_EVENTS 2 // Relaciones de Id con nomnbres -const Uint8 BITMAP0 = 0; -const Uint8 BITMAP1 = 1; -const Uint8 BITMAP2 = 2; -const Uint8 BITMAP3 = 3; -const Uint8 BITMAP4 = 4; -const Uint8 BITMAP5 = 5; -const Uint8 TEXT0 = 6; -const Uint8 TEXT1 = 7; -const Uint8 TEXT2 = 8; -const Uint8 TEXT3 = 9; -const Uint8 TEXT4 = 10; -const Uint8 TEXT5 = 11; -const Uint8 TEXT6 = 12; -const Uint8 TEXT7 = 13; -const Uint8 TEXT8 = 14; +#define BITMAP0 0 +#define BITMAP1 1 +#define BITMAP2 2 +#define BITMAP3 3 +#define BITMAP4 4 +#define BITMAP5 5 +#define TEXT0 6 +#define TEXT1 7 +#define TEXT2 8 +#define TEXT3 9 +#define TEXT4 10 +#define TEXT5 11 +#define TEXT6 12 +#define TEXT7 13 +#define TEXT8 14 // Anclajes para el marcador de puntos const int SCORE_WORD_X = (SCREEN_WIDTH / 4) - ((5 * BLOCK) / 2); @@ -198,85 +197,88 @@ const int HISCORE_NUMBER_Y = SCREEN_HEIGHT - (2 * BLOCK) + 2; const int MULTIPLIER_WORD_X = (SCREEN_WIDTH / 2) - ((4 * BLOCK) / 2); const int MULTIPLIER_WORD_Y = SCREEN_HEIGHT - (3 * BLOCK) + 2; -const int MULTIPLIER_NUMBER_X = (SCREEN_WIDTH / 2) - ((3 * BLOCK) / 2);; +const int MULTIPLIER_NUMBER_X = (SCREEN_WIDTH / 2) - ((3 * BLOCK) / 2); const int MULTIPLIER_NUMBER_Y = SCREEN_HEIGHT - (2 * BLOCK) + 2; // Ningun tipo -const Uint8 NO_KIND = 0; +#define NO_KIND 0 // Tipos de globo -const Uint8 BALLOON_1 = 1; -const Uint8 BALLOON_2 = 2; -const Uint8 BALLOON_3 = 3; -const Uint8 BALLOON_4 = 4; +#define BALLOON_1 1 +#define BALLOON_2 2 +#define BALLOON_3 3 +#define BALLOON_4 4 // Velocidad del globo -const float BALLON_VELX_POSITIVE = 0.7f; -const float BALLON_VELX_NEGATIVE = -0.7f; +#define BALLOON_VELX_POSITIVE 0.7f +#define BALLOON_VELX_NEGATIVE -0.7f // Indice para las animaciones de los globos -const Uint8 BALLOON_MOVING_ANIMATION = 0; -const Uint8 BALLOON_POP_ANIMATION = 1; -const Uint8 BALLOON_BORN_ANIMATION = 2; +#define BALLOON_MOVING_ANIMATION 0 +#define BALLOON_POP_ANIMATION 1 +#define BALLOON_BORN_ANIMATION 2 // Cantidad posible de globos -const Uint8 MAX_BALLOONS = 75; +#define MAX_BALLOONS 75 // Tipos de bala -const Uint8 BULLET_UP = 1; -const Uint8 BULLET_LEFT = 2; -const Uint8 BULLET_RIGHT = 3; +#define BULLET_UP 1 +#define BULLET_LEFT 2 +#define BULLET_RIGHT 3 // Cantidad posible de globos -const Uint8 MAX_BULLETS = 50; +#define MAX_BULLETS 50 // Tipos de objetos -const Uint8 ITEM_POINTS_1_DISK = 1; -const Uint8 ITEM_POINTS_2_GAVINA = 2; -const Uint8 ITEM_POINTS_3_PACMAR = 3; -const Uint8 ITEM_CLOCK = 4; -const Uint8 ITEM_TNT = 5; -const Uint8 ITEM_COFFEE = 6; +#define ITEM_POINTS_1_DISK 1 +#define ITEM_POINTS_2_GAVINA 2 +#define ITEM_POINTS_3_PACMAR 3 +#define ITEM_CLOCK 4 +#define ITEM_TNT 5 +#define ITEM_COFFEE 6 // Cantidad de objetos simultaneos -const Uint8 MAX_ITEMS = 5; +#define MAX_ITEMS 5 // Valores para las variables asociadas a los objetos -const Uint8 REMAINING_EXPLOSIONS = 3; -const Uint8 REMAINING_EXPLOSIONS_TIMER = 50; -const Uint16 TIME_STOPPED_TIMER = 300; +#define REMAINING_EXPLOSIONS 3 +#define REMAINING_EXPLOSIONS_COUNTER 50 +#define TIME_STOPPED_COUNTER 300 // Estados de entrada -const Uint8 NO_INPUT = 0; -const Uint8 INPUT_UP = 1; -const Uint8 INPUT_DOWN = 2; -const Uint8 INPUT_LEFT = 3; -const Uint8 INPUT_RIGHT = 4; -const Uint8 INPUT_ACCEPT = 5; -const Uint8 INPUT_CANCEL = 6; -const Uint8 INPUT_FIRE_UP = 7; -const Uint8 INPUT_FIRE_LEFT = 8; -const Uint8 INPUT_FIRE_RIGHT = 9; -const Uint8 INPUT_PAUSE = 10; +#define NO_INPUT 0 +#define INPUT_UP 1 +#define INPUT_DOWN 2 +#define INPUT_LEFT 3 +#define INPUT_RIGHT 4 +#define INPUT_ACCEPT 5 +#define INPUT_CANCEL 6 +#define INPUT_FIRE_UP 7 +#define INPUT_FIRE_LEFT 8 +#define INPUT_FIRE_RIGHT 9 +#define INPUT_PAUSE 10 // Zona muerta del mando analógico -const int JOYSTICK_DEAD_ZONE = 8000; +#define JOYSTICK_DEAD_ZONE 8000 // Tipos de mensajes para el retorno de las funciones -const Uint8 MSG_OK = 0; -const Uint8 MSG_BULLET_OUT = 1; +#define MSG_OK 0 +#define MSG_BULLET_OUT 1 // Tipos de texto -const Uint8 TEXT_FIXED = 0; -const Uint8 TEXT_VARIABLE = 1; +#define TEXT_FIXED 0 +#define TEXT_VARIABLE 1 // Cantidad de elementos del vector de SmartSprites -const Uint8 MAX_SMART_SPRITES = 10; +#define MAX_SMART_SPRITES 10 + +// Cantidad máxima de gotas de café +#define MAX_COFFEE_DROPS 100 // Contadores -const Uint16 TITLE_TIMER = 800; -const Uint8 STAGE_COUNTER = 200; -const Uint16 INSTRUCTIONS_COUNTER = 600; -const Uint16 DEATH_COUNTER = 350; +#define TITLE_COUNTER 800 +#define STAGE_COUNTER 200 +#define INSTRUCTIONS_COUNTER 600 +#define DEATH_COUNTER 350 #endif \ No newline at end of file diff --git a/source/gamedirector.cpp b/source/gamedirector.cpp index 233a724..4e848e8 100644 --- a/source/gamedirector.cpp +++ b/source/gamedirector.cpp @@ -4,114 +4,59 @@ #include const Uint8 *keystates; - -// Calcula el cuadrado de la distancia entre dos puntos -double distanceSquared(int x1, int y1, int x2, int y2) -{ - int deltaX = x2 - x1; - int deltaY = y2 - y1; - return deltaX * deltaX + deltaY * deltaY; -} - -// Detector de colisiones entre dos circulos -bool checkCollision(Circle &a, Circle &b) -{ - // Calcula el radio total al cuadrado - int totalRadiusSquared = a.r + b.r; - totalRadiusSquared = totalRadiusSquared * totalRadiusSquared; - - // Si la distancia entre el centro de los circulos es inferior a la suma de sus radios - if (distanceSquared(a.x, a.y, b.x, b.y) < (totalRadiusSquared)) - { - // Los circulos han colisionado - return true; - } - - // En caso contrario - return false; -} +float mSin[360]; // Vector con los valores del seno para 360 grados // Constructor -GameDirector::GameDirector() +GameDirector::GameDirector(std::string path) { - // Texturas - mTexture[TEXTURE_BALLOON].texture = new LTexture(); - mTexture[TEXTURE_BULLET].texture = new LTexture(); - mTexture[TEXTURE_FONT_BLACK].texture = new LTexture(); - mTexture[TEXTURE_FONT_NOKIA].texture = new LTexture(); - mTexture[TEXTURE_FONT_WHITE].texture = new LTexture(); - mTexture[TEXTURE_GAME_BG].texture = new LTexture(); - mTexture[TEXTURE_GAME_TEXT].texture = new LTexture(); - mTexture[TEXTURE_INTRO].texture = new LTexture(); - mTexture[TEXTURE_ITEMS].texture = new LTexture(); - mTexture[TEXTURE_LOGO].texture = new LTexture(); - mTexture[TEXTURE_MENU].texture = new LTexture(); - mTexture[TEXTURE_PLAYER_BODY].texture = new LTexture(); - mTexture[TEXTURE_PLAYER_LEGS].texture = new LTexture(); - mTexture[TEXTURE_PLAYER_DEATH].texture = new LTexture(); - mTexture[TEXTURE_TITLE].texture = new LTexture(); - - // Manejador de eventos + // Crea los objetos mEventHandler = new SDL_Event(); - // Objetos para el juego - mPlayer = new Player(); - for (Uint8 i = 0; i < MAX_BALLOONS; i++) - { - mBalloon[i] = new Balloon(); - } - for (Uint8 i = 0; i < MAX_BULLETS; i++) - { - mBullet[i] = new Bullet(); - } - for (Uint8 i = 0; i < MAX_ITEMS; i++) - { - mItem[i] = new Item(); - } - for (Uint8 i = 0; i < MAX_SMART_SPRITES; i++) - { - mSmartSprite[i] = new SmartSprite(); - } - mGameBackgroundFront = new Sprite(); - mGameBackgroundSky = new Sprite(); - mGBClouds1 = new MovingSprite(); - mGBClouds1b = new MovingSprite(); - mGBClouds2 = new MovingSprite(); - mGBClouds2b = new MovingSprite(); - mGrass = new Sprite(); - mTitleTile = new Sprite(); - mText.white = new Text(); - mText.black = new Text(); - mText.nokia = new Text(); - mMenu.title = new Menu(); - mMenu.pause = new Menu(); + mTexture[TEXTURE_MENU].texture = new LTexture(); + mTexture[TEXTURE_FONT_WHITE].texture = new LTexture(); + mTexture[TEXTURE_FONT_WHITE_X2].texture = new LTexture(); + mTexture[TEXTURE_FONT_BLACK].texture = new LTexture(); + mTexture[TEXTURE_FONT_BLACK_X2].texture = new LTexture(); + mTexture[TEXTURE_FONT_NOKIA].texture = new LTexture(); + mMenu.gameOver = new Menu(); mMenu.options = new Menu(); - mMenu.active = new Menu(); - mGetReadyBitmap = new SmartSprite(); - mCoffeeBitmap = new SmartSprite(); - mCrisisBitmap = new SmartSprite(); - mDustSpriteLeft = new AnimatedSprite(); - mDustSpriteRight = new AnimatedSprite(); - m1000Bitmap = new SmartSprite(); - m2500Bitmap = new SmartSprite(); - m5000Bitmap = new SmartSprite(); - mInstructions = new Sprite(); - for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) - { - mIntroBitmap[i] = new SmartSprite(); - } - for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) - { - mIntroText[i] = new Text2(); - } - mLogo.sprite = new Sprite(); + mMenu.pause = new Menu(); + mMenu.title = new Menu(); + + mText.black = new Text(); + mText.blackX2 = new Text(); + mText.nokia = new Text(); + mText.white = new Text(); + mText.whiteX2 = new Text(); + + // Inicializa variables + setExecutablePath(path); + setFileList(); + checkFileList(); + + // Carga recursos + loadMediaProg(); + loadScoreFile(); + loadConfigFile(); + loadDemoFile(); + + // Inicializa JailAudio + initJailAudio(); + + // Inicializa SDL + initSDL(); + + // Inicializa el resto de variables + initProg(); } GameDirector::~GameDirector() { - // Libera los recursos globales - unLoadMedia(GAME_STATE_INIT); + quitProg(); + + // Destuye el manejador de eventos + delete mEventHandler; // Libera el mando if (mGameControllerFound) @@ -120,559 +65,196 @@ GameDirector::~GameDirector() mGameController = NULL; } - // Destuye el manejador de eventos - delete mEventHandler; - // Destruye los objetos - delete mTexture[TEXTURE_BALLOON].texture; - delete mTexture[TEXTURE_BULLET].texture; - delete mTexture[TEXTURE_FONT_BLACK].texture; - delete mTexture[TEXTURE_FONT_NOKIA].texture; - delete mTexture[TEXTURE_FONT_WHITE].texture; - delete mTexture[TEXTURE_GAME_BG].texture; - delete mTexture[TEXTURE_GAME_TEXT].texture; - delete mTexture[TEXTURE_INTRO].texture; - delete mTexture[TEXTURE_ITEMS].texture; - delete mTexture[TEXTURE_LOGO].texture; delete mTexture[TEXTURE_MENU].texture; - delete mTexture[TEXTURE_PLAYER_BODY].texture; - delete mTexture[TEXTURE_PLAYER_LEGS].texture; - delete mTexture[TEXTURE_PLAYER_DEATH].texture; - delete mTexture[TEXTURE_TITLE].texture; + delete mTexture[TEXTURE_FONT_WHITE].texture; + delete mTexture[TEXTURE_FONT_WHITE_X2].texture; + delete mTexture[TEXTURE_FONT_BLACK].texture; + delete mTexture[TEXTURE_FONT_BLACK_X2].texture; + delete mTexture[TEXTURE_FONT_NOKIA].texture; - delete mPlayer; - for (Uint8 i = 0; i < MAX_BALLOONS; i++) - { - delete mBalloon[i]; - } - for (Uint8 i = 0; i < MAX_BULLETS; i++) - { - delete mBullet[i]; - } - for (Uint8 i = 0; i < MAX_ITEMS; i++) - { - delete mItem[i]; - } - for (Uint8 i = 0; i < MAX_SMART_SPRITES; i++) - { - delete mSmartSprite[i]; - } - delete mGameBackgroundFront; - delete mGameBackgroundSky; - delete mGBClouds1; - delete mGBClouds1b; - delete mGBClouds2; - delete mGBClouds2b; - delete mGrass; - delete mTitleTile; - delete mText.white; - delete mText.black; - delete mText.nokia; - delete mMenu.title; - delete mMenu.pause; delete mMenu.gameOver; delete mMenu.options; + delete mMenu.pause; + delete mMenu.title; mMenu.active = nullptr; - delete mGetReadyBitmap; - delete mCoffeeBitmap; - delete mCrisisBitmap; - delete mDustSpriteLeft; - delete mDustSpriteRight; - delete m1000Bitmap; - delete m2500Bitmap; - delete m5000Bitmap; - delete mInstructions; - for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) - { - delete mIntroBitmap[i]; - } - for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) - { - delete mIntroText[i]; - } - delete mLogo.sprite; - // Destruye la ventana + delete mText.black; + delete mText.blackX2; + delete mText.nokia; + delete mText.white; + delete mText.whiteX2; + SDL_DestroyTexture(mBackbuffer); - SDL_DestroyTexture(mTitleSurface); - SDL_DestroyTexture(mInstructionsSurface); SDL_DestroyRenderer(mRenderer); SDL_DestroyWindow(mWindow); mBackbuffer = nullptr; - mTitleSurface = nullptr; - mInstructionsSurface = nullptr; - mWindow = nullptr; mRenderer = nullptr; + mWindow = nullptr; - // Sal del subsistema SDL SDL_Quit(); } -// Iniciador -void GameDirector::init(bool reset) +// Inicia las variables necesarias para arrancar el programa +void GameDirector::initProg() { - if (true) - { - // Variables - mTicks = 0; - mTicksSpeed = 15; - mMenaceLevel = 0; - mMenaceLevelThreshold = 0; - mGame.score = 0; - mGame.hiScoreAchieved = false; - mGame.stage = 1; - mGame.stageCounter = 0; - mGame.paused = false; - mGame.deathCounter = DEATH_COUNTER; - for (Uint8 i = 0; i < STAGE_COUNTER; i++) - { - mGame.stagePath[i] = (sin(double(i * 180.0 / double(STAGE_COUNTER)) * 3.14 / 180.0) * (BLOCK * 4)) - BLOCK; - } - mPlayFieldDrawOnly = true; - mDebug = false; - mTitleStatus = 0; - mTitleTimer = TITLE_TIMER; - mExplosionTime = false; - mRemainingExplosions = REMAINING_EXPLOSIONS; - mRemainingExplosionsTimer = REMAINING_EXPLOSIONS_TIMER; - mTimeStopped = false; - mTimeStoppedTimer = TIME_STOPPED_TIMER; - mInstructionsCounter = INSTRUCTIONS_COUNTER; - mDemo = false; - mDemoRecording = false; - mDemoCounter = 0; - mGameCounter = 0; - mMenuKeyPressed = false; - mMenu.active = mMenu.title; - for (int i = 0; i < 360; i++) - { - mSen[i] = sin(i * 3.14 / 180); - } - mTitleBackgroundTimer = 0; - mTitleBackgroundMode = rand() % 2; - mTitleMenuVisible = false; - mLogo.counter = 0; + // Variables + mProg.quit = false; + mProg.debug = false; + mProg.ticks = 0; + mProg.ticksSpeed = 15; + mProg.section = PROG_SECTION_LOGO; + initSin(); + initPaths(); - // Fondo animado - mGBClouds1->init(0, 0, 256, 52, -0.1f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - mGBClouds1->setSpriteClip(256, 0, 256, 52); + mOptions.displayCoffeeDrops = false; - mGBClouds1b->init(256, 0, 256, 52, -0.1f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - mGBClouds1b->setSpriteClip(256, 0, 256, 52); + mDemo.enabled = false; + mDemo.recording = false; + mDemo.counter = 0; - mGBClouds2->init(0, 52, 256, 32, -0.05f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - mGBClouds2->setSpriteClip(256, 52, 256, 32); + mMenu.keyPressed = false; + mMenu.active = mMenu.title; - mGBClouds2b->init(256, 52, 256, 32, -0.05f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - mGBClouds2b->setSpriteClip(256, 52, 256, 32); + // Teclado + mProg.keyboard.up = SDL_SCANCODE_UP; + mProg.keyboard.down = SDL_SCANCODE_DOWN; + mProg.keyboard.left = SDL_SCANCODE_LEFT; + mProg.keyboard.right = SDL_SCANCODE_RIGHT; + mProg.keyboard.accept = SDL_SCANCODE_RETURN; + mProg.keyboard.cancel = SDL_SCANCODE_ESCAPE; + mProg.keyboard.fire = SDL_SCANCODE_W; + mProg.keyboard.fireLeft = SDL_SCANCODE_Q; + mProg.keyboard.fireRight = SDL_SCANCODE_E; + mProg.keyboard.pause = SDL_SCANCODE_ESCAPE; + mProg.keyboard.escape = SDL_SCANCODE_ESCAPE; - mGrass->init(0, 85, SCREEN_WIDTH, 6, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - mGrass->setPosY(154); + // Buffer de teclado + mProg.keyboardBuffer.up = 0; + mProg.keyboardBuffer.down = 0; + mProg.keyboardBuffer.left = 0; + mProg.keyboardBuffer.right = 0; + mProg.keyboardBuffer.accept = 0; + mProg.keyboardBuffer.cancel = 0; + mProg.keyboardBuffer.fire = 0; + mProg.keyboardBuffer.fireLeft = 0; + mProg.keyboardBuffer.fireRight = 0; + mProg.keyboardBuffer.pause = 0; + mProg.keyboardBuffer.escape = 0; - // Objeto jugador - mPlayer->init(PLAY_AREA_CENTER_X - 12, PLAY_AREA_BOTTOM - 24, mTexture[TEXTURE_PLAYER_LEGS].texture, mTexture[TEXTURE_PLAYER_BODY].texture, mRenderer); + // Inicializa los objetos de texto + mText.white->init(mTexture[TEXTURE_FONT_WHITE].texture, mRenderer, TEXT_FIXED, BLOCK); + mText.whiteX2->init(mTexture[TEXTURE_FONT_WHITE_X2].texture, mRenderer, TEXT_FIXED, BLOCK * 2); + mText.black->init(mTexture[TEXTURE_FONT_BLACK].texture, mRenderer, TEXT_FIXED, BLOCK); + mText.blackX2->init(mTexture[TEXTURE_FONT_BLACK_X2].texture, mRenderer, TEXT_FIXED, BLOCK * 2); + mText.nokia->init(mTexture[TEXTURE_FONT_NOKIA].texture, mRenderer, TEXT_VARIABLE, 10); - // Establece a cero todos los valores del vector de objetos globo - resetBalloons(); + // Inicializa el objeto con el menu del titulo + mMenu.title->init("TITLE", 0, 15 * BLOCK, MENU_BACKGROUND_SOLID, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); + mMenu.title->addItem("PLAY"); + mMenu.title->addItem("OPTIONS", 0, 5); + mMenu.title->addItem("QUIT"); + mMenu.title->setDefaultActionWhenCancel(2); + mMenu.title->setBackgroundColor(0x30, 0x30, 0x40, 192); + mMenu.title->setSelectorColor(0xe5, 0x1c, 0x23, 255); + mMenu.title->setSelectorTextColor(0xFF, 0xF1, 0x76); + mMenu.title->centerMenu(SCREEN_CENTER_X); + mMenu.title->centerMenuElements(); - // Crea objetos globo y los centra en el area de juego - mBalloon[0]->init(0, BLOCK, BALLOON_4, BALLON_VELX_POSITIVE, 0, mTexture[TEXTURE_BALLOON].texture, mRenderer); - mBalloon[0]->allignTo(PLAY_AREA_CENTER_X); + // Inicializa el objeto con el menu de pausa + mMenu.pause->init("PAUSE", 0, 12 * BLOCK, MENU_BACKGROUND_SOLID, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); + mMenu.pause->addItem("CONTINUE"); + mMenu.pause->addItem("EXIT TO TITLE"); + mMenu.pause->setDefaultActionWhenCancel(0); + mMenu.pause->setBackgroundColor(0x29, 0x39, 0x41, 240); + mMenu.pause->setSelectorColor(0xFF, 0x7A, 0x00, 255); + mMenu.pause->setSelectorTextColor(0xFF, 0xFF, 0xFF); + mMenu.pause->centerMenu(SCREEN_CENTER_X); + mMenu.pause->centerMenuElements(); - // Con los globos creados, calcula el nivel de amenaza - calculateMenaceLevel(); + // Inicializa el objeto con el menu de la pantalla de game over + mMenu.gameOver->init("GAME OVER", 0, PLAY_AREA_CENTER_Y + BLOCK * 4, MENU_BACKGROUND_TRANSPARENT, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); + mMenu.gameOver->addItem("YES"); + mMenu.gameOver->addItem("NO"); + mMenu.gameOver->setDefaultActionWhenCancel(1); + mMenu.gameOver->setBackgroundColor(0, 0, 0, 255); + mMenu.gameOver->setSelectorColor(0x54, 0x6e, 0x7a, 255); + mMenu.gameOver->setSelectorColor(0x54, 0x6e, 0x7a, 0); + mMenu.gameOver->setSelectorTextColor(0xFF, 0xFF, 0xFF); + mMenu.gameOver->setSelectorTextColor(0xFF, 0xF1, 0x76); + mMenu.gameOver->centerMenu(SCREEN_CENTER_X); + mMenu.gameOver->centerMenuElements(); - // Establece a cero todos los valores del vector de objetos bala - resetBullets(); + // Inicializa el objeto con el menu de las opciones + mMenu.options->init("OPTIONS", 0, 15 * BLOCK, MENU_BACKGROUND_SOLID, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); + mMenu.options->addItem("FULLSCREEN"); + mMenu.options->addItem("WINDOWS SIZE", 0, 5); + mMenu.options->addItem("[OK]"); + mMenu.options->addItem("[CANCEL]"); + mMenu.options->setDefaultActionWhenCancel(3); + mMenu.options->setBackgroundColor(0x30, 0x30, 0x40, 192); + mMenu.options->setSelectorColor(0xe5, 0x1c, 0x23, 255); + mMenu.options->setSelectorTextColor(0xFF, 0xF1, 0x76); + mMenu.options->centerMenu(SCREEN_CENTER_X); + mMenu.options->centerMenuElements(); - // Establece a cero todos los valores del vector de objetos item - resetItems(); + // Actualiza los elementos del menu de opciones con los valores correspondientes + updateOptionsMenu(); +} - // Establece a cero todos los valores del vector de objetos SmafrtSprite - resetSmartSprites(); +// Carga los recursos necesarios para el programa +bool GameDirector::loadMediaProg() +{ + bool success = true; - // Inicializa el sprite del logo - mLogo.sprite->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture[TEXTURE_LOGO].texture, mRenderer); + // Texturas + success &= loadTextureFromFile(mTexture[TEXTURE_MENU].texture, mTexture[TEXTURE_MENU].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_FONT_WHITE].texture, mTexture[TEXTURE_FONT_WHITE].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_FONT_WHITE_X2].texture, mTexture[TEXTURE_FONT_WHITE_X2].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_FONT_BLACK].texture, mTexture[TEXTURE_FONT_BLACK].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_FONT_BLACK_X2].texture, mTexture[TEXTURE_FONT_BLACK_X2].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_FONT_NOKIA].texture, mTexture[TEXTURE_FONT_NOKIA].file, mRenderer); - // Inicializa el bitmap de GetReady! - mGetReadyBitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); - mGetReadyBitmap->setPosX(-113); - mGetReadyBitmap->setPosY(PLAY_AREA_CENTER_Y - 10); - mGetReadyBitmap->setWidth(109); - mGetReadyBitmap->setHeight(20); - mGetReadyBitmap->setVelX(2.0f); - mGetReadyBitmap->setVelY(0.0f); - mGetReadyBitmap->setAccelX(0.00f); - mGetReadyBitmap->setAccelY(0.0f); - mGetReadyBitmap->setSpriteClip(0, 0, 109, 20); - mGetReadyBitmap->setEnabled(true); - mGetReadyBitmap->setEnabledTimer(0); - mGetReadyBitmap->setDestX(PLAY_AREA_RIGHT); - mGetReadyBitmap->setDestY(PLAY_AREA_CENTER_Y - 10); + // Sonidos + mSound[SOUND_MENU_SELECT].sound = JA_LoadSound(mSound[SOUND_MENU_SELECT].file.c_str()); + mSound[SOUND_MENU_CANCEL].sound = JA_LoadSound(mSound[SOUND_MENU_CANCEL].file.c_str()); + mSound[SOUND_MENU_MOVE].sound = JA_LoadSound(mSound[SOUND_MENU_MOVE].file.c_str()); - // Inicializa el bitmap de Coffee - mCoffeeBitmap->init(mTexture[TEXTURE_TITLE].texture, mRenderer); - mCoffeeBitmap->setId(0); - mCoffeeBitmap->setIntroEvents(&mTitleEvents[0]); - mCoffeeBitmap->setPosX(45); - mCoffeeBitmap->setPosY(11 - 200); - mCoffeeBitmap->setWidth(167); - mCoffeeBitmap->setHeight(46); - mCoffeeBitmap->setVelX(0.0f); - mCoffeeBitmap->setVelY(2.5f); - mCoffeeBitmap->setAccelX(0.0f); - mCoffeeBitmap->setAccelY(0.1f); - //mCoffeeBitmap->setSpriteClip(45, 11, 167, 46); - mCoffeeBitmap->setSpriteClip(0, 0, 167, 46); - mCoffeeBitmap->setEnabled(true); - mCoffeeBitmap->setEnabledTimer(0); - mCoffeeBitmap->setDestX(45); - mCoffeeBitmap->setDestY(11); + // Musicas + mMusic[MUSIC_TITLE].music = JA_LoadMusic(mMusic[MUSIC_TITLE].file.c_str()); - // Inicializa el bitmap de Crisis - mCrisisBitmap->init(mTexture[TEXTURE_TITLE].texture, mRenderer); - mCrisisBitmap->setId(1); - mCrisisBitmap->setIntroEvents(&mTitleEvents[0]); - mCrisisBitmap->setPosX(60); - mCrisisBitmap->setPosY(57 + 200); - mCrisisBitmap->setWidth(137); - mCrisisBitmap->setHeight(46); - mCrisisBitmap->setVelX(0.0f); - mCrisisBitmap->setVelY(-2.5f); - mCrisisBitmap->setAccelX(0.0f); - mCrisisBitmap->setAccelY(-0.1f); - //mCrisisBitmap->setSpriteClip(60, 57, 137, 46); - mCrisisBitmap->setSpriteClip(0, 46, 137, 46); - mCrisisBitmap->setEnabled(true); - mCrisisBitmap->setEnabledTimer(0); - mCrisisBitmap->setDestX(60); - mCrisisBitmap->setDestY(57); + return success; +} - // Inicializa el bitmap de DustRight - mDustSpriteRight->init(mTexture[TEXTURE_TITLE].texture, mRenderer); - mDustSpriteRight->setPosX(218); - mDustSpriteRight->setPosY(47); - mDustSpriteRight->setWidth(16); - mDustSpriteRight->setHeight(14); - mDustSpriteRight->setCurrentFrame(0); - mDustSpriteRight->setAnimationCounter(0); - mDustSpriteRight->setAnimationNumFrames(0, 7); - mDustSpriteRight->setAnimationSpeed(0, 8); - mDustSpriteRight->setAnimationLoop(0, false); - mDustSpriteRight->setAnimationFrames(0, 0, 160 + (mDustSpriteRight->getWidth() * 0), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); - mDustSpriteRight->setAnimationFrames(0, 1, 160 + (mDustSpriteRight->getWidth() * 1), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); - mDustSpriteRight->setAnimationFrames(0, 2, 160 + (mDustSpriteRight->getWidth() * 2), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); - mDustSpriteRight->setAnimationFrames(0, 3, 160 + (mDustSpriteRight->getWidth() * 3), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); - mDustSpriteRight->setAnimationFrames(0, 4, 160 + (mDustSpriteRight->getWidth() * 4), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); - mDustSpriteRight->setAnimationFrames(0, 5, 160 + (mDustSpriteRight->getWidth() * 5), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); - mDustSpriteRight->setAnimationFrames(0, 6, 160 + (mDustSpriteRight->getWidth() * 6), 80, mDustSpriteRight->getWidth(), mDustSpriteRight->getHeight()); +// Libera las variables del programa +void GameDirector::quitProg() +{ + // Guarda los ficheros + saveScoreFile(); + saveConfigFile(); + saveDemoFile(); - // Inicializa el bitmap de DustLeft - mDustSpriteLeft->init(mTexture[TEXTURE_TITLE].texture, mRenderer); - mDustSpriteLeft->setPosX(33); - mDustSpriteLeft->setPosY(47); - mDustSpriteLeft->setWidth(16); - mDustSpriteLeft->setHeight(14); - mDustSpriteLeft->setCurrentFrame(0); - mDustSpriteLeft->setAnimationCounter(0); - mDustSpriteLeft->setAnimationNumFrames(0, 7); - mDustSpriteLeft->setAnimationSpeed(0, 8); - mDustSpriteLeft->setAnimationLoop(0, false); - mDustSpriteLeft->setAnimationFrames(0, 0, 160 + (mDustSpriteLeft->getWidth() * 0), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); - mDustSpriteLeft->setAnimationFrames(0, 1, 160 + (mDustSpriteLeft->getWidth() * 1), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); - mDustSpriteLeft->setAnimationFrames(0, 2, 160 + (mDustSpriteLeft->getWidth() * 2), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); - mDustSpriteLeft->setAnimationFrames(0, 3, 160 + (mDustSpriteLeft->getWidth() * 3), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); - mDustSpriteLeft->setAnimationFrames(0, 4, 160 + (mDustSpriteLeft->getWidth() * 4), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); - mDustSpriteLeft->setAnimationFrames(0, 5, 160 + (mDustSpriteLeft->getWidth() * 5), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); - mDustSpriteLeft->setAnimationFrames(0, 6, 160 + (mDustSpriteLeft->getWidth() * 6), 66, mDustSpriteLeft->getWidth(), mDustSpriteLeft->getHeight()); + // Texturas + mTexture[TEXTURE_MENU].texture->unload(); + mTexture[TEXTURE_FONT_WHITE].texture->unload(); + mTexture[TEXTURE_FONT_WHITE_X2].texture->unload(); + mTexture[TEXTURE_FONT_BLACK].texture->unload(); + mTexture[TEXTURE_FONT_BLACK_X2].texture->unload(); + mTexture[TEXTURE_FONT_NOKIA].texture->unload(); - // Inicializa el bitmap de 1000 puntos - m1000Bitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); - m1000Bitmap->setPosX(0); - m1000Bitmap->setPosY(0); - m1000Bitmap->setWidth(26); - m1000Bitmap->setHeight(9); - m1000Bitmap->setVelX(0.0f); - m1000Bitmap->setVelY(-0.5f); - m1000Bitmap->setAccelX(0.0f); - m1000Bitmap->setAccelY(-0.1f); - m1000Bitmap->setSpriteClip(0, 20, 26, 9); - m1000Bitmap->setEnabled(false); - m1000Bitmap->setEnabledTimer(0); - m1000Bitmap->setDestX(0); - m1000Bitmap->setDestY(0); + // Sonidos + JA_DeleteSound(mSound[SOUND_MENU_SELECT].sound); + JA_DeleteSound(mSound[SOUND_MENU_CANCEL].sound); + JA_DeleteSound(mSound[SOUND_MENU_MOVE].sound); - // Inicializa el bitmap de 2500 puntos - m2500Bitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); - m2500Bitmap->setPosX(0); - m2500Bitmap->setPosY(0); - m2500Bitmap->setWidth(28); - m2500Bitmap->setHeight(9); - m2500Bitmap->setVelX(0.0f); - m2500Bitmap->setVelY(-0.5f); - m2500Bitmap->setAccelX(0.0f); - m2500Bitmap->setAccelY(-0.1f); - m2500Bitmap->setSpriteClip(26, 20, 28, 9); - m2500Bitmap->setEnabled(false); - m2500Bitmap->setEnabledTimer(0); - m2500Bitmap->setDestX(0); - m2500Bitmap->setDestY(0); + // Musicas + JA_DeleteMusic(mMusic[MUSIC_TITLE].music); +} - // Inicializa el bitmap de 5000 puntos - m5000Bitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); - m5000Bitmap->setPosX(0); - m5000Bitmap->setPosY(0); - m5000Bitmap->setWidth(28); - m5000Bitmap->setHeight(9); - m5000Bitmap->setVelX(0.0f); - m5000Bitmap->setVelY(-0.5f); - m5000Bitmap->setAccelX(0.0f); - m5000Bitmap->setAccelY(-0.1f); - m5000Bitmap->setSpriteClip(54, 20, 28, 9); - m5000Bitmap->setEnabled(false); - m5000Bitmap->setEnabledTimer(0); - m5000Bitmap->setDestX(0); - m5000Bitmap->setDestY(0); - - // Inicializa el vector de eventos de la intro - for (Uint8 i = 0; i < INTRO_TOTAL_EVENTS; i++) - { - mIntroEvents[i] = EVENT_WAITING; - } - - // Inicializa el vector de eventos de la pantalla de titulo - for (Uint8 i = 0; i < TITLE_TOTAL_EVENTS; i++) - { - mTitleEvents[i] = EVENT_WAITING; - } - - // Inicializa los bitmaps de la intro - for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) - { - mIntroBitmap[i]->init(mTexture[TEXTURE_INTRO].texture, mRenderer); - mIntroBitmap[i]->setId(i); - mIntroBitmap[i]->setIntroEvents(&mIntroEvents[0]); - mIntroBitmap[i]->setWidth(128); - mIntroBitmap[i]->setHeight(96); - mIntroBitmap[i]->setEnabled(false); - mIntroBitmap[i]->setEnabledTimer(20); - mIntroBitmap[i]->setDestX(SCREEN_CENTER_X - 64); - mIntroBitmap[i]->setDestY(SCREEN_FIRST_QUARTER_Y - 24); - } - - mIntroBitmap[0]->setPosX(-128); - mIntroBitmap[0]->setPosY(SCREEN_FIRST_QUARTER_Y - 24); - mIntroBitmap[0]->setVelX(0.0f); - mIntroBitmap[0]->setVelY(0.0f); - mIntroBitmap[0]->setAccelX(0.6f); - mIntroBitmap[0]->setAccelY(0.0f); - mIntroBitmap[0]->setSpriteClip(0, 0, 128, 96); - - mIntroBitmap[1]->setPosX(SCREEN_WIDTH); - mIntroBitmap[1]->setPosY(SCREEN_FIRST_QUARTER_Y - 24); - mIntroBitmap[1]->setVelX(-1.0f); - mIntroBitmap[1]->setVelY(0.0f); - mIntroBitmap[1]->setAccelX(-0.3f); - mIntroBitmap[1]->setAccelY(0.0f); - mIntroBitmap[1]->setSpriteClip(128, 0, 128, 96); - - mIntroBitmap[2]->setPosX(SCREEN_CENTER_X - 64); - mIntroBitmap[2]->setPosY(-96); - mIntroBitmap[2]->setVelX(0.0f); - mIntroBitmap[2]->setVelY(3.0f); - mIntroBitmap[2]->setAccelX(0.1f); - mIntroBitmap[2]->setAccelY(0.3f); - mIntroBitmap[2]->setSpriteClip(0, 96, 128, 96); - - mIntroBitmap[2]->setEnabledTimer(250); - - mIntroBitmap[3]->setPosX(SCREEN_CENTER_X - 64); - mIntroBitmap[3]->setPosY(SCREEN_HEIGHT); - mIntroBitmap[3]->setVelX(0.0f); - mIntroBitmap[3]->setVelY(-0.7f); - mIntroBitmap[3]->setAccelX(0.0f); - mIntroBitmap[3]->setAccelY(0.0f); - mIntroBitmap[3]->setSpriteClip(128, 96, 128, 96); - - mIntroBitmap[4]->setPosX(SCREEN_CENTER_X - 64); - mIntroBitmap[4]->setPosY(-96); - mIntroBitmap[4]->setVelX(0.0f); - mIntroBitmap[4]->setVelY(3.0f); - mIntroBitmap[4]->setAccelX(0.1f); - mIntroBitmap[4]->setAccelY(0.3f); - mIntroBitmap[4]->setSpriteClip(0, 192, 128, 96); - - mIntroBitmap[5]->setPosX(SCREEN_WIDTH); - mIntroBitmap[5]->setPosY(SCREEN_FIRST_QUARTER_Y - 24); - mIntroBitmap[5]->setVelX(-0.7f); - mIntroBitmap[5]->setVelY(0.0f); - mIntroBitmap[5]->setAccelX(0.0f); - mIntroBitmap[5]->setAccelY(0.0f); - mIntroBitmap[5]->setSpriteClip(128, 192, 128, 96); - - // Inicializa los textos de la intro - for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) - { - mIntroText[i]->init(mTexture[TEXTURE_FONT_NOKIA].texture, mRenderer, TEXT_VARIABLE, 10); - mIntroText[i]->setId(6 + i); - mIntroText[i]->setIntroEvents(&mIntroEvents[0]); - mIntroText[i]->setPosX(BLOCK * 0); - mIntroText[i]->setPosY(SCREEN_HEIGHT - (BLOCK * 6)); - mIntroText[i]->setKerning(-1); - mIntroText[i]->setEnabled(false); - mIntroText[i]->setEnabledTimer(180); - } - - mIntroText[0]->setCaption("Un dia qualsevol de l'any 2000"); - mIntroText[0]->setWrittingSpeed(10); - - mIntroText[1]->setCaption("Tot esta tranquil a la UPV"); - mIntroText[1]->setWrittingSpeed(10); - - mIntroText[2]->setCaption("Fins que un desaprensiu..."); - mIntroText[2]->setWrittingSpeed(15); - - mIntroText[3]->setCaption("HEY! ME ANE A FERME UN CORTAET..."); - mIntroText[3]->setWrittingSpeed(10); - - mIntroText[4]->setCaption("UAAAAAAAAAAAAA!!!"); - mIntroText[4]->setWrittingSpeed(1); - - mIntroText[5]->setCaption("Espera un moment..."); - mIntroText[5]->setWrittingSpeed(20); - - mIntroText[6]->setCaption("Si resulta que no tinc solt!"); - mIntroText[6]->setWrittingSpeed(2); - - mIntroText[7]->setCaption("MERDA DE MAQUINA!"); - mIntroText[7]->setWrittingSpeed(3); - - mIntroText[8]->setCaption("Blop... blop... blop..."); - mIntroText[8]->setWrittingSpeed(20); - - for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) - { - mIntroText[i]->center(SCREEN_CENTER_X); - } - } - - // Esta parte solo se ejecuta al arrancar la aplicación - if (reset == false) - { - // Variables - mGame.status = GAME_STATE_LOGO; - mTitleStatus = 0; - mTiteNextGS = GAME_STATE_PLAYING; - - // Teclado - mKeyboard.up = SDL_SCANCODE_UP; - mKeyboard.down = SDL_SCANCODE_DOWN; - mKeyboard.left = SDL_SCANCODE_LEFT; - mKeyboard.right = SDL_SCANCODE_RIGHT; - mKeyboard.accept = SDL_SCANCODE_RETURN; - mKeyboard.cancel = SDL_SCANCODE_ESCAPE; - mKeyboard.fire = SDL_SCANCODE_W; - mKeyboard.fireLeft = SDL_SCANCODE_Q; - mKeyboard.fireRight = SDL_SCANCODE_E; - mKeyboard.pause = SDL_SCANCODE_ESCAPE; - mKeyboard.escape = SDL_SCANCODE_ESCAPE; - - // Buffer de teclado - mKeyboardBuffer.up = 0; - mKeyboardBuffer.down = 0; - mKeyboardBuffer.left = 0; - mKeyboardBuffer.right = 0; - mKeyboardBuffer.accept = 0; - mKeyboardBuffer.cancel = 0; - mKeyboardBuffer.fire = 0; - mKeyboardBuffer.fireLeft = 0; - mKeyboardBuffer.fireRight = 0; - mKeyboardBuffer.pause = 0; - mKeyboardBuffer.escape = 0; - - // Carga la máxima puntuación a partir del fichero de datos - if (mScoreDataFile[0] == 0) - { - mGame.hiScore = 10000; - } - // Comprueba el checksum para ver si se ha modificado el fichero - else if (mScoreDataFile[0] % 43 == mScoreDataFile[1]) - { - mGame.hiScore = mScoreDataFile[0]; - } - else - { - mGame.hiScore = 10000; - } - - // Los fondos - mGameBackgroundFront->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - mGameBackgroundSky->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture[TEXTURE_GAME_BG].texture, mRenderer); - - // El tile de fondo - mTitleTile->init(0, 0, 64, 64, mTexture[TEXTURE_TITLE].texture, mRenderer); - mTitleTile->setSpriteClip(192, 0, 64, 64); - - // Las instrucciones - //mInstructions->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture.instructions, mRenderer); - - // Objetos texto, uno de cada color - mText.white->init(mTexture[TEXTURE_FONT_WHITE].texture, mRenderer, TEXT_FIXED, BLOCK); - mText.black->init(mTexture[TEXTURE_FONT_BLACK].texture, mRenderer, TEXT_FIXED, BLOCK); - mText.nokia->init(mTexture[TEXTURE_FONT_NOKIA].texture, mRenderer, TEXT_VARIABLE, 10); - - // Inicializa el objeto con el menu del titulo - mMenu.title->init("TITLE", 0, 15 * BLOCK, MENU_BACKGROUND_SOLID, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); - mMenu.title->addItem("PLAY"); - mMenu.title->addItem("OPTIONS", 0, 5); - mMenu.title->addItem("QUIT"); - mMenu.title->setDefaultActionWhenCancel(2); - mMenu.title->setBackgroundColor(0x30, 0x30, 0x40, 192); - mMenu.title->setSelectorColor(0xe5, 0x1c, 0x23, 255); - mMenu.title->setSelectorTextColor(0xFF, 0xF1, 0x76); - mMenu.title->centerMenu(SCREEN_CENTER_X); - mMenu.title->centerMenuElements(); - - // Inicializa el objeto con el menu de pausa - mMenu.pause->init("PAUSE", 0, 12 * BLOCK, MENU_BACKGROUND_SOLID, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); - mMenu.pause->addItem("CONTINUE"); - mMenu.pause->addItem("EXIT TO TITLE"); - mMenu.pause->setDefaultActionWhenCancel(0); - mMenu.pause->setBackgroundColor(0x29, 0x39, 0x41, 240); - mMenu.pause->setSelectorColor(0xFF, 0x7A, 0x00, 255); - mMenu.pause->setSelectorTextColor(0xFF, 0xFF, 0xFF); - mMenu.pause->centerMenu(SCREEN_CENTER_X); - mMenu.pause->centerMenuElements(); - - // Inicializa el objeto con el menu de la pantalla de game over - mMenu.gameOver->init("GAME OVER", 0, PLAY_AREA_CENTER_Y + BLOCK * 4, MENU_BACKGROUND_TRANSPARENT, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); - mMenu.gameOver->addItem("YES"); - mMenu.gameOver->addItem("NO"); - mMenu.gameOver->setDefaultActionWhenCancel(1); - mMenu.gameOver->setBackgroundColor(0, 0, 0, 255); - mMenu.gameOver->setSelectorColor(0x54, 0x6e, 0x7a, 255); - mMenu.gameOver->setSelectorColor(0x54, 0x6e, 0x7a, 0); - mMenu.gameOver->setSelectorTextColor(0xFF, 0xFF, 0xFF); - mMenu.gameOver->setSelectorTextColor(0xFF, 0xF1, 0x76); - mMenu.gameOver->centerMenu(SCREEN_CENTER_X); - mMenu.gameOver->centerMenuElements(); - - // Inicializa el objeto con el menu de las opciones - mMenu.options->init("OPTIONS", 0, 15 * BLOCK, MENU_BACKGROUND_SOLID, mTexture[TEXTURE_MENU].texture, mRenderer, mText.white); - mMenu.options->addItem("FULLSCREEN"); - mMenu.options->addItem("WINDOWS SIZE", 0, 5); - mMenu.options->addItem("[OK]"); - mMenu.options->addItem("[CANCEL]"); - mMenu.options->setDefaultActionWhenCancel(3); - mMenu.options->setBackgroundColor(0x30, 0x30, 0x40, 192); - mMenu.options->setSelectorColor(0xe5, 0x1c, 0x23, 255); - mMenu.options->setSelectorTextColor(0xFF, 0xF1, 0x76); - mMenu.options->centerMenu(SCREEN_CENTER_X); - mMenu.options->centerMenuElements(); - - // Actualiza los elementos del menu de opciones con los valores correspondientes - updateOptionsMenu(); - } +// Inicializa JailAudio +void GameDirector::initJailAudio() +{ + JA_Init(48000, AUDIO_S16, 2); } // Arranca SDL y crea la ventana @@ -695,9 +277,6 @@ bool GameDirector::initSDL() printf("Warning: Nearest texture filtering not enabled!\n"); } - // Inicializa jail_audio - JA_Init(48000, AUDIO_S16, 2); - // Comprueba si hay algun mando conectado if (SDL_NumJoysticks() < 1) { @@ -720,7 +299,7 @@ bool GameDirector::initSDL() printf("%i joysticks were found.\n", SDL_NumJoysticks()); std::cout << SDL_JoystickNumButtons(mGameController) << " buttons\n"; - //Get controller haptic device + // Obtiene el dispositivo de control háptico mControllerHaptic = SDL_HapticOpenFromJoystick(mGameController); if (mControllerHaptic == NULL) { @@ -730,7 +309,7 @@ bool GameDirector::initSDL() { printf("Haptics detected\n"); - //Get initialize rumble + // Inicializa la vibración if (SDL_HapticRumbleInit(mControllerHaptic) < 0) { printf("Warning: Unable to initialize rumble!\nSDL Error: %s\n", SDL_GetError()); @@ -774,22 +353,6 @@ bool GameDirector::initSDL() printf("Backbuffer could not be created!\nSDL Error: %s\n", SDL_GetError()); success = false; } - - // Crea una textura para dibujar el fondo del titulo - mTitleSurface = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2); - if (mTitleSurface == NULL) - { - printf("TitleSurface could not be created!\nSDL Error: %s\n", SDL_GetError()); - success = false; - } - - // Crea una textura para dibujar las instrucciones - mInstructionsSurface = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT); - if (mInstructionsSurface == NULL) - { - printf("InstructionsSurface could not be created!\nSDL Error: %s\n", SDL_GetError()); - success = false; - } } } @@ -797,53 +360,770 @@ bool GameDirector::initSDL() return success; } +// Inicializa el vector con los valores del seno +void GameDirector::initSin() +{ + // Vector con los valores del seno para 360 grados + for (int i = 0; i < 360; i++) + { + mSin[i] = sin((float)i * 3.14f / 180.0f); + } +} + +// Inicializa las variables que contienen puntos de ruta para mover objetos +void GameDirector::initPaths() +{ + int firstPart = STAGE_COUNTER / 4; // 50 + int secondPart = firstPart * 3; // 150 + int centerPoint = PLAY_AREA_CENTER_Y - (BLOCK * 2); + int distance = (PLAY_AREA_BOTTOM) - (PLAY_AREA_CENTER_Y - 16); + + for (int i = 0; i < STAGE_COUNTER; i++) + { + if (i < firstPart) + mGame.stagePath[i] = (mSin[(int)((i * 1.8f) + 90)] * (distance) + centerPoint); + else if (i < secondPart) + mGame.stagePath[i] = (int)centerPoint; + else + mGame.stagePath[i] = (mSin[(int)(((i - 149) * 1.8f) + 90)] * (centerPoint + 17) - 17); + } +} + +// Inicializa las variables necesarias para la sección 'Logo' +void GameDirector::initLogo() +{ + // Reserva memoria para los punteros + mTexture[TEXTURE_LOGO].texture = new LTexture(); + mLogo.sprite = new Sprite(); + + // Carga los recursos + loadMediaLogo(); + + // Inicializa variables + mLogo.counter = 0; + mLogo.sprite->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture[TEXTURE_LOGO].texture, mRenderer); +} + +// Carga los recursos necesarios para la sección 'Logo' +bool GameDirector::loadMediaLogo() +{ + bool success = true; + + success &= loadTextureFromFile(mTexture[TEXTURE_LOGO].texture, mTexture[TEXTURE_LOGO].file, mRenderer); + + return success; +} + +// Libera las variables necesarias para la sección 'Logo' +void GameDirector::quitLogo() +{ + // Texturas + mTexture[TEXTURE_LOGO].texture->unload(); + + // Libera la memoria de los punteros + delete mTexture[TEXTURE_LOGO].texture; + delete mLogo.sprite; + mTexture[TEXTURE_LOGO].texture = nullptr; + mLogo.sprite = nullptr; +} + +// Inicializa las variables necesarias para la sección 'Intro' +void GameDirector::initIntro() +{ + // Reserva memoria para los punteros + mTexture[TEXTURE_INTRO].texture = new LTexture(); + + for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) + mIntro.bitmap[i] = new SmartSprite(); + + for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) + mIntro.text[i] = new Text2(); + + // Carga los recursos + loadMediaIntro(); + + // Inicializa el vector de eventos de la intro + for (Uint8 i = 0; i < INTRO_TOTAL_EVENTS; i++) + mIntro.events[i] = EVENT_WAITING; + + // Inicializa los bitmaps de la intro + for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) + { + mIntro.bitmap[i]->init(mTexture[TEXTURE_INTRO].texture, mRenderer); + mIntro.bitmap[i]->setId(i); + mIntro.bitmap[i]->setIntroEvents(&mIntro.events[0]); + mIntro.bitmap[i]->setWidth(128); + mIntro.bitmap[i]->setHeight(96); + mIntro.bitmap[i]->setEnabled(false); + mIntro.bitmap[i]->setEnabledTimer(20); + mIntro.bitmap[i]->setDestX(SCREEN_CENTER_X - 64); + mIntro.bitmap[i]->setDestY(SCREEN_FIRST_QUARTER_Y - 24); + } + + mIntro.bitmap[0]->setPosX(-128); + mIntro.bitmap[0]->setPosY(SCREEN_FIRST_QUARTER_Y - 24); + mIntro.bitmap[0]->setVelX(0.0f); + mIntro.bitmap[0]->setVelY(0.0f); + mIntro.bitmap[0]->setAccelX(0.6f); + mIntro.bitmap[0]->setAccelY(0.0f); + mIntro.bitmap[0]->setSpriteClip(0, 0, 128, 96); + + mIntro.bitmap[1]->setPosX(SCREEN_WIDTH); + mIntro.bitmap[1]->setPosY(SCREEN_FIRST_QUARTER_Y - 24); + mIntro.bitmap[1]->setVelX(-1.0f); + mIntro.bitmap[1]->setVelY(0.0f); + mIntro.bitmap[1]->setAccelX(-0.3f); + mIntro.bitmap[1]->setAccelY(0.0f); + mIntro.bitmap[1]->setSpriteClip(128, 0, 128, 96); + + mIntro.bitmap[2]->setPosX(SCREEN_CENTER_X - 64); + mIntro.bitmap[2]->setPosY(-96); + mIntro.bitmap[2]->setVelX(0.0f); + mIntro.bitmap[2]->setVelY(3.0f); + mIntro.bitmap[2]->setAccelX(0.1f); + mIntro.bitmap[2]->setAccelY(0.3f); + mIntro.bitmap[2]->setSpriteClip(0, 96, 128, 96); + + mIntro.bitmap[2]->setEnabledTimer(250); + + mIntro.bitmap[3]->setPosX(SCREEN_CENTER_X - 64); + mIntro.bitmap[3]->setPosY(SCREEN_HEIGHT); + mIntro.bitmap[3]->setVelX(0.0f); + mIntro.bitmap[3]->setVelY(-0.7f); + mIntro.bitmap[3]->setAccelX(0.0f); + mIntro.bitmap[3]->setAccelY(0.0f); + mIntro.bitmap[3]->setSpriteClip(128, 96, 128, 96); + + mIntro.bitmap[4]->setPosX(SCREEN_CENTER_X - 64); + mIntro.bitmap[4]->setPosY(-96); + mIntro.bitmap[4]->setVelX(0.0f); + mIntro.bitmap[4]->setVelY(3.0f); + mIntro.bitmap[4]->setAccelX(0.1f); + mIntro.bitmap[4]->setAccelY(0.3f); + mIntro.bitmap[4]->setSpriteClip(0, 192, 128, 96); + + mIntro.bitmap[5]->setPosX(SCREEN_WIDTH); + mIntro.bitmap[5]->setPosY(SCREEN_FIRST_QUARTER_Y - 24); + mIntro.bitmap[5]->setVelX(-0.7f); + mIntro.bitmap[5]->setVelY(0.0f); + mIntro.bitmap[5]->setAccelX(0.0f); + mIntro.bitmap[5]->setAccelY(0.0f); + mIntro.bitmap[5]->setSpriteClip(128, 192, 128, 96); + + // Inicializa los textos de la intro + for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) + { + mIntro.text[i]->init(mTexture[TEXTURE_FONT_NOKIA].texture, mRenderer, TEXT_VARIABLE, 10); + mIntro.text[i]->setId(6 + i); + mIntro.text[i]->setIntroEvents(&mIntro.events[0]); + mIntro.text[i]->setPosX(BLOCK * 0); + mIntro.text[i]->setPosY(SCREEN_HEIGHT - (BLOCK * 6)); + mIntro.text[i]->setKerning(-1); + mIntro.text[i]->setEnabled(false); + mIntro.text[i]->setEnabledTimer(180); + } + + mIntro.text[0]->setCaption("Un dia qualsevol de l'any 2000"); + mIntro.text[0]->setWrittingSpeed(10); + + mIntro.text[1]->setCaption("Tot esta tranquil a la UPV"); + mIntro.text[1]->setWrittingSpeed(10); + + mIntro.text[2]->setCaption("Fins que un desaprensiu..."); + mIntro.text[2]->setWrittingSpeed(15); + + mIntro.text[3]->setCaption("HEY! ME ANE A FERME UN CORTAET..."); + mIntro.text[3]->setWrittingSpeed(10); + + mIntro.text[4]->setCaption("UAAAAAAAAAAAAA!!!"); + mIntro.text[4]->setWrittingSpeed(1); + + mIntro.text[5]->setCaption("Espera un moment..."); + mIntro.text[5]->setWrittingSpeed(20); + + mIntro.text[6]->setCaption("Si resulta que no tinc solt!"); + mIntro.text[6]->setWrittingSpeed(2); + + mIntro.text[7]->setCaption("MERDA DE MAQUINA!"); + mIntro.text[7]->setWrittingSpeed(3); + + mIntro.text[8]->setCaption("Blop... blop... blop..."); + mIntro.text[8]->setWrittingSpeed(20); + + for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) + { + mIntro.text[i]->center(SCREEN_CENTER_X); + } +} + +// Carga los recursos necesarios para la sección 'Intro' +bool GameDirector::loadMediaIntro() +{ + bool success = true; + + // Texturas + success &= loadTextureFromFile(mTexture[TEXTURE_INTRO].texture, mTexture[TEXTURE_INTRO].file, mRenderer); + + // Musicas + mMusic[MUSIC_INTRO].music = JA_LoadMusic(mMusic[MUSIC_INTRO].file.c_str()); + + return success; +} + +// Libera las variables necesarias para la sección 'Intro' +void GameDirector::quitIntro() +{ + // Texturas + mTexture[TEXTURE_INTRO].texture->unload(); + + // Musicas + JA_DeleteMusic(mMusic[MUSIC_INTRO].music); + + // Libera la memoria de los punteros + delete mTexture[TEXTURE_INTRO].texture; + mTexture[TEXTURE_INTRO].texture = nullptr; + + for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) + { + delete mIntro.bitmap[i]; + mIntro.bitmap[i] = nullptr; + } + for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) + { + delete mIntro.text[i]; + mIntro.text[i] = nullptr; + } +} + +// Inicializa las variables necesarias para la sección 'Title' +void GameDirector::initTitle(Uint8 section) +{ + // Reserva memoria para los punteros + mTexture[TEXTURE_TITLE].texture = new LTexture(); + mTexture[TEXTURE_ITEMS].texture = new LTexture(); + mTitle.coffeeBitmap = new SmartSprite(); + mTitle.crisisBitmap = new SmartSprite(); + mTitle.dustBitmapL = new AnimatedSprite(); + mTitle.dustBitmapR = new AnimatedSprite(); + mTitle.tile = new Sprite(); + + // Carga los recursos + loadMediaTitle(); + + // Inicializa variables + mTitle.section = section; + mTitle.counter = TITLE_COUNTER; + mTitle.backgroundCounter = 0; + mTitle.backgroundMode = rand() % 2; + mTitle.menuVisible = false; + mTitle.nextProgSection = PROG_SECTION_GAME; + mTitle.instructionsCounter = INSTRUCTIONS_COUNTER; + + // Inicializa el bitmap de Coffee + mTitle.coffeeBitmap->init(mTexture[TEXTURE_TITLE].texture, mRenderer); + mTitle.coffeeBitmap->setId(0); + mTitle.coffeeBitmap->setIntroEvents(&mTitle.events[0]); + mTitle.coffeeBitmap->setPosX(45); + mTitle.coffeeBitmap->setPosY(11 - 200); + mTitle.coffeeBitmap->setWidth(167); + mTitle.coffeeBitmap->setHeight(46); + mTitle.coffeeBitmap->setVelX(0.0f); + mTitle.coffeeBitmap->setVelY(2.5f); + mTitle.coffeeBitmap->setAccelX(0.0f); + mTitle.coffeeBitmap->setAccelY(0.1f); + mTitle.coffeeBitmap->setSpriteClip(0, 0, 167, 46); + mTitle.coffeeBitmap->setEnabled(true); + mTitle.coffeeBitmap->setEnabledTimer(0); + mTitle.coffeeBitmap->setDestX(45); + mTitle.coffeeBitmap->setDestY(11); + + // Inicializa el bitmap de Crisis + mTitle.crisisBitmap->init(mTexture[TEXTURE_TITLE].texture, mRenderer); + mTitle.crisisBitmap->setId(1); + mTitle.crisisBitmap->setIntroEvents(&mTitle.events[0]); + mTitle.crisisBitmap->setPosX(60); + mTitle.crisisBitmap->setPosY(57 + 200); + mTitle.crisisBitmap->setWidth(137); + mTitle.crisisBitmap->setHeight(46); + mTitle.crisisBitmap->setVelX(0.0f); + mTitle.crisisBitmap->setVelY(-2.5f); + mTitle.crisisBitmap->setAccelX(0.0f); + mTitle.crisisBitmap->setAccelY(-0.1f); + mTitle.crisisBitmap->setSpriteClip(0, 46, 137, 46); + mTitle.crisisBitmap->setEnabled(true); + mTitle.crisisBitmap->setEnabledTimer(0); + mTitle.crisisBitmap->setDestX(60); + mTitle.crisisBitmap->setDestY(57); + + // Inicializa el bitmap de DustRight + mTitle.dustBitmapR->init(mTexture[TEXTURE_TITLE].texture, mRenderer); + mTitle.dustBitmapR->setPosX(218); + mTitle.dustBitmapR->setPosY(47); + mTitle.dustBitmapR->setWidth(16); + mTitle.dustBitmapR->setHeight(14); + mTitle.dustBitmapR->setCurrentFrame(0); + mTitle.dustBitmapR->setAnimationCounter(0); + mTitle.dustBitmapR->setAnimationNumFrames(0, 7); + mTitle.dustBitmapR->setAnimationSpeed(0, 8); + mTitle.dustBitmapR->setAnimationLoop(0, false); + mTitle.dustBitmapR->setAnimationFrames(0, 0, 160 + (mTitle.dustBitmapR->getWidth() * 0), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + mTitle.dustBitmapR->setAnimationFrames(0, 1, 160 + (mTitle.dustBitmapR->getWidth() * 1), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + mTitle.dustBitmapR->setAnimationFrames(0, 2, 160 + (mTitle.dustBitmapR->getWidth() * 2), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + mTitle.dustBitmapR->setAnimationFrames(0, 3, 160 + (mTitle.dustBitmapR->getWidth() * 3), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + mTitle.dustBitmapR->setAnimationFrames(0, 4, 160 + (mTitle.dustBitmapR->getWidth() * 4), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + mTitle.dustBitmapR->setAnimationFrames(0, 5, 160 + (mTitle.dustBitmapR->getWidth() * 5), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + mTitle.dustBitmapR->setAnimationFrames(0, 6, 160 + (mTitle.dustBitmapR->getWidth() * 6), 80, mTitle.dustBitmapR->getWidth(), mTitle.dustBitmapR->getHeight()); + + // Inicializa el bitmap de DustLeft + mTitle.dustBitmapL->init(mTexture[TEXTURE_TITLE].texture, mRenderer); + mTitle.dustBitmapL->setPosX(33); + mTitle.dustBitmapL->setPosY(47); + mTitle.dustBitmapL->setWidth(16); + mTitle.dustBitmapL->setHeight(14); + mTitle.dustBitmapL->setCurrentFrame(0); + mTitle.dustBitmapL->setAnimationCounter(0); + mTitle.dustBitmapL->setAnimationNumFrames(0, 7); + mTitle.dustBitmapL->setAnimationSpeed(0, 8); + mTitle.dustBitmapL->setAnimationLoop(0, false); + mTitle.dustBitmapL->setAnimationFrames(0, 0, 160 + (mTitle.dustBitmapL->getWidth() * 0), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + mTitle.dustBitmapL->setAnimationFrames(0, 1, 160 + (mTitle.dustBitmapL->getWidth() * 1), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + mTitle.dustBitmapL->setAnimationFrames(0, 2, 160 + (mTitle.dustBitmapL->getWidth() * 2), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + mTitle.dustBitmapL->setAnimationFrames(0, 3, 160 + (mTitle.dustBitmapL->getWidth() * 3), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + mTitle.dustBitmapL->setAnimationFrames(0, 4, 160 + (mTitle.dustBitmapL->getWidth() * 4), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + mTitle.dustBitmapL->setAnimationFrames(0, 5, 160 + (mTitle.dustBitmapL->getWidth() * 5), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + mTitle.dustBitmapL->setAnimationFrames(0, 6, 160 + (mTitle.dustBitmapL->getWidth() * 6), 66, mTitle.dustBitmapL->getWidth(), mTitle.dustBitmapL->getHeight()); + + // Inicializa el vector de eventos de la pantalla de titulo + for (Uint8 i = 0; i < TITLE_TOTAL_EVENTS; i++) + mTitle.events[i] = EVENT_WAITING; + + // El tile de fondo + mTitle.tile->init(0, 0, 64, 64, mTexture[TEXTURE_TITLE].texture, mRenderer); + mTitle.tile->setSpriteClip(192, 0, 64, 64); +} + +// Carga los recursos necesarios para la sección 'Title' +bool GameDirector::loadMediaTitle() +{ + // Indicador de éxito en la carga + bool success = true; + + // Texturas + success &= loadTextureFromFile(mTexture[TEXTURE_TITLE].texture, mTexture[TEXTURE_TITLE].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_ITEMS].texture, mTexture[TEXTURE_ITEMS].file, mRenderer); + + // Crea el mosaico de fondo del titulo + mTitleSurface = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2); + if (mTitleSurface == NULL) + { + printf("TitleSurface could not be created!\nSDL Error: %s\n", SDL_GetError()); + success = false; + } + else + { + SDL_SetRenderTarget(mRenderer, mTitleSurface); + SDL_SetRenderDrawColor(mRenderer, 0x43, 0x43, 0x4F, 0xFF); + SDL_RenderClear(mRenderer); + for (Uint8 i = 0; i < 8; i++) + for (Uint8 j = 0; j < 6; j++) + { + mTitle.tile->setPosX(i * 64); + mTitle.tile->setPosY(j * 64); + mTitle.tile->render(); + } + mTitle.backgroundWindow.x = 0; + mTitle.backgroundWindow.y = 0; + mTitle.backgroundWindow.w = SCREEN_WIDTH; + mTitle.backgroundWindow.h = SCREEN_HEIGHT; + SDL_SetRenderTarget(mRenderer, nullptr); + } + + // Crea una textura para dibujar las instrucciones + mInstructionsSurface = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT); + if (mInstructionsSurface == NULL) + { + printf("InstructionsSurface could not be created!\nSDL Error: %s\n", SDL_GetError()); + success = false; + } + + // Sonidos + mSound[SOUND_TITLE].sound = JA_LoadSound(mSound[SOUND_TITLE].file.c_str()); + + return success; +} + +// Libera las variables necesarias para la sección 'Title' +void GameDirector::quitTitle() +{ + // Texturas + mTexture[TEXTURE_TITLE].texture->unload(); + mTexture[TEXTURE_ITEMS].texture->unload(); + + // Sonidos + JA_DeleteSound(mSound[SOUND_TITLE].sound); + + // Libera la memoria de los punteros + delete mTexture[TEXTURE_TITLE].texture; + delete mTexture[TEXTURE_ITEMS].texture; + delete mTitle.coffeeBitmap; + delete mTitle.crisisBitmap; + delete mTitle.dustBitmapL; + delete mTitle.dustBitmapR; + delete mTitle.tile; + mTexture[TEXTURE_TITLE].texture = nullptr; + mTexture[TEXTURE_ITEMS].texture = nullptr; + mTitle.coffeeBitmap = nullptr; + mTitle.crisisBitmap = nullptr; + mTitle.dustBitmapL = nullptr; + mTitle.dustBitmapR = nullptr; + mTitle.tile = nullptr; + + SDL_DestroyTexture(mTitleSurface); + SDL_DestroyTexture(mInstructionsSurface); + mTitleSurface = nullptr; + mInstructionsSurface = nullptr; +} + +// Inicializa las variables necesarias para la sección 'Game' +void GameDirector::initGame() +{ + // Reserva memoria para los punteros + for (Uint8 i = 0; i < MAX_BALLOONS; i++) + mGame.balloon[i] = new Balloon(); + for (Uint8 i = 0; i < MAX_BULLETS; i++) + mGame.bullet[i] = new Bullet(); + for (Uint8 i = 0; i < MAX_ITEMS; i++) + mGame.item[i] = new Item(); + for (Uint8 i = 0; i < MAX_SMART_SPRITES; i++) + mGame.smartSprite[i] = new SmartSprite(); + mTexture[TEXTURE_PLAYER_LEGS].texture = new LTexture(); + mTexture[TEXTURE_PLAYER_BODY].texture = new LTexture(); + mTexture[TEXTURE_PLAYER_DEATH].texture = new LTexture(); + mTexture[TEXTURE_BALLOON].texture = new LTexture(); + mTexture[TEXTURE_BULLET].texture = new LTexture(); + mTexture[TEXTURE_GAME_BG].texture = new LTexture(); + mTexture[TEXTURE_GAME_TEXT].texture = new LTexture(); + mTexture[TEXTURE_ITEMS].texture = new LTexture(); + mGame.player = new Player(); + mGame._1000Bitmap = new SmartSprite(); + mGame._2500Bitmap = new SmartSprite(); + mGame._5000Bitmap = new SmartSprite(); + mGame.background = new Sprite(); + mGame.clouds1a = new MovingSprite(); + mGame.clouds1b = new MovingSprite(); + mGame.clouds2a = new MovingSprite(); + mGame.clouds2b = new MovingSprite(); + mGame.getReadyBitmap = new SmartSprite(); + mGame.gradient = new Sprite(); + mGame.grass = new Sprite(); + + // Carga los recursos + loadMediaGame(); + + // Inicializa variables + mGame.section = GAME_SECTION_PLAY; + mGame.menaceLevelCurrent = 0; + mGame.menaceLevelThreshold = 0; + mGame.score = 0; + mGame.hiScoreAchieved = false; + mGame.stage = 1; + mGame.stageCounter = STAGE_COUNTER; + mGame.deathCounter = DEATH_COUNTER; + mGame.explosionTime = false; + mGame.remainingExplosions = REMAINING_EXPLOSIONS; + mGame.remainingExplosionsCounter = REMAINING_EXPLOSIONS_COUNTER; + mGame.timeStopped = false; + mGame.timeStoppedCounter = TIME_STOPPED_COUNTER; + mGame.playFieldDrawOnly = true; + mProg.debug = false; + mGame.counter = 0; + + // Fondo animado + mGame.clouds1a->init(0, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); + mGame.clouds1a->setSpriteClip(256, 0, 256, 52); + + mGame.clouds1b->init(256, 0, 256, 52, -0.4f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); + mGame.clouds1b->setSpriteClip(256, 0, 256, 52); + + mGame.clouds2a->init(0, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); + mGame.clouds2a->setSpriteClip(256, 52, 256, 32); + + mGame.clouds2b->init(256, 52, 256, 32, -0.2f, 0.0f, 0.0f, 0.0f, mTexture[TEXTURE_GAME_BG].texture, mRenderer); + mGame.clouds2b->setSpriteClip(256, 52, 256, 32); + + mGame.grass->init(0, 85, SCREEN_WIDTH, 6, mTexture[TEXTURE_GAME_BG].texture, mRenderer); + mGame.grass->setPosY(154); + + // Objeto jugador + mGame.player->init(PLAY_AREA_CENTER_X - 12, PLAY_AREA_BOTTOM - 24, mTexture[TEXTURE_PLAYER_LEGS].texture, mTexture[TEXTURE_PLAYER_BODY].texture, mRenderer); + + // Establece a cero todos los valores del vector de objetos globo + resetBalloons(); + + // Crea objetos globo y los centra en el area de juego + mGame.balloon[0]->init(0, BLOCK, BALLOON_4, BALLOON_VELX_POSITIVE, 0, mTexture[TEXTURE_BALLOON].texture, mRenderer); + mGame.balloon[0]->allignTo(PLAY_AREA_CENTER_X); + + // Con los globos creados, calcula el nivel de amenaza + setMenaceLevel(); + + // Establece a cero todos los valores del vector de objetos bala + resetBullets(); + + // Establece a cero todos los valores del vector de objetos item + resetItems(); + + // Establece a cero todos los valores del vector de objetos SmafrtSprite + resetSmartSprites(); + + // Inicializa el bitmap de GetReady! + mGame.getReadyBitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); + mGame.getReadyBitmap->setPosX(-113); + mGame.getReadyBitmap->setPosY(PLAY_AREA_CENTER_Y - 10); + mGame.getReadyBitmap->setWidth(109); + mGame.getReadyBitmap->setHeight(20); + mGame.getReadyBitmap->setVelX(2.0f); + mGame.getReadyBitmap->setVelY(0.0f); + mGame.getReadyBitmap->setAccelX(0.00f); + mGame.getReadyBitmap->setAccelY(0.0f); + mGame.getReadyBitmap->setSpriteClip(0, 0, 109, 20); + mGame.getReadyBitmap->setEnabled(true); + mGame.getReadyBitmap->setEnabledTimer(0); + mGame.getReadyBitmap->setDestX(PLAY_AREA_RIGHT); + mGame.getReadyBitmap->setDestY(PLAY_AREA_CENTER_Y - 10); + + // Inicializa el bitmap de 1000 puntos + mGame._1000Bitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); + mGame._1000Bitmap->setPosX(0); + mGame._1000Bitmap->setPosY(0); + mGame._1000Bitmap->setWidth(26); + mGame._1000Bitmap->setHeight(9); + mGame._1000Bitmap->setVelX(0.0f); + mGame._1000Bitmap->setVelY(-0.5f); + mGame._1000Bitmap->setAccelX(0.0f); + mGame._1000Bitmap->setAccelY(-0.1f); + mGame._1000Bitmap->setSpriteClip(0, 20, 26, 9); + mGame._1000Bitmap->setEnabled(false); + mGame._1000Bitmap->setEnabledTimer(0); + mGame._1000Bitmap->setDestX(0); + mGame._1000Bitmap->setDestY(0); + + // Inicializa el bitmap de 2500 puntos + mGame._2500Bitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); + mGame._2500Bitmap->setPosX(0); + mGame._2500Bitmap->setPosY(0); + mGame._2500Bitmap->setWidth(28); + mGame._2500Bitmap->setHeight(9); + mGame._2500Bitmap->setVelX(0.0f); + mGame._2500Bitmap->setVelY(-0.5f); + mGame._2500Bitmap->setAccelX(0.0f); + mGame._2500Bitmap->setAccelY(-0.1f); + mGame._2500Bitmap->setSpriteClip(26, 20, 28, 9); + mGame._2500Bitmap->setEnabled(false); + mGame._2500Bitmap->setEnabledTimer(0); + mGame._2500Bitmap->setDestX(0); + mGame._2500Bitmap->setDestY(0); + + // Inicializa el bitmap de 5000 puntos + mGame._5000Bitmap->init(mTexture[TEXTURE_GAME_TEXT].texture, mRenderer); + mGame._5000Bitmap->setPosX(0); + mGame._5000Bitmap->setPosY(0); + mGame._5000Bitmap->setWidth(28); + mGame._5000Bitmap->setHeight(9); + mGame._5000Bitmap->setVelX(0.0f); + mGame._5000Bitmap->setVelY(-0.5f); + mGame._5000Bitmap->setAccelX(0.0f); + mGame._5000Bitmap->setAccelY(-0.1f); + mGame._5000Bitmap->setSpriteClip(54, 20, 28, 9); + mGame._5000Bitmap->setEnabled(false); + mGame._5000Bitmap->setEnabledTimer(0); + mGame._5000Bitmap->setDestX(0); + mGame._5000Bitmap->setDestY(0); + + // Los fondos + mGame.background->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture[TEXTURE_GAME_BG].texture, mRenderer); + mGame.gradient->init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, mTexture[TEXTURE_GAME_BG].texture, mRenderer); +} + +// Carga los recursos necesarios para la sección 'Game' +bool GameDirector::loadMediaGame() +{ + bool success = true; + + // Texturas + success &= loadTextureFromFile(mTexture[TEXTURE_PLAYER_LEGS].texture, mTexture[TEXTURE_PLAYER_LEGS].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_PLAYER_BODY].texture, mTexture[TEXTURE_PLAYER_BODY].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_PLAYER_DEATH].texture, mTexture[TEXTURE_PLAYER_DEATH].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_BALLOON].texture, mTexture[TEXTURE_BALLOON].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_BULLET].texture, mTexture[TEXTURE_BULLET].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_GAME_BG].texture, mTexture[TEXTURE_GAME_BG].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_GAME_TEXT].texture, mTexture[TEXTURE_GAME_TEXT].file, mRenderer); + success &= loadTextureFromFile(mTexture[TEXTURE_ITEMS].texture, mTexture[TEXTURE_ITEMS].file, mRenderer); + + // Sonidos + mSound[SOUND_BALLOON].sound = JA_LoadSound(mSound[SOUND_BALLOON].file.c_str()); + mSound[SOUND_BULLET].sound = JA_LoadSound(mSound[SOUND_BULLET].file.c_str()); + mSound[SOUND_PLAYER_COLLISION].sound = JA_LoadSound(mSound[SOUND_PLAYER_COLLISION].file.c_str()); + mSound[SOUND_HISCORE].sound = JA_LoadSound(mSound[SOUND_HISCORE].file.c_str()); + mSound[SOUND_ITEM_DROP].sound = JA_LoadSound(mSound[SOUND_ITEM_DROP].file.c_str()); + mSound[SOUND_ITEM_PICKUP].sound = JA_LoadSound(mSound[SOUND_ITEM_PICKUP].file.c_str()); + mSound[SOUND_COFFEE_OUT].sound = JA_LoadSound(mSound[SOUND_COFFEE_OUT].file.c_str()); + mSound[SOUND_STAGE_CHANGE].sound = JA_LoadSound(mSound[SOUND_STAGE_CHANGE].file.c_str()); + mSound[SOUND_TITLE].sound = JA_LoadSound(mSound[SOUND_TITLE].file.c_str()); + mSound[SOUND_BUBBLE1].sound = JA_LoadSound(mSound[SOUND_BUBBLE1].file.c_str()); + mSound[SOUND_BUBBLE2].sound = JA_LoadSound(mSound[SOUND_BUBBLE2].file.c_str()); + mSound[SOUND_BUBBLE3].sound = JA_LoadSound(mSound[SOUND_BUBBLE3].file.c_str()); + mSound[SOUND_BUBBLE4].sound = JA_LoadSound(mSound[SOUND_BUBBLE4].file.c_str()); + + // Musicas + mMusic[MUSIC_PLAYING].music = JA_LoadMusic(mMusic[MUSIC_PLAYING].file.c_str()); + + return success; +} + +// Libera las variables necesarias para la sección 'Game' +void GameDirector::quitGame() +{ + // Texturas + mTexture[TEXTURE_PLAYER_LEGS].texture->unload(); + mTexture[TEXTURE_PLAYER_BODY].texture->unload(); + mTexture[TEXTURE_PLAYER_DEATH].texture->unload(); + mTexture[TEXTURE_BALLOON].texture->unload(); + mTexture[TEXTURE_BULLET].texture->unload(); + mTexture[TEXTURE_GAME_BG].texture->unload(); + mTexture[TEXTURE_GAME_TEXT].texture->unload(); + mTexture[TEXTURE_ITEMS].texture->unload(); + + // Sonidos + JA_DeleteSound(mSound[SOUND_BALLOON].sound); + JA_DeleteSound(mSound[SOUND_BULLET].sound); + JA_DeleteSound(mSound[SOUND_PLAYER_COLLISION].sound); + JA_DeleteSound(mSound[SOUND_HISCORE].sound); + JA_DeleteSound(mSound[SOUND_ITEM_DROP].sound); + JA_DeleteSound(mSound[SOUND_ITEM_PICKUP].sound); + JA_DeleteSound(mSound[SOUND_COFFEE_OUT].sound); + JA_DeleteSound(mSound[SOUND_STAGE_CHANGE].sound); + JA_DeleteSound(mSound[SOUND_TITLE].sound); + JA_DeleteSound(mSound[SOUND_BUBBLE1].sound); + JA_DeleteSound(mSound[SOUND_BUBBLE2].sound); + JA_DeleteSound(mSound[SOUND_BUBBLE3].sound); + JA_DeleteSound(mSound[SOUND_BUBBLE4].sound); + + // Musicas + JA_DeleteMusic(mMusic[MUSIC_PLAYING].music); + + // Libera la memoria de los punteros + for (Uint8 i = 0; i < MAX_BALLOONS; i++) + { + delete mGame.balloon[i]; + mGame.balloon[i] = nullptr; + } + for (Uint8 i = 0; i < MAX_BULLETS; i++) + { + delete mGame.bullet[i]; + mGame.bullet[i] = nullptr; + } + for (Uint8 i = 0; i < MAX_ITEMS; i++) + { + delete mGame.item[i]; + mGame.item[i] = nullptr; + } + for (Uint8 i = 0; i < MAX_SMART_SPRITES; i++) + { + delete mGame.smartSprite[i]; + mGame.smartSprite[i] = nullptr; + } + delete mTexture[TEXTURE_PLAYER_LEGS].texture; + delete mTexture[TEXTURE_PLAYER_BODY].texture; + delete mTexture[TEXTURE_PLAYER_DEATH].texture; + delete mTexture[TEXTURE_BALLOON].texture; + delete mTexture[TEXTURE_BULLET].texture; + delete mTexture[TEXTURE_GAME_BG].texture; + delete mTexture[TEXTURE_GAME_TEXT].texture; + delete mTexture[TEXTURE_ITEMS].texture; + delete mGame.player; + delete mGame._1000Bitmap; + delete mGame._2500Bitmap; + delete mGame._5000Bitmap; + delete mGame.background; + delete mGame.clouds1a; + delete mGame.clouds1b; + delete mGame.clouds2a; + delete mGame.clouds2b; + delete mGame.getReadyBitmap; + delete mGame.gradient; + delete mGame.grass; + mTexture[TEXTURE_PLAYER_LEGS].texture = nullptr; + mTexture[TEXTURE_PLAYER_BODY].texture = nullptr; + mTexture[TEXTURE_PLAYER_DEATH].texture = nullptr; + mTexture[TEXTURE_BALLOON].texture = nullptr; + mTexture[TEXTURE_BULLET].texture = nullptr; + mTexture[TEXTURE_GAME_BG].texture = nullptr; + mTexture[TEXTURE_GAME_TEXT].texture = nullptr; + mTexture[TEXTURE_ITEMS].texture = nullptr; + mGame.player = nullptr; + mGame._1000Bitmap = nullptr; + mGame._2500Bitmap = nullptr; + mGame._5000Bitmap = nullptr; + mGame.background = nullptr; + mGame.clouds1a = nullptr; + mGame.clouds1b = nullptr; + mGame.clouds2a = nullptr; + mGame.clouds2b = nullptr; + mGame.getReadyBitmap = nullptr; + mGame.gradient = nullptr; + mGame.grass = nullptr; +} + // Crea el indice de ficheros void GameDirector::setFileList() { // Ficheros binarios - mBinFile[BINFILE_SCORE].file = mExecutablePath + "/" + "../data/score.bin"; - mBinFile[BINFILE_DEMO].file = mExecutablePath + "/" + "../data/demo.bin"; - mBinFile[BINFILE_CONFIG].file = mExecutablePath + "/" + "../data/config.bin"; + mBinFile[BINFILE_SCORE].file = mProg.executablePath + "/" + "../data/score.bin"; + mBinFile[BINFILE_DEMO].file = mProg.executablePath + "/" + "../data/demo.bin"; + mBinFile[BINFILE_CONFIG].file = mProg.executablePath + "/" + "../data/config.bin"; // Musicas - mMusic[MUSIC_INTRO].file = mExecutablePath + "/" + "../media/music/intro.ogg"; - mMusic[MUSIC_PLAYING].file = mExecutablePath + "/" + "../media/music/playing.ogg"; - mMusic[MUSIC_TITLE].file = mExecutablePath + "/" + "../media/music/title.ogg"; + mMusic[MUSIC_INTRO].file = mProg.executablePath + "/" + "../media/music/intro.ogg"; + mMusic[MUSIC_PLAYING].file = mProg.executablePath + "/" + "../media/music/playing.ogg"; + mMusic[MUSIC_TITLE].file = mProg.executablePath + "/" + "../media/music/title.ogg"; // Sonidos - mSound[SOUND_BALLON].file = mExecutablePath + "/" + "../media/sound/balloon.wav"; - mSound[SOUND_BULLET].file = mExecutablePath + "/" + "../media/sound/bullet.wav"; - mSound[SOUND_MENU_SELECT].file = mExecutablePath + "/" + "../media/sound/menu_select.wav"; - mSound[SOUND_MENU_CANCEL].file = mExecutablePath + "/" + "../media/sound/menu_cancel.wav"; - mSound[SOUND_MENU_MOVE].file = mExecutablePath + "/" + "../media/sound/menu_move.wav"; - mSound[SOUND_TITLE].file = mExecutablePath + "/" + "../media/sound/title.wav"; - mSound[SOUND_PLAYER_COLLISION].file = mExecutablePath + "/" + "../media/sound/player_collision.wav"; - mSound[SOUND_HISCORE].file = mExecutablePath + "/" + "../media/sound/hiscore.wav"; - mSound[SOUND_ITEM_DROP].file = mExecutablePath + "/" + "../media/sound/itemdrop.wav"; - mSound[SOUND_ITEM_PICKUP].file = mExecutablePath + "/" + "../media/sound/itempickup.wav"; - mSound[SOUND_COFFEE_OUT].file = mExecutablePath + "/" + "../media/sound/coffeeout.wav"; - mSound[SOUND_STAGE_CHANGE].file = mExecutablePath + "/" + "../media/sound/stage_change.wav"; - mSound[SOUND_BUBBLE1].file = mExecutablePath + "/" + "../media/sound/bubble1.wav"; - mSound[SOUND_BUBBLE2].file = mExecutablePath + "/" + "../media/sound/bubble2.wav"; - mSound[SOUND_BUBBLE3].file = mExecutablePath + "/" + "../media/sound/bubble3.wav"; - mSound[SOUND_BUBBLE4].file = mExecutablePath + "/" + "../media/sound/bubble4.wav"; + mSound[SOUND_BALLOON].file = mProg.executablePath + "/" + "../media/sound/balloon.wav"; + mSound[SOUND_BUBBLE1].file = mProg.executablePath + "/" + "../media/sound/bubble1.wav"; + mSound[SOUND_BUBBLE2].file = mProg.executablePath + "/" + "../media/sound/bubble2.wav"; + mSound[SOUND_BUBBLE3].file = mProg.executablePath + "/" + "../media/sound/bubble3.wav"; + mSound[SOUND_BUBBLE4].file = mProg.executablePath + "/" + "../media/sound/bubble4.wav"; + mSound[SOUND_BULLET].file = mProg.executablePath + "/" + "../media/sound/bullet.wav"; + mSound[SOUND_COFFEE_OUT].file = mProg.executablePath + "/" + "../media/sound/coffeeout.wav"; + mSound[SOUND_HISCORE].file = mProg.executablePath + "/" + "../media/sound/hiscore.wav"; + mSound[SOUND_ITEM_DROP].file = mProg.executablePath + "/" + "../media/sound/itemdrop.wav"; + mSound[SOUND_ITEM_PICKUP].file = mProg.executablePath + "/" + "../media/sound/itempickup.wav"; + mSound[SOUND_MENU_CANCEL].file = mProg.executablePath + "/" + "../media/sound/menu_cancel.wav"; + mSound[SOUND_MENU_MOVE].file = mProg.executablePath + "/" + "../media/sound/menu_move.wav"; + mSound[SOUND_MENU_SELECT].file = mProg.executablePath + "/" + "../media/sound/menu_select.wav"; + mSound[SOUND_PLAYER_COLLISION].file = mProg.executablePath + "/" + "../media/sound/player_collision.wav"; + mSound[SOUND_STAGE_CHANGE].file = mProg.executablePath + "/" + "../media/sound/stage_change.wav"; + mSound[SOUND_TITLE].file = mProg.executablePath + "/" + "../media/sound/title.wav"; // Texturas - mTexture[TEXTURE_BALLOON].file = mExecutablePath + "/" + "../media/gfx/balloon.png"; - mTexture[TEXTURE_BULLET].file = mExecutablePath + "/" + "../media/gfx/bullet.png"; - mTexture[TEXTURE_FONT_BLACK].file = mExecutablePath + "/" + "../media/gfx/font_black.png"; - mTexture[TEXTURE_FONT_NOKIA].file = mExecutablePath + "/" + "../media/gfx/font_nokia.png"; - mTexture[TEXTURE_FONT_WHITE].file = mExecutablePath + "/" + "../media/gfx/font_white.png"; - mTexture[TEXTURE_GAME_BG].file = mExecutablePath + "/" + "../media/gfx/game_bg.png"; - mTexture[TEXTURE_GAME_TEXT].file = mExecutablePath + "/" + "../media/gfx/game_text.png"; - mTexture[TEXTURE_INTRO].file = mExecutablePath + "/" + "../media/gfx/intro.png"; - mTexture[TEXTURE_ITEMS].file = mExecutablePath + "/" + "../media/gfx/items.png"; - mTexture[TEXTURE_LOGO].file = mExecutablePath + "/" + "../media/gfx/logo.png"; - mTexture[TEXTURE_MENU].file = mExecutablePath + "/" + "../media/gfx/menu.png"; - mTexture[TEXTURE_PLAYER_LEGS].file = mExecutablePath + "/" + "../media/gfx/player_legs.png"; - mTexture[TEXTURE_PLAYER_BODY].file = mExecutablePath + "/" + "../media/gfx/player_body.png"; - mTexture[TEXTURE_PLAYER_DEATH].file = mExecutablePath + "/" + "../media/gfx/player_death.png"; - mTexture[TEXTURE_TITLE].file = mExecutablePath + "/" + "../media/gfx/title.png"; + mTexture[TEXTURE_BALLOON].file = mProg.executablePath + "/" + "../media/gfx/balloon.png"; + mTexture[TEXTURE_BULLET].file = mProg.executablePath + "/" + "../media/gfx/bullet.png"; + mTexture[TEXTURE_FONT_BLACK_X2].file = mProg.executablePath + "/" + "../media/gfx/font_black_x2.png"; + mTexture[TEXTURE_FONT_BLACK].file = mProg.executablePath + "/" + "../media/gfx/font_black.png"; + mTexture[TEXTURE_FONT_NOKIA].file = mProg.executablePath + "/" + "../media/gfx/font_nokia.png"; + mTexture[TEXTURE_FONT_WHITE_X2].file = mProg.executablePath + "/" + "../media/gfx/font_white_x2.png"; + mTexture[TEXTURE_FONT_WHITE].file = mProg.executablePath + "/" + "../media/gfx/font_white.png"; + mTexture[TEXTURE_GAME_BG].file = mProg.executablePath + "/" + "../media/gfx/game_bg.png"; + mTexture[TEXTURE_GAME_TEXT].file = mProg.executablePath + "/" + "../media/gfx/game_text.png"; + mTexture[TEXTURE_INTRO].file = mProg.executablePath + "/" + "../media/gfx/intro.png"; + mTexture[TEXTURE_ITEMS].file = mProg.executablePath + "/" + "../media/gfx/items.png"; + mTexture[TEXTURE_LOGO].file = mProg.executablePath + "/" + "../media/gfx/logo.png"; + mTexture[TEXTURE_MENU].file = mProg.executablePath + "/" + "../media/gfx/menu.png"; + mTexture[TEXTURE_PLAYER_BODY].file = mProg.executablePath + "/" + "../media/gfx/player_body.png"; + mTexture[TEXTURE_PLAYER_DEATH].file = mProg.executablePath + "/" + "../media/gfx/player_death.png"; + mTexture[TEXTURE_PLAYER_LEGS].file = mProg.executablePath + "/" + "../media/gfx/player_legs.png"; + mTexture[TEXTURE_TITLE].file = mProg.executablePath + "/" + "../media/gfx/title.png"; } // Comprueba que todos los ficheros existen @@ -856,69 +1136,330 @@ bool GameDirector::checkFileList() // Comprueba los ficheros de musica printf("\n>> MUSIC FILES\n"); - for (Uint8 i = 0; i < TOTAL_MUSIC; i++) - { - p = mMusic[i].file.c_str(); - filename = p.substr(p.find_last_of("\\/") + 1); - file = SDL_RWFromFile(p.c_str(), "r+b"); - if (file != NULL) + if (success) + for (Uint8 i = 0; i < TOTAL_MUSIC; i++) { - printf("Checking file %-20s [OK]\n", filename.c_str()); + p = mMusic[i].file.c_str(); + filename = p.substr(p.find_last_of("\\/") + 1); + file = SDL_RWFromFile(p.c_str(), "r+b"); + if (file != NULL) + { + printf("Checking file %-20s [OK]\n", filename.c_str()); + } + else + { + printf("Checking file %-20s [ERROR]\n", filename.c_str()); + success = false; + break; + } + SDL_RWclose(file); } - else - { - success = false; - printf("Checking file %-20s [ERROR]\n", filename.c_str()); - } - SDL_RWclose(file); - } // Comprueba los ficheros de sonidos printf("\n>> SOUND FILES\n"); - for (Uint8 i = 0; i < TOTAL_SOUND; i++) - { - p = mSound[i].file.c_str(); - filename = p.substr(p.find_last_of("\\/") + 1); - file = SDL_RWFromFile(p.c_str(), "r+b"); - if (file != NULL) + if (success) + for (Uint8 i = 0; i < TOTAL_SOUND; i++) { - printf("Checking file %-20s [OK]\n", filename.c_str()); + p = mSound[i].file.c_str(); + filename = p.substr(p.find_last_of("\\/") + 1); + file = SDL_RWFromFile(p.c_str(), "r+b"); + if (file != NULL) + { + printf("Checking file %-20s [OK]\n", filename.c_str()); + } + else + { + printf("Checking file %-20s [ERROR]\n", filename.c_str()); + success = false; + break; + } + SDL_RWclose(file); } - else - { - success = false; - printf("Checking file %-20s [ERROR]\n", filename.c_str()); - } - SDL_RWclose(file); - } // Comprueba los ficheros con texturas printf("\n>> TEXTURE FILES\n"); - for (Uint8 i = 0; i < TOTAL_TEXTURE; i++) - { - p = mTexture[i].file.c_str(); - filename = p.substr(p.find_last_of("\\/") + 1); - file = SDL_RWFromFile(p.c_str(), "r+b"); - if (file != NULL) + if (success) + for (Uint8 i = 0; i < TOTAL_TEXTURE; i++) { - printf("Checking file %-20s [OK]\n", filename.c_str()); + p = mTexture[i].file.c_str(); + filename = p.substr(p.find_last_of("\\/") + 1); + file = SDL_RWFromFile(p.c_str(), "r+b"); + if (file != NULL) + { + printf("Checking file %-20s [OK]\n", filename.c_str()); + } + else + { + printf("Checking file %-20s [ERROR]\n", filename.c_str()); + success = false; + break; + } + SDL_RWclose(file); } - else - { - success = false; - printf("Checking file %-20s [ERROR]\n", filename.c_str()); - } - SDL_RWclose(file); - } // Resultado if (success) - { printf("\n** All files OK.\n\n"); + else + printf("\n** A file is missing. Exiting.\n\n"); + + return success; +} + +// Carga el fichero de puntos +bool GameDirector::loadScoreFile() +{ + // Indicador de éxito en la carga + bool success = true; + std::string path = mProg.executablePath + "/"; + std::string p = mBinFile[BINFILE_SCORE].file.c_str(); + std::string filename = p.substr(p.find_last_of("\\/") + 1); + SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); + + // El fichero no existe + if (file == NULL) + { + printf("Warning: Unable to open %s file\n", filename.c_str()); + + // Creamos el fichero para escritura + file = SDL_RWFromFile(p.c_str(), "w+b"); + if (file != NULL) + { + printf("New file (%s) created!\n", filename.c_str()); + + // Inicializamos los datos + for (int i = 0; i < TOTAL_SCORE_DATA; ++i) + { + mGame.scoreDataFile[i] = 0; + SDL_RWwrite(file, &mGame.scoreDataFile[i], sizeof(Uint32), 1); + } + + // Cerramos el fichero + SDL_RWclose(file); + } + else + { + printf("Error: Unable to create file %s\n", filename.c_str()); + success = false; + } + } + // El fichero existe + else + { + // Cargamos los datos + printf("Reading file %s\n", filename.c_str()); + for (int i = 0; i < TOTAL_SCORE_DATA; ++i) + SDL_RWread(file, &mGame.scoreDataFile[i], sizeof(Uint32), 1); + + // Cierra el fichero + SDL_RWclose(file); + } + + // Establece el valor de la máxima puntuación a partir del vector con los datos + if (mGame.scoreDataFile[0] == 0) + mGame.hiScore = 10000; + // Comprueba el checksum para ver si se ha modificado el fichero + else if (mGame.scoreDataFile[0] % 43 == mGame.scoreDataFile[1]) + mGame.hiScore = mGame.scoreDataFile[0]; + else + mGame.hiScore = 10000; + + return success; +} + +// Carga el fichero de configuración +bool GameDirector::loadConfigFile() +{ + // Indicador de éxito en la carga + bool success = true; + std::string path = mProg.executablePath + "/"; + std::string p = mBinFile[BINFILE_CONFIG].file.c_str(); + std::string filename = p.substr(p.find_last_of("\\/") + 1); + SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); + + // El fichero no existe + if (file == NULL) + { + printf("Warning: Unable to open %s file\n", filename.c_str()); + + // Creamos el fichero para escritura + file = SDL_RWFromFile(p.c_str(), "w+b"); + if (file != NULL) + { + printf("New file (%s) created!\n", filename.c_str()); + + // Inicializamos los datos + mOptions.fullScreenMode = 0; + SDL_RWwrite(file, &mOptions.fullScreenMode, sizeof(mOptions.fullScreenMode), 1); + + mOptions.windowSize = 3; + SDL_RWwrite(file, &mOptions.windowSize, sizeof(mOptions.windowSize), 1); + + // Cerramos el fichero + SDL_RWclose(file); + } + else + { + printf("Error: Unable to create file %s\n", filename.c_str()); + success = false; + } + } + // El fichero existe + else + { + // Cargamos los datos + printf("Reading file %s\n", filename.c_str()); + SDL_RWread(file, &mOptions.fullScreenMode, sizeof(mOptions.fullScreenMode), 1); + SDL_SetWindowFullscreen(mWindow, mOptions.fullScreenMode); + SDL_RWread(file, &mOptions.windowSize, sizeof(mOptions.windowSize), 1); + SDL_SetWindowSize(mWindow, SCREEN_WIDTH * mOptions.windowSize, SCREEN_HEIGHT * mOptions.windowSize); + + // Cierra el fichero + SDL_RWclose(file); + } + + return success; +} + +// Carga el fichero de datos para la demo +bool GameDirector::loadDemoFile() +{ + // Indicador de éxito en la carga + bool success = true; + std::string path = mProg.executablePath + "/"; + std::string p = mBinFile[BINFILE_DEMO].file.c_str(); + std::string filename = p.substr(p.find_last_of("\\/") + 1); + SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); + + // El fichero no existe + if (file == NULL) + { + printf("Warning: Unable to open %s file\n", filename.c_str()); + + // Creamos el fichero para escritura + file = SDL_RWFromFile(p.c_str(), "w+b"); + if (file != NULL) + { + printf("New file (%s) created!\n", filename.c_str()); + + // Inicializamos los datos + for (int i = 0; i < TOTAL_DEMO_DATA; ++i) + { + mDemo.keys.left = 0; + mDemo.keys.right = 0; + mDemo.keys.noInput = 0; + mDemo.keys.fire = 0; + mDemo.keys.fireLeft = 0; + mDemo.keys.fireRight = 0; + mDemo.dataFile[i] = mDemo.keys; + SDL_RWwrite(file, &mDemo.dataFile[i], sizeof(DemoKeys), 1); + } + + // Cerramos el fichero + SDL_RWclose(file); + } + else + { + printf("Error: Unable to create file %s\n", filename.c_str()); + success = false; + } + } + // El fichero existe + else + { + // Cargamos los datos + printf("Reading file %s\n", filename.c_str()); + for (int i = 0; i < TOTAL_DEMO_DATA; ++i) + SDL_RWread(file, &mDemo.dataFile[i], sizeof(DemoKeys), 1); + + // Cierra el fichero + SDL_RWclose(file); + } + + return success; +} + +// Guarda el fichero de puntos +bool GameDirector::saveScoreFile() +{ + bool success = true; + std::string path = mProg.executablePath + "/"; + std::string p = mBinFile[BINFILE_SCORE].file; + std::string filename = p.substr(p.find_last_of("\\/") + 1); + SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); + if (file != NULL) + { + // Guardamos los datos + for (int i = 0; i < TOTAL_SCORE_DATA; ++i) + { + SDL_RWwrite(file, &mGame.scoreDataFile[i], sizeof(Uint32), 1); + } + + printf("Writing file %s\n", filename.c_str()); + + // Cerramos el fichero + SDL_RWclose(file); } else { - printf("\n** File is missing. Exiting.\n\n"); + printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError()); + } + return success; +} + +// Guarda el fichero de configuración +bool GameDirector::saveConfigFile() +{ + bool success = true; + std::string path = mProg.executablePath + "/"; + std::string p = mBinFile[BINFILE_CONFIG].file; + std::string filename = p.substr(p.find_last_of("\\/") + 1); + SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); + if (file != NULL) + { + // Guarda los datos + SDL_RWwrite(file, &mOptions.fullScreenMode, sizeof(Uint32), 1); + SDL_RWwrite(file, &mOptions.windowSize, sizeof(Uint8), 1); + + printf("Writing file %s\n", filename.c_str()); + + // Cierra el fichero + SDL_RWclose(file); + } + else + { + printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError()); + } + return success; +} + +// Guarda el fichero de datos para la demo +bool GameDirector::saveDemoFile() +{ + bool success = true; + std::string path = mProg.executablePath + "/"; + std::string p = mBinFile[BINFILE_DEMO].file; + std::string filename = p.substr(p.find_last_of("\\/") + 1); + if (mDemo.recording) + { + SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); + if (file != NULL) + { + // Guardamos los datos + for (int i = 0; i < TOTAL_DEMO_DATA; ++i) + { + SDL_RWwrite(file, &mDemo.dataFile[i], sizeof(DemoKeys), 1); + } + + printf("Writing file %s\n", filename.c_str()); + + // Cerramos el fichero + SDL_RWclose(file); + } + else + { + printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError()); + } } return success; } @@ -935,466 +1476,16 @@ bool GameDirector::loadTextureFromFile(LTexture *texture, std::string path, SDL_ return success; } -// Carga los recursos necesarios -bool GameDirector::loadMedia(Uint8 section) +// Comprueba el valor de la variable 'quit' +bool GameDirector::exit() { - // Indicador de éxito en la carga - bool success = true; - std::string path = mExecutablePath + "/"; - std::string p; - - switch (section) - { - case GAME_STATE_INIT: - { - p = mBinFile[BINFILE_SCORE].file.c_str(); - std::string filename = p.substr(p.find_last_of("\\/") + 1); - // Abrimos el fichero con la puntuacion para leer en binario - SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); - - // El fichero no existe - if (file == NULL) - { - printf("Warning: Unable to open %s file\n", filename.c_str()); - - // Creamos el fichero para escritura - file = SDL_RWFromFile(p.c_str(), "w+b"); - if (file != NULL) - { - printf("New file (%s) created!\n", filename.c_str()); - - // Inicializamos los datos - for (int i = 0; i < TOTAL_SCORE_DATA; ++i) - { - mScoreDataFile[i] = 0; - SDL_RWwrite(file, &mScoreDataFile[i], sizeof(Uint32), 1); - } - - // Cerramos el fichero - SDL_RWclose(file); - } - else - { - printf("Error: Unable to create file %s\n", filename.c_str()); - success = false; - } - } - // El fichero existe - else - { - // Cargamos los datos - printf("Reading file %s\n", filename.c_str()); - for (int i = 0; i < TOTAL_SCORE_DATA; ++i) - { - SDL_RWread(file, &mScoreDataFile[i], sizeof(Uint32), 1); - } - - // Cierra el fichero - SDL_RWclose(file); - } - - p = mBinFile[BINFILE_DEMO].file.c_str(); - filename = p.substr(p.find_last_of("\\/") + 1); - // Abrimos el fichero con los datos para el modo demo para leer en binario - file = SDL_RWFromFile(p.c_str(), "r+b"); - - // El fichero no existe - if (file == NULL) - { - printf("Warning: Unable to open %s file\n", filename.c_str()); - - // Creamos el fichero para escritura - file = SDL_RWFromFile(p.c_str(), "w+b"); - if (file != NULL) - { - printf("New file (%s) created!\n", filename.c_str()); - - // Inicializamos los datos - for (int i = 0; i < TOTAL_DEMO_DATA; ++i) - { - mDemoKeys.left = 0; - mDemoKeys.right = 0; - mDemoKeys.noInput = 0; - mDemoKeys.fire = 0; - mDemoKeys.fireLeft = 0; - mDemoKeys.fireRight = 0; - mDemoDataFile[i] = mDemoKeys; - SDL_RWwrite(file, &mDemoDataFile[i], sizeof(DemoKeys), 1); - } - - // Cerramos el fichero - SDL_RWclose(file); - } - else - { - printf("Error: Unable to create file %s\n", filename.c_str()); - success = false; - } - } - // El fichero existe - else - { - // Cargamos los datos - printf("Reading file %s\n", filename.c_str()); - for (int i = 0; i < TOTAL_DEMO_DATA; ++i) - { - SDL_RWread(file, &mDemoDataFile[i], sizeof(DemoKeys), 1); - } - - // Cierra el fichero - SDL_RWclose(file); - } - - p = mBinFile[BINFILE_CONFIG].file.c_str(); - filename = p.substr(p.find_last_of("\\/") + 1); - // Abrimos el fichero con la configuracion de las opciones leer en binario - file = SDL_RWFromFile(p.c_str(), "r+b"); - - // El fichero no existe - if (file == NULL) - { - printf("Warning: Unable to open %s file\n", filename.c_str()); - - // Creamos el fichero para escritura - file = SDL_RWFromFile(p.c_str(), "w+b"); - if (file != NULL) - { - printf("New file (%s) created!\n", filename.c_str()); - - // Inicializamos los datos - mFullScreenMode = 0; - SDL_RWwrite(file, &mFullScreenMode, sizeof(mFullScreenMode), 1); - - mWindowSize = 3; - SDL_RWwrite(file, &mWindowSize, sizeof(mWindowSize), 1); - - // Cerramos el fichero - SDL_RWclose(file); - } - else - { - printf("Error: Unable to create file %s\n", filename.c_str()); - success = false; - } - } - // El fichero existe - else - { - // Cargamos los datos - printf("Reading file %s\n", filename.c_str()); - SDL_RWread(file, &mFullScreenMode, sizeof(mFullScreenMode), 1); - SDL_SetWindowFullscreen(mWindow, mFullScreenMode); - SDL_RWread(file, &mWindowSize, sizeof(mWindowSize), 1); - SDL_SetWindowSize(mWindow, SCREEN_WIDTH * mWindowSize, SCREEN_HEIGHT * mWindowSize); - - // Cierra el fichero - SDL_RWclose(file); - } - printf("\n"); - - // Texturas - loadTextureFromFile(mTexture[TEXTURE_MENU].texture, mTexture[TEXTURE_MENU].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_FONT_WHITE].texture, mTexture[TEXTURE_FONT_WHITE].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_FONT_BLACK].texture, mTexture[TEXTURE_FONT_BLACK].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_FONT_NOKIA].texture, mTexture[TEXTURE_FONT_NOKIA].file, mRenderer); - - // Sonidos - mSound[SOUND_MENU_SELECT].sound = JA_LoadSound(mSound[SOUND_MENU_SELECT].file.c_str()); - mSound[SOUND_MENU_CANCEL].sound = JA_LoadSound(mSound[SOUND_MENU_CANCEL].file.c_str()); - mSound[SOUND_MENU_MOVE].sound = JA_LoadSound(mSound[SOUND_MENU_MOVE].file.c_str()); - - // Musicas - mMusic[MUSIC_TITLE].music = JA_LoadMusic(mMusic[MUSIC_TITLE].file.c_str()); - } - break; - - case GAME_STATE_TITLE: - { - // Texturas - loadTextureFromFile(mTexture[TEXTURE_TITLE].texture, mTexture[TEXTURE_TITLE].file, mRenderer); - - // Crea el mosaico de fondo del titulo - SDL_SetRenderTarget(mRenderer, mTitleSurface); - SDL_SetRenderDrawColor(mRenderer, 0x43, 0x43, 0x4F, 0xFF); - SDL_RenderClear(mRenderer); - for (Uint8 i = 0; i < 8; i++) - for (Uint8 j = 0; j < 6; j++) - { - mTitleTile->setPosX(i * 64); - mTitleTile->setPosY(j * 64); - mTitleTile->render(); - } - mBackgroundWindow.x = 0; - mBackgroundWindow.y = 0; - mBackgroundWindow.w = SCREEN_WIDTH; - mBackgroundWindow.h = SCREEN_HEIGHT; - SDL_SetRenderTarget(mRenderer, nullptr); - - // Sonidos - mSound[SOUND_TITLE].sound = JA_LoadSound(mSound[SOUND_TITLE].file.c_str()); - } - break; - - case GAME_STATE_PLAYING: - { - // Texturas - loadTextureFromFile(mTexture[TEXTURE_PLAYER_LEGS].texture, mTexture[TEXTURE_PLAYER_LEGS].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_PLAYER_BODY].texture, mTexture[TEXTURE_PLAYER_BODY].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_PLAYER_DEATH].texture, mTexture[TEXTURE_PLAYER_DEATH].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_BALLOON].texture, mTexture[TEXTURE_BALLOON].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_BULLET].texture, mTexture[TEXTURE_BULLET].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_GAME_BG].texture, mTexture[TEXTURE_GAME_BG].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_GAME_TEXT].texture, mTexture[TEXTURE_GAME_TEXT].file, mRenderer); - loadTextureFromFile(mTexture[TEXTURE_ITEMS].texture, mTexture[TEXTURE_ITEMS].file, mRenderer); - - // Sonidos - mSound[SOUND_BALLON].sound = JA_LoadSound(mSound[SOUND_BALLON].file.c_str()); - mSound[SOUND_BULLET].sound = JA_LoadSound(mSound[SOUND_BULLET].file.c_str()); - mSound[SOUND_PLAYER_COLLISION].sound = JA_LoadSound(mSound[SOUND_PLAYER_COLLISION].file.c_str()); - mSound[SOUND_HISCORE].sound = JA_LoadSound(mSound[SOUND_HISCORE].file.c_str()); - mSound[SOUND_ITEM_DROP].sound = JA_LoadSound(mSound[SOUND_ITEM_DROP].file.c_str()); - mSound[SOUND_ITEM_PICKUP].sound = JA_LoadSound(mSound[SOUND_ITEM_PICKUP].file.c_str()); - mSound[SOUND_COFFEE_OUT].sound = JA_LoadSound(mSound[SOUND_COFFEE_OUT].file.c_str()); - mSound[SOUND_STAGE_CHANGE].sound = JA_LoadSound(mSound[SOUND_STAGE_CHANGE].file.c_str()); - mSound[SOUND_TITLE].sound = JA_LoadSound(mSound[SOUND_TITLE].file.c_str()); - mSound[SOUND_BUBBLE1].sound = JA_LoadSound(mSound[SOUND_BUBBLE1].file.c_str()); - mSound[SOUND_BUBBLE2].sound = JA_LoadSound(mSound[SOUND_BUBBLE2].file.c_str()); - mSound[SOUND_BUBBLE3].sound = JA_LoadSound(mSound[SOUND_BUBBLE3].file.c_str()); - mSound[SOUND_BUBBLE4].sound = JA_LoadSound(mSound[SOUND_BUBBLE4].file.c_str()); - - // Musicas - mMusic[MUSIC_PLAYING].music = JA_LoadMusic(mMusic[MUSIC_PLAYING].file.c_str()); - } - break; - - case GAME_STATE_GAME_OVER_SCREEN: - { - } - break; - - case GAME_STATE_INTRO: - { - // Texturas - loadTextureFromFile(mTexture[TEXTURE_INTRO].texture, mTexture[TEXTURE_INTRO].file, mRenderer); - - // Musicas - mMusic[MUSIC_INTRO].music = JA_LoadMusic(mMusic[MUSIC_INTRO].file.c_str()); - } - break; - - case GAME_STATE_DEMO: - { - } - break; - - case GAME_STATE_INSTRUCTIONS: - { - // Texturas - loadTextureFromFile(mTexture[TEXTURE_ITEMS].texture, mTexture[TEXTURE_ITEMS].file, mRenderer); - } - break; - - case GAME_STATE_LOGO: - { - // Texturas - loadTextureFromFile(mTexture[TEXTURE_LOGO].texture, mTexture[TEXTURE_LOGO].file, mRenderer); - } - break; - - default: - { - } - break; - } - - return success; -} - -// Descrga los recursos necesarios -bool GameDirector::unLoadMedia(Uint8 section) -{ - // Indicador de éxito en la carga - bool success = true; - std::string path = mExecutablePath + "/"; - std::string p; - - switch (section) - { - case GAME_STATE_INIT: - { - p = mBinFile[BINFILE_SCORE].file; - std::string filename = p.substr(p.find_last_of("\\/") + 1); - // Abre el fichero de puntuación para escribir - SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); - if (file != NULL) - { - // Guardamos los datos - for (int i = 0; i < TOTAL_SCORE_DATA; ++i) - { - SDL_RWwrite(file, &mScoreDataFile[i], sizeof(Uint32), 1); - } - - printf("Writing file %s\n", filename.c_str()); - - // Cerramos el fichero - SDL_RWclose(file); - } - else - { - printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError()); - } - - p = mBinFile[BINFILE_CONFIG].file; - filename = p.substr(p.find_last_of("\\/") + 1); - // Abre el fichero de puntuación para escribir - SDL_RWops *file2 = SDL_RWFromFile(p.c_str(), "w+b"); - if (file != NULL) - { - // Guardamos los datos - SDL_RWwrite(file2, &mFullScreenMode, sizeof(Uint32), 1); - SDL_RWwrite(file2, &mWindowSize, sizeof(Uint8), 1); - - printf("Writing file %s\n", filename.c_str()); - - // Cerramos el fichero - SDL_RWclose(file2); - } - else - { - printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError()); - } - - p = mBinFile[BINFILE_DEMO].file; - filename = p.substr(p.find_last_of("\\/") + 1); - // Abre el fichero de demo para escribir - if (mDemoRecording) - { - SDL_RWops *file2 = SDL_RWFromFile(p.c_str(), "w+b"); - if (file2 != NULL) - { - // Guardamos los datos - for (int i = 0; i < TOTAL_DEMO_DATA; ++i) - { - SDL_RWwrite(file2, &mDemoDataFile[i], sizeof(DemoKeys), 1); - } - - printf("Writing file %s\n", filename.c_str()); - - // Cerramos el fichero - SDL_RWclose(file2); - } - else - { - printf("Error: Unable to save %s file! %s\n", filename.c_str(), SDL_GetError()); - } - } - printf("\n"); - - // Texturas - mTexture[TEXTURE_MENU].texture->free(); - mTexture[TEXTURE_FONT_WHITE].texture->free(); - mTexture[TEXTURE_FONT_BLACK].texture->free(); - mTexture[TEXTURE_FONT_NOKIA].texture->free(); - - // Sonidos - JA_DeleteSound(mSound[SOUND_MENU_SELECT].sound); - JA_DeleteSound(mSound[SOUND_MENU_CANCEL].sound); - JA_DeleteSound(mSound[SOUND_MENU_MOVE].sound); - - // Musicas - JA_DeleteMusic(mMusic[MUSIC_TITLE].music); - } - break; - - case GAME_STATE_TITLE: - { - // Texturas - mTexture[TEXTURE_TITLE].texture->free(); - - // Sonidos - JA_DeleteSound(mSound[SOUND_TITLE].sound); - } - break; - - case GAME_STATE_PLAYING: - { - // Texturas - mTexture[TEXTURE_PLAYER_LEGS].texture->free(); - mTexture[TEXTURE_PLAYER_BODY].texture->free(); - mTexture[TEXTURE_PLAYER_DEATH].texture->free(); - mTexture[TEXTURE_BALLOON].texture->free(); - mTexture[TEXTURE_BULLET].texture->free(); - mTexture[TEXTURE_GAME_BG].texture->free(); - mTexture[TEXTURE_GAME_TEXT].texture->free(); - mTexture[TEXTURE_ITEMS].texture->free(); - - // Sonidos - JA_DeleteSound(mSound[SOUND_BALLON].sound); - JA_DeleteSound(mSound[SOUND_BULLET].sound); - JA_DeleteSound(mSound[SOUND_PLAYER_COLLISION].sound); - JA_DeleteSound(mSound[SOUND_HISCORE].sound); - JA_DeleteSound(mSound[SOUND_ITEM_DROP].sound); - JA_DeleteSound(mSound[SOUND_ITEM_PICKUP].sound); - JA_DeleteSound(mSound[SOUND_COFFEE_OUT].sound); - JA_DeleteSound(mSound[SOUND_STAGE_CHANGE].sound); - JA_DeleteSound(mSound[SOUND_TITLE].sound); - JA_DeleteSound(mSound[SOUND_BUBBLE1].sound); - JA_DeleteSound(mSound[SOUND_BUBBLE2].sound); - JA_DeleteSound(mSound[SOUND_BUBBLE3].sound); - JA_DeleteSound(mSound[SOUND_BUBBLE4].sound); - - // Musicas - JA_DeleteMusic(mMusic[MUSIC_PLAYING].music); - } - break; - - case GAME_STATE_GAME_OVER_SCREEN: - { - } - break; - - case GAME_STATE_INTRO: - { - // Texturas - mTexture[TEXTURE_INTRO].texture->free(); - - // Musicas - JA_DeleteMusic(mMusic[MUSIC_INTRO].music); - } - break; - - case GAME_STATE_DEMO: - { - } - break; - - case GAME_STATE_INSTRUCTIONS: - { - // Texturas - mTexture[TEXTURE_ITEMS].texture->free(); - } - break; - - case GAME_STATE_LOGO: - { - // Texturas - mTexture[TEXTURE_LOGO].texture->free(); - } - break; - - default: - { - } - break; - } - - return success; + return mProg.quit; } // Establece el valor de la variable void GameDirector::setExecutablePath(std::string path) { - mExecutablePath = path.substr(0, path.find_last_of("\\/")); + mProg.executablePath = path.substr(0, path.find_last_of("\\/")); } // Establece el valor de la variable @@ -1419,8 +1510,8 @@ void GameDirector::updateHiScore() mGame.hiScore = mGame.score; // Almacena la máxima puntuación en el fichero junto con un checksum - mScoreDataFile[0] = mGame.hiScore; - mScoreDataFile[1] = mGame.hiScore % 43; + mGame.scoreDataFile[0] = mGame.hiScore; + mGame.scoreDataFile[1] = mGame.hiScore % 43; // Si superamos la máxima puntuación if (mGame.hiScoreAchieved == false) @@ -1474,7 +1565,7 @@ void GameDirector::renderScoreBoard() mText.white->write(SCORE_NUMBER_X, SCORE_NUMBER_Y, updateScoreText(mGame.score), 0); mText.white->write(MULTIPLIER_WORD_X, MULTIPLIER_WORD_Y, "MULT", 0); - mText.white->write(MULTIPLIER_NUMBER_X, MULTIPLIER_NUMBER_Y, std::to_string(mPlayer->getScoreMultiplier()), 0, 3); + mText.white->write(MULTIPLIER_NUMBER_X, MULTIPLIER_NUMBER_Y, std::to_string(mGame.player->getScoreMultiplier()), 0, 3); mText.white->write(HISCORE_WORD_X, HISCORE_WORD_Y, "HI-SCORE", 0); mText.white->write(HISCORE_NUMBER_X, HISCORE_NUMBER_Y, updateScoreText(mGame.hiScore), 0); @@ -1489,19 +1580,19 @@ void GameDirector::updateStage() { mGame.stage = realStage; JA_PlaySound(mSound[SOUND_STAGE_CHANGE].sound); - mGame.stageCounter = STAGE_COUNTER; + mGame.stageCounter = 0; } - if (mGame.stageCounter > 0) + if (mGame.stageCounter < STAGE_COUNTER) { - mGame.stageCounter--; + mGame.stageCounter++; } } // Actualiza el estado de muerte void GameDirector::updateDeath() { - if (!mPlayer->isAlive()) + if (!mGame.player->isAlive()) { if (mGame.deathCounter > 0) { @@ -1532,36 +1623,36 @@ void GameDirector::updateDeath() // Animación if ((mGame.deathCounter / 5) % 2 == 0) { - mSmartSprite[mGame.deathIndex]->setSpriteClip(0, 0, 24, 24); + mGame.smartSprite[mGame.deathIndex]->setSpriteClip(0, 0, 24, 24); } else { - mSmartSprite[mGame.deathIndex]->setSpriteClip(24, 0, 24, 24); + mGame.smartSprite[mGame.deathIndex]->setSpriteClip(24, 0, 24, 24); } // Rebote en los laterales - if (mSmartSprite[mGame.deathIndex]->getVelX() > 0) + if (mGame.smartSprite[mGame.deathIndex]->getVelX() > 0) { - if (mSmartSprite[mGame.deathIndex]->getPosX() > (SCREEN_WIDTH - mSmartSprite[mGame.deathIndex]->getWidth())) + if (mGame.smartSprite[mGame.deathIndex]->getPosX() > (SCREEN_WIDTH - mGame.smartSprite[mGame.deathIndex]->getWidth())) { - mSmartSprite[mGame.deathIndex]->setPosX(SCREEN_WIDTH - mSmartSprite[mGame.deathIndex]->getWidth()); - mSmartSprite[mGame.deathIndex]->setVelX(mSmartSprite[mGame.deathIndex]->getVelX() * (-1)); - mSmartSprite[mGame.deathIndex]->setDestX(mSmartSprite[mGame.deathIndex]->getDestX() * (-1)); + mGame.smartSprite[mGame.deathIndex]->setPosX(SCREEN_WIDTH - mGame.smartSprite[mGame.deathIndex]->getWidth()); + mGame.smartSprite[mGame.deathIndex]->setVelX(mGame.smartSprite[mGame.deathIndex]->getVelX() * (-1)); + mGame.smartSprite[mGame.deathIndex]->setDestX(mGame.smartSprite[mGame.deathIndex]->getDestX() * (-1)); } } else { - if (mSmartSprite[mGame.deathIndex]->getPosX() < 0) + if (mGame.smartSprite[mGame.deathIndex]->getPosX() < 0) { - mSmartSprite[mGame.deathIndex]->setPosX(0); - mSmartSprite[mGame.deathIndex]->setVelX(mSmartSprite[mGame.deathIndex]->getVelX() * (-1)); - mSmartSprite[mGame.deathIndex]->setDestX(mSmartSprite[mGame.deathIndex]->getDestX() * (-1)); + mGame.smartSprite[mGame.deathIndex]->setPosX(0); + mGame.smartSprite[mGame.deathIndex]->setVelX(mGame.smartSprite[mGame.deathIndex]->getVelX() * (-1)); + mGame.smartSprite[mGame.deathIndex]->setDestX(mGame.smartSprite[mGame.deathIndex]->getDestX() * (-1)); } } } else { - setGameStatus(GAME_STATE_GAME_OVER_SCREEN); + mGame.section = GAME_SECTION_GAMEOVER; } } } @@ -1569,7 +1660,7 @@ void GameDirector::updateDeath() // Renderiza el fade final cuando se acaba la partida void GameDirector::renderDeathFade() { - if (!mPlayer->isAlive() && (mGame.deathCounter < 150)) + if (!mGame.player->isAlive() && (mGame.deathCounter < 150)) { // 192 / 6 = 32, 6 cuadrados de 32 pixeles SDL_Rect rect[12]; @@ -1594,9 +1685,9 @@ void GameDirector::moveBalloons() { for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if (mBalloon[i]->isActive()) + if (mGame.balloon[i]->isActive()) { - mBalloon[i]->update(); + mGame.balloon[i]->update(); } } } @@ -1606,23 +1697,23 @@ void GameDirector::renderBalloons() { for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if (mBalloon[i]->isActive()) + if (mGame.balloon[i]->isActive()) { - mBalloon[i]->render(); - if ((mDebug) && (mBalloon[i]->isPopping() == false)) - mText.white->write(mBalloon[i]->getPosX() + (mBalloon[i]->getWidth() / 2) - 4, mBalloon[i]->getPosY() - 8, std::to_string(i)); + mGame.balloon[i]->render(); + if ((mProg.debug) && (mGame.balloon[i]->isPopping() == false)) + mText.white->write(mGame.balloon[i]->getPosX() + (mGame.balloon[i]->getWidth() / 2) - 4, mGame.balloon[i]->getPosY() - 8, std::to_string(i)); } } } // Devuelve el primer indice no activo del vector de globos -Uint8 GameDirector::getBallonFreeIndex() +Uint8 GameDirector::getBalloonFreeIndex() { int index = 0; for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if (mBalloon[i]->isActive() == false) + if (mGame.balloon[i]->isActive() == false) { index = i; break; @@ -1635,8 +1726,8 @@ Uint8 GameDirector::getBallonFreeIndex() // Crea un globo nuevo en el vector de globos Uint8 GameDirector::createNewBalloon(float x, int y, Uint8 kind, float velx, Uint16 creationtimer, LTexture *texture) { - Uint8 index = getBallonFreeIndex(); - mBalloon[index]->init(x, y, kind, velx, creationtimer, texture, mRenderer); + Uint8 index = getBalloonFreeIndex(); + mGame.balloon[index]->init(x, y, kind, velx, creationtimer, texture, mRenderer); return index; } @@ -1645,63 +1736,63 @@ void GameDirector::resetBalloons() { for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - mBalloon[i]->erase(); + mGame.balloon[i]->erase(); } } // Explosiona un globo. Lo destruye y crea otros dos si es el caso void GameDirector::popBalloon(Uint8 index) { - if (mBalloon[index]->isActive()) + if (mGame.balloon[index]->isActive()) { // Otorga los puntos correspondientes al globo - mPlayer->addScore(Uint32(mBalloon[index]->getScore() * mPlayer->getScoreMultiplier())); - setScore(mPlayer->getScore()); + mGame.player->addScore(Uint32(mGame.balloon[index]->getScore() * mGame.player->getScoreMultiplier())); + setScore(mGame.player->getScore()); updateHiScore(); - Uint8 kind = mBalloon[index]->getKind(); + Uint8 kind = mGame.balloon[index]->getKind(); Uint8 freeIndex = 0; switch (kind) { // Si es del tipo más pequeño, simplemente elimina el globo case BALLOON_1: - mBalloon[index]->pop(); + mGame.balloon[index]->pop(); break; // En cualquier otro caso, crea dos globos de un tipo inferior default: - freeIndex = getBallonFreeIndex(); - mBalloon[freeIndex]->init(0, mBalloon[index]->getPosY(), mBalloon[index]->getKind() - 1, BALLON_VELX_NEGATIVE, 0, mTexture[TEXTURE_BALLOON].texture, mRenderer); - mBalloon[freeIndex]->allignTo(mBalloon[index]->getPosX() + (mBalloon[index]->getWidth() / 2)); - mBalloon[freeIndex]->setVelY(-2.5); - // if (isTimeStopped()) mBalloon[freeIndex]->setStop(true); + freeIndex = getBalloonFreeIndex(); + mGame.balloon[freeIndex]->init(0, mGame.balloon[index]->getPosY(), mGame.balloon[index]->getKind() - 1, BALLOON_VELX_NEGATIVE, 0, mTexture[TEXTURE_BALLOON].texture, mRenderer); + mGame.balloon[freeIndex]->allignTo(mGame.balloon[index]->getPosX() + (mGame.balloon[index]->getWidth() / 2)); + mGame.balloon[freeIndex]->setVelY(-2.5); + // if (isTimeStopped()) mGame.balloon[freeIndex]->setStop(true); - freeIndex = getBallonFreeIndex(); - mBalloon[freeIndex]->init(0, mBalloon[index]->getPosY(), mBalloon[index]->getKind() - 1, BALLON_VELX_POSITIVE, 0, mTexture[TEXTURE_BALLOON].texture, mRenderer); - mBalloon[freeIndex]->allignTo(mBalloon[index]->getPosX() + (mBalloon[index]->getWidth() / 2)); - mBalloon[freeIndex]->setVelY(-2.5); - // if (isTimeStopped()) mBalloon[freeIndex]->setStop(true); + freeIndex = getBalloonFreeIndex(); + mGame.balloon[freeIndex]->init(0, mGame.balloon[index]->getPosY(), mGame.balloon[index]->getKind() - 1, BALLOON_VELX_POSITIVE, 0, mTexture[TEXTURE_BALLOON].texture, mRenderer); + mGame.balloon[freeIndex]->allignTo(mGame.balloon[index]->getPosX() + (mGame.balloon[index]->getWidth() / 2)); + mGame.balloon[freeIndex]->setVelY(-2.5); + // if (isTimeStopped()) mGame.balloon[freeIndex]->setStop(true); // Elimina el globo - mBalloon[index]->pop(); + mGame.balloon[index]->pop(); break; } // Reproduce el sonido de explotar el globo // JA_PlaySound(mFX.popBalloon); // Recalcula el nivel de amenaza - calculateMenaceLevel(); + setMenaceLevel(); } } // Explosiona todos los globos -void GameDirector::popAllBallons() +void GameDirector::popAllBalloons() { int candidate[MAX_BALLOONS]; Uint8 j = 0; for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if ((mBalloon[i]->isActive()) && (mBalloon[i]->isPopping() == false) && (mBalloon[i]->isBeingCreated() == false)) + if ((mGame.balloon[i]->isActive()) && (mGame.balloon[i]->isPopping() == false) && (mGame.balloon[i]->isBeingCreated() == false)) { candidate[j] = i; } @@ -1718,7 +1809,7 @@ void GameDirector::popAllBallons() popBalloon(i); } } - JA_PlaySound(mSound[SOUND_BALLON].sound); + JA_PlaySound(mSound[SOUND_BALLOON].sound); } // Detiene todos los globos @@ -1726,10 +1817,10 @@ void GameDirector::stopAllBalloons(Uint16 time) { for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if (mBalloon[i]->isActive()) + if (mGame.balloon[i]->isActive()) { - mBalloon[i]->setStop(true); - mBalloon[i]->setStoppedTimer(time); + mGame.balloon[i]->setStop(true); + mGame.balloon[i]->setStoppedTimer(time); } } } @@ -1739,10 +1830,10 @@ void GameDirector::startAllBalloons() { for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if ((mBalloon[i]->isActive()) && (mBalloon[i]->isBeingCreated() == false)) + if ((mGame.balloon[i]->isActive()) && (mGame.balloon[i]->isBeingCreated() == false)) { - mBalloon[i]->setStop(false); - mBalloon[i]->setStoppedTimer(0); + mGame.balloon[i]->setStop(false); + mGame.balloon[i]->setStoppedTimer(0); } } } @@ -1753,7 +1844,7 @@ Uint8 GameDirector::countBalloons() Uint8 num = 0; for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - if (mBalloon[i]->isActive()) + if (mGame.balloon[i]->isActive()) { ++num; } @@ -1762,16 +1853,16 @@ Uint8 GameDirector::countBalloons() } // Comprueba la colisión entre el jugador y los globos activos -bool GameDirector::checkPlayerBallonCollision() +bool GameDirector::checkPlayerBalloonCollision() { bool result = false; for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - //if ((mBalloon[i]->isActive()) && (mBalloon[i]->isStopped() == false)) - if ((mBalloon[i]->isActive()) && !(mBalloon[i]->isStopped()) && !(mBalloon[i]->isInvulnerable())) + //if ((mGame.balloon[i]->isActive()) && (mGame.balloon[i]->isStopped() == false)) + if ((mGame.balloon[i]->isActive()) && !(mGame.balloon[i]->isStopped()) && !(mGame.balloon[i]->isInvulnerable())) { - if (checkCollision(mPlayer->getCollider(), mBalloon[i]->getCollider())) + if (checkCollision(mGame.player->getCollider(), mGame.balloon[i]->getCollider())) { result = true; break; @@ -1784,34 +1875,34 @@ bool GameDirector::checkPlayerBallonCollision() // Comprueba la colisión entre el jugador y los items void GameDirector::checkPlayerItemCollision() { - if (mPlayer->isAlive()) + if (mGame.player->isAlive()) for (Uint8 i = 0; i < MAX_ITEMS; i++) { - if (mItem[i]->isEnabled()) + if (mGame.item[i]->isEnabled()) { - if (checkCollision(mPlayer->getCollider(), mItem[i]->getCollider())) + if (checkCollision(mGame.player->getCollider(), mGame.item[i]->getCollider())) { - switch (mItem[i]->getClass()) + switch (mGame.item[i]->getClass()) { case ITEM_POINTS_1_DISK: - mPlayer->addScore(1000); - setScore(mPlayer->getScore()); + mGame.player->addScore(1000); + setScore(mGame.player->getScore()); updateHiScore(); - createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m1000Bitmap->getWidth() / 2), mItem[i]->getPosY(), m1000Bitmap); + createItemScoreSprite(mGame.item[i]->getPosX() + (mGame.item[i]->getWidth() / 2) - (mGame._1000Bitmap->getWidth() / 2), mGame.item[i]->getPosY(), mGame._1000Bitmap); JA_PlaySound(mSound[SOUND_ITEM_PICKUP].sound); break; case ITEM_POINTS_2_GAVINA: - mPlayer->addScore(2500); - setScore(mPlayer->getScore()); + mGame.player->addScore(2500); + setScore(mGame.player->getScore()); updateHiScore(); - createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m2500Bitmap->getWidth() / 2), mItem[i]->getPosY(), m2500Bitmap); + createItemScoreSprite(mGame.item[i]->getPosX() + (mGame.item[i]->getWidth() / 2) - (mGame._2500Bitmap->getWidth() / 2), mGame.item[i]->getPosY(), mGame._2500Bitmap); JA_PlaySound(mSound[SOUND_ITEM_PICKUP].sound); break; case ITEM_POINTS_3_PACMAR: - mPlayer->addScore(5000); - setScore(mPlayer->getScore()); + mGame.player->addScore(5000); + setScore(mGame.player->getScore()); updateHiScore(); - createItemScoreSprite(mItem[i]->getPosX() + (mItem[i]->getWidth() / 2) - (m5000Bitmap->getWidth() / 2), mItem[i]->getPosY(), m5000Bitmap); + createItemScoreSprite(mGame.item[i]->getPosX() + (mGame.item[i]->getWidth() / 2) - (mGame._5000Bitmap->getWidth() / 2), mGame.item[i]->getPosY(), mGame._5000Bitmap); JA_PlaySound(mSound[SOUND_ITEM_PICKUP].sound); break; case ITEM_CLOCK: @@ -1819,45 +1910,45 @@ void GameDirector::checkPlayerItemCollision() JA_PlaySound(mSound[SOUND_ITEM_PICKUP].sound); break; case ITEM_TNT: - popAllBallons(); + popAllBalloons(); setExplosionTime(true); JA_PlaySound(mSound[SOUND_TITLE].sound); break; case ITEM_COFFEE: - mPlayer->giveExtraHit(); + mGame.player->giveExtraHit(); JA_PlaySound(mSound[SOUND_ITEM_PICKUP].sound); break; default: break; } - mItem[i]->erase(); + mGame.item[i]->erase(); } } } } // Comprueba y procesa la colisión entre las balas y los globos -void GameDirector::checkBulletBallonCollision() +void GameDirector::checkBulletBalloonCollision() { for (Uint8 i = 0; i < MAX_BALLOONS; i++) { for (Uint8 j = 0; j < MAX_BULLETS; j++) { - if (mBalloon[i]->isActive() && !(mBalloon[i]->isInvulnerable()) && mBullet[j]->isActive()) + if (mGame.balloon[i]->isActive() && !(mGame.balloon[i]->isInvulnerable()) && mGame.bullet[j]->isActive()) { - if (checkCollision(mBalloon[i]->getCollider(), mBullet[j]->getCollider())) + if (checkCollision(mGame.balloon[i]->getCollider(), mGame.bullet[j]->getCollider())) { - mPlayer->incScoreMultiplier(); + mGame.player->incScoreMultiplier(); popBalloon(i); - if (mDemo == false) - JA_PlaySound(mSound[SOUND_BALLON].sound); - mBullet[j]->erase(); - calculateMenaceLevel(); + if (mDemo.enabled == false) + JA_PlaySound(mSound[SOUND_BALLOON].sound); + mGame.bullet[j]->erase(); + setMenaceLevel(); Uint8 droppeditem = dropItem(); - if ((droppeditem != NO_KIND) && (mDemo == false) && (mDemoRecording == false)) + if ((droppeditem != NO_KIND) && (mDemo.enabled == false) && (mDemo.recording == false)) { - createItem(mBalloon[i]->getPosX(), mBalloon[i]->getPosY(), droppeditem); + createItem(mGame.balloon[i]->getPosX(), mGame.balloon[i]->getPosY(), droppeditem); JA_PlaySound(mSound[SOUND_ITEM_DROP].sound); } break; @@ -1872,11 +1963,11 @@ void GameDirector::moveBullets() { for (Uint8 i = 0; i < MAX_BULLETS; i++) { - if (mBullet[i]->isActive()) + if (mGame.bullet[i]->isActive()) { - if (mBullet[i]->move() == MSG_BULLET_OUT) + if (mGame.bullet[i]->move() == MSG_BULLET_OUT) { - mPlayer->decScoreMultiplier(); + mGame.player->decScoreMultiplier(); } } } @@ -1887,9 +1978,9 @@ void GameDirector::renderBullets() { for (Uint8 i = 0; i < MAX_BULLETS; i++) { - if (mBullet[i]->isActive()) + if (mGame.bullet[i]->isActive()) { - mBullet[i]->render(); + mGame.bullet[i]->render(); } } } @@ -1901,7 +1992,7 @@ Uint8 GameDirector::getBulletFreeIndex() for (int i = 0; i < MAX_BULLETS; i++) { - if (mBullet[i]->isActive() == false) + if (mGame.bullet[i]->isActive() == false) { index = i; break; @@ -1916,14 +2007,14 @@ void GameDirector::resetBullets() { for (Uint8 i = 0; i < MAX_BULLETS; i++) { - mBullet[i]->erase(); + mGame.bullet[i]->erase(); } } // Crea un objeto bala void GameDirector::createBullet(int x, int y, Uint8 kind) { - mBullet[getBulletFreeIndex()]->init(x, y, kind, mTexture[TEXTURE_BULLET].texture, mRenderer); + mGame.bullet[getBulletFreeIndex()]->init(x, y, kind, mTexture[TEXTURE_BULLET].texture, mRenderer); } // Actualiza los items @@ -1931,7 +2022,7 @@ void GameDirector::updateItems() { for (Uint8 i = 0; i < MAX_ITEMS; i++) { - mItem[i]->update(); + mGame.item[i]->update(); } } @@ -1940,7 +2031,7 @@ void GameDirector::renderItems() { for (Uint8 i = 0; i < MAX_ITEMS; i++) { - mItem[i]->render(); + mGame.item[i]->render(); } } @@ -1951,7 +2042,7 @@ Uint8 GameDirector::getItemFreeIndex() for (int i = 0; i < MAX_ITEMS; i++) { - if (mItem[i]->getClass() == NO_KIND) + if (mGame.item[i]->getClass() == NO_KIND) { index = i; break; @@ -1966,7 +2057,7 @@ void GameDirector::resetItems() { for (Uint8 i = 0; i < MAX_ITEMS; i++) { - mItem[i]->erase(); + mGame.item[i]->erase(); } } @@ -2023,40 +2114,40 @@ Uint8 GameDirector::dropItem() // Crea un objeto item void GameDirector::createItem(int x, int y, Uint8 kind) { - mItem[getItemFreeIndex()]->init(kind, x, y, mTexture[TEXTURE_ITEMS].texture, mRenderer); + mGame.item[getItemFreeIndex()]->init(kind, x, y, mTexture[TEXTURE_ITEMS].texture, mRenderer); } // Crea un objeto SmartSprite para mostrar la puntuación al coger un objeto void GameDirector::createItemScoreSprite(int x, int y, SmartSprite *sprite) { Uint8 index = getSmartSpriteFreeIndex(); - *mSmartSprite[index] = *sprite; - mSmartSprite[index]->setPosX(x); - mSmartSprite[index]->setPosY(y); - mSmartSprite[index]->setDestX(x); - mSmartSprite[index]->setDestY(y - 15); - mSmartSprite[index]->setEnabled(true); - mSmartSprite[index]->setEnabledTimer(100); + *mGame.smartSprite[index] = *sprite; + mGame.smartSprite[index]->setPosX(x); + mGame.smartSprite[index]->setPosY(y); + mGame.smartSprite[index]->setDestX(x); + mGame.smartSprite[index]->setDestY(y - 15); + mGame.smartSprite[index]->setEnabled(true); + mGame.smartSprite[index]->setEnabledTimer(100); } // Crea un SmartSprite para arrojar el item café al recibir un impacto void GameDirector::throwCoffee(int x, int y) { Uint8 index = getSmartSpriteFreeIndex(); - mSmartSprite[index]->init(mTexture[TEXTURE_ITEMS].texture, mRenderer); - mSmartSprite[index]->setPosX(x - 8); - mSmartSprite[index]->setPosY(y - 8); - mSmartSprite[index]->setWidth(16); - mSmartSprite[index]->setHeight(16); - mSmartSprite[index]->setVelX(-1.0f + ((rand() % 5) * 0.5f)); - mSmartSprite[index]->setVelY(-4.0f); - mSmartSprite[index]->setAccelX(0.0f); - mSmartSprite[index]->setAccelY(0.2f); - mSmartSprite[index]->setDestX(x + (mSmartSprite[index]->getVelX() * 50)); - mSmartSprite[index]->setDestY(SCREEN_HEIGHT + 1); - mSmartSprite[index]->setEnabled(true); - mSmartSprite[index]->setEnabledTimer(1); - mSmartSprite[index]->setSpriteClip(80, 16, 16, 16); + mGame.smartSprite[index]->init(mTexture[TEXTURE_ITEMS].texture, mRenderer); + mGame.smartSprite[index]->setPosX(x - 8); + mGame.smartSprite[index]->setPosY(y - 8); + mGame.smartSprite[index]->setWidth(16); + mGame.smartSprite[index]->setHeight(16); + mGame.smartSprite[index]->setVelX(-1.0f + ((rand() % 5) * 0.5f)); + mGame.smartSprite[index]->setVelY(-4.0f); + mGame.smartSprite[index]->setAccelX(0.0f); + mGame.smartSprite[index]->setAccelY(0.2f); + mGame.smartSprite[index]->setDestX(x + (mGame.smartSprite[index]->getVelX() * 50)); + mGame.smartSprite[index]->setDestY(SCREEN_HEIGHT + 1); + mGame.smartSprite[index]->setEnabled(true); + mGame.smartSprite[index]->setEnabledTimer(1); + mGame.smartSprite[index]->setSpriteClip(80, 16, 16, 16); } // Crea un SmartSprite para arrojar el item café al recibir un impacto @@ -2064,20 +2155,20 @@ void GameDirector::throwPlayer(int x, int y) { int sentit = ((rand() % 2) ? 1 : -1); mGame.deathIndex = getSmartSpriteFreeIndex(); - mSmartSprite[mGame.deathIndex]->init(mTexture[TEXTURE_PLAYER_DEATH].texture, mRenderer); - mSmartSprite[mGame.deathIndex]->setPosX(x); - mSmartSprite[mGame.deathIndex]->setPosY(y); - mSmartSprite[mGame.deathIndex]->setWidth(24); - mSmartSprite[mGame.deathIndex]->setHeight(24); - mSmartSprite[mGame.deathIndex]->setVelX(2.0f * sentit); - mSmartSprite[mGame.deathIndex]->setVelY(-5.0f); - mSmartSprite[mGame.deathIndex]->setAccelX(0.0f); - mSmartSprite[mGame.deathIndex]->setAccelY(0.2f); - mSmartSprite[mGame.deathIndex]->setDestX(SCREEN_WIDTH * sentit); - mSmartSprite[mGame.deathIndex]->setDestY(SCREEN_HEIGHT + 1); - mSmartSprite[mGame.deathIndex]->setEnabled(true); - mSmartSprite[mGame.deathIndex]->setEnabledTimer(1); - mSmartSprite[mGame.deathIndex]->setSpriteClip(0, 0, 24, 24); + mGame.smartSprite[mGame.deathIndex]->init(mTexture[TEXTURE_PLAYER_DEATH].texture, mRenderer); + mGame.smartSprite[mGame.deathIndex]->setPosX(x); + mGame.smartSprite[mGame.deathIndex]->setPosY(y); + mGame.smartSprite[mGame.deathIndex]->setWidth(24); + mGame.smartSprite[mGame.deathIndex]->setHeight(24); + mGame.smartSprite[mGame.deathIndex]->setVelX(2.0f * sentit); + mGame.smartSprite[mGame.deathIndex]->setVelY(-5.0f); + mGame.smartSprite[mGame.deathIndex]->setAccelX(0.0f); + mGame.smartSprite[mGame.deathIndex]->setAccelY(0.2f); + mGame.smartSprite[mGame.deathIndex]->setDestX(SCREEN_WIDTH * sentit); + mGame.smartSprite[mGame.deathIndex]->setDestY(SCREEN_HEIGHT + 1); + mGame.smartSprite[mGame.deathIndex]->setEnabled(true); + mGame.smartSprite[mGame.deathIndex]->setEnabledTimer(1); + mGame.smartSprite[mGame.deathIndex]->setSpriteClip(0, 0, 24, 24); } // Actualiza los SmartSprites @@ -2085,7 +2176,7 @@ void GameDirector::updateSmartSprites() { for (int i = 0; i < MAX_SMART_SPRITES; i++) { - mSmartSprite[i]->update(); + mGame.smartSprite[i]->update(); } } @@ -2094,7 +2185,7 @@ void GameDirector::renderSmartSprites() { for (int i = 0; i < MAX_SMART_SPRITES; i++) { - mSmartSprite[i]->render(); + mGame.smartSprite[i]->render(); } } @@ -2105,7 +2196,7 @@ Uint8 GameDirector::getSmartSpriteFreeIndex() for (int i = 0; i < MAX_SMART_SPRITES; i++) { - if (mSmartSprite[i]->isEnabled() == false) + if (mGame.smartSprite[i]->isEnabled() == false) { index = i; break; @@ -2120,20 +2211,74 @@ void GameDirector::resetSmartSprites() { for (Uint8 i = 0; i < MAX_SMART_SPRITES; i++) { - mSmartSprite[i]->erase(); + mGame.smartSprite[i]->erase(); } } +#ifndef UNUSED +// Deshabilita todas las gotas de café +void GameDirector::resetCoffeeDrops() +{ + for (Uint8 i = 0; i < MAX_COFFEE_DROPS; i++) + { + mCoffeeDrop[i]->disable(); + } +} + +// Actualiza las gotas de cafe +void GameDirector::updateCoffeeDrops() +{ + for (Uint8 i = 0; i < MAX_COFFEE_DROPS; i++) + { + mCoffeeDrop[i]->update(); + } +} + +// Dibuja las gotas de cafe +void GameDirector::renderCoffeeDrops() +{ + for (Uint8 i = 0; i < MAX_COFFEE_DROPS; i++) + { + mCoffeeDrop[i]->render(); + } +} + +// Devuelve el primer indice libre del vector de CoffeeDrops +Uint8 GameDirector::getCoffeDropFreeIndex() +{ + Uint8 index = 0; + + for (Uint8 i = 0; i < MAX_COFFEE_DROPS; i++) + { + if (!(mCoffeeDrop[i]->isEnabled())) + { + index = i; + break; + } + } + return index; +} + +// Crea un numero de gotas de cafe +void GameDirector::createCoffeDrops(Uint8 num, int x, int y) +{ + for (Uint8 i = 0; i < num; i++) + { + mCoffeeDrop[getCoffeDropFreeIndex()]->init(mTexture[TEXTURE_GAME_BG].texture, mRenderer, x, y, ((rand() % 7) * 0.5f) - 1.5f, (rand() % 7) * (-0.5f) + 1.0f, PLAY_AREA_BOTTOM); + } +} +#endif + // Acciones a realizar cuando el jugador muere void GameDirector::killPlayer() { - if (mPlayer->hasExtraHit()) + if (mGame.player->hasExtraHit()) { - mPlayer->removeExtraHit(); - throwCoffee(mPlayer->getPosX() + (mPlayer->getWidth() / 2), mPlayer->getPosY() + (mPlayer->getHeight() / 2)); + mGame.player->removeExtraHit(); + throwCoffee(mGame.player->getPosX() + (mGame.player->getWidth() / 2), mGame.player->getPosY() + (mGame.player->getHeight() / 2)); JA_PlaySound(mSound[SOUND_COFFEE_OUT].sound); } - else if (!mPlayer->isInvulnerable()) + else if (!mGame.player->isInvulnerable()) { stopAllBalloons(10); // 5000 JA_StopMusic(); @@ -2141,66 +2286,72 @@ void GameDirector::killPlayer() shakeScreen(); SDL_Delay(500); // 1000 JA_PlaySound(mSound[SOUND_COFFEE_OUT].sound); - throwPlayer(mPlayer->getPosX(), mPlayer->getPosY()); - mPlayer->setAlive(false); + throwPlayer(mGame.player->getPosX(), mGame.player->getPosY()); + mGame.player->setAlive(false); } } -// Calcula y establece el valor de amenaza en funcion de los globos activos -void GameDirector::calculateMenaceLevel() +// Obtiene el valor de la variable +Uint8 GameDirector::getSubsection() { - mMenaceLevel = 0; + return mProg.subsection; +} + +// Calcula y establece el valor de amenaza en funcion de los globos activos +void GameDirector::setMenaceLevel() +{ + mGame.menaceLevelCurrent = 0; for (Uint8 i = 0; i < MAX_BALLOONS; i++) { - mMenaceLevel += mBalloon[i]->getMenace(); + mGame.menaceLevelCurrent += mGame.balloon[i]->getMenace(); } } // Obtiene el valor de la variable Uint8 GameDirector::getMenaceLevel() { - return mMenaceLevel; + return mGame.menaceLevelCurrent; } // Obtiene el valor de la variable bool GameDirector::isPlayFieldDrawOnly() { - return mPlayFieldDrawOnly; + return mGame.playFieldDrawOnly; } // Establece el valor de la variable void GameDirector::setPlayFieldDrawOnly(bool state) { - mPlayFieldDrawOnly = state; + mGame.playFieldDrawOnly = state; } // Establece el valor de la variable void GameDirector::setTimeStopped(bool value) { - mTimeStopped = value; + mGame.timeStopped = value; } // Obtiene el valor de la variable bool GameDirector::isTimeStopped() { - return mTimeStopped; + return mGame.timeStopped; } // Establece el valor de la variable -void GameDirector::setTimeStoppedTimer(Uint16 value) +void GameDirector::setTimeStoppedCounter(Uint16 value) { - mTimeStoppedTimer = value; + mGame.timeStoppedCounter = value; } // Actualiza y comprueba el valor de la variable -void GameDirector::updateTimeStoppedTimer() +void GameDirector::updateTimeStoppedCounter() { if (isTimeStopped()) { - if (mTimeStoppedTimer > 0) + if (mGame.timeStoppedCounter > 0) { - mTimeStoppedTimer--; - stopAllBalloons(TIME_STOPPED_TIMER); + mGame.timeStoppedCounter--; + stopAllBalloons(TIME_STOPPED_COUNTER); } else { @@ -2212,41 +2363,41 @@ void GameDirector::updateTimeStoppedTimer() // Establece el valor de la variable void GameDirector::setExplosionTime(bool value) { - mExplosionTime = value; + mGame.explosionTime = value; } // Obtiene el valor de la variable bool GameDirector::isExplosionTime() { - return mExplosionTime; + return mGame.explosionTime; } // Establece el valor de la variable void GameDirector::setRemainingExplosions(Uint8 value) { - mRemainingExplosions = value; + mGame.remainingExplosions = value; } // Actualiza y comprueba el valor de la variable -void GameDirector::updateRemainingExplosionsTimer() +void GameDirector::updateRemainingExplosionsCounter() { if (isExplosionTime()) { - if (mRemainingExplosionsTimer > 0) + if (mGame.remainingExplosionsCounter > 0) { - --mRemainingExplosionsTimer; + --mGame.remainingExplosionsCounter; } - else if (mRemainingExplosions > 0) + else if (mGame.remainingExplosions > 0) { - popAllBallons(); - --mRemainingExplosions; - mRemainingExplosionsTimer = REMAINING_EXPLOSIONS_TIMER; + popAllBalloons(); + --mGame.remainingExplosions; + mGame.remainingExplosionsCounter = REMAINING_EXPLOSIONS_COUNTER; } else { - mExplosionTime = false; - mRemainingExplosions = REMAINING_EXPLOSIONS; - mRemainingExplosionsTimer = REMAINING_EXPLOSIONS_TIMER; + mGame.explosionTime = false; + mGame.remainingExplosions = REMAINING_EXPLOSIONS; + mGame.remainingExplosionsCounter = REMAINING_EXPLOSIONS_COUNTER; } } } @@ -2260,7 +2411,7 @@ void GameDirector::updatePlayField() checkGameInput(); // Actualiza el jugador - mPlayer->update(); + mGame.player->update(); // Mueve los globos moveBalloons(); @@ -2281,65 +2432,61 @@ void GameDirector::updatePlayField() updateSmartSprites(); // Actualiza los contadores de estado - updateTimeStoppedTimer(); - updateRemainingExplosionsTimer(); + updateTimeStoppedCounter(); + updateRemainingExplosionsCounter(); // Comprueba las colisiones entre globos y balas - checkBulletBallonCollision(); + checkBulletBalloonCollision(); // Comprueba las colisiones entre elk jugador y los items checkPlayerItemCollision(); // Comprueba el nivel de amenaza - checkMenaceLevel(); + updateMenaceLevel(); // Comprueba la colisión entre el jugador y los globos - if (checkPlayerBallonCollision()) + if (checkPlayerBalloonCollision()) { - if (mPlayer->isAlive()) + if (mGame.player->isAlive()) { - if (mDemo) - { - mGame.status = GAME_STATE_INSTRUCTIONS; - } + if (mDemo.enabled) + setProgSection(PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS); else - { killPlayer(); - } } } } else { // Actualiza el mensaje de GetReady - mGetReadyBitmap->update(); + mGame.getReadyBitmap->update(); } } // Actualiza el fondo void GameDirector::updateBackground() { - mGBClouds1->move(); - mGBClouds1b->move(); - mGBClouds2->move(); - mGBClouds2b->move(); - if (mGBClouds1->getPosX() < -mGBClouds1->getWidth()) + mGame.clouds1a->move(); + mGame.clouds1b->move(); + mGame.clouds2a->move(); + mGame.clouds2b->move(); + if (mGame.clouds1a->getPosX() < -mGame.clouds1a->getWidth()) { - mGBClouds1->setPosX(mGBClouds1->getWidth()); + mGame.clouds1a->setPosX(mGame.clouds1a->getWidth()); } - if (mGBClouds1b->getPosX() < -mGBClouds1b->getWidth()) + if (mGame.clouds1b->getPosX() < -mGame.clouds1b->getWidth()) { - mGBClouds1b->setPosX(mGBClouds1b->getWidth()); + mGame.clouds1b->setPosX(mGame.clouds1b->getWidth()); } - if (mGBClouds2->getPosX() < -mGBClouds2->getWidth()) + if (mGame.clouds2a->getPosX() < -mGame.clouds2a->getWidth()) { - mGBClouds2->setPosX(mGBClouds2->getWidth()); + mGame.clouds2a->setPosX(mGame.clouds2a->getWidth()); } - if (mGBClouds2b->getPosX() < -mGBClouds2b->getWidth()) + if (mGame.clouds2b->getPosX() < -mGame.clouds2b->getWidth()) { - mGBClouds2b->setPosX(mGBClouds2b->getWidth()); + mGame.clouds2b->setPosX(mGame.clouds2b->getWidth()); } - mGrass->setSpriteClip(256, 85 + (6 * (mGameCounter / 20 % 2)), SCREEN_WIDTH, 6); + mGame.grass->setSpriteClip(256, 85 + (6 * (mGame.counter / 20 % 2)), SCREEN_WIDTH, 6); } // Dibuja el fondo @@ -2353,21 +2500,21 @@ void GameDirector::renderBackground() } updateBackground(); - mGameBackgroundSky->setSpriteClip(SCREEN_WIDTH, 192, SCREEN_WIDTH, SCREEN_HEIGHT); + mGame.gradient->setSpriteClip(SCREEN_WIDTH, 192, SCREEN_WIDTH, SCREEN_HEIGHT); mTexture[TEXTURE_GAME_BG].texture->setAlpha(255); - mGameBackgroundSky->render(); + mGame.gradient->render(); - mGameBackgroundSky->setSpriteClip(0, 192, SCREEN_WIDTH, SCREEN_HEIGHT); + mGame.gradient->setSpriteClip(0, 192, SCREEN_WIDTH, SCREEN_HEIGHT); mTexture[TEXTURE_GAME_BG].texture->setAlpha(alpha); - mGameBackgroundSky->render(); + mGame.gradient->render(); mTexture[TEXTURE_GAME_BG].texture->setAlpha(255); - mGBClouds1->render(); - mGBClouds1b->render(); - mGBClouds2->render(); - mGBClouds2b->render(); - mGameBackgroundFront->render(); - mGrass->render(); + mGame.clouds1a->render(); + mGame.clouds1b->render(); + mGame.clouds2a->render(); + mGame.clouds2b->render(); + mGame.background->render(); + mGame.grass->render(); } // Dibuja el campo de juego @@ -2378,9 +2525,9 @@ void GameDirector::renderPlayField() renderBullets(); renderItems(); renderSmartSprites(); - mPlayer->render(); + mGame.player->render(); renderDeathFade(); - if (!mDemo) + if (!mDemo.enabled) { renderScoreBoard(); } @@ -2396,32 +2543,32 @@ void GameDirector::renderPlayField() } // Gestiona el nivel de amenaza -void GameDirector::checkMenaceLevel() +void GameDirector::updateMenaceLevel() { // Aumenta el nivel de amenaza en función de la puntuación - mMenaceLevelThreshold = 7 + (4 * (mGame.score / 10000)); + mGame.menaceLevelThreshold = 7 + (4 * (mGame.score / 10000)); // Si el nivel de amenza es inferior al umbral - if (mMenaceLevel < mMenaceLevelThreshold) + if (mGame.menaceLevelCurrent < mGame.menaceLevelThreshold) { Uint8 index = 0; // Obtiene el centro del jugador en el eje X - int x = mPlayer->getPosX() + (mPlayer->getWidth() / 2); + int x = mGame.player->getPosX() + (mGame.player->getWidth() / 2); // Crea un globo sobre el jugador en dirección hacia el centro if (x < (PLAY_AREA_WIDTH / 2)) { - index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLON_VELX_POSITIVE, 400, mTexture[TEXTURE_BALLOON].texture); + index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLOON_VELX_POSITIVE, 400, mTexture[TEXTURE_BALLOON].texture); } else { - index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLON_VELX_NEGATIVE, 400, mTexture[TEXTURE_BALLOON].texture); + index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLOON_VELX_NEGATIVE, 400, mTexture[TEXTURE_BALLOON].texture); } - mBalloon[index]->allignTo(x); + mGame.balloon[index]->allignTo(x); // Recalcula el nivel de amenaza con el nuevo globo - calculateMenaceLevel(); + setMenaceLevel(); } } @@ -2489,175 +2636,170 @@ void GameDirector::checkGameInput() // Obtiene el estado de las teclas pulsadas del teclado keystates = SDL_GetKeyboardState(NULL); - mDemoKeys.left = 0; - mDemoKeys.right = 0; - mDemoKeys.noInput = 0; - mDemoKeys.fire = 0; - mDemoKeys.fireLeft = 0; - mDemoKeys.fireRight = 0; + mDemo.keys.left = 0; + mDemo.keys.right = 0; + mDemo.keys.noInput = 0; + mDemo.keys.fire = 0; + mDemo.keys.fireLeft = 0; + mDemo.keys.fireRight = 0; // Modo Demo activo - if (mDemo) + if (mDemo.enabled) { - if (mDemoDataFile[mDemoCounter].left == 1) - mPlayer->setInput(INPUT_LEFT); - if (mDemoDataFile[mDemoCounter].right == 1) - mPlayer->setInput(INPUT_RIGHT); - if (mDemoDataFile[mDemoCounter].noInput == 1) - mPlayer->setInput(NO_INPUT); - if (mDemoDataFile[mDemoCounter].fire == 1) - if (mPlayer->canFire()) + if (mDemo.dataFile[mDemo.counter].left == 1) + mGame.player->setInput(INPUT_LEFT); + if (mDemo.dataFile[mDemo.counter].right == 1) + mGame.player->setInput(INPUT_RIGHT); + if (mDemo.dataFile[mDemo.counter].noInput == 1) + mGame.player->setInput(NO_INPUT); + if (mDemo.dataFile[mDemo.counter].fire == 1) + if (mGame.player->canFire()) { - mPlayer->setInput(INPUT_FIRE_UP); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP); - mPlayer->setFireCooldown(10); + mGame.player->setInput(INPUT_FIRE_UP); + createBullet(mGame.player->getPosX() + (mGame.player->getWidth() / 2) - 4, mGame.player->getPosY() + (mGame.player->getHeight() / 2), BULLET_UP); + mGame.player->setFireCooldown(10); } - if (mDemoDataFile[mDemoCounter].fireLeft == 1) - if (mPlayer->canFire()) + if (mDemo.dataFile[mDemo.counter].fireLeft == 1) + if (mGame.player->canFire()) { - mPlayer->setInput(INPUT_FIRE_LEFT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP); - mPlayer->setFireCooldown(10); + mGame.player->setInput(INPUT_FIRE_LEFT); + createBullet(mGame.player->getPosX() + (mGame.player->getWidth() / 2) - 4, mGame.player->getPosY() + (mGame.player->getHeight() / 2), BULLET_UP); + mGame.player->setFireCooldown(10); } - if (mDemoDataFile[mDemoCounter].fireRight == 1) - if (mPlayer->canFire()) + if (mDemo.dataFile[mDemo.counter].fireRight == 1) + if (mGame.player->canFire()) { - mPlayer->setInput(INPUT_FIRE_RIGHT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP); - mPlayer->setFireCooldown(10); + mGame.player->setInput(INPUT_FIRE_RIGHT); + createBullet(mGame.player->getPosX() + (mGame.player->getWidth() / 2) - 4, mGame.player->getPosY() + (mGame.player->getHeight() / 2), BULLET_UP); + mGame.player->setFireCooldown(10); } // Comprobamos la tecla o el botón de pausa/menu - if ((keystates[mKeyboard.accept] != 0) || (keystates[mKeyboard.cancel] != 0) || (checkGameController(INPUT_PAUSE)) || (checkGameController(INPUT_ACCEPT)) || (checkGameController(INPUT_CANCEL))) + if ((keystates[mProg.keyboard.accept] != 0) || (keystates[mProg.keyboard.cancel] != 0) || (checkGameController(INPUT_PAUSE)) || (checkGameController(INPUT_ACCEPT)) || (checkGameController(INPUT_CANCEL))) { - setGameStatus(GAME_STATE_TITLE); + setProgSection(PROG_SECTION_TITLE); } - if (mDemoCounter < TOTAL_DEMO_DATA) - { - mDemoCounter++; - } + if (mDemo.counter < TOTAL_DEMO_DATA) + mDemo.counter++; else - { - mGame.status = GAME_STATE_INSTRUCTIONS; - //mDemoCounter = 0; - } + setProgSection(PROG_SECTION_TITLE, TITLE_SECTION_INSTRUCTIONS); } // Modo Demo no activo - else if (mPlayer->isAlive()) + else if (mGame.player->isAlive()) { // Tecla izquierda o el mando hacia la izquierda - if ((keystates[mKeyboard.left] != 0) || (checkGameController(INPUT_LEFT))) + if ((keystates[mProg.keyboard.left] != 0) || (checkGameController(INPUT_LEFT))) { - mPlayer->setInput(INPUT_LEFT); - mDemoKeys.left = 1; + mGame.player->setInput(INPUT_LEFT); + mDemo.keys.left = 1; } else { // Tecla derecha o el mando hacia la derecha - if ((keystates[mKeyboard.right] != 0) || (checkGameController(INPUT_RIGHT))) + if ((keystates[mProg.keyboard.right] != 0) || (checkGameController(INPUT_RIGHT))) { - mPlayer->setInput(INPUT_RIGHT); - mDemoKeys.right = 1; + mGame.player->setInput(INPUT_RIGHT); + mDemo.keys.right = 1; } else { // Ninguna de las dos direcciones pulsadas - mPlayer->setInput(NO_INPUT); - mDemoKeys.noInput = 1; + mGame.player->setInput(NO_INPUT); + mDemo.keys.noInput = 1; } } // Comprueba la tecla o el botón de disparo central - if ((keystates[mKeyboard.fire] != 0) || (checkGameController(INPUT_FIRE_UP))) + if ((keystates[mProg.keyboard.fire] != 0) || (checkGameController(INPUT_FIRE_UP))) { - if (mPlayer->canFire()) + if (mGame.player->canFire()) { - mPlayer->setInput(INPUT_FIRE_UP); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_UP); - mPlayer->setFireCooldown(10); + mGame.player->setInput(INPUT_FIRE_UP); + createBullet(mGame.player->getPosX() + (mGame.player->getWidth() / 2) - 4, mGame.player->getPosY() + (mGame.player->getHeight() / 2), BULLET_UP); + mGame.player->setFireCooldown(10); // Reproduce el sonido de disparo JA_PlaySound(mSound[SOUND_BULLET].sound); - mDemoKeys.fire = 1; + mDemo.keys.fire = 1; } } // Comprueba la tecla o el botón de disparo izquierdo - if ((keystates[mKeyboard.fireLeft] != 0) || (checkGameController(INPUT_FIRE_LEFT))) + if ((keystates[mProg.keyboard.fireLeft] != 0) || (checkGameController(INPUT_FIRE_LEFT))) { - if (mPlayer->canFire()) + if (mGame.player->canFire()) { - mPlayer->setInput(INPUT_FIRE_LEFT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_LEFT); - mPlayer->setFireCooldown(10); + mGame.player->setInput(INPUT_FIRE_LEFT); + createBullet(mGame.player->getPosX() + (mGame.player->getWidth() / 2) - 4, mGame.player->getPosY() + (mGame.player->getHeight() / 2), BULLET_LEFT); + mGame.player->setFireCooldown(10); // Reproduce el sonido de disparo JA_PlaySound(mSound[SOUND_BULLET].sound); - mDemoKeys.fireLeft = 1; + mDemo.keys.fireLeft = 1; } } // Comprueba la tecla o el botón de disparo derecho - if ((keystates[mKeyboard.fireRight] != 0) || (checkGameController(INPUT_FIRE_RIGHT))) + if ((keystates[mProg.keyboard.fireRight] != 0) || (checkGameController(INPUT_FIRE_RIGHT))) { - if (mPlayer->canFire()) + if (mGame.player->canFire()) { - mPlayer->setInput(INPUT_FIRE_RIGHT); - createBullet(mPlayer->getPosX() + (mPlayer->getWidth() / 2) - 4, mPlayer->getPosY() + (mPlayer->getHeight() / 2), BULLET_RIGHT); - mPlayer->setFireCooldown(10); + mGame.player->setInput(INPUT_FIRE_RIGHT); + createBullet(mGame.player->getPosX() + (mGame.player->getWidth() / 2) - 4, mGame.player->getPosY() + (mGame.player->getHeight() / 2), BULLET_RIGHT); + mGame.player->setFireCooldown(10); // Reproduce el sonido de disparo JA_PlaySound(mSound[SOUND_BULLET].sound); - mDemoKeys.fireRight = 1; + mDemo.keys.fireRight = 1; } } // Para la pausa actuaremos cuando se suelte la tecla de pausa // Comprueba la tecla o el botón de pausa/menu y su buffer - if (((keystates[mKeyboard.pause] != 0) || (checkGameController(INPUT_PAUSE))) && (mKeyboardBuffer.pause == 0)) //|| ((mGameControllerFound) && (SDL_JoystickGetButton(mGameController, BUTTON_START)))) + if (((keystates[mProg.keyboard.pause] != 0) || (checkGameController(INPUT_PAUSE))) && (mProg.keyboardBuffer.pause == 0)) //|| ((mGameControllerFound) && (SDL_JoystickGetButton(mGameController, BUTTON_START)))) { // Se acaba de pulsar la tecla. Lo anotamos en su buffer - mKeyboardBuffer.pause = 1; + mProg.keyboardBuffer.pause = 1; } else { // Aqui sigue la tecla pulsada, mantenemos el buffer activo - if (((keystates[mKeyboard.pause] != 0) || (checkGameController(INPUT_PAUSE))) && (mKeyboardBuffer.pause != 0)) + if (((keystates[mProg.keyboard.pause] != 0) || (checkGameController(INPUT_PAUSE))) && (mProg.keyboardBuffer.pause != 0)) { - mKeyboardBuffer.pause = 1; + mProg.keyboardBuffer.pause = 1; } else { // Se ha soltado la tecla, procedemos a ejecutar la accion - if (((keystates[mKeyboard.pause] == 0) || (!checkGameController(INPUT_PAUSE))) && (mKeyboardBuffer.pause != 0)) + if (((keystates[mProg.keyboard.pause] == 0) || (!checkGameController(INPUT_PAUSE))) && (mProg.keyboardBuffer.pause != 0)) { - //setGameStatus(GAME_STATE_PAUSED); - mGame.paused = true; + mGame.section = GAME_SECTION_PAUSE; if (JA_GetMusicState() == JA_MUSIC_PLAYING) { JA_PauseMusic(); } - mKeyboardBuffer.pause = 0; + mProg.keyboardBuffer.pause = 0; } } } - if (mDemoCounter < TOTAL_DEMO_DATA) + if (mDemo.counter < TOTAL_DEMO_DATA) { - if (mDemoRecording) + if (mDemo.recording) { - mDemoDataFile[mDemoCounter] = mDemoKeys; + mDemo.dataFile[mDemo.counter] = mDemo.keys; } - mDemoCounter++; + mDemo.counter++; } - else if (mDemoRecording) + else if (mDemo.recording) { - mGame.status = GAME_STATE_QUIT; + mProg.quit = true; + ; } } } @@ -2668,61 +2810,62 @@ void GameDirector::checkMenuInput(Menu *menu) // Obtiene el estado de las teclas pulsadas del teclado keystates = SDL_GetKeyboardState(NULL); - if (!mMenuKeyPressed) + if (!mMenu.keyPressed) { // Tecla arriba o el mando hacia arriba - if ((keystates[mKeyboard.up] != 0) || (checkGameController(INPUT_UP))) + if ((keystates[mProg.keyboard.up] != 0) || (checkGameController(INPUT_UP))) { if (menu->checkInput(INPUT_UP)) { - mMenuKeyPressed = true; + mMenu.keyPressed = true; JA_PlaySound(mSound[SOUND_MENU_MOVE].sound); } } // Tecla abajo o el mando hacia abajo - if ((keystates[mKeyboard.down] != 0) || (checkGameController(INPUT_DOWN))) + if ((keystates[mProg.keyboard.down] != 0) || (checkGameController(INPUT_DOWN))) { if (menu->checkInput(INPUT_DOWN)) { - mMenuKeyPressed = true; + mMenu.keyPressed = true; JA_PlaySound(mSound[SOUND_MENU_MOVE].sound); } } // Tecla o el botón de aceptar - if ((keystates[mKeyboard.accept] != 0) || (checkGameController(INPUT_ACCEPT))) + if ((keystates[mProg.keyboard.accept] != 0) || (checkGameController(INPUT_ACCEPT))) { menu->checkInput(INPUT_ACCEPT); - mMenuKeyPressed = true; + mMenu.keyPressed = true; } // Tecla o el botón de cancelar - if ((keystates[mKeyboard.cancel] != 0) || (checkGameController(INPUT_CANCEL))) + if ((keystates[mProg.keyboard.cancel] != 0) || (checkGameController(INPUT_CANCEL))) { menu->checkInput(INPUT_CANCEL); - mMenuKeyPressed = true; + mMenu.keyPressed = true; } } // Ningún botón, libera la variable - if ((keystates[mKeyboard.up] == 0) && (keystates[mKeyboard.down] == 0) && (keystates[mKeyboard.accept] == 0) && - (keystates[mKeyboard.cancel] == 0) && (checkGameController(NO_INPUT))) + if ((keystates[mProg.keyboard.up] == 0) && (keystates[mProg.keyboard.down] == 0) && (keystates[mProg.keyboard.accept] == 0) && + (keystates[mProg.keyboard.cancel] == 0) && (checkGameController(NO_INPUT))) { - mMenuKeyPressed = false; + mMenu.keyPressed = false; } } // Obtiene el valor de la variable -Uint8 GameDirector::getGameStatus() +Uint8 GameDirector::getProgSection() { - return mGame.status; + return mProg.section; } // Establece el valor de la variable -void GameDirector::setGameStatus(Uint8 status) +void GameDirector::setProgSection(Uint8 section, Uint8 subsection) { - mGame.status = status; + mProg.section = section; + mProg.subsection = subsection; } // Pinta una transición en pantalla @@ -2859,42 +3002,45 @@ void GameDirector::renderFade(Uint8 index) // Pinta diferentes mensajes en la pantalla void GameDirector::renderMessages() { - //mGetReadyBitmap->update(); - mGetReadyBitmap->render(); - if (!mGetReadyBitmap->isEnabled()) + // GETREADY! + mGame.getReadyBitmap->render(); + if (!mGame.getReadyBitmap->isEnabled()) setPlayFieldDrawOnly(false); - if (mTimeStopped) + // Time Stopped + if (mGame.timeStopped) { - if ((mTimeStoppedTimer > 100) || (mTimeStoppedTimer % 10 > 4)) + if ((mGame.timeStoppedCounter > 100) || (mGame.timeStoppedCounter % 10 > 4)) { - mText.black->writeCentered(PLAY_AREA_CENTER_X + 1, PLAY_AREA_FIRST_QUARTER_Y + 1, "Time Stopped: " + std::to_string(mTimeStoppedTimer / 10), 0); - mText.white->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, "Time Stopped: " + std::to_string(mTimeStoppedTimer / 10), 0); + mText.black->writeCentered(PLAY_AREA_CENTER_X + 1, PLAY_AREA_FIRST_QUARTER_Y + 1, "Time Stopped: " + std::to_string(mGame.timeStoppedCounter / 10)); + mText.white->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, "Time Stopped: " + std::to_string(mGame.timeStoppedCounter / 10)); } } - if (mDemo) + // D E M O + if (mDemo.enabled) { - if (mDemoCounter % 30 > 14) + if (mDemo.counter % 30 > 14) { - mText.black->writeCentered(PLAY_AREA_CENTER_X + 1, PLAY_AREA_FIRST_QUARTER_Y + 1, "D E M O", 0); - mText.white->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, "D E M O", 0); + mText.black->writeCentered(PLAY_AREA_CENTER_X + 1, PLAY_AREA_FIRST_QUARTER_Y + 1, "D E M O"); + mText.white->writeCentered(PLAY_AREA_CENTER_X, PLAY_AREA_FIRST_QUARTER_Y, "D E M O"); } } - if (mGame.stageCounter > 0) + // STAGE NUMBER + if (mGame.stageCounter < STAGE_COUNTER) { - mText.black->writeCentered(PLAY_AREA_CENTER_X + 1, int(mGame.stagePath[mGame.stageCounter - 1]) + 1, "STAGE " + std::to_string(mGame.stage), 0); - mText.white->writeCentered(PLAY_AREA_CENTER_X, int(mGame.stagePath[mGame.stageCounter - 1]), "STAGE " + std::to_string(mGame.stage), 0); + mText.blackX2->writeCentered(PLAY_AREA_CENTER_X + 2, mGame.stagePath[mGame.stageCounter] + 2, "STAGE " + std::to_string(mGame.stage)); + mText.whiteX2->writeCentered(PLAY_AREA_CENTER_X, mGame.stagePath[mGame.stageCounter], "STAGE " + std::to_string(mGame.stage)); } } // Habilita el efecto del item de detener el tiempo void GameDirector::enableTimeStopItem() { - stopAllBalloons(TIME_STOPPED_TIMER); + stopAllBalloons(TIME_STOPPED_COUNTER); setTimeStopped(true); - setTimeStoppedTimer(TIME_STOPPED_TIMER); + setTimeStoppedCounter(TIME_STOPPED_COUNTER); if (JA_GetMusicState() == JA_MUSIC_PLAYING) { JA_PauseMusic(); @@ -2904,8 +3050,8 @@ void GameDirector::enableTimeStopItem() // Deshabilita el efecto del item de detener el tiempo void GameDirector::disableTimeStopItem() { - mTimeStopped = false; - mTimeStoppedTimer = TIME_STOPPED_TIMER; + mGame.timeStopped = false; + mGame.timeStoppedCounter = TIME_STOPPED_COUNTER; startAllBalloons(); if (JA_GetMusicState() == JA_MUSIC_PAUSED) { @@ -2916,20 +3062,20 @@ void GameDirector::disableTimeStopItem() // Cambia el valor de la variable de modo de pantalla completa void GameDirector::changeFullScreenMode() { - switch (mFullScreenMode) + switch (mOptions.fullScreenMode) { case 0: - mFullScreenMode = SDL_WINDOW_FULLSCREEN; + mOptions.fullScreenMode = SDL_WINDOW_FULLSCREEN; break; case SDL_WINDOW_FULLSCREEN: - mFullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP; + mOptions.fullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP; break; case SDL_WINDOW_FULLSCREEN_DESKTOP: - mFullScreenMode = 0; + mOptions.fullScreenMode = 0; break; default: - mFullScreenMode = 0; + mOptions.fullScreenMode = 0; break; } } @@ -2937,7 +3083,7 @@ void GameDirector::changeFullScreenMode() // Actualiza los elementos del menu de opciones void GameDirector::updateOptionsMenu() { - switch (mFullScreenMode) + switch (mOptions.fullScreenMode) { case 0: mMenu.options->setItemCaption(0, "WINDOWED"); @@ -2953,7 +3099,7 @@ void GameDirector::updateOptionsMenu() mMenu.options->setItemCaption(0, "WINDOWED"); break; } - mMenu.options->setItemCaption(1, "WINDOWS SIZE " + std::to_string(mWindowSize)); + mMenu.options->setItemCaption(1, "WINDOWS SIZE " + std::to_string(mOptions.windowSize)); mMenu.options->centerMenu(SCREEN_CENTER_X); mMenu.options->centerMenuElements(); } @@ -2969,25 +3115,25 @@ void GameDirector::shakeScreen() SDL_RenderClear(mRenderer); // Dibuja los objetos - mGameBackgroundFront->setPosX(0); - mGameBackgroundFront->setWidth(1); - mGameBackgroundFront->setSpriteClip(0, 0, 1, 192); + mGame.background->setPosX(0); + mGame.background->setWidth(1); + mGame.background->setSpriteClip(0, 0, 1, 192); renderBackground(); - mGameBackgroundFront->setPosX(255); - mGameBackgroundFront->setSpriteClip(255, 0, 1, 192); - mGameBackgroundFront->render(); + mGame.background->setPosX(255); + mGame.background->setSpriteClip(255, 0, 1, 192); + mGame.background->render(); - mGameBackgroundFront->setPosX(v[n]); - mGameBackgroundFront->setWidth(256); - mGameBackgroundFront->setSpriteClip(0, 0, 256, 192); - mGameBackgroundFront->render(); + mGame.background->setPosX(v[n]); + mGame.background->setWidth(256); + mGame.background->setSpriteClip(0, 0, 256, 192); + mGame.background->render(); - mGrass->render(); + mGame.grass->render(); renderBalloons(); renderBullets(); renderItems(); - mPlayer->render(); + mGame.player->render(); renderScoreBoard(); // Actualiza la pantalla @@ -2999,7 +3145,9 @@ void GameDirector::shakeScreen() // Bucle para el logo del juego void GameDirector::runLogo() { - while (mGame.status == GAME_STATE_LOGO) + initLogo(); + + while (mProg.section == PROG_SECTION_LOGO) { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3007,14 +3155,14 @@ void GameDirector::runLogo() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } // Cualquier tecla pulsada if ((mEventHandler->type == SDL_KEYDOWN) || (mEventHandler->type == SDL_JOYBUTTONDOWN)) { - setGameStatus(GAME_STATE_TITLE); + setProgSection(PROG_SECTION_TITLE); } } @@ -3054,10 +3202,10 @@ void GameDirector::runLogo() SDL_RenderPresent(mRenderer); // Comprueba si ha terminado el logo - if (SDL_GetTicks() - mTicks > mTicksSpeed) + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) { // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); + mProg.ticks = SDL_GetTicks(); if (mLogo.counter == 0) { @@ -3070,7 +3218,7 @@ void GameDirector::runLogo() if (mLogo.counter == 500) // minimo 200 + 255 { mLogo.counter = 0; - setGameStatus(GAME_STATE_INTRO); + setProgSection(PROG_SECTION_INTRO); } else { @@ -3078,11 +3226,15 @@ void GameDirector::runLogo() } } } + + quitLogo(); } // Bucle para la intro del juego void GameDirector::runIntro() { + initIntro(); + // Si la música no está sonando if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) { @@ -3090,12 +3242,12 @@ void GameDirector::runIntro() JA_PlayMusic(mMusic[MUSIC_INTRO].music, false); } - while (mGame.status == GAME_STATE_INTRO) + while (mProg.section == PROG_SECTION_INTRO) { - if (SDL_GetTicks() - mTicks > mTicksSpeed) + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) { // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); + mProg.ticks = SDL_GetTicks(); // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3103,137 +3255,137 @@ void GameDirector::runIntro() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } if ((mEventHandler->type == SDL_KEYDOWN) || (mEventHandler->type == SDL_JOYBUTTONDOWN)) { JA_StopMusic(); - setGameStatus(GAME_STATE_TITLE); + setProgSection(PROG_SECTION_TITLE); } } // Actualiza los objetos for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) { - mIntroBitmap[i]->update(); + mIntro.bitmap[i]->update(); } for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) { - mIntroText[i]->update(); + mIntro.text[i]->update(); } // Guión de eventos // Primera imagen - UPV - if (mIntroEvents[BITMAP0] == EVENT_WAITING) + if (mIntro.events[BITMAP0] == EVENT_WAITING) { - mIntroBitmap[0]->setEnabled(true); - mIntroEvents[BITMAP0] = EVENT_RUNNING; + mIntro.bitmap[0]->setEnabled(true); + mIntro.events[BITMAP0] = EVENT_RUNNING; } // Primer texto de la primera imagen - if ((mIntroEvents[BITMAP0] == EVENT_COMPLETED) && (mIntroEvents[TEXT0] == EVENT_WAITING)) + if ((mIntro.events[BITMAP0] == EVENT_COMPLETED) && (mIntro.events[TEXT0] == EVENT_WAITING)) { - mIntroText[0]->setEnabled(true); - mIntroEvents[TEXT0] = EVENT_RUNNING; + mIntro.text[0]->setEnabled(true); + mIntro.events[TEXT0] = EVENT_RUNNING; } // Segundo texto de la primera imagen - if ((mIntroEvents[TEXT0] == EVENT_COMPLETED) && (mIntroEvents[TEXT1] == EVENT_WAITING)) + if ((mIntro.events[TEXT0] == EVENT_COMPLETED) && (mIntro.events[TEXT1] == EVENT_WAITING)) { - mIntroText[0]->setEnabled(false); - mIntroText[1]->setEnabled(true); - mIntroEvents[TEXT1] = EVENT_RUNNING; + mIntro.text[0]->setEnabled(false); + mIntro.text[1]->setEnabled(true); + mIntro.events[TEXT1] = EVENT_RUNNING; } // Tercer texto de la primera imagen - if ((mIntroEvents[TEXT1] == EVENT_COMPLETED) && (mIntroEvents[TEXT2] == EVENT_WAITING)) + if ((mIntro.events[TEXT1] == EVENT_COMPLETED) && (mIntro.events[TEXT2] == EVENT_WAITING)) { - mIntroText[1]->setEnabled(false); - mIntroText[2]->setEnabled(true); - mIntroEvents[TEXT2] = EVENT_RUNNING; + mIntro.text[1]->setEnabled(false); + mIntro.text[2]->setEnabled(true); + mIntro.events[TEXT2] = EVENT_RUNNING; } // Segunda imagen - Máquina - if ((mIntroEvents[TEXT2] == EVENT_COMPLETED) && (mIntroEvents[BITMAP1] == EVENT_WAITING)) + if ((mIntro.events[TEXT2] == EVENT_COMPLETED) && (mIntro.events[BITMAP1] == EVENT_WAITING)) { - mIntroBitmap[0]->setEnabled(false); - mIntroText[2]->setEnabled(false); - mIntroBitmap[1]->setEnabled(true); - mIntroEvents[BITMAP1] = EVENT_RUNNING; + mIntro.bitmap[0]->setEnabled(false); + mIntro.text[2]->setEnabled(false); + mIntro.bitmap[1]->setEnabled(true); + mIntro.events[BITMAP1] = EVENT_RUNNING; } // Primer texto de la segunda imagen - if ((mIntroEvents[BITMAP1] == EVENT_COMPLETED) && (mIntroEvents[TEXT3] == EVENT_WAITING)) + if ((mIntro.events[BITMAP1] == EVENT_COMPLETED) && (mIntro.events[TEXT3] == EVENT_WAITING)) { - mIntroText[3]->setEnabled(true); - mIntroEvents[TEXT3] = EVENT_RUNNING; + mIntro.text[3]->setEnabled(true); + mIntro.events[TEXT3] = EVENT_RUNNING; } // Tercera imagen junto con primer texto - GRITO - if ((mIntroEvents[TEXT3] == EVENT_COMPLETED) && (mIntroEvents[BITMAP2] == EVENT_WAITING) && (mIntroEvents[TEXT4] == EVENT_WAITING)) + if ((mIntro.events[TEXT3] == EVENT_COMPLETED) && (mIntro.events[BITMAP2] == EVENT_WAITING) && (mIntro.events[TEXT4] == EVENT_WAITING)) { - mIntroBitmap[1]->setEnabled(false); - mIntroText[3]->setEnabled(false); - mIntroBitmap[2]->setEnabled(true); - mIntroText[4]->setEnabled(true); - mIntroEvents[BITMAP2] = EVENT_RUNNING; - mIntroEvents[TEXT4] = EVENT_RUNNING; + mIntro.bitmap[1]->setEnabled(false); + mIntro.text[3]->setEnabled(false); + mIntro.bitmap[2]->setEnabled(true); + mIntro.text[4]->setEnabled(true); + mIntro.events[BITMAP2] = EVENT_RUNNING; + mIntro.events[TEXT4] = EVENT_RUNNING; } // Cuarta imagen junto con primer texto - Reflexión - if ((mIntroEvents[TEXT4] == EVENT_COMPLETED) && (mIntroEvents[BITMAP3] == EVENT_WAITING) && (mIntroEvents[TEXT5] == EVENT_WAITING)) + if ((mIntro.events[TEXT4] == EVENT_COMPLETED) && (mIntro.events[BITMAP3] == EVENT_WAITING) && (mIntro.events[TEXT5] == EVENT_WAITING)) { - mIntroBitmap[2]->setEnabled(false); - mIntroText[4]->setEnabled(false); - mIntroBitmap[3]->setEnabled(true); - mIntroText[5]->setEnabled(true); - mIntroEvents[BITMAP3] = EVENT_RUNNING; - mIntroEvents[TEXT5] = EVENT_RUNNING; + mIntro.bitmap[2]->setEnabled(false); + mIntro.text[4]->setEnabled(false); + mIntro.bitmap[3]->setEnabled(true); + mIntro.text[5]->setEnabled(true); + mIntro.events[BITMAP3] = EVENT_RUNNING; + mIntro.events[TEXT5] = EVENT_RUNNING; } // Segundo texto de la cuarta imagen - if ((mIntroEvents[TEXT5] == EVENT_COMPLETED) && (mIntroEvents[TEXT6] == EVENT_WAITING)) + if ((mIntro.events[TEXT5] == EVENT_COMPLETED) && (mIntro.events[TEXT6] == EVENT_WAITING)) { - mIntroText[5]->setEnabled(false); - mIntroText[6]->setEnabled(true); - mIntroEvents[TEXT6] = EVENT_RUNNING; + mIntro.text[5]->setEnabled(false); + mIntro.text[6]->setEnabled(true); + mIntro.events[TEXT6] = EVENT_RUNNING; } // Quinta imagen - Patada - if ((mIntroEvents[TEXT6] == EVENT_COMPLETED) && (mIntroEvents[BITMAP4] == EVENT_WAITING)) + if ((mIntro.events[TEXT6] == EVENT_COMPLETED) && (mIntro.events[BITMAP4] == EVENT_WAITING)) { - mIntroBitmap[3]->setEnabled(false); - mIntroText[6]->setEnabled(false); - mIntroBitmap[4]->setEnabled(true); - mIntroEvents[BITMAP4] = EVENT_RUNNING; + mIntro.bitmap[3]->setEnabled(false); + mIntro.text[6]->setEnabled(false); + mIntro.bitmap[4]->setEnabled(true); + mIntro.events[BITMAP4] = EVENT_RUNNING; } // Primer texto de la quinta imagen - if ((mIntroEvents[BITMAP4] == EVENT_COMPLETED) && (mIntroEvents[TEXT7] == EVENT_WAITING)) + if ((mIntro.events[BITMAP4] == EVENT_COMPLETED) && (mIntro.events[TEXT7] == EVENT_WAITING)) { - mIntroText[7]->setEnabled(true); - mIntroEvents[TEXT7] = EVENT_RUNNING; + mIntro.text[7]->setEnabled(true); + mIntro.events[TEXT7] = EVENT_RUNNING; } // Sexta imagen junto con texto - Globos de café - if ((mIntroEvents[TEXT7] == EVENT_COMPLETED) && (mIntroEvents[BITMAP5] == EVENT_WAITING) && (mIntroEvents[TEXT8] == EVENT_WAITING)) + if ((mIntro.events[TEXT7] == EVENT_COMPLETED) && (mIntro.events[BITMAP5] == EVENT_WAITING) && (mIntro.events[TEXT8] == EVENT_WAITING)) { - mIntroBitmap[4]->setEnabled(false); - mIntroText[7]->setEnabled(false); - mIntroBitmap[5]->setEnabled(true); - mIntroText[8]->setEnabled(true); - mIntroEvents[BITMAP5] = EVENT_RUNNING; - mIntroEvents[TEXT8] = EVENT_RUNNING; + mIntro.bitmap[4]->setEnabled(false); + mIntro.text[7]->setEnabled(false); + mIntro.bitmap[5]->setEnabled(true); + mIntro.text[8]->setEnabled(true); + mIntro.events[BITMAP5] = EVENT_RUNNING; + mIntro.events[TEXT8] = EVENT_RUNNING; } // Acaba el último texto - if (mIntroEvents[TEXT8] == EVENT_COMPLETED) + if (mIntro.events[TEXT8] == EVENT_COMPLETED) { - mIntroText[8]->setEnabled(false); + mIntro.text[8]->setEnabled(false); JA_StopMusic(); - mGame.status = GAME_STATE_TITLE; + setProgSection(PROG_SECTION_TITLE); } } @@ -3243,31 +3395,30 @@ void GameDirector::runIntro() // Dibuja los objetos for (Uint8 i = 0; i < INTRO_TOTAL_BITMAPS; i++) - { - mIntroBitmap[i]->render(); - } + mIntro.bitmap[i]->render(); for (Uint8 i = 0; i < INTRO_TOTAL_TEXTS; i++) - { - mIntroText[i]->render(); - } + mIntro.text[i]->render(); // Actualiza la pantalla SDL_RenderPresent(mRenderer); } + + quitIntro(); } // Bucle para el titulo del juego -void GameDirector::runTitle() +void GameDirector::runTitle(Uint8 section) { - Uint8 R, G, B; - R = 0x27; - G = 0x27; - B = 0x36; + Uint8 R = 0x27; + Uint8 G = 0x27; + Uint8 B = 0x36; - while (mGame.status == GAME_STATE_TITLE) + initTitle(); + + while (mProg.section == PROG_SECTION_TITLE) { - // Estado 0 - Titulo desplazandose - if (mTitleStatus == 0) + // Sección 1 - Titulo desplazandose + if (mTitle.section == TITLE_SECTION_1) { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3275,20 +3426,20 @@ void GameDirector::runTitle() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } } // Calcula la lógica de los objetos - if (SDL_GetTicks() - mTicks > mTicksSpeed) + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) { // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); + mProg.ticks = SDL_GetTicks(); // Actualiza los objetos - mCoffeeBitmap->update(); - mCrisisBitmap->update(); + mTitle.coffeeBitmap->update(); + mTitle.crisisBitmap->update(); } // Limpia la pantalla @@ -3296,16 +3447,16 @@ void GameDirector::runTitle() SDL_RenderClear(mRenderer); // Dibuja los objetos - mCoffeeBitmap->render(); - mCrisisBitmap->render(); + mTitle.coffeeBitmap->render(); + mTitle.crisisBitmap->render(); // Actualiza la pantalla SDL_RenderPresent(mRenderer); - // Si los objetos han llegado a su destino, cambiamos de estado - if ((mTitleEvents[0] == EVENT_COMPLETED) && (mTitleEvents[0] == EVENT_COMPLETED)) + // Si los objetos han llegado a su destino, cambiamos de Sección + if ((mTitle.events[0] == EVENT_COMPLETED) && (mTitle.events[0] == EVENT_COMPLETED)) { - mTitleStatus = 1; + mTitle.section = TITLE_SECTION_2; // Pantallazo blanco SDL_SetRenderDrawColor(mRenderer, 0xFF, 0xFF, 0xFF, 0xFF); @@ -3314,8 +3465,8 @@ void GameDirector::runTitle() } } - // Estado 1 - Titulo vibrando - if (mTitleStatus == 1) + // Sección 2 - Titulo vibrando + if (mTitle.section == TITLE_SECTION_2) { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3323,7 +3474,7 @@ void GameDirector::runTitle() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } } @@ -3333,8 +3484,8 @@ void GameDirector::runTitle() // Agita la pantalla int v[] = {-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0}; - int a = mCoffeeBitmap->getPosX(); - int b = mCrisisBitmap->getPosX(); + int a = mTitle.coffeeBitmap->getPosX(); + int b = mTitle.crisisBitmap->getPosX(); for (Uint8 n = 0; n < 11 * 3; n++) { // Limpia la pantalla @@ -3342,26 +3493,26 @@ void GameDirector::runTitle() SDL_RenderClear(mRenderer); // Dibuja los objetos - mCoffeeBitmap->setPosX(a + v[n / 3]); - mCrisisBitmap->setPosX(b + v[n / 3]); - mCoffeeBitmap->render(); - mCrisisBitmap->render(); - mDustSpriteRight->animate(0); - mDustSpriteLeft->animate(0); - mDustSpriteRight->render(); - mDustSpriteLeft->render(); + mTitle.coffeeBitmap->setPosX(a + v[n / 3]); + mTitle.crisisBitmap->setPosX(b + v[n / 3]); + mTitle.coffeeBitmap->render(); + mTitle.crisisBitmap->render(); + mTitle.dustBitmapR->animate(0); + mTitle.dustBitmapL->animate(0); + mTitle.dustBitmapR->render(); + mTitle.dustBitmapL->render(); // Actualiza la pantalla SDL_RenderPresent(mRenderer); } - mTitleStatus = 2; + mTitle.section = 2; } - // Estado 2 - La pantalla de titulo con el menú y la música - if (mTitleStatus == 2) + // Sección 3 - La pantalla de titulo con el menú y la música + if (mTitle.section == TITLE_SECTION_3) { - if (mTitleTimer > 0) + if (mTitle.counter > 0) { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3369,14 +3520,14 @@ void GameDirector::runTitle() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } if ((mEventHandler->type == SDL_KEYUP) || (mEventHandler->type == SDL_JOYBUTTONUP)) { - mTitleMenuVisible = true; - mTitleTimer = TITLE_TIMER; + mTitle.menuVisible = true; + mTitle.counter = TITLE_COUNTER; } } // Si la música no está sonando @@ -3387,10 +3538,10 @@ void GameDirector::runTitle() } // Calcula la lógica de los objetos - if (SDL_GetTicks() - mTicks > mTicksSpeed) + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) { // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); + mProg.ticks = SDL_GetTicks(); // Actualiza la lógica del menu mMenu.active->update(); @@ -3404,46 +3555,47 @@ void GameDirector::runTitle() SDL_RenderClear(mRenderer); // Pinta el tileado de fondo - switch (mTitleBackgroundMode) + switch (mTitle.backgroundMode) { - case 0: - mBackgroundWindow.x++; - mBackgroundWindow.x %= 64; - mBackgroundWindow.y++; - mBackgroundWindow.y %= 64; + case 0: // El tileado de fondo se desplaza en diagonal + mTitle.backgroundWindow.x++; + mTitle.backgroundWindow.x %= 64; + mTitle.backgroundWindow.y++; + mTitle.backgroundWindow.y %= 64; break; - case 1: - mTitleBackgroundTimer++; - mTitleBackgroundTimer %= 360; - mBackgroundWindow.x = 128 + (int(mSen[(mTitleBackgroundTimer + 270) % 360] * 128)); - mBackgroundWindow.y = 96 + (int(mSen[(360 - mTitleBackgroundTimer) % 360] * 96)); + case 1: // El tileado de fondo se desplaza en circulo + ++mTitle.backgroundCounter %= 360; + mTitle.backgroundWindow.x = 128 + (int(mSin[(mTitle.backgroundCounter + 270) % 360] * 128)); + mTitle.backgroundWindow.y = 96 + (int(mSin[(360 - mTitle.backgroundCounter) % 360] * 96)); break; default: break; } - SDL_RenderCopy(mRenderer, mTitleSurface, &mBackgroundWindow, NULL); + SDL_RenderCopy(mRenderer, mTitleSurface, &mTitle.backgroundWindow, NULL); // Dibuja los objetos - mCoffeeBitmap->render(); - mCrisisBitmap->render(); - if (mTitleMenuVisible == true) + mTitle.coffeeBitmap->render(); + mTitle.crisisBitmap->render(); + if (mTitle.menuVisible == true) { mMenu.active->render(); } - mDustSpriteRight->animate(0); - mDustSpriteLeft->animate(0); - mDustSpriteRight->render(); - mDustSpriteLeft->render(); + mTitle.dustBitmapR->animate(0); + mTitle.dustBitmapL->animate(0); + mTitle.dustBitmapR->render(); + mTitle.dustBitmapL->render(); - if ((mTitleTimer % 50 > 14) && (mTitleMenuVisible == false)) + // PRESS ANY KEY! + if ((mTitle.counter % 50 > 14) && (mTitle.menuVisible == false)) { mText.black->writeCentered(SCREEN_CENTER_X + 1, PLAY_AREA_THIRD_QUARTER_Y + BLOCK + 1, "PRESS ANY KEY!", 0); mText.white->writeCentered(SCREEN_CENTER_X, PLAY_AREA_THIRD_QUARTER_Y + BLOCK, "PRESS ANY KEY!", 0); } + // texto con el copyright y versión mText.black->writeCentered(SCREEN_CENTER_X + 1, SCREEN_HEIGHT - (BLOCK * 2) + 1, TEXT_COPYRIGHT, 0); mText.white->writeCentered(SCREEN_CENTER_X, SCREEN_HEIGHT - (BLOCK * 2), TEXT_COPYRIGHT, 0); @@ -3457,7 +3609,7 @@ void GameDirector::runTitle() SDL_RenderPresent(mRenderer); // Comprueba las entradas para el menu - if (mTitleMenuVisible == true) + if (mTitle.menuVisible == true) { checkMenuInput(mMenu.active); } @@ -3468,26 +3620,25 @@ void GameDirector::runTitle() switch (mMenu.active->getItemSelected()) { case 0: - setGameStatus(GAME_STATE_PLAYING); + setProgSection(PROG_SECTION_GAME); mMenu.active->reset(); - mMenuKeyPressed = false; + mMenu.keyPressed = false; JA_PlaySound(mSound[SOUND_MENU_SELECT].sound); renderFade(1); JA_StopMusic(); - init(true); disableDemoMode(); break; case 1: JA_PlaySound(mSound[SOUND_MENU_SELECT].sound); mMenu.active->reset(); mMenu.active = mMenu.options; - mFullScreenModePrevious = mFullScreenMode; - mWindowSizePrevious = mWindowSize; + mOptions.fullScreenModePrevious = mOptions.fullScreenMode; + mOptions.windowSizePrevious = mOptions.windowSize; break; case 2: - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; mMenu.active->reset(); - mMenuKeyPressed = false; + mMenu.keyPressed = false; JA_PlaySound(mSound[SOUND_MENU_CANCEL].sound); renderFade(1); JA_StopMusic(); @@ -3511,23 +3662,23 @@ void GameDirector::runTitle() break; case 1: // Windows size JA_PlaySound(mSound[SOUND_MENU_SELECT].sound); - mWindowSize++; - if (mWindowSize == 5) - mWindowSize = 1; + mOptions.windowSize++; + if (mOptions.windowSize == 5) + mOptions.windowSize = 1; updateOptionsMenu(); mMenu.active->deselectItem(); break; case 2: // OK JA_PlaySound(mSound[SOUND_MENU_SELECT].sound); - SDL_SetWindowFullscreen(mWindow, mFullScreenMode); - SDL_SetWindowSize(mWindow, SCREEN_WIDTH * mWindowSize, SCREEN_HEIGHT * mWindowSize); + SDL_SetWindowFullscreen(mWindow, mOptions.fullScreenMode); + SDL_SetWindowSize(mWindow, SCREEN_WIDTH * mOptions.windowSize, SCREEN_HEIGHT * mOptions.windowSize); mMenu.active->reset(); mMenu.active = mMenu.title; break; case 3: // CANCEL JA_PlaySound(mSound[SOUND_MENU_CANCEL].sound); - mFullScreenMode = mFullScreenModePrevious; - mWindowSize = mWindowSizePrevious; + mOptions.fullScreenMode = mOptions.fullScreenModePrevious; + mOptions.windowSize = mOptions.windowSizePrevious; updateOptionsMenu(); mMenu.active->reset(); mMenu.active = mMenu.title; @@ -3540,94 +3691,125 @@ void GameDirector::runTitle() if (mMenu.active->getName() == "TITLE") { - mTitleTimer--; + mTitle.counter--; } } - else if (mTitleTimer == 0) + else if (mTitle.counter == 0) { - mTitleTimer = TITLE_TIMER; - mGame.status = mTiteNextGS; + mTitle.counter = TITLE_COUNTER; + setProgSection(mTitle.nextProgSection); mMenu.active->reset(); toogleTitleNextGS(); renderFade(1); - if (mGame.status == GAME_STATE_INTRO) + if (mProg.section == PROG_SECTION_INTRO) { JA_StopMusic(); } - init(true); enableDemoMode(); } } + + // Sección Instrucciones + if (mTitle.section == TITLE_SECTION_INSTRUCTIONS) + runInstructions(); } + + quitTitle(); } // Bucle para el juego void GameDirector::runGame() { - while (mGame.status == GAME_STATE_PLAYING) - { - // Si la música no está sonando - if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) - { - // Reproduce la música - if (mPlayer->isAlive()) - JA_PlayMusic(mMusic[MUSIC_PLAYING].music, true); - } + initGame(); - // Lógica del juego - if (mGame.paused) + while (mProg.section == PROG_SECTION_GAME) + { + // Sección juego en pausa + if (mGame.section == GAME_SECTION_PAUSE) runPausedGame(); - // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego - if (SDL_GetTicks() - mTicks > mTicksSpeed) + // Sección Game Over + if (mGame.section == GAME_SECTION_GAMEOVER) + runGameOverScreen(); + + // Sección juego jugando + if (mGame.section == GAME_SECTION_PLAY) { - // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); - - // Actualiza el contador de juego - mGameCounter++; - - // Comprueba los eventos que hay en la cola - while (SDL_PollEvent(mEventHandler) != 0) + // Si la música no está sonando + if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) { - // Evento de salida de la aplicación - if (mEventHandler->type == SDL_QUIT) - { - setGameStatus(GAME_STATE_QUIT); - break; - } + // Reproduce la música + if (mGame.player->isAlive()) + JA_PlayMusic(mMusic[MUSIC_PLAYING].music, true); } - // Actualiza la lógica del juego - updatePlayField(); + // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) + { + // Actualiza el contador de ticks + mProg.ticks = SDL_GetTicks(); + + // Actualiza el contador de juego + mGame.counter++; + + // Comprueba los eventos que hay en la cola + while (SDL_PollEvent(mEventHandler) != 0) + { + // Evento de salida de la aplicación + if (mEventHandler->type == SDL_QUIT) + { + mProg.quit = true; + break; + } + else if ((mEventHandler->type == SDL_KEYDOWN) && (mEventHandler->key.repeat == 0)) + { + switch (mEventHandler->key.keysym.scancode) + { + case SDL_SCANCODE_T: + mProg.ticksSpeed *= 2; + break; + case SDL_SCANCODE_G: + mProg.ticksSpeed /= 2; + break; + default: + break; + } + } + } + + // Actualiza la lógica del juego + updatePlayField(); + } + + // Cambia el destino donde se pinta todo + SDL_SetRenderTarget(mRenderer, mBackbuffer); + + // Limpia la pantalla + SDL_SetRenderDrawColor(mRenderer, 0x00, 0x00, 0x00, 0xFF); + SDL_RenderClear(mRenderer); + + // Dibuja los objetos + renderPlayField(); + + // Vuelve a usar el renderizador como destino + SDL_SetRenderTarget(mRenderer, NULL); + + // Volca el contenido de la textura en el renderizador + SDL_RenderCopy(mRenderer, mBackbuffer, NULL, NULL); + + // Actualiza la pantalla + if (mProg.section == PROG_SECTION_GAME) + SDL_RenderPresent(mRenderer); } - - // Cambia el destino donde se pinta todo - SDL_SetRenderTarget(mRenderer, mBackbuffer); - - // Limpia la pantalla - SDL_SetRenderDrawColor(mRenderer, 0x00, 0x00, 0x00, 0xFF); - SDL_RenderClear(mRenderer); - - // Dibuja los objetos - renderPlayField(); - - // Vuelve a usar el renderizador como destino - SDL_SetRenderTarget(mRenderer, NULL); - - // Volca el contenido de la textura en el renderizador - SDL_RenderCopy(mRenderer, mBackbuffer, NULL, NULL); - - // Actualiza la pantalla - if (mGame.status == GAME_STATE_PLAYING) - SDL_RenderPresent(mRenderer); } + + quitGame(); } // Bucle para el menu de pausa del juego void GameDirector::runPausedGame() { - while (mGame.paused) + while (mGame.section == GAME_SECTION_PAUSE) { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3635,16 +3817,16 @@ void GameDirector::runPausedGame() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } } // Calcula la lógica de los objetos - if (SDL_GetTicks() - mTicks > mTicksSpeed) + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) { // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); + mProg.ticks = SDL_GetTicks(); // Actualiza la lógica del menu mMenu.pause->update(); @@ -3657,7 +3839,7 @@ void GameDirector::runPausedGame() renderBackground(); renderBalloons(); renderBullets(); - mPlayer->render(); + mGame.player->render(); renderScoreBoard(); mMenu.pause->render(); @@ -3678,10 +3860,9 @@ void GameDirector::runPausedGame() { case 0: JA_PlaySound(mSound[SOUND_MENU_SELECT].sound); - //setGameStatus(GAME_STATE_PLAYING); - mGame.paused = false; + mGame.section = GAME_SECTION_PLAY; mMenu.pause->reset(); - mMenuKeyPressed = false; + mMenu.keyPressed = false; if (JA_GetMusicState() == JA_MUSIC_PAUSED) { JA_ResumeMusic(); @@ -3689,12 +3870,11 @@ void GameDirector::runPausedGame() break; case 1: JA_PlaySound(mSound[SOUND_MENU_CANCEL].sound); - setGameStatus(GAME_STATE_TITLE); + setProgSection(PROG_SECTION_TITLE); mMenu.pause->reset(); - mMenuKeyPressed = false; + mMenu.keyPressed = false; JA_StopMusic(); renderFade(1); - init(true); break; default: break; @@ -3707,16 +3887,16 @@ void GameDirector::runInstructions() { SDL_Rect window = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; Sprite *sprite = new Sprite(); - SDL_Rect rect1 = {60, 88, 16, 16}; - SDL_Rect rect2 = {60, 104, 16, 16}; - SDL_Rect rect3 = {60, 120, 16, 16}; - SDL_Rect rect4 = {60, 136, 16, 16}; - SDL_Rect rect5 = {60, 152, 16, 16}; - SDL_Rect rect6 = {60, 168, 16, 16}; + SDL_Rect rect1 = {60, 88, 16, 16}; // Disquito + SDL_Rect rect2 = {60, 104, 16, 16}; // Gavineixon + SDL_Rect rect3 = {60, 120, 16, 16}; // Pacmar + SDL_Rect rect4 = {60, 136, 16, 16}; // Time Stopper + SDL_Rect rect5 = {60, 152, 16, 16}; // Explosive + SDL_Rect rect6 = {60, 168, 16, 16}; // Coffee SDL_Rect rect = {0, 0, 16, 16}; - sprite->init(rect1, mTexture[TEXTURE_ITEMS].texture, mRenderer); - while (mGame.status == GAME_STATE_INSTRUCTIONS) + + while (mTitle.section == TITLE_SECTION_INSTRUCTIONS) { int y = 0; // Comprueba los eventos que hay en la cola @@ -3725,14 +3905,14 @@ void GameDirector::runInstructions() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } if ((mEventHandler->type == SDL_KEYDOWN) || (mEventHandler->type == SDL_JOYBUTTONDOWN)) { JA_StopMusic(); - setGameStatus(GAME_STATE_TITLE); + setProgSection(PROG_SECTION_TITLE); } } @@ -3756,32 +3936,32 @@ void GameDirector::runInstructions() sprite->init(rect1, mTexture[TEXTURE_ITEMS].texture, mRenderer); sprite->setSpriteClip(rect); rect.x += rect.w; - rect.y = 16 * (((mInstructionsCounter + 3) / 36) % 2); + rect.y = 16 * (((mTitle.instructionsCounter + 3) / 36) % 2); sprite->render(); sprite->init(rect2, mTexture[TEXTURE_ITEMS].texture, mRenderer); sprite->setSpriteClip(rect); rect.x += rect.w; - rect.y = 16 * (((mInstructionsCounter + 6) / 36) % 2); + rect.y = 16 * (((mTitle.instructionsCounter + 6) / 36) % 2); sprite->render(); sprite->init(rect3, mTexture[TEXTURE_ITEMS].texture, mRenderer); sprite->setSpriteClip(rect); rect.x += rect.w; - rect.y = 16 * (((mInstructionsCounter + 9) / 36) % 2); + rect.y = 16 * (((mTitle.instructionsCounter + 9) / 36) % 2); sprite->render(); sprite->init(rect4, mTexture[TEXTURE_ITEMS].texture, mRenderer); sprite->setSpriteClip(rect); rect.x += rect.w; - rect.y = 16 * (((mInstructionsCounter + 12) / 36) % 2); + rect.y = 16 * (((mTitle.instructionsCounter + 12) / 36) % 2); sprite->render(); sprite->init(rect5, mTexture[TEXTURE_ITEMS].texture, mRenderer); sprite->setSpriteClip(rect); rect.x += rect.w; - rect.y = 16 * (((mInstructionsCounter + 15) / 36) % 2); + rect.y = 16 * (((mTitle.instructionsCounter + 15) / 36) % 2); sprite->render(); sprite->init(rect6, mTexture[TEXTURE_ITEMS].texture, mRenderer); sprite->setSpriteClip(rect); rect.x = 0; - rect.y = 16 * (((mInstructionsCounter + 0) / 36) % 2); + rect.y = 16 * (((mTitle.instructionsCounter + 0) / 36) % 2); sprite->render(); SDL_SetRenderTarget(mRenderer, nullptr); @@ -3791,7 +3971,7 @@ void GameDirector::runInstructions() SDL_RenderClear(mRenderer); // Dibuja los objetos - y = SCREEN_HEIGHT - (INSTRUCTIONS_COUNTER - mInstructionsCounter) + 100; + y = SCREEN_HEIGHT - (INSTRUCTIONS_COUNTER - mTitle.instructionsCounter) + 100; if (y < 0) { y = 0; @@ -3803,12 +3983,12 @@ void GameDirector::runInstructions() // Muestra la pantalla SDL_RenderPresent(mRenderer); - mInstructionsCounter--; + mTitle.instructionsCounter--; - if (mInstructionsCounter == 0) + if (mTitle.instructionsCounter == 0) { - mInstructionsCounter = INSTRUCTIONS_COUNTER; - setGameStatus(GAME_STATE_TITLE); + mTitle.instructionsCounter = INSTRUCTIONS_COUNTER; + mTitle.section = TITLE_SECTION_1; } } delete sprite; @@ -3817,7 +3997,7 @@ void GameDirector::runInstructions() // Bucle para la pantalla de game over void GameDirector::runGameOverScreen() { - while (mGame.status == GAME_STATE_GAME_OVER_SCREEN) + while (mGame.section == GAME_SECTION_GAMEOVER) { // Comprueba los eventos que hay en la cola while (SDL_PollEvent(mEventHandler) != 0) @@ -3825,16 +4005,16 @@ void GameDirector::runGameOverScreen() // Evento de salida de la aplicación if (mEventHandler->type == SDL_QUIT) { - setGameStatus(GAME_STATE_QUIT); + mProg.quit = true; break; } } // Calcula la lógica de los objetos - if (SDL_GetTicks() - mTicks > mTicksSpeed) + if (SDL_GetTicks() - mProg.ticks > mProg.ticksSpeed) { // Actualiza el contador de ticks - mTicks = SDL_GetTicks(); + mProg.ticks = SDL_GetTicks(); // Actualiza la lógica del menu mMenu.gameOver->update(); @@ -3869,24 +4049,22 @@ void GameDirector::runGameOverScreen() switch (mMenu.gameOver->getItemSelected()) { case 0: - setGameStatus(GAME_STATE_PLAYING); + setProgSection(PROG_SECTION_GAME); mMenu.gameOver->reset(); - mMenuKeyPressed = false; + mMenu.keyPressed = false; JA_PlaySound(mSound[SOUND_MENU_SELECT].sound); JA_StopMusic(); - init(true); renderFade(1); disableDemoMode(); break; case 1: - setGameStatus(GAME_STATE_TITLE); + setProgSection(PROG_SECTION_TITLE); mMenu.gameOver->reset(); - mMenuKeyPressed = false; + mMenu.keyPressed = false; JA_PlaySound(mSound[SOUND_MENU_CANCEL].sound); JA_StopMusic(); - init(true); renderFade(1); - mTiteNextGS = GAME_STATE_PLAYING; + mTitle.nextProgSection = PROG_SECTION_GAME; enableDemoMode(); break; default: @@ -3898,12 +4076,12 @@ void GameDirector::runGameOverScreen() // Dibuja la informacion de debug en pantalla void GameDirector::renderDebugInfo() { - if (mDebug) + if (mProg.debug) { - mText.white->write(0, 0 * BLOCK, "menace: " + std::to_string(mMenaceLevelThreshold) + "/" + std::to_string(mMenaceLevel)); - mText.white->write(0, 1 * BLOCK, "item[0].TTL: " + std::to_string(mItem[0]->mTimeToLive)); + mText.white->write(0, 0 * BLOCK, "menace: " + std::to_string(mGame.menaceLevelThreshold) + "/" + std::to_string(mGame.menaceLevelCurrent)); + mText.white->write(0, 1 * BLOCK, "item[0].TTL: " + std::to_string(mGame.item[0]->mTimeToLive)); mText.white->write(0, 2 * BLOCK, "mGame.stage: " + std::to_string(mGame.stage)); - mText.white->write(0, 3 * BLOCK, "mGameCounter : " + std::to_string(mGameCounter)); + mText.white->write(0, 3 * BLOCK, "mGame.counter : " + std::to_string(mGame.counter)); mText.white->write(0, 4 * BLOCK, ": "); mText.white->write(0, 5 * BLOCK, ": "); } @@ -3912,26 +4090,26 @@ void GameDirector::renderDebugInfo() // Activa el modo Demo void GameDirector::enableDemoMode() { - mDemo = true; - mGetReadyBitmap->setEnabled(false); + mDemo.enabled = true; + mGame.getReadyBitmap->setEnabled(false); } // Desactiva el modo Demo void GameDirector::disableDemoMode() { - mDemo = false; - mGetReadyBitmap->setEnabled(true); + mDemo.enabled = false; + mGame.getReadyBitmap->setEnabled(true); } // Actualiza el proximo estado del juego despues del titulo void GameDirector::toogleTitleNextGS() { - if (mTiteNextGS == GAME_STATE_LOGO) + if (mTitle.nextProgSection == PROG_SECTION_LOGO) { - mTiteNextGS = GAME_STATE_PLAYING; + mTitle.nextProgSection = PROG_SECTION_GAME; } else { - mTiteNextGS = GAME_STATE_LOGO; + mTitle.nextProgSection = PROG_SECTION_LOGO; } } \ No newline at end of file diff --git a/source/gamedirector.h b/source/gamedirector.h index a2b5b43..5821539 100644 --- a/source/gamedirector.h +++ b/source/gamedirector.h @@ -6,12 +6,14 @@ #include "player.h" #include "balloon.h" #include "bullet.h" +#include "coffeedrop.h" #include "item.h" #include "text.h" #include "text2.h" #include "menu.h" #include "const.h" #include "jail_audio.h" +#include "utils.h" #include #ifndef GAMEDIRECTOR_H @@ -20,33 +22,272 @@ // GameDirector class GameDirector { +private: + SDL_Window *mWindow; // La ventana donde dibujamos + SDL_Renderer *mRenderer; // El renderizador de la ventana + SDL_Event *mEventHandler; // Manejador de eventos + + SDL_Texture *mBackbuffer; // Textura para usar como backbuffer + SDL_Texture *mTitleSurface; // Textura para dibujar el fondo de la pantalla de título + SDL_Texture *mInstructionsSurface; // Textura donde dibujar las instrucciones + + SDL_Joystick *mGameController; // Manejador para el mando 1 + SDL_Haptic *mControllerHaptic; // Manejador para el mando con vibración + bool mGameControllerFound; // Variable para saber si hay un mando conectado + +#ifndef UNUSED + CoffeeDrop *mCoffeeDrop[MAX_COFFEE_DROPS]; // Vector con todas ls gotas de café; +#endif + + struct text + { + Text *white; // Texto blanco de 8x8 + Text *whiteX2; // Texto blanco de 16x16 + Text *black; // Texto negro de 8x8 + Text *blackX2; // Texto negro de 16x16 + Text *nokia; // Texto de anchura variable y 10px de alto + }; + text mText; // Variable con todos los objetos de texto + + struct menu + { + Menu *title; // Menu de la pantalla de título + Menu *pause; // Menú de la pantalla de pausa + Menu *gameOver; // Menú de la pantalla de game over + Menu *options; // Menú de la pantalla de opciones + Menu *active; // Menu activo (de momento para la pantalla del titulo) + bool keyPressed; // Variable para evitar la repetición de teclas en los menus + }; + menu mMenu; // Variable con todos los objetos menus y sus variables + + struct intro + { + SmartSprite *bitmap[INTRO_TOTAL_BITMAPS]; // Vector con los sprites inteligentes para los dibujos de la intro + Text2 *text[INTRO_TOTAL_TEXTS]; // Textos de la intro + Uint8 events[INTRO_TOTAL_EVENTS]; // Vector para coordinar los eventos de la intro + }; + intro mIntro; // Contiene todas las variables de la sección 'Intro' + + struct game + { + Uint32 score; // Puntuación actual + Uint32 hiScore; // Puntuación máxima + Uint8 section; // Seccion actual dentro del juego + bool hiScoreAchieved; // Indica si se ha superado la puntuación máxima + Uint8 stage; // Pantalla actual + Uint8 stageCounter; // Contador para el tiempo visible del texto de Stage + float stagePath[STAGE_COUNTER]; // Vector con los puntos Y por donde pasará la etiqueta + Uint16 deathCounter; // Contador para la animación de muerte del jugador + Uint8 deathIndex; // Indice del vector de smartsprites que contiene el sprite del jugador + Uint8 menaceLevelCurrent; // Nivel de amenaza actual + Uint8 menaceLevelThreshold; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el numero de globos + bool playFieldDrawOnly; // Indica si el bucle de juego avanza o solo pinta + bool timeStopped; // Indica si el tiempo está detenido + Uint16 timeStoppedCounter; // Temporizador para llevar la cuenta del tiempo detenido + Uint8 remainingExplosions; // Cantidad de explosiones restantes + Uint16 remainingExplosionsCounter; // Temporizador para la cantidad de explosiones restantes + bool explosionTime; // Indica si las explosiones estan en marcha + Uint32 counter; // Contador para el juego + Uint32 scoreDataFile[TOTAL_SCORE_DATA]; // Datos del fichero de puntos + SmartSprite *getReadyBitmap; // Sprite para el texto de GetReady del principio de la partida + SmartSprite *_1000Bitmap; // Sprite con el texto 1.000 + SmartSprite *_2500Bitmap; // Sprite con el texto 2.500 + SmartSprite *_5000Bitmap; // Sprite con el texto 5.000 + Sprite *background; // Sprite con los graficos frontales del fondo + Sprite *gradient; // Sprite con los graficos del degradado de color de fondo + MovingSprite *clouds1a; // Sprite para las nubes superiores + MovingSprite *clouds1b; // Sprite para las nubes superiores + MovingSprite *clouds2a; // Sprite para las nubes inferiores + MovingSprite *clouds2b; // Sprite para las nubes inferiores + Sprite *grass; // Sprite para la hierba + Player *player; // El jugador + Balloon *balloon[MAX_BALLOONS]; // Vector con los objetos globo + Bullet *bullet[MAX_BULLETS]; // Vector con los objetos bala + Item *item[MAX_ITEMS]; // Vector con los objetos item + SmartSprite *smartSprite[MAX_SMART_SPRITES]; // Vector para almacenar y gestionar SmartSprites + }; + game mGame; // Variable con todas las variables usadas durante el juego + + struct title + { + Uint16 counter; // Temporizador para la pantalla de titulo + Uint16 backgroundCounter; // Temporizador para el fondo de tiles de la pantalla de titulo + Uint8 backgroundMode; // Variable para almacenar el tipo de efecto que hará el fondo de la pantalla de titulo + bool menuVisible; // Indicador para saber si se muestra el menu del titulo o la frase intermitente + Sprite *tile; // Sprite para dibujar el fondo de pantalla del título + SDL_Rect backgroundWindow; // Ventana visible para la textura de fondo del titulo + Uint8 section; // Indicador para el bucle del titulo + Uint8 nextProgSection; // Indica cual es la siguiente sección a cargar cuando termine el contador del titulo + Uint8 events[TITLE_TOTAL_EVENTS]; // Vector para coordinar los eventos de la pantalla de titulo + Uint16 instructionsCounter; // Contador para las instrucciones + SmartSprite *coffeeBitmap; // Sprite con la palabra COFFEE para la pantalla de titulo + SmartSprite *crisisBitmap; // Sprite con la palabra CRISIS para la pantalla de titulo + AnimatedSprite *dustBitmapL; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo + AnimatedSprite *dustBitmapR; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo + }; + title mTitle; // Variable con todas las variables de la pantalla de titulo + + struct demo + { + bool enabled; // Indica si está activo el modo demo + bool recording; // Indica si está activado el modo para grabar la demo + Uint16 counter; // Contador para el modo demo + DemoKeys keys; // Variable con las pulsaciones de teclas del modo demo + DemoKeys dataFile[TOTAL_DEMO_DATA]; // Datos del fichero con los movimientos para la demo + }; + demo mDemo; // Variable con todas las variables relacionadas con el modo demo + + struct options + { + Uint32 fullScreenMode; // Contiene el valor del modo de pantalla completa + Uint32 fullScreenModePrevious; + Uint8 windowSize; // Contiene el valor del tamaño de la ventana + Uint8 windowSizePrevious; + bool displayCoffeeDrops; // Indica si se han de mostar las gotas de cafe + }; + options mOptions; // Variable con todas las variables de las opciones del programa + + struct logo + { + Uint16 counter; // Contador + Sprite *sprite; // Sprite con la textura del logo + }; + logo mLogo; // Variable con las variables para el logo + + struct prog + { + bool debug; // Indica si se va a mostrar la información de debug + bool quit; // Indica si hay que salir del programa + Input keyboard; // Almacena los códigos de teclado correspondientes + Input keyboardBuffer; // Buffer para teclas pulsadas + std::string executablePath; // Path del ejecutable + Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa + Uint8 section; // Sección actual del programa; + Uint8 subsection; // Subseccion dentro de la sección; + Uint8 ticksSpeed; // Velocidad a la que se repiten los bucles del programa + }; + prog mProg; // Contiene todas las variables globales del programa + + struct resourceBinFile + { + std::string file; // Ruta al fichero + }; + resourceBinFile mBinFile[TOTAL_BINFILE]; // Todos los ficheros binarios + + struct resourceSound + { + std::string file; // Ruta al fichero + JA_Sound sound; // Variable con el sonido + }; + resourceSound mSound[TOTAL_SOUND]; // Todos los sonidos + + struct resourceMusic + { + std::string file; // Ruta al fichero + JA_Music music; // Variable con la música + }; + resourceMusic mMusic[TOTAL_MUSIC]; // Todas las músicas + + struct resourceTexture + { + std::string file; // Ruta al fichero + LTexture *texture; // Variable con la textura + }; + resourceTexture mTexture[TOTAL_TEXTURE]; // Todos los gráficos + public: // Constructor - GameDirector(); + GameDirector(std::string path); // Destructor ~GameDirector(); - // Iniciador - void init(bool reset); + // Inicia las variables necesarias para arrancar el programa + void initProg(); + + // Carga los recursos necesarios para el programa + bool loadMediaProg(); + + // Libera las variables del programa + void quitProg(); + + // Inicializa jail_audio + void initJailAudio(); // Arranca SDL y crea la ventana bool initSDL(); + // Inicializa el vector con los valores del seno + void initSin(); + + // Inicializa las variables que contienen puntos de ruta para mover objetos + void initPaths(); + + // Inicializa las variables necesarias para la sección 'Logo' + void initLogo(); + + // Carga los recursos necesarios para la sección 'Logo' + bool loadMediaLogo(); + + // Libera las variables necesarias para la sección 'Logo' + void quitLogo(); + + // Inicializa las variables necesarias para la sección 'Intro' + void initIntro(); + + // Carga los recursos necesarios para la sección 'Intro' + bool loadMediaIntro(); + + // Libera las variables necesarias para la sección 'Intro' + void quitIntro(); + + // Inicializa las variables necesarias para la sección 'Title' + void initTitle(Uint8 section = TITLE_SECTION_1); + + // Carga los recursos necesarios para la sección 'Title' + bool loadMediaTitle(); + + // Libera las variables necesarias para la sección 'Title' + void quitTitle(); + + // Inicializa las variables necesarias para la sección 'Game' + void initGame(); + + // Carga los recursos necesarios para la sección 'Game' + bool loadMediaGame(); + + // Libera las variables necesarias para la sección 'Game' + void quitGame(); + // Crea el indice de ficheros void setFileList(); // Comprueba que todos los ficheros existen bool checkFileList(); + // Carga el fichero de puntos + bool loadScoreFile(); + + // Carga el fichero de configuración + bool loadConfigFile(); + + // Carga el fichero de datos para la demo + bool loadDemoFile(); + + // Guarda el fichero de puntos + bool saveScoreFile(); + + // Guarda el fichero de configuración + bool saveConfigFile(); + + // Guarda el fichero de datos para la demo + bool saveDemoFile(); + // Carga un archivo de imagen en una textura bool loadTextureFromFile(LTexture *texture, std::string path, SDL_Renderer *renderer); - // Carga los recursos necesarios - bool loadMedia(Uint8 section); - - // Descrga los recursos necesarios - bool unLoadMedia(Uint8 section); + // Comprueba el valor de la variable 'quit' + bool exit(); // Establece el valor de la variable void setExecutablePath(std::string path); @@ -82,10 +323,10 @@ public: void renderBalloons(); // Devuelve el primer indice no activo del vector de globos - Uint8 getBallonFreeIndex(); + Uint8 getBalloonFreeIndex(); // Crea un globo nuevo en el vector de globos - Uint8 createNewBalloon(float x, int y, Uint8 kind, float velx, Uint16 stoppedtimer, LTexture *texture); + Uint8 createNewBalloon(float x, int y, Uint8 kind, float velx, Uint16 stoppedcounter, LTexture *texture); // Establece a cero todos los valores del vector de objetos globo void resetBalloons(); @@ -94,7 +335,7 @@ public: void popBalloon(Uint8 index); // Explosiona todos los globos - void popAllBallons(); + void popAllBalloons(); // Detiene todos los globos void stopAllBalloons(Uint16 time); @@ -106,13 +347,13 @@ public: Uint8 countBalloons(); // Comprueba la colisión entre el jugador y los globos activos - bool checkPlayerBallonCollision(); + bool checkPlayerBalloonCollision(); // Comprueba la colisión entre el jugador y los items void checkPlayerItemCollision(); // Comprueba la colisión entre las balas y los globos - void checkBulletBallonCollision(); + void checkBulletBalloonCollision(); // Mueve las balas activas void moveBullets(); @@ -168,11 +409,30 @@ public: // Establece a cero todos los valores del vector de objetos SmafrtSprite void resetSmartSprites(); +#ifndef UNUSED + // Deshabilita todas las gotas de café + void resetCoffeeDrops(); + + // Actualiza las gotas de cafe + void updateCoffeeDrops(); + + // Dibuja las gotas de cafe + void renderCoffeeDrops(); + + // Devuelve el primer indice libre del vector de CoffeeDrops + Uint8 getCoffeDropFreeIndex(); + + // Crea un numero de gotas de cafe + void createCoffeDrops(Uint8 num, int x, int y); +#endif // Acciones a realizar cuando el jugador muere void killPlayer(); + // Obtiene el valor de la variable + Uint8 getSubsection(); + // Calcula y establece el valor de amenaza en funcion de los globos activos - void calculateMenaceLevel(); + void setMenaceLevel(); // Obtiene el valor de la variable Uint8 getMenaceLevel(); @@ -190,10 +450,10 @@ public: bool isTimeStopped(); // Establece el valor de la variable - void setTimeStoppedTimer(Uint16 value); + void setTimeStoppedCounter(Uint16 value); // Actualiza y comprueba el valor de la variable - void updateTimeStoppedTimer(); + void updateTimeStoppedCounter(); // Establece el valor de la variable void setExplosionTime(bool value); @@ -205,10 +465,10 @@ public: void setRemainingExplosions(Uint8 value); // Actualiza y comprueba el valor de la variable - void updateRemainingExplosionsTimer(); + void updateRemainingExplosionsCounter(); // Gestiona el nivel de amenaza - void checkMenaceLevel(); + void updateMenaceLevel(); // Actualiza el campo de juego void updatePlayField(); @@ -232,10 +492,10 @@ public: void checkMenuInput(Menu *menu); // Obtiene el valor de la variable - Uint8 getGameStatus(); + Uint8 getProgSection(); // Establece el valor de la variable - void setGameStatus(Uint8 status); + void setProgSection(Uint8 section, Uint8 subsection = 0); // Pinta una transición en pantalla void renderFade(Uint8 index); @@ -265,7 +525,7 @@ public: void runIntro(); // Bucle para el titulo del juego - void runTitle(); + void runTitle(Uint8 section = TITLE_SECTION_1); // Bucle para el juego void runGame(); @@ -290,260 +550,6 @@ public: // Intercambia el proximo estado del juego despues del titulo void toogleTitleNextGS(); - -private: - // La ventana donde dibujamos - SDL_Window *mWindow; - - // El renderizador de la ventana - SDL_Renderer *mRenderer; - - // Texturas donde dibujar - SDL_Texture *mBackbuffer; - SDL_Texture *mTitleSurface; - SDL_Texture *mInstructionsSurface; - - // Manejador para el mando 1 - SDL_Joystick *mGameController; - bool mGameControllerFound; - SDL_Haptic *mControllerHaptic; - - // Datos del fichero - Uint32 mScoreDataFile[TOTAL_SCORE_DATA]; - DemoKeys mDemoDataFile[TOTAL_DEMO_DATA]; - - // Manejador de eventos - SDL_Event *mEventHandler; - - // El jugador - Player *mPlayer; - - // Vector con los objetos globo - Balloon *mBalloon[MAX_BALLOONS]; - - // Vector con los objetos bala - Bullet *mBullet[MAX_BULLETS]; - - // Vector con los objetos item - Item *mItem[MAX_ITEMS]; - - // Fondo del juego - Sprite *mGameBackgroundFront; - Sprite *mGameBackgroundSky; - MovingSprite *mGBClouds1; - MovingSprite *mGBClouds1b; - MovingSprite *mGBClouds2; - MovingSprite *mGBClouds2b; - Sprite *mGrass; - - // Instrucciones - Sprite *mInstructions; - - // Fondo de la pantalla de titulo - Sprite *mTitleTile; - - // Ventana visible de la textura de fondo del titulo - SDL_Rect mBackgroundWindow; - - // Vector con los valores del seno para 360 grados - double mSen[360]; - - // Texto - struct text - { - Text *white; - Text *black; - Text *nokia; - }; - - text mText; - - // Variable con lkos menus del juego - struct menu - { - Menu *title; // Menu de la pantalla de título - Menu *pause; // Menú de la pantalla de pausa - Menu *gameOver; // Menú de la pantalla de game over - Menu *options; // Menú de la pantalla de opciones - Menu *active; // Menu activo (de momento para la pantalla del titulo) - }; - - menu mMenu; - - // Notificación GetReady! - SmartSprite *mGetReadyBitmap; - - // Dibujos de la intro - SmartSprite *mIntroBitmap[INTRO_TOTAL_BITMAPS]; - - // Sprites con el titulo del juego para la pantalla de titulo - SmartSprite *mCoffeeBitmap; - SmartSprite *mCrisisBitmap; - AnimatedSprite *mDustSpriteLeft; - AnimatedSprite *mDustSpriteRight; - - // Sprites con los puntos de algunos objetos - SmartSprite *m1000Bitmap; - SmartSprite *m2500Bitmap; - SmartSprite *m5000Bitmap; - - // Vector para almacenar y gestionar SmartSprites - SmartSprite *mSmartSprite[MAX_SMART_SPRITES]; - - // Textos de la intro - Text2 *mIntroText[INTRO_TOTAL_TEXTS]; - - // Vector para coordinar los eventos de la intro - Uint8 mIntroEvents[INTRO_TOTAL_EVENTS]; - - // Vector para coordinar los eventos de la pantalla de titulo - Uint8 mTitleEvents[TITLE_TOTAL_EVENTS]; - - // Indicador para el bucle del titulo - Uint8 mTitleStatus; - - struct game - { - Uint32 score; // Puntuación actual - Uint32 hiScore; // Puntuación máxima - Uint8 status; // Indicador para el bucle principal - bool paused; // Idica si el juego está en pausa - bool hiScoreAchieved; // Indica si se ha superado la puntuación máxima - Uint8 stage; // Pantalla actual - Uint8 stageCounter; // Contador para el tiempo visible del texto de Stage - double stagePath[STAGE_COUNTER]; // Vector con los puntos Y por donde pasará la etiqueta - Uint16 deathCounter; // Contador para la animación de muerte del jugador - Uint8 deathIndex; // Indice del vector de smartsprites que contiene el sprite del jugador - }; - - game mGame; - - // Contador de ticks para ajustar la velocidad del juego - Uint32 mTicks; - - // Velocidad a la que se repite el bucle de juego - Uint8 mTicksSpeed; - - // Nivel de amenaza actual - Uint8 mMenaceLevel; - - // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, - // se generan más globos. Si el umbral aumenta, aumenta el numero de globos - Uint8 mMenaceLevelThreshold; - - // Indica si el bucle de juego avanza o solo pinta - bool mPlayFieldDrawOnly; - - // Indica si se va a mostrar la información de debug - bool mDebug; - - // Almacena los códigos de teclado correspondientes - Input mKeyboard; - - // Buffer para teclas pulsadas - Input mKeyboardBuffer; - - // Indica si el tiempo está detenido - bool mTimeStopped; - - // Temporizador para llevar la cuenta del tiempo detenido - Uint16 mTimeStoppedTimer; - - // Cantidad de explosiones restantes - Uint8 mRemainingExplosions; - - // Temporizador para la cantidad de explosiones restantes - Uint16 mRemainingExplosionsTimer; - - // Indica si las explosiones estan en marcha - bool mExplosionTime; - - // Contador para las instrucciones - Uint16 mInstructionsCounter; - - // Temporizador para la pantalla de titulo - Uint16 mTitleTimer; - - // Temporizador para el fondo de tiles de la pantalla de titulo - Uint16 mTitleBackgroundTimer; - - // Variable para almacenar el tipo de efecto que hará el foindo del titulo - Uint8 mTitleBackgroundMode; - - // Indicador para saber si se muestra el menu del titulo o la frase intermitente - bool mTitleMenuVisible; - - // Indica si está activo el modo demo - bool mDemo; - - // Indica si está activado el modo para grabar la demo - bool mDemoRecording; - - // Contador para el modo demo - Uint16 mDemoCounter; - DemoKeys mDemoKeys; - - // Indica a que estado pasara el juego cuando acabe el temporizador del titulo - Uint8 mTiteNextGS; - - // Contador para el juego - Uint32 mGameCounter; - - // Variable para evitar la repetición de teclas en los menus - bool mMenuKeyPressed; - - // Variables para el tamaño y modo de la ventana y variables para almacenar el valor si cancelamos en el menu de opciones - Uint32 mFullScreenMode; - Uint32 mFullScreenModePrevious; - Uint8 mWindowSize; - Uint8 mWindowSizePrevious; - - // Variables para el logo - struct logo - { - Uint16 counter; - Sprite *sprite; - }; - logo mLogo; - - // Path del ejecutable - std::string mExecutablePath; - - // Recursos - struct resourceBinFile - { - std::string file; - bool loaded; - }; - - resourceBinFile mBinFile[TOTAL_BINFILE]; - - struct resourceSound - { - std::string file; - bool loaded; - JA_Sound sound; - }; - - resourceSound mSound[TOTAL_SOUND]; - - struct resourceMusic - { - std::string file; - bool loaded; - JA_Music music; - }; - - resourceMusic mMusic[TOTAL_MUSIC]; - - struct resourceTexture - { - std::string file; - bool loaded; - LTexture *texture; - }; - - resourceTexture mTexture[TOTAL_TEXTURE]; }; #endif diff --git a/source/ifdefs.h b/source/ifdefs.h index c0a80c0..14980c7 100644 --- a/source/ifdefs.h +++ b/source/ifdefs.h @@ -12,4 +12,6 @@ #ifdef __linux__ #include "/usr/include/SDL2/SDL.h" -#endif \ No newline at end of file +#endif + +#define UNUSED \ No newline at end of file diff --git a/source/item.h b/source/item.h index 2f0706a..b554a3f 100644 --- a/source/item.h +++ b/source/item.h @@ -1,7 +1,7 @@ #pragma once #include "ifdefs.h" #include "animatedsprite.h" -#include "struct.h" +#include "utils.h" #ifndef ITEM_H #define ITEM_H diff --git a/source/ltexture.cpp b/source/ltexture.cpp index 3b44063..cc2d146 100644 --- a/source/ltexture.cpp +++ b/source/ltexture.cpp @@ -16,7 +16,7 @@ LTexture::LTexture() LTexture::~LTexture() { // Deallocate - free(); + unload(); } bool LTexture::loadFromFile(std::string path, SDL_Renderer *renderer) @@ -46,14 +46,14 @@ bool LTexture::loadFromFile(std::string path, SDL_Renderer *renderer) } // Get rid of preexisting texture - free(); + unload(); // The final texture SDL_Texture *newTexture = NULL; // Load image at specified path //SDL_Surface *loadedSurface = IMG_Load(path.c_str()); - SDL_Surface *loadedSurface = SDL_CreateRGBSurfaceWithFormatFrom((void*)data, width, height, depth, pitch, pixel_format); + SDL_Surface *loadedSurface = SDL_CreateRGBSurfaceWithFormatFrom((void *)data, width, height, depth, pitch, pixel_format); if (loadedSurface == NULL) { printf("Unable to load image %s!\n", path.c_str()); @@ -61,7 +61,7 @@ bool LTexture::loadFromFile(std::string path, SDL_Renderer *renderer) else { // Color key image - SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, COLOR_KEY_R, COLOR_KEY_G, COLOR_KEY_B)); + //SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, COLOR_KEY_R, COLOR_KEY_G, COLOR_KEY_B)); // Create texture from surface pixels newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface); @@ -102,7 +102,7 @@ bool LTexture::createBlank(SDL_Renderer *renderer, int width, int height, SDL_Te return mTexture != NULL; } -void LTexture::free() +void LTexture::unload() { // Free texture if it exists if (mTexture != NULL) @@ -132,7 +132,7 @@ void LTexture::setAlpha(Uint8 alpha) SDL_SetTextureAlphaMod(mTexture, alpha); } -void LTexture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, double angle, SDL_Point *center, SDL_RendererFlip flip) +void LTexture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, float zoomW, float zoomH, double angle, SDL_Point *center, SDL_RendererFlip flip) { // Set rendering space and render to screen SDL_Rect renderQuad = {x, y, mWidth, mHeight}; @@ -144,6 +144,9 @@ void LTexture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, doub renderQuad.h = clip->h; } + renderQuad.w = renderQuad.w * zoomW; + renderQuad.h = renderQuad.h * zoomH; + // Render to screen SDL_RenderCopyEx(renderer, mTexture, clip, &renderQuad, angle, center, flip); } diff --git a/source/ltexture.h b/source/ltexture.h index 3321666..e533620 100644 --- a/source/ltexture.h +++ b/source/ltexture.h @@ -23,7 +23,7 @@ public: bool createBlank(SDL_Renderer *renderer, int width, int height, SDL_TextureAccess = SDL_TEXTUREACCESS_STREAMING); // Deallocates texture - void free(); + void unload(); // Set color modulation void setColor(Uint8 red, Uint8 green, Uint8 blue); @@ -35,7 +35,7 @@ public: void setAlpha(Uint8 alpha); // Renders texture at given point - void render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip = NULL, double angle = 0.0, SDL_Point *center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE); + void render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip = NULL, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_Point *center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE); // Set self as render target void setAsRenderTarget(SDL_Renderer *renderer); diff --git a/source/main.cpp b/source/main.cpp index 4d42b08..24f7ec3 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,10 +1,10 @@ /* This source code copyrighted by JailDesigner (2020) started on Castalla 15-07-2020. -Using some sample source code from Lazy Foo' Productions */ -/*Descripción del enfoque utilizado para crear el juego. +/* +Descripción del enfoque utilizado para crear el juego. El programa contine una serie de clases/objetos básicos: la clase sprite permite dibujar partes de un fichero png en pantalla. La clase AnimatedSprite @@ -37,11 +37,11 @@ un tipo asociado diferente a NO_KIND */ #include "ifdefs.h" +#include "const.h" +#include "gamedirector.h" #include #include #include -#include "const.h" -#include "gamedirector.h" int main(int argc, char *args[]) { @@ -49,82 +49,33 @@ int main(int argc, char *args[]) srand(time(nullptr)); // Crea el objeto gameDirector - GameDirector *gameDirector = new GameDirector(); + GameDirector *gameDirector = new GameDirector(args[0]); + printf("Starting the game...\n\n"); - // Establece el valor de la variable con el path del ejecutable - gameDirector->setExecutablePath(args[0]); - - // Inicializa la lista de ficheros - gameDirector->setFileList(); - - // Comprueba que existen todos los ficheros - if (!gameDirector->checkFileList()) + // Mientras no se quiera salir del juego + while (!(gameDirector->exit())) { - return -1; - } - - // Arranca SDL y crea la ventana - if (!gameDirector->initSDL()) - { - printf("Failed to initialize!\n"); - return -1; - } - else - { - // Carga los recursos - if (!gameDirector->loadMedia(GAME_STATE_INIT)) + switch (gameDirector->getProgSection()) { - printf("Failed to load media!\n"); + case PROG_SECTION_LOGO: + gameDirector->runLogo(); + break; + case PROG_SECTION_INTRO: + gameDirector->runIntro(); + break; + case PROG_SECTION_TITLE: + gameDirector->runTitle(gameDirector->getSubsection()); + break; + case PROG_SECTION_GAME: + gameDirector->runGame(); + break; } - else - { - // Inicializa el objeto gameDirector - gameDirector->init(false); - printf("Starting the game...\n\n"); - - // Mientras no se quiera salir del juego - while (!(gameDirector->getGameStatus() == GAME_STATE_QUIT)) - { - switch (gameDirector->getGameStatus()) - { - case GAME_STATE_LOGO: - gameDirector->loadMedia(GAME_STATE_LOGO); - gameDirector->runLogo(); - gameDirector->unLoadMedia(GAME_STATE_LOGO); - break; - case GAME_STATE_INTRO: - gameDirector->loadMedia(GAME_STATE_INTRO); - gameDirector->runIntro(); - gameDirector->unLoadMedia(GAME_STATE_INTRO); - break; - case GAME_STATE_TITLE: - gameDirector->loadMedia(GAME_STATE_TITLE); - gameDirector->runTitle(); - gameDirector->unLoadMedia(GAME_STATE_TITLE); - break; - case GAME_STATE_PLAYING: - gameDirector->loadMedia(GAME_STATE_PLAYING); - gameDirector->runGame(); - gameDirector->unLoadMedia(GAME_STATE_PLAYING); - break; - case GAME_STATE_GAME_OVER_SCREEN: - gameDirector->loadMedia(GAME_STATE_GAME_OVER_SCREEN); - gameDirector->runGameOverScreen(); - gameDirector->unLoadMedia(GAME_STATE_GAME_OVER_SCREEN); - break; - case GAME_STATE_INSTRUCTIONS: - gameDirector->loadMedia(GAME_STATE_INSTRUCTIONS); - gameDirector->runInstructions(); - gameDirector->unLoadMedia(GAME_STATE_INSTRUCTIONS); - break; - } - } - } - - // Libera todos los recursos y cierra SDL - delete gameDirector; - printf("Shutting down the game...\n"); - - return 0; } + + // Libera todos los recursos y cierra SDL + delete gameDirector; + gameDirector = nullptr; + printf("Shutting down the game...\n"); + + return 0; } diff --git a/source/movingsprite.cpp b/source/movingsprite.cpp index 8954677..63ec6a5 100644 --- a/source/movingsprite.cpp +++ b/source/movingsprite.cpp @@ -33,6 +33,10 @@ void MovingSprite::init(float x, float y, int w, int h, float velx, float vely, setAccelX(accelx); setAccelY(accely); + // Establece el zoom W,H del sprite + setZoomW(1); + setZoomH(1); + // Establece la textura donde están los gráficos para el sprite setTexture(texture); @@ -56,7 +60,8 @@ void MovingSprite::move() // Muestra el sprite por pantalla void MovingSprite::render() { - mTexture->render(mRenderer, (int)mPosX, (int)mPosY, &mSpriteClip); + //mTexture->render(mRenderer, (int)mPosX, (int)mPosY, &mSpriteClip); + mTexture->render(mRenderer, (int)mPosX, (int)mPosY, &mSpriteClip, mZoomW, mZoomH); } // Establece el valor de la variable @@ -95,6 +100,18 @@ float MovingSprite::getAccelY() return mAccelY; } +// Establece el valor de la variable +float MovingSprite::getZoomW() +{ + return mZoomW; +} + +// Establece el valor de la variable +float MovingSprite::getZoomH() +{ + return mZoomH; +} + // Establece el valor de la variable void MovingSprite::setPosX(float x) { @@ -129,4 +146,16 @@ void MovingSprite::setAccelX(float x) void MovingSprite::setAccelY(float y) { mAccelY = y; +} + +// Establece el valor de la variable +void MovingSprite::setZoomW(float w) +{ + mZoomW = w; +} + +// Establece el valor de la variable +void MovingSprite::setZoomH(float h) +{ + mZoomH = h; } \ No newline at end of file diff --git a/source/movingsprite.h b/source/movingsprite.h index f4bdcd6..d609fca 100644 --- a/source/movingsprite.h +++ b/source/movingsprite.h @@ -8,6 +8,19 @@ // Clase MovingSprite. Añade posicion y velocidad en punto flotante class MovingSprite : public Sprite { +private: + float mPosX; // Posición en el eje X + float mPosY; // Posición en el eje Y + + float mVelX; // Velocidad en el eje X. Cantidad de pixeles a desplazarse + float mVelY; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse + + float mAccelX; // Aceleración en el eje X. Variación de la velocidad + float mAccelY; // Aceleración en el eje Y. Variación de la velocidad + + float mZoomW; // Zoom aplicado a la anchura + float mZoomH; // Zoom aplicado a la altura + public: // Constructor MovingSprite(); @@ -26,52 +39,51 @@ public: // Obten el valor de la variable float getPosX(); - + // Obten el valor de la variable float getPosY(); - + // Obten el valor de la variable float getVelX(); - + // Obten el valor de la variable float getVelY(); // Obten el valor de la variable float getAccelX(); - + // Obten el valor de la variable float getAccelY(); - + + // Obten el valor de la variable + float getZoomW(); + + // Obten el valor de la variable + float getZoomH(); + // Establece el valor de la variable void setPosX(float x); - + // Establece el valor de la variable void setPosY(float y); // Establece el valor de la variable void setVelX(float x); - + // Establece el valor de la variable void setVelY(float y); // Establece el valor de la variable void setAccelX(float x); - + // Establece el valor de la variable void setAccelY(float y); -private: - // Posición - float mPosX; - float mPosY; + // Establece el valor de la variable + void setZoomW(float w); - // Velocidad - float mVelX; - float mVelY; - - // Aceleración - float mAccelX; - float mAccelY; + // Establece el valor de la variable + void setZoomH(float h); }; #endif diff --git a/source/player.cpp b/source/player.cpp index a0f86d4..83a0cf1 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -6,6 +6,7 @@ Player::Player() { mSpriteLegs = new AnimatedSprite(); mSpriteBody = new AnimatedSprite(); + mSpriteHead = new AnimatedSprite(); init(0, 0, nullptr, nullptr, nullptr); } @@ -17,6 +18,7 @@ Player::~Player() mSpriteBody = nullptr; delete mSpriteLegs; delete mSpriteBody; + delete mSpriteHead; } // Iniciador @@ -27,8 +29,9 @@ void Player::init(float x, int y, LTexture *textureLegs, LTexture *textureBody, mStatusWalking = PLAYER_STATUS_WALKING_STOP; mStatusFiring = PLAYER_STATUS_FIRING_NO; mInvulnerable = false; - mInvulnerableTimer = PLAYER_INVULNERABLE_TIMER; + mInvulnerableCounter = PLAYER_INVULNERABLE_COUNTER; mExtraHit = false; + mCoffees = 0; // Establece la altura y el ancho del jugador mWidth = 3 * BLOCK; @@ -51,12 +54,8 @@ void Player::init(float x, int y, LTexture *textureLegs, LTexture *textureBody, // Establece la velocidad base mBaseSpeed = 1.5; - // Establece el numero inicial de vidas - mStartingLives = 3; - mLives = mStartingLives; - // Establece la puntuación inicial - mScore = 0; + mScore = 9500; // Establece el multiplicador de puntos inicial mScoreMultiplier = 1.0f; @@ -331,7 +330,7 @@ void Player::render() { if (mInvulnerable) { - if ((mInvulnerableTimer % 10) > 4) + if ((mInvulnerableCounter % 10) > 4) { mSpriteLegs->render(); mSpriteBody->render(); @@ -694,26 +693,26 @@ void Player::setInvulnerable(bool value) // Obtiene el valor de la variable bool Player::getInvulnerableTimer() { - return mInvulnerableTimer; + return mInvulnerableCounter; } // Establece el valor de la variable void Player::setInvulnerableTimer(Uint16 value) { - mInvulnerableTimer = value; + mInvulnerableCounter = value; } // Actualiza el valor de la variable void Player::updateInvulnerableTimer() { - if (mInvulnerableTimer > 0) + if (mInvulnerableCounter > 0) { - --mInvulnerableTimer; + --mInvulnerableCounter; } else { mInvulnerable = false; - mInvulnerableTimer = PLAYER_INVULNERABLE_TIMER; + mInvulnerableCounter = PLAYER_INVULNERABLE_COUNTER; } } @@ -734,7 +733,7 @@ void Player::removeExtraHit() { mExtraHit = false; mInvulnerable = true; - mInvulnerableTimer = PLAYER_INVULNERABLE_TIMER; + mInvulnerableCounter = PLAYER_INVULNERABLE_COUNTER; } // Obtiene el circulo de colisión diff --git a/source/player.h b/source/player.h index 0a9148c..322b67d 100644 --- a/source/player.h +++ b/source/player.h @@ -1,5 +1,5 @@ #pragma once -#include "struct.h" +#include "utils.h" #include "animatedsprite.h" #ifndef PLAYER_H @@ -8,6 +8,38 @@ // The player class Player { +private: + float mPosX; // Posicion en el eje X + int mPosY; // Posicion en el eje Y + + Uint8 mWidth; // Anchura + Uint8 mHeight; // Altura + + float mVelX; // Cantidad de pixeles a desplazarse en el eje X + int mVelY; // Cantidad de pixeles a desplazarse en el eje Y + + float mBaseSpeed; // Velocidad base del jugador + int mCooldown; // Contador durante el cual no puede disparar + + Uint32 mScore; // Puntos del jugador + float mScoreMultiplier; // Multiplicador de puntos + + Uint8 mStatusWalking; // Estado del jugador + Uint8 mStatusFiring; // Estado del jugador + + bool mAlive; // Indica si el jugador está vivo + bool mInvulnerable; // Indica si el jugador es invulnerable + Uint16 mInvulnerableCounter; // Temporizador para la invulnerabilidad + bool mExtraHit; // Indica si el jugador tiene un toque extra + Uint8 mCoffees; // Indica cuantos cafes lleva acumulados + + AnimatedSprite *mSpriteLegs; // Sprite para dibujar las piernas + AnimatedSprite *mSpriteBody; // Sprite para dibujar el cuerpo + AnimatedSprite *mSpriteHead; // Sprite para dibujar la cabeza + + Circle mCollider; // Circulo de colisión del jugador + void shiftColliders(); // Actualiza el circulo de colisión a la posición del jugador + public: // Constructor Player(); @@ -111,63 +143,6 @@ public: // Obtiene el circulo de colisión Circle &getCollider(); - -private: - // Posición X, Y del jugador - float mPosX; - int mPosY; - - // Altura y anchura del jugador - Uint8 mWidth; - Uint8 mHeight; - - // Velocidad X, Y del jugador - float mVelX; - int mVelY; - - // Velocidad base del jugador - float mBaseSpeed; - - // Contador durante el cual no puede disparar - int mCooldown; - - // Vidas actuales del jugador - Uint8 mLives; - - // Vidas iniciales del jugador - Uint8 mStartingLives; - - // Puntos del jugador - Uint32 mScore; - - // Multiplicador de puntos - float mScoreMultiplier; - - // Estado del jugador - Uint8 mStatusWalking; - Uint8 mStatusFiring; - - // Indica si el jugador está vivo - bool mAlive; - - // Indica si el jugador es invulnerable - bool mInvulnerable; - - // Temporizador para la invulnerabilidad - Uint16 mInvulnerableTimer; - - // Indica si el jugador tiene un toque extra - bool mExtraHit; - - // Sprite para dibujar al jugador en pantalla - AnimatedSprite *mSpriteLegs; - AnimatedSprite *mSpriteBody; - - // Circulo de colisión del jugador - Circle mCollider; - - // Actualiza el circulo de colisión a la posición del jugador - void shiftColliders(); }; #endif diff --git a/source/text.cpp b/source/text.cpp index b4b8cce..dbc8ba8 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -31,7 +31,6 @@ void Text::init(LTexture *texture, SDL_Renderer *renderer, Uint8 type, Uint8 siz mSprite->setSpriteClip(0, 0, mSprite->getWidth(), mSprite->getHeight()); // Cadena con los caracteres ascii que se van a inicializar - // std::string text = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-/().:#!"; std::string text = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ{\\[]]^_`abcdefghijklmnopqrstuvwxyz"; // Inicializa a cero el vector con las coordenadas diff --git a/source/text.h b/source/text.h index f651c59..8f6f86b 100644 --- a/source/text.h +++ b/source/text.h @@ -7,6 +7,20 @@ // Clase texto. Pinta texto en pantalla a partir de un bitmap class Text { + private: + Sprite *mSprite;// Objeto con los graficos para el texto + + struct Offset + { + int x; + int y; + Uint8 w; + }; + Offset mOffset[255];// Vector con las posiciones y ancho de cada letra + + Uint8 mType;// Indica si el texto es de anchura fija o variable + Uint8 mSize;// Altura del texto + public: // Constructor Text(); @@ -26,7 +40,7 @@ public: void writeColored(int x, int y, std::string text, Uint8 R, Uint8 G, Uint8 B); // Escribe el texto centrado en un punto x y con kerning - void writeCentered(int x, int y, std::string text, int kerning); + void writeCentered(int x, int y, std::string text, int kerning = 0); // Obtiene la longitud en pixels de una cadena Uint16 lenght(std::string text, int kerning); @@ -42,25 +56,6 @@ public: // Establece el valor de la variable void setSize(Uint8 size); - -private: - // Objeto con los graficos para el texto - Sprite *mSprite; - - // Coordenadas dentro del PNG para cada código ascii y su anchura - struct Offset - { - int x; - int y; - Uint8 w; - }; - - // Vector con las posiciones y ancho de cada letra - Offset mOffset[255]; - - // Indica si el texto es de anchura fija o variable - Uint8 mType; - Uint8 mSize; }; #endif diff --git a/source/utils.cpp b/source/utils.cpp new file mode 100644 index 0000000..ca82b32 --- /dev/null +++ b/source/utils.cpp @@ -0,0 +1,112 @@ +#include "utils.h" + +// Calcula el cuadrado de la distancia entre dos puntos +double distanceSquared(int x1, int y1, int x2, int y2) +{ + int deltaX = x2 - x1; + int deltaY = y2 - y1; + return deltaX * deltaX + deltaY * deltaY; +} + +// Detector de colisiones entre dos circulos +bool checkCollision(Circle &a, Circle &b) +{ + // Calcula el radio total al cuadrado + int totalRadiusSquared = a.r + b.r; + totalRadiusSquared = totalRadiusSquared * totalRadiusSquared; + + // Si la distancia entre el centro de los circulos es inferior a la suma de sus radios + if (distanceSquared(a.x, a.y, b.x, b.y) < (totalRadiusSquared)) + { + // Los circulos han colisionado + return true; + } + + // En caso contrario + return false; +} + +// Detector de colisiones entre un circulo y un rectangulo +bool checkCollision(Circle &a, SDL_Rect &b) +{ + //Closest point on collision box + int cX, cY; + + //Find closest x offset + if (a.x < b.x) + { + cX = b.x; + } + else if (a.x > b.x + b.w) + { + cX = b.x + b.w; + } + else + { + cX = a.x; + } + + //Find closest y offset + if (a.y < b.y) + { + cY = b.y; + } + else if (a.y > b.y + b.h) + { + cY = b.y + b.h; + } + else + { + cY = a.y; + } + + //If the closest point is inside the circle + if (distanceSquared(a.x, a.y, cX, cY) < a.r * a.r) + { + //This box and the circle have collided + return true; + } + + //If the shapes have not collided + return false; +} + +// Detector de colisiones entre un dos rectangulos +bool checkCollision(SDL_Rect &a, SDL_Rect &b) +{ + //Calculate the sides of rect A + int leftA = a.x; + int rightA = a.x + a.w; + int topA = a.y; + int bottomA = a.y + a.h; + + //Calculate the sides of rect B + int leftB = b.x; + int rightB = b.x + b.w; + int topB = b.y; + int bottomB = b.y + b.h; + + //If any of the sides from A are outside of B + if (bottomA <= topB) + { + return false; + } + + if (topA >= bottomB) + { + return false; + } + + if (rightA <= leftB) + { + return false; + } + + if (leftA >= rightB) + { + return false; + } + + //If none of the sides from A are outside B + return true; +} \ No newline at end of file diff --git a/source/struct.h b/source/utils.h similarity index 51% rename from source/struct.h rename to source/utils.h index bfde6fc..2efa4e9 100644 --- a/source/struct.h +++ b/source/utils.h @@ -1,42 +1,57 @@ -#pragma once -#include "ifdefs.h" - -#ifndef STRUCT_H -#define STRUCT_H - -// Estructura para definir un circulo -struct Circle -{ - Uint16 x; - Uint16 y; - Uint8 r; -}; - -// Estructura para definir todas las entradas que aceptará el programa -struct Input -{ - Uint8 up; - Uint8 down; - Uint8 left; - Uint8 right; - Uint8 escape; - Uint8 pause; - Uint8 fire; - Uint8 fireLeft; - Uint8 fireRight; - Uint8 accept; - Uint8 cancel; -}; - -// Estructura para mapear el teclado usado en la demo -struct DemoKeys -{ - Uint8 left; - Uint8 right; - Uint8 noInput; - Uint8 fire; - Uint8 fireLeft; - Uint8 fireRight; -}; - -#endif +#pragma once +#include "ifdefs.h" + +#ifndef UTILS_H +#define UTILS_H + +// Estructura para definir un circulo +struct Circle +{ + Uint16 x; + Uint16 y; + Uint8 r; +}; + +// Estructura para definir todas las entradas que aceptará el programa +struct Input +{ + Uint8 up; + Uint8 down; + Uint8 left; + Uint8 right; + Uint8 escape; + Uint8 pause; + Uint8 fire; + Uint8 fireLeft; + Uint8 fireRight; + Uint8 accept; + Uint8 cancel; +}; + +// Estructura para mapear el teclado usado en la demo +struct DemoKeys +{ + Uint8 left; + Uint8 right; + Uint8 noInput; + Uint8 fire; + Uint8 fireLeft; + Uint8 fireRight; +}; + +// Calcula el cuadrado de la distancia entre dos puntos +double distanceSquared(int x1, int y1, int x2, int y2); + +// Detector de colisiones entre dos circulos +bool checkCollision(Circle &a, Circle &b); + +// Detector de colisiones entre un circulo y un rectangulo +bool checkCollision(Circle &a, SDL_Rect &b); + +// Detector de colisiones entre un dos rectangulos +bool checkCollision(SDL_Rect a, SDL_Rect b); + +// Inicializa el vector con los valores del seno +void initSin(); + +#endif \ No newline at end of file