Primer commit

This commit is contained in:
2022-10-20 13:45:49 +02:00
commit eb7538ab59
143 changed files with 4339 additions and 0 deletions

26
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "g++.exe - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}\\bin\\${workspaceFolderBasename}_debug.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}\\bin",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++.exe build active file"
}
]
}

52
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,52 @@
{
"files.associations": {
"new": "cpp",
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"optional": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"bit": "cpp",
"compare": "cpp",
"concepts": "cpp",
"functional": "cpp",
"iterator": "cpp",
"numeric": "cpp",
"random": "cpp",
"numbers": "cpp"
}
}

33
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe build active file",
"command": "g++.exe",
"args": [
"${workspaceFolder}\\*.cpp",
"-g",
"-std=c++11",
"-lmingw32",
"-lSDL2main",
"-lSDL2_image",
"-lSDL2_mixer",
"-lSDL2",
"-o",
"${workspaceFolder}\\bin\\${workspaceFolderBasename}_debug.exe"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compiler: g++.exe"
}
],
"version": "2.0.0"
}

15
Makefile Normal file
View File

@@ -0,0 +1,15 @@
executable = super_pang_clone
source = *.cpp
windows:
@echo off
if not exist bin\ (mkdir bin)
g++ $(source) -std=c++11 -Wall -O2 -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -o bin/$(executable).exe
strip -s -R .comment -R .gnu.version bin/$(executable).exe --strip-unneeded
macos:
mkdir -p bin
g++ $(source) -std=c++11 -Wall -O2 -lSDL2 -lSDL2_image -lSDL2_mixer -ffunction-sections -fdata-sections -o bin/$(executable)_macos
linux:
mkdir -p bin
g++ $(source) -std=c++11 -Wall -Os -lSDL2 -lSDL2_image -lSDL2_mixer -ffunction-sections -fdata-sections -Wl,--gc-sections -o bin/$(executable)_linux
strip -s -R .comment -R .gnu.version bin/$(executable)_linux --strip-unneeded

31
background.cpp Normal file
View File

@@ -0,0 +1,31 @@
#include "background.h"
//Constructor
Background::Background()
{
init(0, 0, 0, 0, NULL);
}
//Inicializador
void Background::init(int x, int y, int w, int h, LTexture *texture)
{
//Establece el alto y el ancho del sprite del fondo
mSprite.setWidth(w);
mSprite.setHeight(h);
//Establece la posición X,Y del sprite del fondo
mSprite.setPosX(x);
mSprite.setPosY(y);
//Establece la textura donde están los gráficos para el sprite del fondo
mSprite.setTexture(*texture);
//Establece el rectangulo de donde coger la imagen
mSprite.setSpriteClip(0, 0, mSprite.getWidth(), mSprite.getHeight());
}
//Pinta el fondo en la pantalla
void Background::render()
{
mSprite.render();
}

24
background.h Normal file
View File

@@ -0,0 +1,24 @@
#include "sprite.h"
#ifndef BACKGROUND_H
#define BACKGROUND_H
//Clase para el fondo de pantalla del juego
class Background
{
public:
//Constructor
Background();
//Inicializador
void init(int x, int y, int w, int h, LTexture *texture);
//Pinta el fondo en la pantalla
void render();
private:
//Variables
Sprite mSprite;
};
#endif

469
balloon.cpp Normal file
View File

@@ -0,0 +1,469 @@
#include "const.h"
#include "globals.h"
#include "balloon.h"
//Constructor
Balloon::Balloon()
{
init(0, 0, NO_KIND, BALLON_VELX_POSITIVE, 0);
}
//Inicializador
void Balloon::init(int x, int y, Uint8 kind, float velx, Uint16 creationtimer)
{
switch (kind)
{
case BALLOON_1:
//Posición inicial
mPosX = x;
mPosY = y;
//Alto y ancho del objeto
mWidth = 8;
mHeight = mWidth;
//Inicializa los valores de velocidad y gravedad
mVelX = velx;
mVelY = 0;
mMaxVelY = 3;
mGravity = 0.09;
mDefaultVelY = 3;
//Puntos que da el globo al ser destruido
mScore = 50;
//Rectangulo con la imagen del sprite
mSprite.setSpriteClip(37 + 21 + 13, 0, mWidth, mHeight);
break;
case BALLOON_2:
//Posición inicial
mPosX = x;
mPosY = y;
//Alto y ancho del objeto
mWidth = 13;
mHeight = mWidth;
//Inicializa los valores de velocidad y gravedad
mVelX = velx;
mVelY = 0;
mMaxVelY = 3;
mGravity = 0.10;
mDefaultVelY = 4;
//Puntos que da el globo al ser destruido
mScore = 100;
//Rectangulo con la imagen del sprite
mSprite.setSpriteClip(37 + 21, 0, mWidth, mHeight);
break;
case BALLOON_3:
//Posición inicial
mPosX = x;
mPosY = y;
//Alto y ancho del objeto
mWidth = 21;
mHeight = mWidth;
//Inicializa los valores de velocidad y gravedad
mVelX = velx;
mVelY = 0;
mMaxVelY = 3;
mGravity = 0.10;
mDefaultVelY = 4.5;
//Puntos que da el globo al ser destruido
mScore = 200;
//Rectangulo con la imagen del sprite
mSprite.setSpriteClip(37, 0, mWidth, mHeight);
break;
case BALLOON_4:
//Posición inicial
mPosX = x;
mPosY = y;
//Alto y ancho del objeto
mWidth = 37;
mHeight = mWidth;
//Inicializa los valores de velocidad y gravedad
mVelX = velx;
mVelY = 0;
mMaxVelY = 3;
mGravity = 0.10;
mDefaultVelY = 5;
//Puntos que da el globo al ser destruido
mScore = 400;
//Rectangulo con la imagen del sprite
mSprite.setSpriteClip(0, 0, mWidth, mHeight);
break;
default:
//Posición inicial
mPosX = x;
mPosY = y;
//Alto y ancho del objeto
mWidth = 0;
mHeight = mWidth;
//Inicializa los valores de velocidad y gravedad
mVelX = velx;
mVelY = 0;
mMaxVelY = 0;
mGravity = 0;
mDefaultVelY = 0;
//Puntos que da el globo al ser destruido
mScore = 0;
//Rectangulo con la imagen del sprite
mSprite.setSpriteClip(0, 0, mWidth, mHeight);
break;
}
//Textura con los gráficos del sprite
mSprite.setTexture(gBalloonTexture);
//Alto y ancho del sprite
mSprite.setWidth(mWidth);
mSprite.setHeight(mHeight);
//Posición X,Y del sprite
mSprite.setPosX(mPosX);
mSprite.setPosY(mPosY);
//Tamaño del circulo de colisión
mCollider.r = mWidth / 2;
//Alinea el circulo de colisión con el objeto
shiftColliders();
//Inicializa variables
mStopped = true;
mStoppedTimer = 0;
mBlinking = false;
mVisible = true;
mInvulnerable = false;
mBeingCreated = true;
mCreationTimer = creationtimer;
//Tipo
mKind = kind;
}
//Centra el globo en la posición X
void Balloon::allignTo(int x)
{
mPosX = x - (mWidth / 2);
if (mPosX < PLAY_AREA_LEFT)
{
mPosX = PLAY_AREA_LEFT + 1;
}
else if ((mPosX + mWidth) > PLAY_AREA_RIGHT)
{
mPosX = PLAY_AREA_RIGHT - mWidth - 1;
}
//Posición X,Y del sprite
mSprite.setPosX(getPosX());
mSprite.setPosY(getPosY());
//Alinea el circulo de colisión con el objeto
shiftColliders();
}
//Pinta el globo en la pantalla
void Balloon::render()
{
if (mVisible)
{
mSprite.render();
}
}
//Actualiza la posición y estados del globo
void Balloon::move()
{
//Comprobamos si se puede mover
if (isStopped() == false)
{
//Lo movemos a izquierda o derecha
mPosX += mVelX;
//Si queda fuera de pantalla, corregimos su posición y cambiamos su sentido
if ((mPosX < PLAY_AREA_LEFT) || (mPosX + mWidth > PLAY_AREA_RIGHT))
{
//Corregir posición
mPosX -= mVelX;
//Invertir sentido
mVelX = -mVelX;
}
//Mueve el globo hacia arriba o hacia abajo
mPosY += int(mVelY);
//Si se sale por arriba
if (mPosY < PLAY_AREA_TOP)
{
//Corregimos
mPosY -= int(mVelY);
//Invertimos sentido
mVelY = -mVelY;
}
//Si el globo se sale por la parte inferior
if (mPosY + mHeight > PLAY_AREA_BOTTOM)
{
//Corregimos
mPosY -= int(mVelY);
//Invertimos colocando una velocidad por defecto
mVelY = -mDefaultVelY;
}
//Aplica gravedad al objeto, sin pasarse de un limite establecido
if (int(mVelY) > mMaxVelY)
{
mVelY = mMaxVelY;
}
else
{
mVelY += mGravity;
}
//Actualiza la posición del sprite
mSprite.setPosX(getPosX());
mSprite.setPosY(mPosY);
//Actualiza la posición del circulo de colisión
shiftColliders();
}
//Si no se puede mover:
//Comprobar si se está creando
else if (isBeingCreated() == true)
{
//Actualiza el valor de las variables
setStop(true);
setInvulnerable(true);
//Todavia tiene tiempo en el contador
if (mCreationTimer > 0)
{
//Desplaza lentamente el globo hacia abajo y hacia un lado
if (mCreationTimer % 10 == 0)
{
++mPosY;
mPosX += mVelX;
//Actualiza la posición del sprite
mSprite.setPosX(getPosX());
mSprite.setPosY(mPosY);
//Actualiza la posición del circulo de colisión
shiftColliders();
}
//Hace visible el globo de forma intermitente
if (mCreationTimer > 100)
{
setVisible(mCreationTimer / 10 % 2 == 0);
}
else
{
setVisible(mCreationTimer / 5 % 2 == 0);
}
--mCreationTimer;
}
//El contador ha llegado a cero
else
{
setBeingCreated(false);
setStop(false);
setVisible(true);
setInvulnerable(false);
}
}
//Comprobar si está detenido
else if (isStopped() == true)
{
//Si todavía está detenido, reduce el contador
if (mStoppedTimer > 0)
{
--mStoppedTimer;
} //Si el contador ha llegado a cero, ya no está detenido
else
{
setStop(false);
}
}
}
//Pone a cero todos los valores del globo
void Balloon::erase()
{
init(0, 0, NO_KIND, 0, 0);
}
//Comprueba si el globo tiene algun tipo asignado
bool Balloon::isActive()
{
if (mKind == NO_KIND)
{
return false;
}
else
{
return true;
}
}
//Obtiene del valor de la variable
int Balloon::getPosX()
{
return int(mPosX);
}
//Obtiene del valor de la variable
int Balloon::getPosY()
{
return mPosY;
}
//Obtiene del valor de la variable
float Balloon::getVelY()
{
return mVelY;
}
//Obtiene del valor de la variable
int Balloon::getWidth()
{
return mWidth;
}
//Obtiene del valor de la variable
int Balloon::getHeight()
{
return mHeight;
}
//Establece el valor de la variable
void Balloon::setVelY(float velY)
{
mVelY = velY;
}
//Obtiene del valor de la variable
int Balloon::getKind()
{
return mKind;
}
//Establece el valor de la variable
void Balloon::setStop(bool state)
{
mStopped = state;
}
//Obtiene del valor de la variable
bool Balloon::isStopped()
{
return mStopped;
}
//Establece el valor de la variable
void Balloon::setBlink(bool state)
{
mBlinking = state;
}
//Obtiene del valor de la variable
bool Balloon::isBlinking()
{
return mBlinking;
}
//Establece el valor de la variable
void Balloon::setVisible(bool state)
{
mVisible = state;
}
//Obtiene del valor de la variable
bool Balloon::isVisible()
{
return mVisible;
}
//Establece el valor de la variable
void Balloon::setInvulnerable(bool state)
{
mInvulnerable = state;
}
//Obtiene del valor de la variable
bool Balloon::isInvulnerable()
{
return mInvulnerable;
}
//Establece el valor de la variable
void Balloon::setBeingCreated(bool state)
{
mBeingCreated = state;
}
//Obtiene del valor de la variable
bool Balloon::isBeingCreated()
{
return mBeingCreated;
}
//Establece el valor de la variable
void Balloon::setStoppedTimer(Uint16 time)
{
mStoppedTimer = time;
}
//Obtiene del valor de la variable
Uint16 Balloon::getStoppedTimer()
{
return mStoppedTimer;
}
//Obtiene del valor de la variable
Uint16 Balloon::getScore()
{
return mScore;
}
//Obtiene el circulo de colisión
Circle &Balloon::getCollider()
{
return mCollider;
}
//Alinea el circulo de colisión con la posición del objeto globo
void Balloon::shiftColliders()
{
//Align collider to center of balloon
mCollider.x = mPosX + mCollider.r;
mCollider.y = mPosY + mCollider.r;
}

