From 5da7c43edf41ace258cb4b9db6b5e6edc48f09b4 Mon Sep 17 00:00:00 2001 From: Maurice Date: Sun, 7 Dec 2025 00:07:47 +0100 Subject: [PATCH] added projectile system and sample fireball projectile --- assets/projectile/fireball_down_1.png | Bin 0 -> 222 bytes assets/projectile/fireball_down_2.png | Bin 0 -> 213 bytes assets/projectile/fireball_left_1.png | Bin 0 -> 189 bytes assets/projectile/fireball_left_2.png | Bin 0 -> 204 bytes assets/projectile/fireball_right_1.png | Bin 0 -> 192 bytes assets/projectile/fireball_right_2.png | Bin 0 -> 216 bytes assets/projectile/fireball_up_1.png | Bin 0 -> 210 bytes assets/projectile/fireball_up_2.png | Bin 0 -> 210 bytes assets/projectile/rock_down_1.png | Bin 0 -> 5651 bytes src/de/miaurizius/jgame2d/core/GamePanel.java | 9 +++ .../jgame2d/core/enums/EntityType.java | 1 + .../jgame2d/core/handlers/KeyHandler.java | 4 +- .../jgame2d/core/handlers/Sound.java | 1 + src/de/miaurizius/jgame2d/entity/Entity.java | 6 +- src/de/miaurizius/jgame2d/entity/Player.java | 15 +++-- .../entity/projectile/FireballObj.java | 35 ++++++++++ .../jgame2d/entity/projectile/Projectile.java | 61 ++++++++++++++++++ 17 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 assets/projectile/fireball_down_1.png create mode 100644 assets/projectile/fireball_down_2.png create mode 100644 assets/projectile/fireball_left_1.png create mode 100644 assets/projectile/fireball_left_2.png create mode 100644 assets/projectile/fireball_right_1.png create mode 100644 assets/projectile/fireball_right_2.png create mode 100644 assets/projectile/fireball_up_1.png create mode 100644 assets/projectile/fireball_up_2.png create mode 100644 assets/projectile/rock_down_1.png create mode 100644 src/de/miaurizius/jgame2d/entity/projectile/FireballObj.java create mode 100644 src/de/miaurizius/jgame2d/entity/projectile/Projectile.java diff --git a/assets/projectile/fireball_down_1.png b/assets/projectile/fireball_down_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c4ba85e0573f081976920ee0ea99b198782848 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`OFdm2LoEEyP7V}oG2n5D_f=pJ z&2UtR3TSLF4ou@ttWs4yTpPPTVb-3UO}m-U@G``1yv@U%K(;Y{%xC1Mi_ zmL2ts{G+RwmCjXv3y zJ)pE{-@g3xc(%2Q$Fw)~Ce5hhyQF?b>-0LuS-M{C>;AMZzWl zyy5@!V1owl1g{pEZ7w{G=MUM&Eo?ff+FkjE^-05-wn=YV*E#mpZpi-3B$2|PE5o*a zGK0VphBLiVeS8mUvREcwd(N03k}}OnBH%mM3a2d=*#|zbU3_%=*v0F~|MWwo-^=c= qJ17yDSjG3R=li|Dd4`c@I~bq$Y73gk=sX8HiNVv=&t;ucLK6UXp-8#_ literal 0 HcmV?d00001 diff --git a/assets/projectile/fireball_right_2.png b/assets/projectile/fireball_right_2.png new file mode 100644 index 0000000000000000000000000000000000000000..d639f33d2283687f90a452afe38f40ee36283f58 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`b3I)gLoEF7PP)t6V8GGRuPSpu z)2f@<%6oYM!}J3UTaxN8wI36&G|b$w+rPme(q!fF?QDCRHrn)vygs1jD7Nk$d;hkJ zryH0pwyPFyn4S@D>}7I9TH;d$Q`hU@$v6C?de+S63sAdIBDme<>8fwP9W_=-YD^3{ zzry{2vr(`4Cu0l7gW+BG6!)^dnsq9akKZ#qYidyKiwg-Quj~zWFobN?5}akU+YabZ P22WQ%mvv4FO$-bGLzhyQ literal 0 HcmV?d00001 diff --git a/assets/projectile/fireball_up_1.png b/assets/projectile/fireball_up_1.png new file mode 100644 index 0000000000000000000000000000000000000000..918cb78ed5c6d090442b82d6c5c96bae7ead9773 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Gd*1#LoEEyPQJ_Apup48uPW1^ zIpZkf+*VDA1FBhl5loFu$HXg@GT*;G-+1`=W1YPf9mistW}5S)d<Q z0;7R~t%AdXM+^%07O?EN(SM0y)+>?Mibq~Nl5ALzY;){9!<&$j&SqJi=@ATjE^wAU z?Cs@E*`I5old|sbl+r1lUrie%C#UaW(>W6CaIdxfOr27(Ua_K^;FR+H-9Se&c)I$z JtaD0e0swKIQE31G literal 0 HcmV?d00001 diff --git a/assets/projectile/fireball_up_2.png b/assets/projectile/fireball_up_2.png new file mode 100644 index 0000000000000000000000000000000000000000..13150029782a5c2c26244ffb36b2bdd88e1b00a1 GIT binary patch literal 210 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 projectileList = new ArrayList<>(); ArrayList entityList = new ArrayList<>(); // GAME STATE @@ -109,6 +110,13 @@ public class GamePanel extends JPanel implements Runnable { if(!m.alive) monster[i] = null; } } + for(int i = 0; i < projectileList.size(); i++) { + Entity m = projectileList.get(i); + if(m != null) { + if(m.alive) m.update(); + else projectileList.remove(i); + } + } break; case PAUSE: break; @@ -136,6 +144,7 @@ public class GamePanel extends JPanel implements Runnable { for(Entity entity : npc) if(entity != null) entityList.add(entity); for(Entity entity : obj) if(entity != null) entityList.add(entity); for(Entity entity : monster) if(entity != null) entityList.add(entity); + for(Entity entity : projectileList) if(entity != null) entityList.add(entity); entityList.sort(Comparator.comparingInt(o -> o.worldY)); for(Entity entity : entityList) entity.draw(graphics2d); entityList.clear(); diff --git a/src/de/miaurizius/jgame2d/core/enums/EntityType.java b/src/de/miaurizius/jgame2d/core/enums/EntityType.java index 128e0d2..61e5494 100644 --- a/src/de/miaurizius/jgame2d/core/enums/EntityType.java +++ b/src/de/miaurizius/jgame2d/core/enums/EntityType.java @@ -7,6 +7,7 @@ public enum EntityType { MONSTER, ITEM, WORLD, + PROJECTILE, WEAPON, SHIELD; diff --git a/src/de/miaurizius/jgame2d/core/handlers/KeyHandler.java b/src/de/miaurizius/jgame2d/core/handlers/KeyHandler.java index 92c10cf..b9e4a30 100644 --- a/src/de/miaurizius/jgame2d/core/handlers/KeyHandler.java +++ b/src/de/miaurizius/jgame2d/core/handlers/KeyHandler.java @@ -8,7 +8,7 @@ import java.awt.event.KeyListener; public class KeyHandler implements KeyListener { - public boolean upPressed, downPressed, leftPressed, rightPressed, spacePressed; + public boolean upPressed, downPressed, leftPressed, rightPressed, spacePressed, shotKeyPressed; public GamePanel panel; public boolean debug; @@ -49,6 +49,7 @@ public class KeyHandler implements KeyListener { case KeyEvent.VK_A, KeyEvent.VK_LEFT -> leftPressed = true; case KeyEvent.VK_D, KeyEvent.VK_RIGHT -> rightPressed = true; case KeyEvent.VK_SPACE -> spacePressed = true; + case KeyEvent.VK_F -> shotKeyPressed = true; // DEBUG OPTIONS case KeyEvent.VK_T -> debug = !debug; @@ -142,6 +143,7 @@ public class KeyHandler implements KeyListener { case KeyEvent.VK_S, KeyEvent.VK_DOWN -> downPressed = false; case KeyEvent.VK_A, KeyEvent.VK_LEFT -> leftPressed = false; case KeyEvent.VK_D, KeyEvent.VK_RIGHT -> rightPressed = false; + case KeyEvent.VK_F -> shotKeyPressed = false; } } } diff --git a/src/de/miaurizius/jgame2d/core/handlers/Sound.java b/src/de/miaurizius/jgame2d/core/handlers/Sound.java index a41c584..deecf87 100644 --- a/src/de/miaurizius/jgame2d/core/handlers/Sound.java +++ b/src/de/miaurizius/jgame2d/core/handlers/Sound.java @@ -26,6 +26,7 @@ public class Sound { load(7, "assets/sounds/blocked.wav"); load(8, "assets/sounds/levelup.wav"); load(9, "assets/sounds/cursor.wav"); + load(10, "assets/sounds/burning.wav"); } @Deprecated diff --git a/src/de/miaurizius/jgame2d/entity/Entity.java b/src/de/miaurizius/jgame2d/entity/Entity.java index 0fe7ca4..fd15315 100644 --- a/src/de/miaurizius/jgame2d/entity/Entity.java +++ b/src/de/miaurizius/jgame2d/entity/Entity.java @@ -5,6 +5,7 @@ import de.miaurizius.jgame2d.core.enums.Direction; import de.miaurizius.jgame2d.core.GamePanel; import de.miaurizius.jgame2d.core.Utility; import de.miaurizius.jgame2d.core.enums.EntityType; +import de.miaurizius.jgame2d.entity.projectile.Projectile; import javax.imageio.ImageIO; import java.awt.*; @@ -59,14 +60,18 @@ public class Entity { public int exp; public int nextLevelExp; public int coins; + public int maxMana; + public int mana; public Entity currentWeapon; public Entity currentShield; + public Projectile projectile; // ITEM ATTRIBUTES public EntityType.WeaponType weaponType; public int attackValue; public int defenseValue; public String description; + public int useCost; public Entity(GamePanel panel) { this.panel = panel; @@ -187,7 +192,6 @@ public class Entity { 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; } } diff --git a/src/de/miaurizius/jgame2d/entity/Player.java b/src/de/miaurizius/jgame2d/entity/Player.java index fae6b8b..68fe8b0 100644 --- a/src/de/miaurizius/jgame2d/entity/Player.java +++ b/src/de/miaurizius/jgame2d/entity/Player.java @@ -7,6 +7,7 @@ import de.miaurizius.jgame2d.core.enums.GameState; import de.miaurizius.jgame2d.core.handlers.KeyHandler; import de.miaurizius.jgame2d.entity.item.ShieldWoodObj; import de.miaurizius.jgame2d.entity.item.SwordNormalObj; +import de.miaurizius.jgame2d.entity.projectile.FireballObj; import java.awt.*; import java.util.ArrayList; @@ -106,6 +107,12 @@ public class Player extends Entity { } } + if(panel.keyH.shotKeyPressed && !projectile.alive) { + projectile.set(worldX, worldY, direction, true, this); + panel.projectileList.add(projectile); + panel.playSE(10); + } + // INVINCIBLE COUNTER if(!invincible) return; invincibleCount++; @@ -130,8 +137,7 @@ public class Player extends Entity { public void interactMonster(int index) { if(index == 999) return; - if(invincible) return; - if(panel.monster[index].dying || !panel.monster[index].alive) return; + if(invincible || panel.monster[index].dying || !panel.monster[index].alive) return; int damage = panel.monster[index].attack - defense; @@ -163,7 +169,7 @@ public class Player extends Entity { solidArea.height = attackArea.height; int monsterIndex = panel.collisionH.checkEntity(this, panel.monster); - damageMonster(monsterIndex); + damageMonster(monsterIndex, attack); worldX = currentWorldX; worldY = currentWorldY; @@ -177,7 +183,7 @@ public class Player extends Entity { attacking = false; } } - public void damageMonster(int index) { + public void damageMonster(int index, int attack) { if(index == 999) return; if(panel.monster[index].invincible) return; @@ -262,6 +268,7 @@ public class Player extends Entity { coins = 0; currentWeapon = new SwordNormalObj(panel); currentShield = new ShieldWoodObj(panel); + projectile = new FireballObj(panel); attack = getAttack(); defense = getDefense(); diff --git a/src/de/miaurizius/jgame2d/entity/projectile/FireballObj.java b/src/de/miaurizius/jgame2d/entity/projectile/FireballObj.java new file mode 100644 index 0000000..456b5b5 --- /dev/null +++ b/src/de/miaurizius/jgame2d/entity/projectile/FireballObj.java @@ -0,0 +1,35 @@ +package de.miaurizius.jgame2d.entity.projectile; + +import de.miaurizius.jgame2d.core.GamePanel; +import de.miaurizius.jgame2d.core.enums.EntityType; + +public class FireballObj extends Projectile { + + GamePanel panel; + + public FireballObj(GamePanel panel) { + super(panel); + this.panel = panel; + + name = "Fireball"; + type = EntityType.PROJECTILE; + + speed = 5; + maxLife = 80; + life = maxLife; + attack = 2; + useCost = 1; + alive = false; + + // INITIALISATION OF IMAGES + up1 = initEntitySprites("/projectile/fireball_up_1"); + up2 = initEntitySprites("/projectile/fireball_up_2"); + down1 = initEntitySprites("/projectile/fireball_down_1"); + down2 = initEntitySprites("/projectile/fireball_down_2"); + left1 = initEntitySprites("/projectile/fireball_left_1"); + left2 = initEntitySprites("/projectile/fireball_left_2"); + right1 = initEntitySprites("/projectile/fireball_right_1"); + right2 = initEntitySprites("/projectile/fireball_right_2"); + } + +} diff --git a/src/de/miaurizius/jgame2d/entity/projectile/Projectile.java b/src/de/miaurizius/jgame2d/entity/projectile/Projectile.java new file mode 100644 index 0000000..03ea489 --- /dev/null +++ b/src/de/miaurizius/jgame2d/entity/projectile/Projectile.java @@ -0,0 +1,61 @@ +package de.miaurizius.jgame2d.entity.projectile; + +import de.miaurizius.jgame2d.core.GamePanel; +import de.miaurizius.jgame2d.core.enums.Direction; +import de.miaurizius.jgame2d.core.enums.EntityType; +import de.miaurizius.jgame2d.entity.Entity; + +public class Projectile extends Entity { + + Entity user; + + public Projectile(GamePanel panel) { + super(panel); + } + + public void set(int worldX, int worldY, Direction direction, boolean alive, Entity user) { + this.worldX = worldX; + this.worldY = worldY; + this.direction = direction; + this.alive = alive; + this.user = user; + this.life = maxLife; + } + + public void update() { + + if(user.type == EntityType.PLAYER) { + int monsterIndex = panel.collisionH.checkEntity(this, panel.monster); + if(monsterIndex != 999) { + panel.player.damageMonster(monsterIndex, attack); + alive = false; + } + } + + if(user.type == EntityType.MONSTER) { + + } + + switch(direction) { + case UP -> worldY -= speed; + case DOWN -> worldY += speed; + case LEFT -> worldX -= speed; + case RIGHT -> worldX += speed; + } + + life--; + if(life <= 0) { + alive = false; + return; + } + + spriteCounter++; + if(spriteCounter > 12) { + if(spriteNum == 1) spriteNum = 2; + else if(spriteNum == 2) spriteNum = 1; + else spriteNum = 0; + spriteCounter = 0; + } + } + +}