package de.miaurizius.jgame2d.entity; import de.miaurizius.jgame2d.core.Boot; 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.*; import java.awt.image.BufferedImage; import java.io.FileInputStream; import java.io.IOException; import java.util.logging.Level; public class Entity { 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; protected String[] dialogue = new String[20]; // STATE public int worldX, worldY; public Direction direction = Direction.DOWN; public int spriteNum = 1; int dialogueIndex; public boolean collisionOn; public boolean invincible; boolean attacking; public boolean alive = true; public boolean dying; public boolean hpBarOn; public boolean consumable; // COUNTER public int spriteCounter; public int actionLock; public int invincibleCount; int dyingCount; int hpBarCounter; // CHARACTER ATTRIBUTES public EntityType type; public String name; public int speed; public int maxLife; public int life; public int level; public int strength; public int dexterity; public int attack; public int defense; 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 int value; public Entity(GamePanel panel) { this.panel = panel; } // DEFAULT public void update() { setAction(); collisionOn = false; panel.collisionH.checkTile(this); panel.collisionH.checkObject(this, false); panel.collisionH.checkEntity(this, panel.npc); panel.collisionH.checkEntity(this, panel.monster); boolean contactPlayer = panel.collisionH.checkPlayer(this); if(this.type == EntityType.MONSTER && contactPlayer) damagePlayer(attack); if(!collisionOn) { switch (direction) { case UP -> worldY -= speed; case DOWN -> worldY += speed; case LEFT ->worldX -= speed; case RIGHT -> worldX += speed; } } spriteCounter++; if(spriteCounter > 12) { if(spriteNum == 1) spriteNum = 2; else if(spriteNum == 2) spriteNum = 1; else spriteNum = 0; spriteCounter = 0; } // INVINCIBLE COUNTER if(!invincible) return; invincibleCount++; if(invincibleCount > 40) { invincible = false; invincibleCount = 0; } } public void draw(Graphics2D graphics2d) { int screenX = worldX - panel.player.worldX + panel.player.screenX; int screenY = worldY - panel.player.worldY + panel.player.screenY; if(worldX + panel.tileSize > panel.player.worldX - panel.player.screenX && worldX - panel.tileSize < panel.player.worldX + panel.player.screenX && worldY + panel.tileSize > panel.player.worldY - panel.player.screenY && worldY - panel.tileSize < panel.player.worldY + panel.player.screenY ) { // 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; } } // 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); changeOpacity(graphics2d, 1f); } } // INTERACTION public void setAction() {} public void damageReaction() {} public void damagePlayer(int attack) { if(panel.player.invincible) return; panel.playSE(6); int damage = attack - panel.player.defense; panel.player.life -= Math.max(damage, 0); panel.player.invincible = true; } public void speak() { if(dialogue[dialogueIndex] == null) dialogueIndex = 0; panel.ui.currentDialogue = dialogue[dialogueIndex]; dialogueIndex++; switch(panel.player.direction) { case UP -> direction = Direction.DOWN; case DOWN -> direction = Direction.UP; case LEFT -> direction = Direction.RIGHT; case RIGHT -> direction = Direction.LEFT; } } 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) { alive = false; } } public void use(Entity entity) { } //If entity is consumable public void checkDrop() { } public void dropItem(Entity droppedItem) { for(int i = 0; i < panel.obj.length; i++) { if(panel.obj[i] == null) { panel.obj[i] = droppedItem; panel.obj[i].worldX = worldX; panel.obj[i].worldY = worldY; break; } } } // SETTING THINGS UP BufferedImage parseSprite() { return switch (direction) { case UP -> (spriteNum == 1) ? up1 : up2; case DOWN -> (spriteNum == 1) ? down1 : down2; case LEFT -> (spriteNum == 1) ? left1 : left2; case RIGHT -> (spriteNum == 1) ? right1 : right2; }; } BufferedImage parseSpriteATK() { return switch (direction) { case UP -> (spriteNum == 1) ? attackUp1 : attackUp2; case DOWN -> (spriteNum == 1) ? attackDown1 : attackDown2; case LEFT -> (spriteNum == 1) ? attackLeft1 : attackLeft2; case RIGHT -> (spriteNum == 1) ? attackRight1 : attackRight2; }; } public BufferedImage initEntitySprites(String name) { try { return Utility.scaleImage(ImageIO.read(new FileInputStream("assets/" + name + ".png")), panel.tileSize, panel.tileSize); } catch (IOException e) { Boot.logger.log(Level.SEVERE, "Could not load entity-image", e); } return null; } public BufferedImage initEntitySprites(String name, int width, int height) { try { return Utility.scaleImage(ImageIO.read(new FileInputStream("assets/" + name + ".png")), width, height); } catch (IOException e) { Boot.logger.log(Level.SEVERE, "Could not load entity-image", e); } return null; } public void changeOpacity(Graphics2D graphics2d, float opacity) { graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)); } }