148
balloon.h Normal file
View File

@@ -0,0 +1,148 @@
#include "struct.h"
#include "sprite.h"
#ifndef BALLOON_H
#define BALLOON_H
//Clase globo
class Balloon
{
public:
//Constructor
Balloon();
//Inicializador
void init(int x, int y, Uint8 kind, float velx, Uint16 creationtimer);
//Centra el globo en la posición X
void allignTo(int x);
//Pinta el globo en la pantalla
void render();
//Actualiza la posición y estados del globo
void move();
//Pone a cero todos los valores del globo
void erase();
//Comprueba si el globo tiene algun tipo asignado
bool isActive();
//Obtiene del valor de la variable
int getPosX();
//Obtiene del valor de la variable
int getPosY();
//Obtiene del valor de la variable
float getVelY();
//Obtiene del valor de la variable
int getWidth();
//Obtiene del valor de la variable
int getHeight();
//Establece el valor de la variable
void setVelY(float velY);
//Obtiene del valor de la variable
int getKind();
//Establece el valor de la variable
void setStop(bool state);
//Obtiene del valor de la variable
bool isStopped();
//Establece el valor de la variable
void setBlink(bool state);
//Obtiene del valor de la variable
bool isBlinking();
//Establece el valor de la variable
void setVisible(bool state);
//Obtiene del valor de la variable
bool isVisible();
//Establece el valor de la variable
void setInvulnerable(bool state);
//Obtiene del valor de la variable
bool isInvulnerable();
//Establece el valor de la variable
void setBeingCreated(bool state);
//Obtiene del valor de la variable
bool isBeingCreated();
//Establece el valor de la variable
void setStoppedTimer(Uint16 time);
//Obtiene del valor de la variable
Uint16 getStoppedTimer();
//Obtiene del valor de la variable
Uint16 getScore();
//Obtiene el circulo de colisión
Circle &getCollider();
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;
//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;
//Temporizador para controlar el estado "creandose"
Uint16 mCreationTimer;
//Tipo de globo
Uint8 mKind;
//Sprite del objeto globo
Sprite 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

192
bullet.cpp Normal file
View File

@@ -0,0 +1,192 @@
#include "const.h"
#include "globals.h"
#include "bullet.h"
//Constructor
Bullet::Bullet()
{
init(0, 0, NO_KIND);
}
//Iniciador
void Bullet::init(int x, int y, int kind)
{
//Posición inicial del objeto
mPosX = x;
mPosY = y;
//Alto y ancho del objeto
mWidth = 8;
mHeight = mWidth;
//Velocidad inicial en el eje Y
mVelY = -3;
//Tipo de bala
mKind = kind;
//Textura con los gráficos del objeto
mSprite.setTexture(gBulletTexture);
//Alto y ancho del sprite
mSprite.setWidth(mWidth);
mSprite.setHeight(mHeight);
//Posición inicial del sprite
mSprite.setPosX(mPosX);
mSprite.setPosY(mPosY);
//Valores especificos según el tipo
switch (kind)
{
case BULLET_UP:
//Establece la velocidad inicial
mVelX = 0;
//Rectangulo con los gráficos del objeto
mSprite.setSpriteClip(0 * mWidth, 0, mSprite.getWidth(), mSprite.getHeight());
break;
case BULLET_LEFT:
//Establece la velocidad inicial
mVelX = -2;
//Rectangulo con los gráficos del objeto
mSprite.setSpriteClip(1 * mWidth, 0, mSprite.getWidth(), mSprite.getHeight());
break;
case BULLET_RIGHT:
//Establece la velocidad inicial
mVelX = 2;
//Rectangulo con los gráficos del objeto
mSprite.setSpriteClip(2 * mWidth, 0, mSprite.getWidth(), mSprite.getHeight());
break;
default:
break;
}
//Establece el tamaño del circulo de colisión
mCollider.r = mWidth / 2;
//Alinea el circulo de colisión con el objeto
shiftColliders();
}
//Pinta el objeto en pantalla
void Bullet::render()
{
mSprite.render();
}
//Actualiza la posición y estado del objeto en horizontal
void Bullet::move()
{
//Mueve el objeto a su nueva posición
mPosX += mVelX;
//Si el objeto se sale del area de juego por los laterales
if ((mPosX < PLAY_AREA_LEFT) || (mPosX + mWidth > PLAY_AREA_RIGHT))
{
//Se deshabilita
mKind = NO_KIND;
}
//Mueve el objeto a su nueva posición en vertical
mPosY += int(mVelY);
//Si el objeto se sale del area de juego por la parte superior o inferior
if ((mPosY < PLAY_AREA_TOP) || (mPosY + mHeight > PLAY_AREA_BOTTOM))
{
//Se deshabilita
mKind = NO_KIND;
}
//Actualiza la posición del sprite
mSprite.setPosX(mPosX);
mSprite.setPosY(mPosY);
//Alinea el circulo de colisión con el objeto
shiftColliders();
}
#ifdef TEST
void Bullet::testMove()
{
//Update sprite position
mSprite.setPosX(mPosX);
mSprite.setPosY(mPosY);
//Update circle colliders
shiftColliders();
}
#endif
//Deshabilita el objeto
void Bullet::erase()
{
mKind = NO_KIND;
}
//Comprueba si el objeto está activo
bool Bullet::isActive()
{
if (mKind == NO_KIND)
{
return false;
}
else
{
return true;
}
}
//Obtiene el valor de la variable
int Bullet::getPosX()
{
return mPosX;
}
//Obtiene el valor de la variable
int Bullet::getPosY()
{
return mPosY;
}
//Establece el valor de la variable
void Bullet::setPosX(int x)
{
mPosX = x;
}
//Establece el valor de la variable
void Bullet::setPosY(int y)
{
mPosY = y;
}
//Obtiene el valor de la variable
float Bullet::getVelY()
{
return mVelY;
}
//Obtiene el valor de la variable
int Bullet::getKind()
{
return mKind;
}
//Obtiene el circulo de colisión
Circle &Bullet::getCollider()
{
return mCollider;
}
//Alinea el circulo de colisión con el objeto
void Bullet::shiftColliders()
{
mCollider.x = mPosX + mCollider.r;
mCollider.y = mPosY + mCollider.r;
}

78
bullet.h Normal file
View File

@@ -0,0 +1,78 @@
#include "struct.h"
#include "sprite.h"
#ifndef BULLET_H
#define BULLET_H
//Clase bala
class Bullet
{
public:
//Constructor
Bullet();
//Iniciador
void init(int x, int y, int kind);
//Pinta el objeto en pantalla
void render();
//Actualiza la posición y estado del objeto
void move();
#ifdef TEST
void testMove();
#endif
//Deshabilita el objeto
void erase();
//Comprueba si el objeto está activo
bool isActive();
//Obtiene el valor de la variable
int getPosX();
//Obtiene el valor de la variable
int getPosY();
//Establece el valor de la variable
void setPosX(int x);
//Establece el valor de la variable
void setPosY(int y);
//Obtiene el valor de la variable
float getVelY();
//Obtiene el valor de la variable
int getKind();
//Obtiene el circulo de colisión
Circle &getCollider();
private:
//Posición X/Y del objeto
int mPosX;
int mPosY;
//Alto y ancho el objeto
Uint8 mWidth;
Uint8 mHeight;
//Velocidad del objeto
int mVelX;
int mVelY;
//Tipo de objeto
int mKind;
//Sprite con los graficos y métodos de pintado
Sprite mSprite;
//Balloon's collision circle
Circle mCollider;
//Alinea el circulo de colisión con el objeto
void shiftColliders();
};
#endif

109
const.h Normal file
View File

@@ -0,0 +1,109 @@
#include <SDL2/SDL.h>
#ifndef CONST_H
#define CONST_H
//Tamaño de bloque
const int BLOCK = 8;
//Tamaño de la pantalla real
const int 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;
const int VIEW_HEIGHT = SCREEN_HEIGHT * 3;
//Zona de juego
const int PLAY_AREA_TOP = (0 * BLOCK);
const int PLAY_AREA_BOTTOM = SCREEN_HEIGHT - (4 * BLOCK);
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;
//Color transparente para los sprites
const int COLOR_KEY_R = 0xff;
const int COLOR_KEY_G = 0x00;
const int 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);
//Tipos de fondos para el menu
const int MENU_BACKGROUND_TRANSPARENT = 0;
const int MENU_BACKGROUND_SOLID = 1;
//Estados del jugador
const int PLAYER_STATE_STOPPED = 0;
const int PLAYER_STATE_WALKING_LEFT = 1;
const int PLAYER_STATE_WALKING_RIGHT = 2;
const int PLAYER_STATE_TOTAL = 3;
//Estados del juego
const int GAME_STATE_TITLE = 0;
const int GAME_STATE_PLAYING = 1;
const int GAME_STATE_PAUSED = 2;
const int GAME_STATE_QUIT = 3;
const int GAME_STATE_TOTAL = 4;
//Anclajes para el marcador de puntos
const int SCORE_WORD_X = (SCREEN_WIDTH / 4) - ((5 * BLOCK) / 2);
const int SCORE_WORD_Y = SCREEN_HEIGHT - (3 * BLOCK) + 4;
const int SCORE_NUMBER_X = (SCREEN_WIDTH / 4) - (3 * BLOCK);
const int SCORE_NUMBER_Y = SCREEN_HEIGHT - (2 * BLOCK) + 4;
const int HISCORE_WORD_X = ((SCREEN_WIDTH / 4) * 3) - ((8 * BLOCK) / 2);
const int HISCORE_WORD_Y = SCREEN_HEIGHT - (3 * BLOCK) + 4;
const int HISCORE_NUMBER_X = ((SCREEN_WIDTH / 4) * 3) - (3 * BLOCK);
const int HISCORE_NUMBER_Y = SCREEN_HEIGHT - (2 * BLOCK) + 4;
//Ningun tipo
const int NO_KIND = 0;
//Tipos de globo
const int BALLOON_1 = 1;
const int BALLOON_2 = 2;
const int BALLOON_3 = 3;
const int BALLOON_4 = 4;
//Velocidad del globo
const float BALLON_VELX_POSITIVE = 0.7;
const float BALLON_VELX_NEGATIVE = -0.7;
//Tipos de bala
const int BULLET_UP = 1;
const int BULLET_LEFT = 2;
const int BULLET_RIGHT = 3;
//Estados de entrada
const int NO_INPUT = 0;
const int INPUT_UP = 1;
const int INPUT_DOWN = 2;
const int INPUT_LEFT = 3;
const int INPUT_RIGHT = 4;
const int INPUT_FIRE = 5;
//Zona muerta del mando analógico
const int JOYSTICK_DEAD_ZONE = 8000;
//Mapeo de bottones (8bitdo)
const int BUTTON_A = 0;
const int BUTTON_B = 1;
const int BUTTON_X = 3;
const int BUTTON_Y = 4;
const int BUTTON_SELECT = 10;
const int BUTTON_START = 11;
const int BUTTON_L = 6;
const int BUTTON_R = 7;
//Estado del teclado SDL
const Uint8 *keystates;
#endif

