Add success music

Make portal able to switch between active and inactive
Make game "winnable"

Signed-off-by: Chris Cromer <chris@cromer.cl>
This commit is contained in:
Chris Cromer 2019-09-29 18:38:03 -03:00
parent cc42ae71d2
commit e38fca75b6
10 changed files with 261 additions and 108 deletions

View File

@ -5,7 +5,7 @@
<option name="OPTION_SCOPE" value="private" />
<option name="OPEN_IN_BROWSER" value="false" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11 OpenJDK" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8 Oracle" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

BIN
res/snd/Success.wav Normal file

Binary file not shown.

View File

@ -168,12 +168,12 @@ public class Celda extends JComponent implements Constantes {
*/
@Override
public void update(Graphics g) {
// Set the text font
//g.setFont(new Font("monospaced", Font.BOLD, 10));
for (BufferedImage tile : textures) {
if (tile != null) {
g.drawImage(tile, xPixels, yPixels, null);
// Don't replace with foreach because it can cause a race condition
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < textures.size(); i++) {
BufferedImage texture = textures.get(i);
if (texture != null) {
g.drawImage(texture, xPixels, yPixels, null);
}
}

View File

@ -585,6 +585,9 @@ public class Escenario extends JComponent implements Constantes {
sound = new Sound("/snd/GetKey.wav");
sounds.put(Sound.SoundType.GET_KEY, sound);
sound = new Sound("/snd/Success.wav");
sounds.put(Sound.SoundType.SUCCESS, sound);
}
catch (SoundException e) {
logger.warning(e.getMessage());

View File

@ -23,6 +23,7 @@ import cl.cromer.azaraka.sprite.Animation;
import cl.cromer.azaraka.sprite.AnimationException;
import javax.sound.sampled.Clip;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
@ -201,7 +202,7 @@ public class Lienzo extends Canvas implements Constantes {
case 2:
try {
keyAnimation = escenario.getSprites().get(Animation.SpriteType.KEY);
keyAnimation.setFrame(4);
keyAnimation.setCurrentFrame(4);
graphicBuffer.drawImage(keyAnimation.getFrame(), 69, 8, null);
}
catch (AnimationException e) {
@ -211,7 +212,7 @@ public class Lienzo extends Canvas implements Constantes {
try {
if (keyAnimation == null) {
keyAnimation = escenario.getSprites().get(Animation.SpriteType.KEY);
keyAnimation.setFrame(4);
keyAnimation.setCurrentFrame(4);
}
graphicBuffer.drawImage(keyAnimation.getFrame(), 40, 8, null);
}
@ -230,7 +231,7 @@ public class Lienzo extends Canvas implements Constantes {
Animation heartAnimation = escenario.getSprites().get(Animation.SpriteType.HEART);
if (health >= 4) {
try {
heartAnimation.setFrame(4);
heartAnimation.setCurrentFrame(4);
}
catch (AnimationException e) {
logger.warning(e.getMessage());
@ -238,7 +239,7 @@ public class Lienzo extends Canvas implements Constantes {
}
else {
try {
heartAnimation.setFrame(health);
heartAnimation.setCurrentFrame(health);
}
catch (AnimationException e) {
logger.warning(e.getMessage());
@ -261,33 +262,11 @@ public class Lienzo extends Canvas implements Constantes {
if (gameOver) {
if (!gameOverRan) {
try {
if (backgroundMusic.isPlaying()) {
backgroundMusic.stop();
backgroundMusicThread.interrupt();
}
}
catch (SoundException e) {
logger.warning(e.getMessage());
}
stopBackgroundMusic();
new Thread(escenario.getSounds().get(Sound.SoundType.GAME_OVER)).start();
// Stop all the active threads
for (Map.Entry<Object, Thread> entry : threads.entrySet()) {
Thread thread = entry.getValue();
if (thread.isAlive()) {
Object object = entry.getKey();
object.setActive(false);
thread.interrupt();
try {
thread.join();
}
catch (InterruptedException e) {
logger.info(e.getMessage());
}
}
}
stopThreads();
gameOverRan = true;
}
@ -312,6 +291,51 @@ public class Lienzo extends Canvas implements Constantes {
g.drawImage(imageBuffer, 0, 0, null);
}
private void stopBackgroundMusic() {
try {
if (backgroundMusic.isPlaying()) {
backgroundMusic.stop();
backgroundMusicThread.interrupt();
}
}
catch (SoundException e) {
logger.warning(e.getMessage());
}
}
/**
* Stop all active threads
*/
private void stopThreads() {
for (Map.Entry<Object, Thread> entry : threads.entrySet()) {
Thread thread = entry.getValue();
if (thread.isAlive()) {
Object object = entry.getKey();
object.setActive(false);
thread.interrupt();
try {
thread.join();
}
catch (InterruptedException e) {
logger.info(e.getMessage());
}
}
}
}
/**
* Called when the game is won
*/
public void win() {
stopBackgroundMusic();
new Thread(escenario.getSounds().get(Sound.SoundType.SUCCESS)).start();
stopThreads();
JOptionPane.showMessageDialog(null, "Ganaste!");
System.exit(0);
}
/**
* Change the speed of the enemies
*
@ -350,6 +374,15 @@ public class Lienzo extends Canvas implements Constantes {
return player;
}
/**
* Get the portal
*
* @return Returns the portal object
*/
public Portal getPortal() {
return portal;
}
/**
* Get a list of the keys that exist
*

View File

@ -70,7 +70,7 @@ public class Chest extends Object implements Constantes {
else if (state == State.CLOSED) {
logger.info("Chest is closed");
try {
getCelda().getAnimation().setFrame(0);
getCelda().getAnimation().setCurrentFrame(0);
}
catch (AnimationException e) {
logger.warning(e.getMessage());
@ -85,7 +85,7 @@ public class Chest extends Object implements Constantes {
private void animate() {
try {
getCelda().getAnimation().getNextFrame();
if (getCelda().getAnimation().getFrameNumber() == getCelda().getAnimation().getFrameCount() - 1) {
if (getCelda().getAnimation().getCurrentFrame() == getCelda().getAnimation().getFrameCount() - 1) {
setState(State.OPENED);
}
}

View File

@ -125,6 +125,9 @@ public class Player extends Object implements Constantes {
getEscenario().getCeldas()[x][y].setAnimation(null);
setY(getY() - 1);
}
else if (type == Celda.Type.PORTAL && getEscenario().getCanvas().getPortal().getState() == Portal.State.ACTIVE) {
getEscenario().getCanvas().win();
}
else {
if (changeDirection(Animation.Direction.UP)) {
try {
@ -156,35 +159,50 @@ public class Player extends Object implements Constantes {
int y = getY();
logger.info("Down key pressed");
Celda.Type type = getEscenario().getCeldas()[x][y + 1].getType();
if (y < (VERTICAL_CELLS - 1) && (type == Celda.Type.SPACE || type == Celda.Type.KEY)) {
if (type == Celda.Type.KEY) {
for (Key key : getEscenario().getCanvas().getKeys()) {
if (key.checkPosition(x, y + 1)) {
// Get the key
getKey(key);
// Remove the key from the cell
getEscenario().getCeldas()[x][y + 1].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x][y + 1].setAnimation(null);
break;
if (y < (VERTICAL_CELLS - 1)) {
if (type == Celda.Type.SPACE || type == Celda.Type.KEY) {
if (type == Celda.Type.KEY) {
for (Key key : getEscenario().getCanvas().getKeys()) {
if (key.checkPosition(x, y + 1)) {
// Get the key
getKey(key);
// Remove the key from the cell
getEscenario().getCeldas()[x][y + 1].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x][y + 1].setAnimation(null);
break;
}
}
}
getEscenario().getCeldas()[x][y].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x][y + 1].setType(Celda.Type.PLAYER);
if (changeDirection(Animation.Direction.DOWN)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
getEscenario().getCeldas()[x][y + 1].setAnimation(getEscenario().getCeldas()[x][y].getAnimation());
getEscenario().getCeldas()[x][y].setAnimation(null);
setY(getY() + 1);
}
else if (type == Celda.Type.PORTAL && getEscenario().getCanvas().getPortal().getState() == Portal.State.ACTIVE) {
getEscenario().getCanvas().win();
}
else {
if (changeDirection(Animation.Direction.DOWN)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
}
getEscenario().getCeldas()[x][y].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x][y + 1].setType(Celda.Type.PLAYER);
if (changeDirection(Animation.Direction.DOWN)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
getEscenario().getCeldas()[x][y + 1].setAnimation(getEscenario().getCeldas()[x][y].getAnimation());
getEscenario().getCeldas()[x][y].setAnimation(null);
setY(getY() + 1);
}
else {
if (changeDirection(Animation.Direction.DOWN)) {
@ -237,6 +255,9 @@ public class Player extends Object implements Constantes {
getEscenario().getCeldas()[x][y].setAnimation(null);
setX(getX() - 1);
}
else if (type == Celda.Type.PORTAL && getEscenario().getCanvas().getPortal().getState() == Portal.State.ACTIVE) {
getEscenario().getCanvas().win();
}
else {
if (changeDirection(Animation.Direction.LEFT)) {
try {
@ -248,6 +269,16 @@ public class Player extends Object implements Constantes {
}
}
}
else {
if (changeDirection(Animation.Direction.LEFT)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
}
}
/**
@ -258,35 +289,50 @@ public class Player extends Object implements Constantes {
int y = getY();
logger.info("Right key pressed");
Celda.Type type = getEscenario().getCeldas()[x + 1][y].getType();
if (x < (HORIZONTAL_CELLS - 1) && (type == Celda.Type.SPACE || type == Celda.Type.KEY)) {
if (type == Celda.Type.KEY) {
for (Key key : getEscenario().getCanvas().getKeys()) {
if (key.checkPosition(x + 1, y)) {
// Get the key
getKey(key);
// Remove the key from the cell
getEscenario().getCeldas()[x + 1][y].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x + 1][y].setAnimation(null);
break;
if (x < (HORIZONTAL_CELLS - 1)) {
if (type == Celda.Type.SPACE || type == Celda.Type.KEY) {
if (type == Celda.Type.KEY) {
for (Key key : getEscenario().getCanvas().getKeys()) {
if (key.checkPosition(x + 1, y)) {
// Get the key
getKey(key);
// Remove the key from the cell
getEscenario().getCeldas()[x + 1][y].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x + 1][y].setAnimation(null);
break;
}
}
}
getEscenario().getCeldas()[x][y].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x + 1][y].setType(Celda.Type.PLAYER);
if (changeDirection(Animation.Direction.RIGHT)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
getEscenario().getCeldas()[x + 1][y].setAnimation(getEscenario().getCeldas()[x][y].getAnimation());
getEscenario().getCeldas()[x][y].setAnimation(null);
setX(getX() + 1);
}
else if (type == Celda.Type.PORTAL && getEscenario().getCanvas().getPortal().getState() == Portal.State.ACTIVE) {
getEscenario().getCanvas().win();
}
else {
if (changeDirection(Animation.Direction.RIGHT)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
}
getEscenario().getCeldas()[x][y].setType(Celda.Type.SPACE);
getEscenario().getCeldas()[x + 1][y].setType(Celda.Type.PLAYER);
if (changeDirection(Animation.Direction.RIGHT)) {
try {
getEscenario().getCeldas()[x][y].getAnimation().getNextFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
getEscenario().getCeldas()[x + 1][y].setAnimation(getEscenario().getCeldas()[x][y].getAnimation());
getEscenario().getCeldas()[x][y].setAnimation(null);
setX(getX() + 1);
}
else {
if (changeDirection(Animation.Direction.RIGHT)) {
@ -356,17 +402,23 @@ public class Player extends Object implements Constantes {
gainHealth(1);
int openedChests = 0;
for (Chest chest : getEscenario().getCanvas().getChests()) {
if (chest.checkPosition(x, y - 1)) {
if (chest.getState() == Chest.State.OPENED) {
return;
if (chest.getState() == Chest.State.CLOSED) {
chest.setState(Chest.State.OPENING);
useKey();
}
chest.setState(Chest.State.OPENING);
break;
}
if (chest.getState() == Chest.State.OPENED || chest.getState() == Chest.State.OPENING) {
openedChests++;
}
}
useKey();
// All chests are opened, active portal
if (openedChests == getEscenario().getCanvas().getChests().size()) {
getEscenario().getCanvas().getPortal().setState(Portal.State.ACTIVE);
}
}
}
}

View File

@ -18,6 +18,7 @@ package cl.cromer.azaraka.object;
import cl.cromer.azaraka.Celda;
import cl.cromer.azaraka.Constantes;
import cl.cromer.azaraka.Escenario;
import cl.cromer.azaraka.sprite.Animation;
import cl.cromer.azaraka.sprite.AnimationException;
import java.util.logging.Logger;
@ -26,10 +27,15 @@ import java.util.logging.Logger;
* This class handles the portal functionality
*/
public class Portal extends Object implements Constantes {
/**
* The current state of the portal
*/
private State state = State.INACTIVE;
/**
* The logger
*/
private Logger logger;
/**
* Initialize the portal
*
@ -53,6 +59,50 @@ public class Portal extends Object implements Constantes {
}
}
/**
* Get the current status of the portal
*
* @return Returns the status
*/
public State getState() {
return state;
}
/**
* Sets a new status for the portal
*
* @param state The new status
*/
public void setState(State state) {
this.state = state;
int frame = 0;
try {
frame = getCelda().getAnimation().getCurrentFrame();
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
if (state == State.ACTIVE) {
getCelda().setAnimation(getEscenario().getSprites().get(Animation.SpriteType.ACTIVE_PORTAL));
try {
getCelda().getAnimation().setCurrentFrame(frame);
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
else if (state == State.INACTIVE) {
getCelda().setAnimation(getEscenario().getSprites().get(Animation.SpriteType.INACTIVE_PORTAL));
try {
getCelda().getAnimation().setCurrentFrame(frame);
}
catch (AnimationException e) {
logger.warning(e.getMessage());
}
}
}
/**
* This method is run when the thread starts
*/

View File

@ -214,6 +214,10 @@ public class Sound implements Runnable, Constantes {
/**
* Enemy attack sound
*/
ENEMY_ATTACK
ENEMY_ATTACK,
/**
* Sounds when receiving gem, purifying gem, or winning
*/
SUCCESS
}
}

View File

@ -54,14 +54,6 @@ public class Animation implements Cloneable, Constantes {
*/
private Logger logger;
/**
* Get the frame number
* @return The current frame number
*/
public int getFrameNumber() {
return currentFrame;
}
/**
* Initialize the sprite
*/
@ -230,19 +222,40 @@ public class Animation implements Cloneable, Constantes {
ACTIVE_PORTAL
}
/**
* Get the current frame
*
* @return Returns the current frame
* @throws AnimationException Thrown if there are no frame in the current animation
*/
public int getCurrentFrame() throws AnimationException {
ArrayList<BufferedImage> images;
if (imageHash.containsKey(currentDirection)) {
images = imageHash.get(currentDirection);
if (images.size() == 0) {
throw new AnimationException("The direction has no images assigned!");
}
}
else {
throw new AnimationException("There is no direction assigned to the animation!");
}
return currentFrame;
}
/**
* Set which frame is to be shown in the sprite manually
*
* @param frame The frame to show
* @throws AnimationException Thrown if the frame number does not exist
*/
public void setFrame(int frame) throws AnimationException {
public void setCurrentFrame(int frame) throws AnimationException {
ArrayList<BufferedImage> images;
if (imageHash.containsKey(currentDirection)) {
images = imageHash.get(currentDirection);
}
else {
throw new AnimationException("The direction has no images assigned!");
throw new AnimationException("There is no direction assigned to the animation");
}
if (frame < 0) {
@ -257,16 +270,14 @@ public class Animation implements Cloneable, Constantes {
/**
* Returns the next frame in the sprite
*
* @return Returns the next frame in the sprite
* @throws AnimationException Thrown when there are no images in the sprite
*/
public BufferedImage getNextFrame() throws AnimationException {
public void getNextFrame() throws AnimationException {
ArrayList<BufferedImage> images = getImagesFromHash();
currentFrame++;
if (currentFrame >= images.size()) {
currentFrame = 0;
}
return images.get(currentFrame);
}
/**