Compare commits

..

6 Commits

Author SHA1 Message Date
43212a033b slime runs away when it gets hit 2025-11-30 00:49:04 +01:00
2ed21add1c make hp bar hideable 2025-11-30 00:44:12 +01:00
8ec1805877 added health bar to monster 2025-11-30 00:38:00 +01:00
9aae9ad20f add death animation to dying monsters 2025-11-30 00:13:54 +01:00
c55bf8d043 re-arranged some variables 2025-11-29 23:40:47 +01:00
8a228685b1 fixed arrangement 2025-11-29 23:33:53 +01:00
6 changed files with 81 additions and 26 deletions

View File

@@ -17,10 +17,8 @@ public class GamePanel extends JPanel implements Runnable {
// SCREEN SETTINGS
final int originalTileSize = 16; //16x16 tile
final int scale = 3;
public final int tileSize = originalTileSize * scale; //48x48 tile
// 4:3 ratio
public final int maxScreenCol = 16;
public final int tileSize = originalTileSize * scale; //48x48 tile
public final int maxScreenRow = 12;
public final int screenWidth = tileSize * maxScreenCol; // 768 pixels
public final int screenHeight = tileSize * maxScreenRow; // 576 pixels
@@ -36,12 +34,12 @@ public class GamePanel extends JPanel implements Runnable {
// SYSTEM
public TileManager tileM = new TileManager(this);
public KeyHandler keyH = new KeyHandler(this);
Sound se = new Sound();
Sound music = new Sound();
public CollisionHandler collisionH = new CollisionHandler(this);
public AssetSetter assetSetter = new AssetSetter(this);
public UI ui = new UI(this);
public EventHandler eventH = new EventHandler(this);
Sound se = new Sound();
Sound music = new Sound();
Thread gameThread;
// ENTITY AND OBJECT
@@ -63,7 +61,6 @@ public class GamePanel extends JPanel implements Runnable {
}
// GAME THREAD / CORE
public void startGameThread() {
gameThread = new Thread(this);
gameThread.start();
@@ -103,7 +100,13 @@ public class GamePanel extends JPanel implements Runnable {
case PLAY:
player.update();
for(Entity entity : npc) if(entity != null) entity.update();
for(Entity entity : monster) if(entity != null) entity.update();
for(int i = 0; i < monster.length; i++) {
Entity m = monster[i];
if(m != null) {
if(m.alive && !m.dying) m.update();
if(!m.alive) monster[i] = null;
}
}
break;
case PAUSE:
break;

View File

@@ -14,7 +14,7 @@ public class UI {
Font arial_40, arial_80B; //TODO: Custom font loader: https://www.youtube.com/watch?v=g-wrebFVP3E
BufferedImage heart_full, heart_half, heart_blank;
public String currentDialogue;
public int commandNum = 0;
public int commandNum;
public UI(GamePanel panel) {
this.panel = panel;

View File

@@ -24,6 +24,7 @@ public class Sound {
soundURL[4] = new File("assets/sounds/fanfare.wav").toURI().toURL();
soundURL[5] = new File("assets/sounds/hitmonster.wav").toURI().toURL();
soundURL[6] = new File("assets/sounds/receivedamage.wav").toURI().toURL();
soundURL[7] = new File("assets/sounds/blocked.wav").toURI().toURL();
} catch(MalformedURLException e) {
Boot.logger.log(Level.SEVERE, e.getMessage());
}

View File

@@ -15,29 +15,34 @@ import java.util.logging.Level;
public class Entity {
GamePanel panel;
protected GamePanel panel;
public BufferedImage up1, up2, down1, down2, left1, left2, right1, right2;
public BufferedImage attackUp1, attackUp2, attackDown1, attackDown2, attackLeft1, attackLeft2, attackRight1, attackRight2;
public BufferedImage image, image2, image3;
public Rectangle solidArea = new Rectangle(0, 0, 48, 48);
public Rectangle attackArea = new Rectangle(0, 0, 0, 0);
public int solidAreaDefaultX, solidAreaDefaultY;
public boolean collision = false;
public boolean collision;
String[] dialogue = new String[20];
// STATE
public int worldX, worldY;
public Direction direction = Direction.DOWN;
public int spriteNum = 1;
int dialogueIndex = 0;
public boolean collisionOn = false;
public boolean invincible = false;
boolean attacking = false; //TODO: https://youtu.be/HL39xRzPpm4?t=551
int dialogueIndex;
public boolean collisionOn;
public boolean invincible;
boolean attacking;
public boolean alive = true;
public boolean dying;
public boolean hpBarOn;
// COUNTER
public int spriteCounter = 0;
public int actionLock = 0;
public int invincibleCount = 0;
public int spriteCounter;
public int actionLock;
public int invincibleCount;
int dyingCount;
int hpBarCounter;
// ATTRIBUTES
public EntityType type;
@@ -62,6 +67,7 @@ public class Entity {
if(this.type == EntityType.MONSTER && contactPlayer) {
if(panel.player.invincible) return;
panel.playSE(6);
panel.player.life -= 1;
panel.player.invincible = true;
}
@@ -100,23 +106,43 @@ public class Entity {
worldY + panel.tileSize > panel.player.worldY - panel.player.screenY &&
worldY - panel.tileSize < panel.player.worldY + panel.player.screenY
) {
if(invincible) {
graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
// MONSTER HP-BAR
if(this.type == EntityType.MONSTER && hpBarOn) {
graphics2d.setColor(new Color(35, 35, 35));
graphics2d.fillRect(screenX-1, screenY-6, panel.tileSize+2, 12);
graphics2d.setColor(new Color(255, 0, 30));
graphics2d.fillRect(screenX, screenY-5, (int) ((double) panel.tileSize/maxLife)*life, 10);
hpBarCounter++;
if(hpBarCounter > 600) { //bar disappears after 10 seconds
hpBarCounter = 0;
hpBarOn = false;
}
}
// only modify sprite render position for player because I dont know yet how monster attack sprite are gonna look
if(type == EntityType.PLAYER) {
// DRAW ENTITY
if(invincible) {
hpBarOn = true;
hpBarCounter = 0;
changeOpacity(graphics2d, 0.4f);
}
if(dying) dyingAnimation(graphics2d);
if(type == EntityType.PLAYER) { // only modify sprite render position for player because I dont know yet how monster attack sprite are gonna look
if(attacking) graphics2d.drawImage(parseSpriteATK(),
(direction == Direction.LEFT) ? screenX - panel.tileSize : screenX,
(direction == Direction.UP) ? screenY - panel.tileSize : screenY, null);
else graphics2d.drawImage(parseSprite(), screenX, screenY, null);
} else graphics2d.drawImage(parseSprite(), screenX, screenY, null);
graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
changeOpacity(graphics2d, 1f);
}
}
// INTERACTION
public void setAction() {}
public void damageReaction() {};
public void speak() {
if(dialogue[dialogueIndex] == null) dialogueIndex = 0;
panel.ui.currentDialogue = dialogue[dialogueIndex];
@@ -129,7 +155,22 @@ public class Entity {
case RIGHT -> direction = Direction.LEFT;
}
}
public void setAction() {}
public void dyingAnimation(Graphics2D graphics2d) {
dyingCount++;
int incr = 5;
if(dyingCount <= incr) changeOpacity(graphics2d, 0f);
if(dyingCount > incr && dyingCount <= incr*2) changeOpacity(graphics2d, 1f);
if(dyingCount > incr*2 && dyingCount <= incr*3) changeOpacity(graphics2d, 0f);
if(dyingCount > incr*3 && dyingCount <= incr*4) changeOpacity(graphics2d, 1f);
if(dyingCount > incr*4 && dyingCount <= incr*5) changeOpacity(graphics2d, 0f);
if(dyingCount > incr*5 && dyingCount <= incr*6) changeOpacity(graphics2d, 1f);
if(dyingCount > incr*6 && dyingCount <= incr*7) changeOpacity(graphics2d, 0f);
if(dyingCount > incr*7 && dyingCount <= incr*8) changeOpacity(graphics2d, 1f);
if(dyingCount > incr*8) {
dying = false;
alive = false;
}
}
// SETTING THINGS UP
BufferedImage parseSprite() {
@@ -164,5 +205,8 @@ public class Entity {
}
return null;
}
public void changeOpacity(Graphics2D graphics2d, float opacity) {
graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
}
}

View File

@@ -11,7 +11,6 @@ import java.awt.*;
public class Player extends Entity {
KeyHandler keyH;
public final int screenX;
public final int screenY;
@@ -156,12 +155,16 @@ public class Player extends Entity {
panel.monster[index].life -= 1;
panel.playSE(5);
panel.monster[index].invincible = true;
if(panel.monster[index].life <= 0) panel.monster[index] = null;
panel.monster[index].damageReaction();
if(panel.monster[index].life <= 0) panel.monster[index].dying = true;
}
public void interactNPC(int index) {
if(index == 999) {
if(panel.keyH.spacePressed) attacking = true;
if(panel.keyH.spacePressed) {
attacking = true;
//panel.playSE(7); //remains disabled because game does weird things while playing the sound
}
return;
}
//if(!panel.keyH.spacePressed) return; //Only uncomment if text should only appear if player hits space

View File

@@ -39,6 +39,10 @@ public class GreenSlimeMON extends Entity {
if(i > 75) direction = Direction.RIGHT;
actionLock = 0;
}
public void damageReaction() {
actionLock = 0;
direction = panel.player.direction;
}
// SETTING THINGS UP
public void getImage() {