981
gamedirector.cpp Normal file
View File

@@ -0,0 +1,981 @@
#include "const.h"
#include "struct.h"
#include "ltexture.h"
#include "globals.h"
#include "player.h"
#include "balloon.h"
#include "bullet.h"
#include "background.h"
#include "text.h"
#include "menu.h"
#include "gamedirector.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;
}
//Constructor
GameDirector::GameDirector()
{
init();
}
//Iniciador
void GameDirector::init()
{
//Variables
mGameStatus = GAME_STATE_TITLE;
mOldTicks = 0;
mMaxBalloons = 50;
mMaxBullets = 50;
mGameSpeed = 15;
mMenaceLevel = 0;
mMenaceLevelThreshold = 7;
mScore = 0;
mHiScore = 0;
mScoreText = std::to_string(mScore);
mHiScoreText = std::to_string(mHiScore);
mGetReady = true;
//Objeto jugador
player.init();
//Establece a cero todos los valores del vector de objetos globo
resetBalloons();
//Crea dos objetos globo y los centra en el area de juego
//balloon[0].init(0, BLOCK, BALLOON_4, BALLON_VELX_POSITIVE, 0);
//balloon[0].allignTo(PLAY_AREA_WIDTH / 2);
//balloon[1].init(0, BLOCK, BALLOON_4, BALLON_VELX_NEGATIVE, 0);
//balloon[1].allignTo(PLAY_AREA_WIDTH / 2);
//Con los globos creados, calcula el nivel de amenaza
calculateMenaceLevel();
//Establece a cero todos los valores del vector de objetos bala
resetBullets();
#ifdef TEST
balloonTest.init(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, BALLOON_4, 0);
balloonTest.stop();
bulletTest.init(SCREEN_WIDTH / 4, SCREEN_HEIGHT / 2, BULLET_UP);
#endif
//Los fondos
gameBackground.init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - (0 * BLOCK), &gGameBackgroundTexture);
titleBackground.init(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, &gTitleBackgroundTexture);
//Objetos texto, uno de cada color
whiteText.init(&gWhiteFontTexture);
blackText.init(&gBlackFontTexture);
//Inicializa el objeto con el menu del titulo
menuTitle.init(0, 16 * BLOCK, MENU_SELECTOR_WHITE, MENU_BACKGROUND_TRANSPARENT);
menuTitle.addItem("START");
menuTitle.addItem("EXIT");
menuTitle.setBackgroundColor(0, 0, 0, 255);
menuTitle.centerMenuOnScreen();
//Inicializa el objeto con el menu de pausa
menuPause.init(0, 12 * BLOCK, MENU_SELECTOR_WHITE, MENU_BACKGROUND_SOLID);
menuPause.addItem("CONTINUE");
menuPause.addItem("EXIT TO TITLE");
menuPause.setBackgroundColor(0x73, 0x27, 0x5c, 255);
menuPause.centerMenuOnScreen();
}
//Hace una pausa de milisegundos
void GameDirector::sleep(Uint16 time)
{
Uint32 ticks = SDL_GetTicks();
while (SDL_GetTicks() - ticks < time)
{
/* code */
}
}
//Establece el valor de la variable
void GameDirector::setScore(Uint32 score)
{
mScore = score;
}
//Establece el valor de la variable
void GameDirector::setHiScore(Uint32 score)
{
mHiScore = score;
}
//Actualiza el valor de HiScore en caso necesario
void GameDirector::updateHiScore()
{
if (mScore > mHiScore)
{
mHiScore = mScore;
}
}
//Transforma un valor numérico en una cadena de 6 cifras
std::string GameDirector::updateScoreText(Uint32 num)
{
switch (num)
{
case 0 ... 9:
return ("00000" + std::to_string(num));
break;
case 10 ... 99:
return ("0000" + std::to_string(num));
break;
case 100 ... 999:
return ("000" + std::to_string(num));
break;
case 1000 ... 9999:
return ("00" + std::to_string(num));
break;
case 10000 ... 99999:
return ("0" + std::to_string(num));
break;
case 100000 ... 999999:
return (std::to_string(num));
break;
default:
return (std::to_string(num));
break;
}
}
//Pinta el marcador en pantalla usando un objeto texto
void GameDirector::renderScoreBoard(Text &text)
{
mScoreText = updateScoreText(mScore);
mHiScoreText = updateScoreText(mHiScore);
text.write(SCORE_WORD_X, SCORE_WORD_Y, "SCORE");
text.write(SCORE_NUMBER_X, SCORE_NUMBER_Y, mScoreText);
text.write(HISCORE_WORD_X, HISCORE_WORD_Y, "HI-SCORE");
text.write(HISCORE_NUMBER_X, HISCORE_NUMBER_Y, mHiScoreText);
}
//Mueve todos los globos activos
void GameDirector::moveBalloons()
{
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive())
{
balloon[i].move();
}
}
}
//Pinta en pantalla todos los globos activos
void GameDirector::renderBalloons()
{
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive())
{
balloon[i].render();
}
}
}
//Devuelve el primer indice no activo del vector de globos
Uint8 GameDirector::getBallonFreeIndex()
{
int index = 0;
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive() == false)
{
index = i;
break;
}
}
return index;
}
//Crea un globo nuevo en el vector de globos
Uint8 GameDirector::createNewBalloon(int x, int y, Uint8 kind, float velx, Uint16 creationtimer)
{
Uint8 index = getBallonFreeIndex();
balloon[index].init(x, y, kind, velx, creationtimer);
return index;
}
//Establece a cero todos los valores del vector de objetos globo
void GameDirector::resetBalloons()
{
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
balloon[i].erase();
}
}
//Explosiona un globo. Lo destruye y crea otros dos si es el caso
void GameDirector::popBalloon(Uint8 index)
{
if (balloon[index].isActive())
{
Uint8 kind = balloon[index].getKind();
Uint8 freeIndex = 0;
switch (kind)
{
//Si es del tipo más pequeño, simplemente elimina el globo
case BALLOON_1:
balloon[index].erase();
break;
//En cualquier otro caso, crea dos globos de un tipo inferior
default:
freeIndex = getBallonFreeIndex();
balloon[freeIndex].init(0, balloon[index].getPosY(), balloon[index].getKind() - 1, BALLON_VELX_NEGATIVE, 0);
balloon[freeIndex].allignTo(balloon[index].getPosX() + (balloon[index].getWidth() / 2));
balloon[freeIndex].setVelY(-2.5);
freeIndex = getBallonFreeIndex();
balloon[freeIndex].init(0, balloon[index].getPosY(), balloon[index].getKind() - 1, BALLON_VELX_POSITIVE, 0);
balloon[freeIndex].allignTo(balloon[index].getPosX() + (balloon[index].getWidth() / 2));
balloon[freeIndex].setVelY(-2.5);
//Elimina el globo
balloon[index].erase();
break;
}
}
}
//Detiene todos los globos
void GameDirector::stopAllBalloons()
{
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive())
{
balloon[i].setStop(true);
}
}
}
//Pone en marcha todos los globos
void GameDirector::startAllBalloons()
{
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive())
{
balloon[i].setStop(false);
}
}
}
//Obtiene el numero de globos activos
Uint8 GameDirector::countBalloons()
{
Uint8 num = 0;
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive())
{
++num;
}
}
return num;
}
//Comprueba la colisión entre el jugador y los globos activos
bool GameDirector::checkPlayerBallonCollision()
{
bool result = false;
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
if (balloon[i].isActive())
{
if (checkCollision(player.getCollider(), balloon[i].getCollider()))
{
result = true;
break;
}
}
}
return result;
}
//Comprueba y procesa la colisión entre las balas y los globos
void GameDirector::processBulletBallonCollision()
{
bool result = false;
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
for (Uint8 j = 0; j < mMaxBullets; j++)
{
if (balloon[i].isActive() && !(balloon[i].isInvulnerable()) && bullet[j].isActive())
{
if (checkCollision(balloon[i].getCollider(), bullet[j].getCollider()))
{
player.addScore(balloon[i].getScore());
setScore(player.getScore());
updateHiScore();
popBalloon(i);
Mix_PlayChannel(-1, gPopBalloonFX, 0);
bullet[j].erase();
calculateMenaceLevel();
break;
}
}
}
}
}
//Mueve las balas activas
void GameDirector::moveBullets()
{
for (Uint8 i = 0; i < mMaxBullets; i++)
{
if (bullet[i].isActive())
{
bullet[i].move();
}
}
}
//Pinta las balas activas
void GameDirector::renderBullets()
{
for (Uint8 i = 0; i < mMaxBullets; i++)
{
if (bullet[i].isActive())
{
bullet[i].render();
}
}
}
//Devuelve el primer indice no activo del vector de balas
Uint8 GameDirector::getBulletFreeIndex()
{
Uint8 index = 0;
for (int i = 0; i < mMaxBullets; i++)
{
if (bullet[i].isActive() == false)
{
index = i;
break;
}
}
return index;
}
//Establece a cero todos los valores del vector de objetos bala
void GameDirector::resetBullets()
{
for (Uint8 i = 0; i < mMaxBullets; i++)
{
bullet[i].init(0, 0, NO_KIND);
}
}
//Crea un objeto bala
void GameDirector::createBullet(int x, int y, Uint8 kind)
{
bullet[getBulletFreeIndex()].init(x, y, kind);
}
//Calcula y establece el valor de amenaza en funcion de los globos activos
void GameDirector::calculateMenaceLevel()
{
mMenaceLevel = 0;
for (Uint8 i = 0; i < mMaxBalloons; i++)
{
switch (balloon[i].getKind())
{
case BALLOON_1:
mMenaceLevel += 1;
break;
case BALLOON_2:
mMenaceLevel += 2;
break;
case BALLOON_3:
mMenaceLevel += 4;
break;
case BALLOON_4:
mMenaceLevel += 8;
break;
default:
mMenaceLevel += 0;
break;
}
}
}
//Obtiene el valor de la variable
Uint8 GameDirector::getMenaceLevel()
{
return mMenaceLevel;
}
//Gestiona el nivel de amenaza
void GameDirector::checkMenaceLevel()
{
//Aumenta el nivel de amenaza en función de la puntuación
mMenaceLevelThreshold = 7 + (4 * (mScore / 10000));
//Si el nivel de amenza es inferior al umbral
if (mMenaceLevel < mMenaceLevelThreshold)
{
Uint8 index = 0;
//Obtiene el centro del jugador en el eje X
int x = player.getPosX() + (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);
}
else
{
index = createNewBalloon(0, PLAY_AREA_TOP + BLOCK - 37, BALLOON_4, BALLON_VELX_NEGATIVE, 400);
}
balloon[index].allignTo(x);
//Recalcula el nivel de amenaza con el nuevo globo
calculateMenaceLevel();
}
}
//Gestiona la entrada de teclado y mando durante el juego
void GameDirector::checkGameInput()
{
//Obtiene el estado de las teclas pulsadas del teclado
keystates = SDL_GetKeyboardState(NULL);
//Si está pulsada la tecla izquierda o el mando hacia la izquierda
if ((keystates[SDL_SCANCODE_LEFT] != 0) || (SDL_JoystickGetAxis(gGameController, 0) < -JOYSTICK_DEAD_ZONE))
{
player.checkInput(INPUT_LEFT);
}
//Si está pulsada la tecla derecha o el mando hacia la derecha
else if ((keystates[SDL_SCANCODE_RIGHT] != 0) || (SDL_JoystickGetAxis(gGameController, 0) > JOYSTICK_DEAD_ZONE))
{
player.checkInput(INPUT_RIGHT);
}
//Ninguna de las dos direcciones pulsadas
else
{
player.checkInput(NO_INPUT);
}
//Comprobamos la tecla o el botón de disparo central
if ((SDL_JoystickGetButton(gGameController, BUTTON_X)) || (keystates[SDL_SCANCODE_W] != 0))
{
if (player.canFire())
{
createBullet(player.getPosX() + (player.getWidth() / 2) - 4, player.getPosY(), BULLET_UP);
player.setFireCooldown(10);
//Reproduce el sonido de disparo
Mix_PlayChannel(-1, gBulletFX, 0);
}
}
//Comprobamos la tecla o el botón de disparo izquierdo
if ((SDL_JoystickGetButton(gGameController, BUTTON_Y)) || (keystates[SDL_SCANCODE_Q] != 0))
{
if (player.canFire())
{
createBullet(player.getPosX() + (player.getWidth() / 2) - 4, player.getPosY(), BULLET_LEFT);
player.setFireCooldown(10);
//Reproduce el sonido de disparo
Mix_PlayChannel(-1, gBulletFX, 0);
}
}
//Comprobamos la tecla o el botón de disparo derecho
if ((SDL_JoystickGetButton(gGameController, BUTTON_A)) || (keystates[SDL_SCANCODE_E] != 0))
{
if (player.canFire())
{
createBullet(player.getPosX() + (player.getWidth() / 2) - 4, player.getPosY(), BULLET_RIGHT);
player.setFireCooldown(10);
//Reproduce el sonido de disparo
Mix_PlayChannel(-1, gBulletFX, 0);
}
}
//Comprobamos la tecla o el botón de pausa/menu
if ((SDL_JoystickGetButton(gGameController, BUTTON_START)) || (keystates[SDL_SCANCODE_ESCAPE] != 0))
{
setGameStatus(GAME_STATE_PAUSED);
//Detiene la música
Mix_HaltMusic();
}
}
//Gestiona la entrada de teclado y mando durante el menu
void GameDirector::checkMenuInput(Menu *menu)
{
//Obtiene el estado de las teclas pulsadas del teclado
keystates = SDL_GetKeyboardState(NULL);
//Si está pulsada la tecla izquierda o el mando hacia la izquierda
if ((keystates[SDL_SCANCODE_UP] != 0) || (SDL_JoystickGetAxis(gGameController, 1) < -JOYSTICK_DEAD_ZONE))
{
menu->checkInput(INPUT_UP);
}
//Si está pulsada la tecla derecha o el mando hacia la derecha
else if ((keystates[SDL_SCANCODE_DOWN] != 0) || (SDL_JoystickGetAxis(gGameController, 1) > JOYSTICK_DEAD_ZONE))
{
menu->checkInput(INPUT_DOWN);
}
//Comprobamos la tecla o el botón de menu/pausa
else if (keystates[SDL_SCANCODE_RETURN] != 0 || (SDL_JoystickGetButton(gGameController, BUTTON_A)))
{
menu->checkInput(INPUT_FIRE);
}
#ifdef TEST
if (SDL_JoystickGetButton(gGameController, 1))
{
std::cout << "button1\n";
}
if (SDL_JoystickGetButton(gGameController, 1))
{
std::cout << "button1\n";
}
if (SDL_JoystickGetButton(gGameController, 2))
{
std::cout << "button2\n";
}
if (SDL_JoystickGetButton(gGameController, 3))
{
std::cout << "button3\n";
}
if (SDL_JoystickGetButton(gGameController, 4))
{
std::cout << "button4\n";
}
if (SDL_JoystickGetButton(gGameController, 5))
{
std::cout << "button5\n";
}
if (SDL_JoystickGetButton(gGameController, 6))
{
std::cout << "button6\n";
}
if (SDL_JoystickGetButton(gGameController, 7))
{
std::cout << "button7\n";
}
if (SDL_JoystickGetButton(gGameController, 8))
{
std::cout << "button8\n";
}
if (SDL_JoystickGetButton(gGameController, 9))
{
std::cout << "button9\n";
}
if (SDL_JoystickGetButton(gGameController, 10))
{
std::cout << "button10\n";
}
if (SDL_JoystickGetButton(gGameController, 11))
{
std::cout << "button11\n";
}
if (SDL_JoystickGetButton(gGameController, 12))
{
std::cout << "button12\n";
}
if (SDL_JoystickGetButton(gGameController, 13))
{
std::cout << "button13\n";
}
if (SDL_JoystickGetButton(gGameController, 14))
{
std::cout << "button14\n";
}
if (SDL_JoystickGetButton(gGameController, 15))
{
std::cout << "button15\n";
}
#endif
}
//Obtiene el valor de la variable
Uint8 GameDirector::getGameStatus()
{
return mGameStatus;
}
//Establece el valor de la variable
void GameDirector::setGameStatus(Uint8 status)
{
mGameStatus = status;
}
//Pinta una transición en pantalla
void GameDirector::renderTransition(Uint8 index)
{
switch (index)
{
case 0:
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = SCREEN_WIDTH;
rect.h = 0;
SDL_RenderPresent(gRenderer);
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
for (Uint16 i = 0; i < SCREEN_HEIGHT; i = i + 2)
{
rect.h = i;
SDL_RenderFillRect(gRenderer, &rect);
SDL_RenderPresent(gRenderer);
}
break;
case 1:
SDL_Rect rect1;
rect1.x = 0;
rect1.y = 0;
rect1.w = SCREEN_WIDTH;
rect1.h = 0;
SDL_Rect rect2;
rect2.x = 0;
rect2.y = 0;
rect2.w = SCREEN_WIDTH;
rect2.h = 0;
SDL_RenderPresent(gRenderer);
SDL_SetRenderDrawBlendMode(gRenderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 64);
for (Uint16 i = 0; i < (SCREEN_HEIGHT / 2); i = i + 4)
{
rect1.h = i;
SDL_RenderFillRect(gRenderer, &rect1);
rect2.h = i;
rect2.y = SCREEN_HEIGHT - (i);
SDL_RenderFillRect(gRenderer, &rect2);
SDL_RenderPresent(gRenderer);
}
rect1.x = 0;
rect1.y = 0;
rect1.w = SCREEN_WIDTH;
rect1.h = SCREEN_HEIGHT;
for (Uint16 i = 0; i < (SCREEN_HEIGHT / 2); i = i + 4)
{
SDL_RenderFillRect(gRenderer, &rect1);
SDL_RenderPresent(gRenderer);
}
break;
default:
break;
}
}
//Pinta el texto GetReady en pantalla
void GameDirector::renderGetReady()
{
if (mGetReady)
{
Sprite sprite;
sprite.setTexture(gMiscTexture);
sprite.setWidth(53);
sprite.setHeight(10);
sprite.setPosX((PLAY_AREA_WIDTH / 2) - (sprite.getWidth() / 2));
sprite.setPosY((PLAY_AREA_HEIGHT / 2) - (sprite.getHeight() / 2));
sprite.setSpriteClip(0, 0, sprite.getWidth(), sprite.getHeight());
for (Uint8 i = 0; i < 1; i++)
{
sprite.render();
SDL_RenderPresent(gRenderer);
SDL_Delay(1500);
}
mGetReady = false;
}
}
//Bucle para el titulo del juego
void GameDirector::runTitle()
{
//Si la música no está sonando
if (Mix_PlayingMusic() == 0)
{
//Reproduce la música
Mix_PlayMusic(gTitleMusic, -1);
}
//Comprueba los eventos que hay en la cola
while (SDL_PollEvent(&eventHandler) != 0)
{
//Evento de salida de la aplicación
if (eventHandler.type == SDL_QUIT)
{
setGameStatus(GAME_STATE_QUIT);
}
}
//Limpia la pantalla
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(gRenderer);
//Dibuja los objetos
titleBackground.render();
menuTitle.render(whiteText);
//Actualiza la pantalla
SDL_RenderPresent(gRenderer);
//Comprueba las entradas para el menu
checkMenuInput(&menuTitle);
//Comprueba si se ha seleccionado algún item del menú
switch (menuTitle.getItemSelected())
{
case 0:
setGameStatus(GAME_STATE_PLAYING);
menuTitle.resetMenu();
renderTransition(1);
Mix_HaltMusic();
SDL_Delay(1200);
break;
case 1:
setGameStatus(GAME_STATE_QUIT);
menuTitle.resetMenu();
renderTransition(1);
Mix_HaltMusic();
break;
default:
break;
}
}
//Bucle para el juego
void GameDirector::runGame()
{
//Si la música no está sonando
if (Mix_PlayingMusic() == 0)
{
//Reproduce la música
Mix_PlayMusic(gPlayingMusic, -1);
}
//Lógica del juego
//Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
if (SDL_GetTicks() - mOldTicks > mGameSpeed)
{
//Actualiza el contador de ticks
mOldTicks = SDL_GetTicks();
//Comprueba el teclado/mando
checkGameInput();
//Comprueba los eventos que hay en la cola
while (SDL_PollEvent(&eventHandler) != 0)
{
//Evento de salida de la aplicación
if (eventHandler.type == SDL_QUIT)
{
setGameStatus(GAME_STATE_QUIT);
}
//Tecla T pulsada
if (eventHandler.key.keysym.sym == SDLK_t)
{
//startAllBalloons();
popBalloon(0);
break;
}
#ifdef TEST
//W key pressed
if (eventHandler.key.keysym.sym == SDLK_w)
{
bulletTest.setPosY(bulletTest.getPosY() - 1);
bulletTest.testMove();
break;
}
//S key pressed
if (eventHandler.key.keysym.sym == SDLK_s)
{
bulletTest.setPosY(bulletTest.getPosY() + 1);
bulletTest.testMove();
break;
}
//A key pressed
if (eventHandler.key.keysym.sym == SDLK_a)
{
bulletTest.setPosX(bulletTest.getPosX() - 1);
bulletTest.testMove();
break;
}
//D key pressed
if (eventHandler.key.keysym.sym == SDLK_d)
{
bulletTest.setPosX(bulletTest.getPosX() + 1);
bulletTest.testMove();
break;
}
#endif
}
//Actualiza el jugador
player.update();
//Mueve los globos
moveBalloons();
#ifdef TEST
balloonTest.move();
#endif
//Mueve las balas
moveBullets();
//Procesa las colisiones entre globos y balas
processBulletBallonCollision();
//Comprueba el nivel de amenaza
checkMenaceLevel();
//Comprueba la colisión entre el jugador y los globos
if (checkPlayerBallonCollision())
{
//stopAllBalloons();
}
}
//Limpia la pantalla
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(gRenderer);
//Dibuja los objetos
gameBackground.render();
renderBalloons();
#ifdef TEST
balloonTest.render();
bulletTest.render();
if (checkCollision(balloonTest.getCollider(), bulletTest.getCollider()))
{
whiteText.write(0, 0, "X");
}
#endif
//whiteText.write(0, 0, std::to_string(mMenaceLevelThreshold));
//whiteText.write(0, BLOCK, std::to_string(player.getPosX() + player.getWidth()));
renderBullets();
player.render();
renderScoreBoard(whiteText);
renderGetReady();
//Actualiza la pantalla
SDL_RenderPresent(gRenderer);
}
//Bucle para el menu de pausa del juego
void GameDirector::runPausedGame()
{
//Comprueba los eventos que hay en la cola
while (SDL_PollEvent(&eventHandler) != 0)
{
//Evento de salida de la aplicación
if (eventHandler.type == SDL_QUIT)
{
setGameStatus(GAME_STATE_QUIT);
}
}
//Dibuja los objetos
gameBackground.render();
renderBalloons();
renderBullets();
player.render();
renderScoreBoard(whiteText);
menuPause.render(whiteText);
//Limpia la pantalla
SDL_RenderPresent(gRenderer);
//Comprueba las entradas para el menu
checkMenuInput(&menuPause);
//Comprueba si se ha seleccionado algún item del menú
switch (menuPause.getItemSelected())
{
case 0:
setGameStatus(GAME_STATE_PLAYING);
menuPause.resetMenu();
break;
case 1:
setGameStatus(GAME_STATE_TITLE);
menuPause.resetMenu();
renderTransition(1);
init();
break;
default:
break;
}
}

