add Orc monster implementation and enhance player-monster interaction

This commit is contained in:
2025-12-13 20:21:28 +01:00
parent d092a39115
commit 4f9d1dfcb6
7 changed files with 195 additions and 62 deletions

View File

@@ -3,6 +3,7 @@ package de.miaurizius.jgame2d.core.handlers;
import de.miaurizius.jgame2d.core.GamePanel; import de.miaurizius.jgame2d.core.GamePanel;
import de.miaurizius.jgame2d.core.enums.Map; import de.miaurizius.jgame2d.core.enums.Map;
import de.miaurizius.jgame2d.entity.item.*; import de.miaurizius.jgame2d.entity.item.*;
import de.miaurizius.jgame2d.entity.monster.OrcMON;
import de.miaurizius.jgame2d.entity.npc.MerchantNPC; import de.miaurizius.jgame2d.entity.npc.MerchantNPC;
import de.miaurizius.jgame2d.entity.npc.OldManNPC; import de.miaurizius.jgame2d.entity.npc.OldManNPC;
import de.miaurizius.jgame2d.entity.monster.GreenSlimeMON; import de.miaurizius.jgame2d.entity.monster.GreenSlimeMON;
@@ -76,6 +77,11 @@ public class AssetSetter {
panel.monster[Map.OVERWORLD.getIndex()][i] = new GreenSlimeMON(panel); panel.monster[Map.OVERWORLD.getIndex()][i] = new GreenSlimeMON(panel);
panel.monster[Map.OVERWORLD.getIndex()][i].worldX = panel.tileSize*38; panel.monster[Map.OVERWORLD.getIndex()][i].worldX = panel.tileSize*38;
panel.monster[Map.OVERWORLD.getIndex()][i].worldY = panel.tileSize*42; panel.monster[Map.OVERWORLD.getIndex()][i].worldY = panel.tileSize*42;
i++;
panel.monster[Map.OVERWORLD.getIndex()][i] = new OrcMON(panel);
panel.monster[Map.OVERWORLD.getIndex()][i].worldX = panel.tileSize*12;
panel.monster[Map.OVERWORLD.getIndex()][i].worldY = panel.tileSize*33;
} }
public void setITiles() { public void setITiles() {

View File

@@ -1,6 +1,7 @@
package de.miaurizius.jgame2d.core.handlers; package de.miaurizius.jgame2d.core.handlers;
import de.miaurizius.jgame2d.core.GamePanel; import de.miaurizius.jgame2d.core.GamePanel;
import de.miaurizius.jgame2d.core.enums.Direction;
import de.miaurizius.jgame2d.entity.Entity; import de.miaurizius.jgame2d.entity.Entity;
public class CollisionHandler { public class CollisionHandler {
@@ -25,7 +26,11 @@ public class CollisionHandler {
int tileNum1, tileNum2; int tileNum1, tileNum2;
switch(entity.direction) { // TEMP DIRECTION FOR KNOCKBACK
Direction direction = entity.direction;
if(entity.knockback) direction = entity.knockbackDirection;
switch(direction) {
case UP: case UP:
entityTopRow = (entityTopWorldY - entity.speed)/panel.tileSize; entityTopRow = (entityTopWorldY - entity.speed)/panel.tileSize;
tileNum1 = panel.tileM.mapTileNum[panel.currentMap.getIndex()][entityLeftCol][entityTopRow]; tileNum1 = panel.tileM.mapTileNum[panel.currentMap.getIndex()][entityLeftCol][entityTopRow];

View File

@@ -14,6 +14,7 @@ import java.awt.image.BufferedImage;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
import java.util.Random; import java.util.Random;
import java.util.logging.Level; import java.util.logging.Level;
@@ -25,6 +26,7 @@ public class Entity {
public BufferedImage image, image2, image3; public BufferedImage image, image2, image3;
public Rectangle solidArea = new Rectangle(0, 0, 48, 48); public Rectangle solidArea = new Rectangle(0, 0, 48, 48);
public Rectangle attackArea = new Rectangle(0, 0, 0, 0); public Rectangle attackArea = new Rectangle(0, 0, 0, 0);
public Entity attacker;
public int solidAreaDefaultX, solidAreaDefaultY; public int solidAreaDefaultX, solidAreaDefaultY;
public boolean collision; public boolean collision;
protected String[] dialogue = new String[20]; protected String[] dialogue = new String[20];
@@ -36,13 +38,14 @@ public class Entity {
int dialogueIndex; int dialogueIndex;
public boolean collisionOn; public boolean collisionOn;
public boolean invincible; public boolean invincible;
boolean attacking; public boolean attacking;
public boolean alive = true; public boolean alive = true;
public boolean dying; public boolean dying;
public boolean hpBarOn; public boolean hpBarOn;
public boolean consumable; public boolean consumable;
public boolean onPath; public boolean onPath;
public boolean knockback; public boolean knockback;
public Direction knockbackDirection;
// COUNTER // COUNTER
public int spriteCount; public int spriteCount;
@@ -105,7 +108,7 @@ public class Entity {
return; return;
} }
switch(panel.player.direction) { switch(knockbackDirection) {
case UP -> worldY -= speed; case UP -> worldY -= speed;
case DOWN -> worldY += speed; case DOWN -> worldY += speed;
case LEFT ->worldX -= speed; case LEFT ->worldX -= speed;
@@ -118,7 +121,7 @@ public class Entity {
knockback = false; knockback = false;
knockbackCount = 0; knockbackCount = 0;
speed = defaultSpeed; speed = defaultSpeed;
} else { } else if(attacking) attacking(); else {
setAction(); setAction();
checkCollision(); checkCollision();
@@ -130,14 +133,14 @@ public class Entity {
case RIGHT -> worldX += speed; case RIGHT -> worldX += speed;
} }
} }
}
spriteCount++; spriteCount++;
if(spriteCount > 24) { if(spriteCount > 24) {
if(spriteNum == 1) spriteNum = 2; if(spriteNum == 1) spriteNum = 2;
else if(spriteNum == 2) spriteNum = 1; else if(spriteNum == 2) spriteNum = 1;
else spriteNum = 0; else spriteNum = 0;
spriteCount = 0; spriteCount = 0;
}
} }
// INVINCIBLE COUNTER // INVINCIBLE COUNTER
@@ -179,8 +182,9 @@ public class Entity {
hpBarCount = 0; hpBarCount = 0;
changeOpacity(graphics2d, 0.4f); changeOpacity(graphics2d, 0.4f);
} }
//TODO: fix attacking sprite drawing position for monsters
if(dying) dyingAnimation(graphics2d); 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(type == EntityType.PLAYER || name.equals("orc")) { // only modify sprite render position for player because I dont know yet how monster attack sprite are gonna look
if(attacking) graphics2d.drawImage(parseSpriteATK(), if(attacking) graphics2d.drawImage(parseSpriteATK(),
(direction == Direction.LEFT) ? screenX - panel.tileSize : screenX, (direction == Direction.LEFT) ? screenX - panel.tileSize : screenX,
(direction == Direction.UP) ? screenY - panel.tileSize : screenY, null); (direction == Direction.UP) ? screenY - panel.tileSize : screenY, null);
@@ -199,6 +203,48 @@ public class Entity {
// INTERACTION // INTERACTION
public void setAction() {} public void setAction() {}
public void damageReaction() {} public void damageReaction() {}
public void attacking() {
if(panel.player.attackCancel && type == EntityType.PLAYER) return;
spriteCount++;
if(spriteCount <= 5) spriteNum = 1;
if(spriteCount > 5 && spriteCount <= 25) {
spriteNum = 2;
int currentWorldX = worldX;
int currentWorldY = worldY;
int solidAreaWidth = solidArea.width;
int solidAreaHeight = solidArea.height;
switch(direction) {
case UP -> worldY -= attackArea.height;
case DOWN -> worldY += attackArea.height;
case LEFT -> worldX -= attackArea.width;
case RIGHT -> worldX += attackArea.width;
}
solidArea.width = attackArea.width;
solidArea.height = attackArea.height;
if(type == EntityType.MONSTER) if(panel.collisionH.checkPlayer(this)) damagePlayer(attackValue);
if(type == EntityType.PLAYER) {
int monsterIndex = panel.collisionH.checkEntity(this, panel.monster[panel.currentMap.getIndex()]);
panel.player.damageMonster(monsterIndex, this, attack, currentWeapon.knockbackVal);
int iTileIndex = panel.collisionH.checkEntity(this, panel.iTile[panel.currentMap.getIndex()]);
panel.player.interactTile(iTileIndex);
}
worldX = currentWorldX;
worldY = currentWorldY;
solidArea.width = solidAreaWidth;
solidArea.height = solidAreaHeight;
}
if(spriteCount > 25) {
spriteNum = 1;
spriteCount = 0;
attacking = false;
}
}
public void damagePlayer(int attack) { public void damagePlayer(int attack) {
if(panel.player.invincible) return; if(panel.player.invincible) return;
panel.playSE(6); panel.playSE(6);
@@ -292,6 +338,12 @@ public class Entity {
} }
return index; return index;
} }
public void setKnockback(Entity target, Entity attacker, int knockbackVal) {
this.attacker = attacker;
target.knockbackDirection = attacker.direction;
target.speed += knockbackVal;
target.knockback = true;
}
// PARTICLE SETUP // PARTICLE SETUP
public Color getParticleColor() { public Color getParticleColor() {
@@ -345,9 +397,10 @@ public class Entity {
return Math.abs(worldX - target.worldX); return Math.abs(worldX - target.worldX);
} }
public int dY(Entity target) { public int dY(Entity target) {
return Math.abs(worldY - target.worldX); return Math.abs(worldY - target.worldY);
} }
public int dTile(Entity target) { public int dTile(Entity target) {
if(Objects.equals(name, "orc")) System.out.println("dX: " + dX(target) + " dY: " + dY(target));
return (dX(target) + dY(target)) / panel.tileSize; return (dX(target) + dY(target)) / panel.tileSize;
} }
public int getGoalCol(Entity target) { public int getGoalCol(Entity target) {
@@ -479,10 +532,11 @@ public class Entity {
} }
} }
public void checkStopChasing(Entity target, int distance, int rate) { public void checkStopChasing(Entity target, int distance, int rate) {
if(dTile(target) > distance) if(new Random().nextInt(rate) == 0) onPath = false; if(Objects.equals(name, "orc")) System.out.println("dTile: " + dTile(target) + " distance: " + distance);
if(dTile(target) > distance) onPath = false;
} }
public void checkStartChasing(Entity target, int distance, int rate) { public void checkStartChasing(Entity target, int distance, int rate) {
if(dTile(target) < distance) if(new Random().nextInt(rate) == 0) onPath = true; if(dTile(target) < distance) onPath = true;
} }
public void checkShooting(int rate, int shotInterval) { public void checkShooting(int rate, int shotInterval) {
if(new Random().nextInt(rate) == 0 && projectile.alive == false && shotAvailableCount == shotInterval) { if(new Random().nextInt(rate) == 0 && projectile.alive == false && shotAvailableCount == shotInterval) {
@@ -498,6 +552,34 @@ public class Entity {
shotAvailableCount = 0; shotAvailableCount = 0;
} }
} }
public void checkAttack(int rate, int straight, int horizontal) {
boolean targetInRange = false;
int xDist = dX(panel.player);
int yDist = dY(panel.player);
switch(direction) {
case UP -> {
if(panel.player.worldY < worldY && yDist < straight && xDist < horizontal) targetInRange = true;
}
case DOWN -> {
if(panel.player.worldY > worldY && yDist < straight && xDist < horizontal) targetInRange = true;
}
case LEFT -> {
if(panel.player.worldX < worldX && xDist < straight && yDist < horizontal) targetInRange = true;
}
case RIGHT -> {
if(panel.player.worldX > worldX && xDist < straight && yDist < horizontal) targetInRange = true;
}
}
if(targetInRange)
if (new Random().nextInt(rate) == 0) {
attacking = true;
spriteNum = 1;
spriteCount = 0;
shotAvailableCount = 0;
}
}
public void setRandomDirection() { public void setRandomDirection() {
actionLock++; actionLock++;
if(actionLock == 120) { //lock action for x frames if(actionLock == 120) { //lock action for x frames

View File

@@ -176,45 +176,7 @@ public class Player extends Entity {
} }
} }
public void attacking() { public void damageMonster(int index, Entity attacker, int attack, int knockbackVal) {
if(attackCancel) return;
spriteCount++;
if(spriteCount <= 5) spriteNum = 1;
if(spriteCount > 5 && spriteCount <= 25) {
spriteNum = 2;
int currentWorldX = worldX;
int currentWorldY = worldY;
int solidAreaWidth = solidArea.width;
int solidAreaHeight = solidArea.height;
switch(direction) {
case UP -> worldY -= attackArea.height;
case DOWN -> worldY += attackArea.height;
case LEFT -> worldX -= attackArea.width;
case RIGHT -> worldX += attackArea.width;
}
solidArea.width = attackArea.width;
solidArea.height = attackArea.height;
int monsterIndex = panel.collisionH.checkEntity(this, panel.monster[panel.currentMap.getIndex()]);
damageMonster(monsterIndex, attack, currentWeapon.knockbackVal);
int iTileIndex = panel.collisionH.checkEntity(this, panel.iTile[panel.currentMap.getIndex()]);
interactTile(iTileIndex);
worldX = currentWorldX;
worldY = currentWorldY;
solidArea.width = solidAreaWidth;
solidArea.height = solidAreaHeight;
}
if(spriteCount > 25) {
spriteNum = 1;
spriteCount = 0;
attacking = false;
}
}
public void damageMonster(int index, int attack, int knockbackVal) {
if(index == 999) return; if(index == 999) return;
if(panel.monster[panel.currentMap.getIndex()][index].invincible) return; if(panel.monster[panel.currentMap.getIndex()][index].invincible) return;
@@ -222,7 +184,7 @@ public class Player extends Entity {
if(damage > 0) { if(damage > 0) {
panel.playSE(5); panel.playSE(5);
if(knockbackVal > 0) knockback(panel.monster[panel.currentMap.getIndex()][index], knockbackVal); if(knockbackVal > 0) setKnockback(panel.monster[panel.currentMap.getIndex()][index], attacker, knockbackVal);
panel.monster[panel.currentMap.getIndex()][index].life -= damage; panel.monster[panel.currentMap.getIndex()][index].life -= damage;
panel.monster[panel.currentMap.getIndex()][index].invincible = true; panel.monster[panel.currentMap.getIndex()][index].invincible = true;
} }
@@ -235,11 +197,6 @@ public class Player extends Entity {
checkLevelUp(); checkLevelUp();
} }
} }
public void knockback(Entity entity, int knockbackVal) {
entity.direction = direction;
entity.speed += knockbackVal;
entity.knockback = true;
}
public void interactTile(int index) { public void interactTile(int index) {
if(index == 999 || !panel.iTile[panel.currentMap.getIndex()][index].destructible || panel.iTile[panel.currentMap.getIndex()][index].invincible) return; if(index == 999 || !panel.iTile[panel.currentMap.getIndex()][index].destructible || panel.iTile[panel.currentMap.getIndex()][index].invincible) return;

View File

@@ -0,0 +1,83 @@
package de.miaurizius.jgame2d.entity.monster;
import de.miaurizius.jgame2d.core.GamePanel;
import de.miaurizius.jgame2d.core.enums.EntityType;
import de.miaurizius.jgame2d.entity.Entity;
import de.miaurizius.jgame2d.entity.item.CoinObj;
import de.miaurizius.jgame2d.entity.item.HeartObj;
import de.miaurizius.jgame2d.entity.item.PotionObj;
import java.util.Random;
public class OrcMON extends Entity {
public OrcMON(GamePanel panel) {
super(panel);
type = EntityType.MONSTER;
name = "orc";
defaultSpeed = 1;
speed = defaultSpeed;
maxLife = 10;
life = maxLife;
attack = 8;
defense = 2;
exp = 10;
solidArea.x = 4;
solidArea.y = 4;
solidArea.width = 40;
solidArea.height = 44;
solidAreaDefaultX = solidArea.x;
solidAreaDefaultY = solidArea.y;
attackArea.width = panel.tileSize;
attackArea.height = panel.tileSize;
getImage();
getAttackImage();
}
// INTERACTION
public void setAction() {
if(!onPath) checkStartChasing(panel.player, 10 ,100);
checkStopChasing(panel.player, 15, 100);
if(onPath) {
followPlayer();
return;
}
setRandomDirection();
if(!attacking) checkAttack(30, panel.tileSize*4, panel.tileSize);
}
public void damageReaction() {
actionLock = 0;
onPath = true;
}
public void checkDrop() {
int i = new Random().nextInt(100)+1;
if(i < 50) dropItem(new CoinObj(panel));
if(i >= 50 && i < 75) dropItem(new HeartObj(panel));
if(i >= 75 && i < 100) dropItem(new PotionObj(panel));
}
// SETTING THINGS UP
public void getImage() {
up1 = initEntitySprites("monster/orc_up_1");
up2 = initEntitySprites("monster/orc_up_2");
down1 = initEntitySprites("monster/orc_down_1");
down2 = initEntitySprites("monster/orc_down_2");
left1 = initEntitySprites("monster/orc_left_1");
left2 = initEntitySprites("monster/orc_left_2");
right1 = initEntitySprites("monster/orc_right_1");
right2 = initEntitySprites("monster/orc_right_2");
}
public void getAttackImage() {
attackUp1 = initEntitySprites("monster/orc_attack_up_1");
attackUp2 = initEntitySprites("monster/orc_attack_up_2");
attackDown1 = initEntitySprites("monster/orc_attack_down_1");
attackDown2 = initEntitySprites("monster/orc_attack_down_2");
attackLeft1 = initEntitySprites("monster/orc_attack_left_1");
attackLeft2 = initEntitySprites("monster/orc_attack_left_2");
attackRight1 = initEntitySprites("monster/orc_attack_right_1");
attackRight2 = initEntitySprites("monster/orc_attack_right_2");
}
}

View File

@@ -28,7 +28,7 @@ public class Projectile extends Entity {
if(user.type == EntityType.PLAYER) { if(user.type == EntityType.PLAYER) {
int monsterIndex = panel.collisionH.checkEntity(this, panel.monster[panel.currentMap.getIndex()]); int monsterIndex = panel.collisionH.checkEntity(this, panel.monster[panel.currentMap.getIndex()]);
if(monsterIndex != 999) { if(monsterIndex != 999) {
panel.player.damageMonster(monsterIndex, attack, knockbackVal); panel.player.damageMonster(monsterIndex, this, attack, knockbackVal);
generateParticle(user.projectile, panel.monster[panel.currentMap.getIndex()][monsterIndex]); generateParticle(user.projectile, panel.monster[panel.currentMap.getIndex()][monsterIndex]);
alive = false; alive = false;
} }

View File

@@ -35,7 +35,7 @@ public class Lighting {
} }
g2.setColor(Color.white); g2.setColor(Color.white);
g2.setFont(g2.getFont().deriveFont(50f)); g2.setFont(g2.getFont().deriveFont(50f));
g2.drawString(s, 800, 500); g2.drawString(s + " " + dayCount, 700, 500);
} }
} }
public void update() { public void update() {