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="OPTION_SCOPE" value="private" />
<option name="OPEN_IN_BROWSER" value="false" /> <option name="OPEN_IN_BROWSER" value="false" />
</component> </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" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </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 @Override
public void update(Graphics g) { public void update(Graphics g) {
// Set the text font // Don't replace with foreach because it can cause a race condition
//g.setFont(new Font("monospaced", Font.BOLD, 10)); //noinspection ForLoopReplaceableByForEach
for (int i = 0; i < textures.size(); i++) {
for (BufferedImage tile : textures) { BufferedImage texture = textures.get(i);
if (tile != null) { if (texture != null) {
g.drawImage(tile, xPixels, yPixels, 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"); sound = new Sound("/snd/GetKey.wav");
sounds.put(Sound.SoundType.GET_KEY, sound); sounds.put(Sound.SoundType.GET_KEY, sound);
sound = new Sound("/snd/Success.wav");
sounds.put(Sound.SoundType.SUCCESS, sound);
} }
catch (SoundException e) { catch (SoundException e) {
logger.warning(e.getMessage()); logger.warning(e.getMessage());

View File

@ -23,6 +23,7 @@ import cl.cromer.azaraka.sprite.Animation;
import cl.cromer.azaraka.sprite.AnimationException; import cl.cromer.azaraka.sprite.AnimationException;
import javax.sound.sampled.Clip; import javax.sound.sampled.Clip;
import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
@ -201,7 +202,7 @@ public class Lienzo extends Canvas implements Constantes {
case 2: case 2:
try { try {
keyAnimation = escenario.getSprites().get(Animation.SpriteType.KEY); keyAnimation = escenario.getSprites().get(Animation.SpriteType.KEY);
keyAnimation.setFrame(4); keyAnimation.setCurrentFrame(4);
graphicBuffer.drawImage(keyAnimation.getFrame(), 69, 8, null); graphicBuffer.drawImage(keyAnimation.getFrame(), 69, 8, null);
} }
catch (AnimationException e) { catch (AnimationException e) {
@ -211,7 +212,7 @@ public class Lienzo extends Canvas implements Constantes {
try { try {
if (keyAnimation == null) { if (keyAnimation == null) {
keyAnimation = escenario.getSprites().get(Animation.SpriteType.KEY); keyAnimation = escenario.getSprites().get(Animation.SpriteType.KEY);
keyAnimation.setFrame(4); keyAnimation.setCurrentFrame(4);
} }
graphicBuffer.drawImage(keyAnimation.getFrame(), 40, 8, null); 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); Animation heartAnimation = escenario.getSprites().get(Animation.SpriteType.HEART);
if (health >= 4) { if (health >= 4) {
try { try {
heartAnimation.setFrame(4); heartAnimation.setCurrentFrame(4);
} }
catch (AnimationException e) { catch (AnimationException e) {
logger.warning(e.getMessage()); logger.warning(e.getMessage());
@ -238,7 +239,7 @@ public class Lienzo extends Canvas implements Constantes {
} }
else { else {
try { try {
heartAnimation.setFrame(health); heartAnimation.setCurrentFrame(health);
} }
catch (AnimationException e) { catch (AnimationException e) {
logger.warning(e.getMessage()); logger.warning(e.getMessage());
@ -261,33 +262,11 @@ public class Lienzo extends Canvas implements Constantes {
if (gameOver) { if (gameOver) {
if (!gameOverRan) { if (!gameOverRan) {
try { stopBackgroundMusic();
if (backgroundMusic.isPlaying()) {
backgroundMusic.stop();
backgroundMusicThread.interrupt();
}
}
catch (SoundException e) {
logger.warning(e.getMessage());
}
new Thread(escenario.getSounds().get(Sound.SoundType.GAME_OVER)).start(); new Thread(escenario.getSounds().get(Sound.SoundType.GAME_OVER)).start();
// Stop all the active threads 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());
}
}
}
gameOverRan = true; gameOverRan = true;
} }
@ -312,6 +291,51 @@ public class Lienzo extends Canvas implements Constantes {
g.drawImage(imageBuffer, 0, 0, null); 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 * Change the speed of the enemies
* *
@ -350,6 +374,15 @@ public class Lienzo extends Canvas implements Constantes {
return player; return player;
} }
/**
* Get the portal
*
* @return Returns the portal object
*/
public Portal getPortal() {
return portal;
}
/** /**
* Get a list of the keys that exist * 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) { else if (state == State.CLOSED) {
logger.info("Chest is closed"); logger.info("Chest is closed");
try { try {
getCelda().getAnimation().setFrame(0); getCelda().getAnimation().setCurrentFrame(0);
} }
catch (AnimationException e) { catch (AnimationException e) {
logger.warning(e.getMessage()); logger.warning(e.getMessage());
@ -85,7 +85,7 @@ public class Chest extends Object implements Constantes {
private void animate() { private void animate() {
try { try {
getCelda().getAnimation().getNextFrame(); getCelda().getAnimation().getNextFrame();
if (getCelda().getAnimation().getFrameNumber() == getCelda().getAnimation().getFrameCount() - 1) { if (getCelda().getAnimation().getCurrentFrame() == getCelda().getAnimation().getFrameCount() - 1) {
setState(State.OPENED); setState(State.OPENED);
} }
} }

View File

@ -125,6 +125,9 @@ public class Player extends Object implements Constantes {
getEscenario().getCeldas()[x][y].setAnimation(null); getEscenario().getCeldas()[x][y].setAnimation(null);
setY(getY() - 1); setY(getY() - 1);
} }
else if (type == Celda.Type.PORTAL && getEscenario().getCanvas().getPortal().getState() == Portal.State.ACTIVE) {
getEscenario().getCanvas().win();
}
else { else {
if (changeDirection(Animation.Direction.UP)) { if (changeDirection(Animation.Direction.UP)) {
try { try {
@ -156,35 +159,50 @@ public class Player extends Object implements Constantes {
int y = getY(); int y = getY();
logger.info("Down key pressed"); logger.info("Down key pressed");
Celda.Type type = getEscenario().getCeldas()[x][y + 1].getType(); Celda.Type type = getEscenario().getCeldas()[x][y + 1].getType();
if (y < (VERTICAL_CELLS - 1) && (type == Celda.Type.SPACE || type == Celda.Type.KEY)) { if (y < (VERTICAL_CELLS - 1)) {
if (type == Celda.Type.KEY) { if (type == Celda.Type.SPACE || type == Celda.Type.KEY) {
for (Key key : getEscenario().getCanvas().getKeys()) { if (type == Celda.Type.KEY) {
if (key.checkPosition(x, y + 1)) { for (Key key : getEscenario().getCanvas().getKeys()) {
// Get the key if (key.checkPosition(x, y + 1)) {
getKey(key); // Get the key
// Remove the key from the cell getKey(key);
getEscenario().getCeldas()[x][y + 1].setType(Celda.Type.SPACE); // Remove the key from the cell
getEscenario().getCeldas()[x][y + 1].setAnimation(null); getEscenario().getCeldas()[x][y + 1].setType(Celda.Type.SPACE);
break; 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 { else {
if (changeDirection(Animation.Direction.DOWN)) { if (changeDirection(Animation.Direction.DOWN)) {
@ -237,6 +255,9 @@ public class Player extends Object implements Constantes {
getEscenario().getCeldas()[x][y].setAnimation(null); getEscenario().getCeldas()[x][y].setAnimation(null);
setX(getX() - 1); setX(getX() - 1);
} }
else if (type == Celda.Type.PORTAL && getEscenario().getCanvas().getPortal().getState() == Portal.State.ACTIVE) {
getEscenario().getCanvas().win();
}
else { else {
if (changeDirection(Animation.Direction.LEFT)) { if (changeDirection(Animation.Direction.LEFT)) {
try { 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(); int y = getY();
logger.info("Right key pressed"); logger.info("Right key pressed");
Celda.Type type = getEscenario().getCeldas()[x + 1][y].getType(); Celda.Type type = getEscenario().getCeldas()[x + 1][y].getType();
if (x < (HORIZONTAL_CELLS - 1) && (type == Celda.Type.SPACE || type == Celda.Type.KEY)) { if (x < (HORIZONTAL_CELLS - 1)) {
if (type == Celda.Type.KEY) { if (type == Celda.Type.SPACE || type == Celda.Type.KEY) {
for (Key key : getEscenario().getCanvas().getKeys()) { if (type == Celda.Type.KEY) {
if (key.checkPosition(x + 1, y)) { for (Key key : getEscenario().getCanvas().getKeys()) {
// Get the key if (key.checkPosition(x + 1, y)) {
getKey(key); // Get the key
// Remove the key from the cell getKey(key);
getEscenario().getCeldas()[x + 1][y].setType(Celda.Type.SPACE); // Remove the key from the cell
getEscenario().getCeldas()[x + 1][y].setAnimation(null); getEscenario().getCeldas()[x + 1][y].setType(Celda.Type.SPACE);
break; 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 { else {
if (changeDirection(Animation.Direction.RIGHT)) { if (changeDirection(Animation.Direction.RIGHT)) {
@ -356,17 +402,23 @@ public class Player extends Object implements Constantes {
gainHealth(1); gainHealth(1);
int openedChests = 0;
for (Chest chest : getEscenario().getCanvas().getChests()) { for (Chest chest : getEscenario().getCanvas().getChests()) {
if (chest.checkPosition(x, y - 1)) { if (chest.checkPosition(x, y - 1)) {
if (chest.getState() == Chest.State.OPENED) { if (chest.getState() == Chest.State.CLOSED) {
return; 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.Celda;
import cl.cromer.azaraka.Constantes; import cl.cromer.azaraka.Constantes;
import cl.cromer.azaraka.Escenario; import cl.cromer.azaraka.Escenario;
import cl.cromer.azaraka.sprite.Animation;
import cl.cromer.azaraka.sprite.AnimationException; import cl.cromer.azaraka.sprite.AnimationException;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -26,10 +27,15 @@ import java.util.logging.Logger;
* This class handles the portal functionality * This class handles the portal functionality
*/ */
public class Portal extends Object implements Constantes { public class Portal extends Object implements Constantes {
/**
* The current state of the portal
*/
private State state = State.INACTIVE;
/** /**
* The logger * The logger
*/ */
private Logger logger; private Logger logger;
/** /**
* Initialize the portal * 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 * 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 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; private Logger logger;
/**
* Get the frame number
* @return The current frame number
*/
public int getFrameNumber() {
return currentFrame;
}
/** /**
* Initialize the sprite * Initialize the sprite
*/ */
@ -230,19 +222,40 @@ public class Animation implements Cloneable, Constantes {
ACTIVE_PORTAL 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 * Set which frame is to be shown in the sprite manually
* *
* @param frame The frame to show * @param frame The frame to show
* @throws AnimationException Thrown if the frame number does not exist * @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; ArrayList<BufferedImage> images;
if (imageHash.containsKey(currentDirection)) { if (imageHash.containsKey(currentDirection)) {
images = imageHash.get(currentDirection); images = imageHash.get(currentDirection);
} }
else { else {
throw new AnimationException("The direction has no images assigned!"); throw new AnimationException("There is no direction assigned to the animation");
} }
if (frame < 0) { if (frame < 0) {
@ -257,16 +270,14 @@ public class Animation implements Cloneable, Constantes {
/** /**
* Returns the next frame in the sprite * 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 * @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(); ArrayList<BufferedImage> images = getImagesFromHash();
currentFrame++; currentFrame++;
if (currentFrame >= images.size()) { if (currentFrame >= images.size()) {
currentFrame = 0; currentFrame = 0;
} }
return images.get(currentFrame);
} }
/** /**