190
gamedirector.h Normal file
View File

@@ -0,0 +1,190 @@
#include "player.h"
#include "balloon.h"
#include "bullet.h"
#include "background.h"
#include "text.h"
#include "menu.h"
#ifndef GAMEDIRECTOR_H
#define GAMEDIRECTOR_H
//GameDirector
class GameDirector
{
public:
//Constructor
GameDirector();
//Iniciador
void init();
//Hace una pausa de milisegundos
void sleep(Uint16 time);
//Establece el valor de la variable
void setScore(Uint32 score);
//Establece el valor de la variable
void setHiScore(Uint32 score);
//Actualiza el valor de HiScore en caso necesario
void updateHiScore();
//Transforma un valor numérico en una cadena de 6 cifras
std::string updateScoreText(Uint32 num);
//Pinta el marcador en pantalla usando un objeto texto
void renderScoreBoard(Text &text);
//Mueve todos los globos activos
void moveBalloons();
//Pinta en pantalla todos los globos activos
void renderBalloons();
//Devuelve el primer indice no activo del vector de globos
Uint8 getBallonFreeIndex();
//Crea un globo nuevo en el vector de globos
Uint8 createNewBalloon(int x, int y, Uint8 kind, float velx, Uint16 stoppedtimer);
//Establece a cero todos los valores del vector de objetos globo
void resetBalloons();
//Explosiona un globo. Lo destruye y crea otros dos si es el caso
void popBalloon(Uint8 index);
//Detiene todos los globos
void stopAllBalloons();
//Pone en marcha todos los globos
void startAllBalloons();
//Obtiene el numero de globos activos
Uint8 countBalloons();
//Comprueba la colisión entre el jugador y los globos activos
bool checkPlayerBallonCollision();
//Comprueba y procesa la colisión entre las balas y los globos
void processBulletBallonCollision();
//Mueve las balas activas
void moveBullets();
//Pinta las balas activas
void renderBullets();
//Devuelve el primer indice no activo del vector de balas
Uint8 getBulletFreeIndex();
//Establece a cero todos los valores del vector de objetos bala
void resetBullets();
//Crea un objeto bala
void createBullet(int x, int y, Uint8 kind);
//Calcula y establece el valor de amenaza en funcion de los globos activos
void calculateMenaceLevel();
//Obtiene el valor de la variable
Uint8 getMenaceLevel();
//Gestiona el nivel de amenaza
void checkMenaceLevel();
//Gestiona la entrada de teclado y mando durante el juego
void checkGameInput();
//Gestiona la entrada de teclado y mando durante el menu
void checkMenuInput(Menu* menu);
//Obtiene el valor de la variable
Uint8 getGameStatus();
//Establece el valor de la variable
void setGameStatus(Uint8 status);
//Pinta una transición en pantalla
void renderTransition(Uint8 index);
//Pinta el texto GetReady en pantalla
void renderGetReady();
//Bucle para el titulo del juego
void runTitle();
//Bucle para el juego
void runGame();
//Bucle para el menu de pausa del juego
void runPausedGame();
private:
//Manejador de eventos
SDL_Event eventHandler;
//El jugador
Player player;
//Vector con los objetos globo
Balloon balloon[50];
#ifdef TEST
Balloon balloonTest;
Bullet bulletTest;
#endif
//Vector con los objetos bala
Bullet bullet[50];
//Fondo del juego
Background gameBackground;
//Fondo de la pantalla de titulo
Background titleBackground;
//Texto blanco
Text whiteText;
//Texto negro
Text blackText;
//Menu de la pantalla de título
Menu menuTitle;
//Menú de la pantalla de pausa
Menu menuPause;
//Indicador para el bucle principal
Uint8 mGameStatus;
//Puntuación actual y puntuación máxima
Uint32 mScore;
Uint32 mHiScore;
//Cadena de texto con la puntuación actual y la puntuación máxima de 6 cifras
std::string mScoreText;
std::string mHiScoreText;
//Número máximo de globos y balas que puede almacenar el vector
Uint8 mMaxBalloons;
Uint8 mMaxBullets;
//Contador de ticks para ajustar la velocidad del juego
Uint32 mOldTicks;
//Velocidad a la que se repite el bucle de juego
Uint8 mGameSpeed;
//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 ha de aparecer el texto de GetReady en pantalla
bool mGetReady;
};
#endif

37
globals.h Normal file
View File

@@ -0,0 +1,37 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include "ltexture.h"
#ifndef GLOBALS_H
#define GLOBALS_H
//La ventana donde dibujamos
SDL_Window *gWindow = NULL;
//El renderizador de la ventana
SDL_Renderer *gRenderer = NULL;
//Texturas con gráficos
LTexture gPlayerTexture;
LTexture gGameBackgroundTexture;
LTexture gTitleBackgroundTexture;
LTexture gWhiteFontTexture;
LTexture gBlackFontTexture;
LTexture gMenuTexture;
LTexture gBalloonTexture;
LTexture gBulletTexture;
LTexture gMiscTexture;
//Manejador para el mando 1
SDL_Joystick* gGameController = NULL;
//Objetos con la música del juego
Mix_Music *gTitleMusic = NULL;
Mix_Music *gPlayingMusic = NULL;
//Objetos con los efectos de sonido del juego
Mix_Chunk *gPopBalloonFX = NULL;
Mix_Chunk *gBulletFX = NULL;
#endif

BIN
libFLAC-8.dll Normal file

Binary file not shown.

BIN
libjpeg-9.dll Normal file

Binary file not shown.

BIN
libmodplug-1.dll Normal file

Binary file not shown.

BIN
libmpg123-0.dll Normal file

Binary file not shown.

BIN
libogg-0.dll Normal file

Binary file not shown.

BIN
libopus-0.dll Normal file

Binary file not shown.

BIN
libopusfile-0.dll Normal file

Binary file not shown.

BIN
libpng16-16.dll Normal file

Binary file not shown.

BIN
libtiff-5.dll Normal file

Binary file not shown.

BIN
libvorbis-0.dll Normal file

Binary file not shown.

BIN
libvorbisfile-3.dll Normal file

Binary file not shown.

BIN
libwebp-7.dll Normal file

Binary file not shown.

141
ltexture.cpp Normal file
View File

@@ -0,0 +1,141 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <string>
#include "const.h"
#include "globals.h"
#include "ltexture.h"
LTexture::LTexture()
{
//Initialize
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
LTexture::~LTexture()
{
//Deallocate
free();
}
bool LTexture::loadFromFile(std::string path)
{
//Get rid of preexisting texture
free();
//The final texture
SDL_Texture *newTexture = NULL;
//Load image at specified path
SDL_Surface *loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
}
else
{
//Color key image
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(gRenderer, loadedSurface);
if (newTexture == NULL)
{
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
else
{
//Get image dimensions
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
//Return success
mTexture = newTexture;
return mTexture != NULL;
}
bool LTexture::createBlank( int width, int height, SDL_TextureAccess access )
{
//Create uninitialized texture
mTexture = SDL_CreateTexture( gRenderer, SDL_PIXELFORMAT_RGBA8888, access, width, height );
if( mTexture == NULL )
{
printf( "Unable to create blank texture! SDL Error: %s\n", SDL_GetError() );
}
else
{
mWidth = width;
mHeight = height;
}
return mTexture != NULL;
}
void LTexture::free()
{
//Free texture if it exists
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void LTexture::setColor(Uint8 red, Uint8 green, Uint8 blue)
{
//Modulate texture rgb
SDL_SetTextureColorMod(mTexture, red, green, blue);
}
void LTexture::setBlendMode(SDL_BlendMode blending)
{
//Set blending function
SDL_SetTextureBlendMode(mTexture, blending);
}
void LTexture::setAlpha(Uint8 alpha)
{
//Modulate texture alpha
SDL_SetTextureAlphaMod(mTexture, alpha);
}
void LTexture::render(int x, int y, SDL_Rect *clip, double angle, SDL_Point *center, SDL_RendererFlip flip)
{
//Set rendering space and render to screen
SDL_Rect renderQuad = {x, y, mWidth, mHeight};
//Set clip rendering dimensions
if (clip != NULL)
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopyEx(gRenderer, mTexture, clip, &renderQuad, angle, center, flip);
}
void LTexture::setAsRenderTarget()
{
//Make self render target
SDL_SetRenderTarget( gRenderer, mTexture );
}
int LTexture::getWidth()
{
return mWidth;
}
int LTexture::getHeight()
{
return mHeight;
}

66
ltexture.h Normal file
View File

@@ -0,0 +1,66 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <string>
#ifndef LTEXTURE_H
#define LTEXTURE_H
//Texture wrapper class
class LTexture
{
public:
//Initializes variables
LTexture();
//Deallocates memory
~LTexture();
//Loads image at specified path
bool loadFromFile( std::string path );
//Creates blank texture
bool createBlank( int width, int height, SDL_TextureAccess = SDL_TEXTUREACCESS_STREAMING );
//Deallocates texture
void free();
//Set color modulation
void setColor( Uint8 red, Uint8 green, Uint8 blue );
//Set blending
void setBlendMode( SDL_BlendMode blending );
//Set alpha modulation
void setAlpha( Uint8 alpha );
//Renders texture at given point
void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );
//Set self as render target
void setAsRenderTarget();
//Gets image dimensions
int getWidth();
int getHeight();
//Pixel manipulators
bool lockTexture();
bool unlockTexture();
void* getPixels();
void copyPixels( void* pixels );
int getPitch();
Uint32 getPixel32( unsigned int x, unsigned int y );
private:
//The actual hardware texture
SDL_Texture* mTexture;
void* mPixels;
int mPitch;
//Image dimensions
int mWidth;
int mHeight;
};
#endif

356
main.cpp Normal file
View File

@@ -0,0 +1,356 @@
/*
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.
El programa contine una serie de clases/objetos básicos: la clase sprite
permite dibujar partes de un fichero png en pantalla. La clase spriteanimated
contiene funcionalidad adicional para crear animaciones. La clase text permite
dibujar letras de un png en pantalla a partir de una cadena de texto. La clase
menu permite crear una estructura con diferentes elementos, escribirlos en
pantalla y seleccionar uno de ellos.
A continuación tenemos las clases enfocadas a la lógica del juego, la clase player
contiene la información del jugador, la clase balloon la de los enemigos y la
clase bullet para las balas que dispara el jugador. La clase background es
muy simple y sirve para pintar el fondo de la pantalla. Por ultimo, la clase
gamedirector es la que realiza toda la lógica y se encarga de hacer interactuar
al resto de objetos entre si.
El objeto gamedirector tiene tres estados: titulo, juego y pausa. Segun su estado
el bucle que recorre es distinto. En el bucle juego, el objeto gamedirector
tiene un objeto jugador, un vector con los objetos globo y un vector con los
objetos bala. Se encarga de comprobar las entradas de teclado o gamepad para
cerrar la aplicacion, saltar al estado de pausa y para mover al jugador. Recorre
el vector de globos y de balas y si tienen algun tipo asignado las gestiona.
Comprueba las colisiones entre los globos y el jugador y entre las balas y los
globos. Tiene ademas un nivel de amenaza que calcula en funcion del numero de globos
en pantalla y que se va incrementando conforme aumenta la puntuación del jugador.
Los objetos globo tienen varios contadores para alternar de un estado a otro.
En los vectores que contienen objetos, se considera activos los objetos que tienen
un tipo asociado diferente a NO_KIND
*/
#define TEST_
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include <stdio.h>
#include <string>
#include "const.h"
#include "struct.h"
#include "ltexture.h"
#include "globals.h"
#include "sprite.h"
#include "spriteanimated.h"
#include "player.h"
#include "balloon.h"
#include "bullet.h"
#include "background.h"
#include "text.h"
#include "menu.h"
#include "gamedirector.h"
#include "ltexture.cpp"
#include "sprite.cpp"
#include "spriteanimated.cpp"
#include "player.cpp"
#include "balloon.cpp"
#include "bullet.cpp"
#include "background.cpp"
#include "text.cpp"
#include "menu.cpp"
#include "gamedirector.cpp"
//Arranca SDL y crea la ventana
bool init();
//Carga todos los recursos
bool loadMedia();
//Libera todos los recursos y cierra SDL
void close();
//Arranca SDL y crea la ventana
bool init()
{
//Indicador de inicialización
bool success = true;
//Inicializa SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Establece el filtro de la textura a nearest
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"))
{
printf("Warning: Nearest texture filtering not enabled!");
}
//Inicializa SDL_mixer
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0)
{
printf("SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError());
success = false;
}
//Comprueba los mandos
if (SDL_NumJoysticks() < 1)
{
printf("Warning: No joysticks connected!\n");
}
else
{
//Carga el mando
gGameController = SDL_JoystickOpen(0);
if (gGameController == NULL)
{
printf("Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError());
}
printf("%i joysticks were found.\n", SDL_NumJoysticks());
std::cout << SDL_JoystickNumButtons(gGameController) << " buttons\n";
}
//Crea la ventana
gWindow = SDL_CreateWindow("Super Popping (Like Loc) in Jailers World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VIEW_WIDTH, VIEW_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Crea un renderizador para la ventana con vsync
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (gRenderer == NULL)
{
printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Inicializa el color de renderizado
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);
//Establece el tamaño del buffer de renderizado
SDL_RenderSetLogicalSize(gRenderer, SCREEN_WIDTH, SCREEN_HEIGHT);
//Inicializa el cargador de PNG
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
success = false;
}
}
}
}
return success;
}
//Carga todos los recursos
bool loadMedia()
{
//Indicador de éxito en la carga
bool success = true;
//Carga los gráficos del jugador
if (!gPlayerTexture.loadFromFile("media/gfx/player.png"))
{
printf("Failed to load player texture!\n");
success = false;
}
//Carga los gráficos de los globos
if (!gBalloonTexture.loadFromFile("media/gfx/balloon.png"))
{
printf("Failed to load balloon texture!\n");
success = false;
}
//Carga los gráficos de las balas
if (!gBulletTexture.loadFromFile("media/gfx/bullet.png"))
{
printf("Failed to load bullet texture!\n");
success = false;
}
//Carga los gráficos del fondo del juego
if (!gGameBackgroundTexture.loadFromFile("media/gfx/background.png"))
{
printf("Failed to load game background texture!\n");
success = false;
}
//Carga los gráficos del fondo de la pantalla de titulo
if (!gTitleBackgroundTexture.loadFromFile("media/gfx/title.png"))
{
printf("Failed to load title texture!\n");
success = false;
}
//Carga varios gráficos para varios propósitos
if (!gMiscTexture.loadFromFile("media/gfx/misc.png"))
{
printf("Failed to load misc texture!\n");
success = false;
}
//Carga los gráficos para el menu
if (!gMenuTexture.loadFromFile("media/gfx/menu.png"))
{
printf("Failed to load menu texture!\n");
success = false;
}
//Carga los gráficos para el texto blanco
if (!gWhiteFontTexture.loadFromFile("media/gfx/white_font.png"))
{
printf("Failed to load white font texture!\n");
success = false;
}
//Carga los gráficos para el texto negro
if (!gBlackFontTexture.loadFromFile("media/gfx/black_font.png"))
{
printf("Failed to load black font texture!\n");
success = false;
}
//Carga la música del titulo
gTitleMusic = Mix_LoadMUS("media/music/title.ogg");
if (gTitleMusic == NULL)
{
printf("Failed to load title music! SDL_mixer Error: %s\n", Mix_GetError());
success = false;
}
//Carga la música del juego
gPlayingMusic = Mix_LoadMUS("media/music/playing.ogg");
if (gPlayingMusic == NULL)
{
printf("Failed to load playing music! SDL_mixer Error: %s\n", Mix_GetError());
success = false;
}
//Carga los efectos de sonido para la explosión de los globos
gPopBalloonFX = Mix_LoadWAV("media/sound/balloon.wav");
if (gPopBalloonFX == NULL)
{
printf("Failed to load balloon sound effect! SDL_mixer Error: %s\n", Mix_GetError());
success = false;
}
//Carga los efectos de sonido para los disparos del jugador
gBulletFX = Mix_LoadWAV("media/sound/bullet.wav");
if (gBulletFX == NULL)
{
printf("Failed to load bullet sound effect! SDL_mixer Error: %s\n", Mix_GetError());
success = false;
}
return success;
}
//Libera todos los recursos y cierra SDL
void close()
{
//Libera todas las imagenes
gPlayerTexture.free();
gGameBackgroundTexture.free();
gTitleBackgroundTexture.free();
gWhiteFontTexture.free();
gBlackFontTexture.free();
gMenuTexture.free();
gBalloonTexture.free();
gMiscTexture.free();
//Libera los efectos de sonido
Mix_FreeChunk(gPopBalloonFX);
Mix_FreeChunk(gBulletFX);
gPopBalloonFX = NULL;
gBulletFX = NULL;
//Libra la música
Mix_FreeMusic(gTitleMusic);
gTitleMusic = NULL;
Mix_FreeMusic(gPlayingMusic);
gPlayingMusic = NULL;
//Libera el mando
SDL_JoystickClose(gGameController);
gGameController = NULL;
//Destruye la ventana
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
gWindow = NULL;
gRenderer = NULL;
//Sal del subsistema SDL
IMG_Quit();
SDL_Quit();
}
int main(int argc, char *args[])
{
//Arranca SDL y crea la ventana
if (!init())
{
printf("Failed to initialize!\n");
return -1;
}
else
{
//Carga los recursos
if (!loadMedia())
{
printf("Failed to load media!\n");
}
else
{
//Crea el objeto gameDirector
GameDirector gameDirector;
//Inicializa el objeto gameDirector
gameDirector.init();
#ifdef TEST
gameDirector.resetBalloons();
#endif
//Mientras no se quiera salir del juego
while (!(gameDirector.getGameStatus() == GAME_STATE_QUIT))
{
switch (gameDirector.getGameStatus())
{
case GAME_STATE_TITLE:
gameDirector.runTitle();
break;
case GAME_STATE_PLAYING:
gameDirector.runGame();
break;
case GAME_STATE_PAUSED:
gameDirector.runPausedGame();
break;
}
}
}
//Libera todos los recursos y cierra SDL
close();
return 0;
}
}

BIN
media/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,10 @@
The assets in this repository are created at Sparklin Labs by Pixel-boy: https://twitter.com/2pblog1
Their creation is funded by your support on Patreon (http://patreon.com/SparklinLabs) and through donations (http://sparklinlabs.itch.io/superpowers) Thanks!
Originally downloaded from https://github.com/sparklinlabs/superpowers-asset-packs
Attribution/Licensing:
Creative Commons Zero: http://creativecommons.org/publicdomain/zero/1.0/
Attribution is not required but appreciated. Placing a link to http://superpowers-html5.com/ somewhere would be awesome :)
Also available at http://opengameart.org/content/superpowers-assets-bitmap-fonts

View File

@@ -0,0 +1,116 @@
CC0 1.0 Universal
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.
For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

BIN
media/gfx/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
media/gfx/balloon.aseprite Normal file

Binary file not shown.

BIN
media/gfx/balloon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

BIN
media/gfx/black_font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
media/gfx/bullet.aseprite Normal file

Binary file not shown.

BIN
media/gfx/bullet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

BIN
media/gfx/menu.aseprite Normal file

Binary file not shown.

BIN
media/gfx/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

BIN
media/gfx/misc.aseprite Normal file

Binary file not shown.

BIN
media/gfx/misc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

BIN
media/gfx/player.aseprite Normal file

Binary file not shown.

BIN
media/gfx/player.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
media/gfx/title.aseprite Normal file

Binary file not shown.

BIN
media/gfx/title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

BIN
media/gfx/white_font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
media/music/.DS_Store vendored Normal file

Binary file not shown.

BIN
media/music/playing.ogg Normal file

Binary file not shown.

BIN
media/music/title.ogg Normal file

Binary file not shown.

BIN
media/resources/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

BIN
media/resources/balloon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backingScale</key>
<real>1</real>
<key>mode</key>
<integer>0</integer>
<key>shapeSelectionFilename</key>
<string>shapeSelection</string>
<key>size</key>
<data>
NC10UHpTVFAQAAAAQCAAAAAAAABAIgAAAAAAAA==
</data>
<key>softness</key>
<real>0.0</real>
<key>timestamp</key>
<real>617963639.40729403</real>
<key>transform</key>
<array>
<real>1</real>
<real>0.0</real>
<real>0.0</real>
<real>1</real>
<real>0.0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.0</real>
</array>
<key>version</key>
<integer>2</integer>
</dict>
</plist>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backingScale</key>
<real>1</real>
<key>pathFilename</key>
<string>path</string>
<key>version</key>
<integer>1</integer>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show More