Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 5 of 5

Thread: Game hitboxes

  1. #1
    Junior Member
    Join Date
    Oct 2024
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Post Game hitboxes

    I'm making a little game in java to learn, and I encounter a problem with my weapon hitbox, I tried a lot of things but the hitbox is never applied exactly where the weapon is.
    The sword is correctly displayed, I tried to draw the hitbox but it didn't match with the real hitbox. Here is my code below:

    I have a weapon class that will handle all other weapons in my game but for now I just have a sword class that is used. My problem is the interaction between monsters and weapon to apply damage to the monster. There is a problem with the hitbox that is not where the sword is displayed (which it is correctly displayed). When I try to drawRect the collision box, it does not appear. In reality I do not understand well how I can make my collision box that corresponds to the translation and rotation of the image of my sword.



    package weapon;
     
    import entity.Entity;
    import main.GamePanel;
    import java.awt.*;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
     
    public abstract class Weapon {
     
    protected GamePanel gp;
    public boolean isAttacking = false;
    public boolean collisionOn = false;
     
    //animations
    protected boolean isDrawing = false;
    protected BufferedImage[] frames;
    protected int currentFrame = 0;
    protected int counterFrames = 0;
    protected BufferedImage[] framesEffect;
     
    //angles
    public double angle = 0;
    protected double initialAngle = 0;
    protected double startAngle;
    protected double turn = Math.PI;
     
    //characteristics
    public int distanceFromPlayer = 50;
    protected int speed = 5;
    protected int damage;
    public Rectangle solidArea;
    public int solidAreaDefaultX, solidAreaDefaultY;
     
    public Weapon(GamePanel gp, int damage) {
    this.gp = gp;
    this.damage = damage;
     
    solidArea = new Rectangle();
    solidArea.x = 0;
    solidArea.y = 0;
    solidAreaDefaultX = solidArea.x;
    solidAreaDefaultY = solidArea.y;
    solidArea.width = gp.tileSize - 2*solidArea.x;
    solidArea.height = gp.tileSize - solidArea.y;
     
    getImage();
    getEffect();
    }
     
     
    protected abstract void getImage();
    protected abstract void getEffect();
     
    public void startAttack(String direction) {
    if (!isDrawing) {
    isDrawing = true;
     
    startAngle = switch (direction) {
    case "up" -> Math.toRadians(180) + initialAngle;
    case "down" -> initialAngle;
    case "left" -> Math.toRadians(90) + initialAngle;
    case "right" -> Math.toRadians(-90) + initialAngle;
    default -> initialAngle;
    };
    angle = startAngle;
    }
    }
     
    public void update() {
    if (isDrawing) {
    angle += Math.toRadians(speed);
    if (angle - startAngle >= turn) {
    isDrawing = false;
    }
    counterFrames++;
    if (counterFrames > 5) {
    currentFrame = (currentFrame + 1) % frames.length;
    counterFrames = 0;
    }
     
    int weaponHitboxX = gp.playerCenterX + (int) (distanceFromPlayer * Math.cos(angle) + gp.tileSize);
    int weaponHitboxY = gp.playerCenterY + (int) (distanceFromPlayer * Math.sin(angle)) + gp.tileSize / 2;
     
    solidArea.x = weaponHitboxX;
    solidArea.y = weaponHitboxY;
     
    int monsterIndex = checkEntityWithWeapon(this, gp.mon);
    if (monsterIndex != 999) {
    damageMonster(monsterIndex);
    }
     
     
    }
    }
     
    public void draw(Graphics2D g2, int playerCenterX, int playerCenterY) {
    if (isDrawing) {
    int weaponX = playerCenterX + (int) (distanceFromPlayer * Math.cos(angle) + gp.tileSize);
    int weaponY = playerCenterY + (int) (distanceFromPlayer * Math.sin(angle)) + gp.tileSize/2;
     
    AffineTransform originalTransform = g2.getTransform();
    AffineTransform weaponTransform = new AffineTransform();
    weaponTransform.translate(weaponX, weaponY);
    weaponTransform.rotate(angle + Math.PI / 2, gp.tileSize / 2, gp.tileSize / 2);
    g2.setTransform(weaponTransform);
     
    if (frames[currentFrame] != null) {
     
    g2.drawImage(frames[currentFrame], 0, 0, gp.tileSize, gp.tileSize, null);}
     
    g2.setTransform(originalTransform);
    }
    }
     
    public int checkEntityWithWeapon(Weapon weapon, Entity[] target) {
    int index = 999;
    for (int i = 0; i < target.length; i++) {
    if (target[i] != null) {
     
    target[i].solidArea.x = target[i].worldX + target[i].solidArea.x;
    target[i].solidArea.y = target[i].worldY + target[i].solidArea.y;
     
    if (weapon.solidArea.intersects(target[i].solidArea)) { // intersects vérifie si 2 rectangles sont en collision
    collisionOn = true;
    index = i;
    }
     
    target[i].solidArea.x = target[i].solidAreaDefaultX;
    target[i].solidArea.y = target[i].solidAreaDefaultY;
    }
    }
    return index;
    }
     
     
     
    public boolean isDrawing() {
    return isDrawing;
    }
     
    public int getWeaponTipY(int playerCenterY) {
    return playerCenterY + (int) (distanceFromPlayer * Math.sin(angle));
    }
     
    public void damageMonster(int i){
    if(i != 999) {
     
    if (gp.mon[i].invincible == false) {
    gp.mon[i].life -= 1;
    gp.mon[i].invincible = true;
     
    if(gp.mon[i].life <= 0){
    gp.mon[i] = null;
    }
    }
    }
    }
    }




     
    package weapon;
     
    import main.GamePanel;
    import main.UtilityTool;
    import java.awt.image.BufferedImage;
     
    public class Sword extends Weapon {
     
        public Sword(GamePanel gp) {
            super(gp, 10); 
     
            solidArea.x = 24;
            solidArea.y = 0;
            solidAreaDefaultX = solidArea.x;
            solidAreaDefaultY = solidArea.y;
            solidArea.width = gp.tileSize - 2*solidArea.x;
            solidArea.height = gp.tileSize - solidArea.y;
     
            initialAngle = Math.toRadians(22.5);
            turn = Math.toRadians(135);
        }
     
        @Override
        protected void getImage() {
            BufferedImage swordSpriteSheet = UtilityTool.setup("/resources/weapons/sword2", 1, gp.tileSize);
            this.frames = UtilityTool.extractFrames(swordSpriteSheet, 1, gp.tileSize);
        }
     
    // ------------------------------not used for now------------------
        protected void getEffect() {
            BufferedImage swordSpriteSheet = UtilityTool.setup("/resources/effects/slash1", 4, gp.tileSize);
            this.framesEffect = UtilityTool.extractFrames(swordSpriteSheet, 4, gp.tileSize);
        }
    }
    Last edited by Ario; October 31st, 2024 at 07:32 AM.

  2. #2
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,162
    Thanks
    65
    Thanked 2,725 Times in 2,675 Posts

    Default Re: Game hitboxes

    the hitbox is never applied exactly where the weapon is.
    Please explain in more detail.

    Please edit your post and wrap your code with code tags:

    [code]
    **YOUR CODE GOES HERE**
    [/code]

    to get highlighting and preserve formatting.

    How can someone execute your code for testing? I do not see a main() method for starting its execution.
    If you don't understand my answer, don't ignore it, ask a question.

  3. #3
    Junior Member
    Join Date
    Oct 2024
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Re: Game hitboxes

    How can I provide my entire code for it to be tested? there are many other classes and even with the main, the code could not be executed I must provide the whole.

    --- Update ---

    I can try to comment on every part of my code. I'm providing a simpler version where everything is working, basically I need to add a hitbox to my weapon.

    package weapon;
     
    import entity.Entity;
    import main.GamePanel;
    import java.awt.*;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
     
    public abstract class Weapon {
     
        protected GamePanel gp;
        public boolean isAttacking = false;
        public boolean collisionOn = false;
     
        //animations
        protected boolean isDrawing = false;
        protected BufferedImage[] frames; 
        protected int currentFrame = 0;
        protected int counterFrames = 0;
        protected BufferedImage[] framesEffect; 
     
        //angles
        public double angle = 0;
        protected double initialAngle = 0;
        protected double startAngle; 
        protected double turn = Math.PI; 
     
        //characteristics
        public int distanceFromPlayer = 50;
        protected int speed = 5;
        protected int damage;
        public Rectangle solidArea;
        public int solidAreaDefaultX, solidAreaDefaultY;
     
        public Weapon(GamePanel gp, int damage) {
            this.gp = gp;
            this.damage = damage;
     
            solidArea = new Rectangle();
            solidArea.x = 0;
            solidArea.y = 0;
            solidAreaDefaultX = solidArea.x;
            solidAreaDefaultY = solidArea.y;
            solidArea.width = gp.tileSize - 2*solidArea.x;
            solidArea.height = gp.tileSize - solidArea.y;
     
            getImage();
            getEffect();
        }
     
     
        protected abstract void getImage();
        protected abstract void getEffect();
     
        public void startAttack(String direction) {
            if (!isDrawing) {
                isDrawing = true;
     
                startAngle = switch (direction) {
                    case "up" -> Math.toRadians(180) + initialAngle;
                    case "down" -> initialAngle;
                    case "left" -> Math.toRadians(90) + initialAngle;
                    case "right" -> Math.toRadians(-90) + initialAngle;
                    default -> initialAngle;
                };
                angle = startAngle;
            }
        }
     
        public void update() {
            if (isDrawing) {
                angle += Math.toRadians(speed);
                if (angle - startAngle >= turn) {
                    isDrawing = false;
                }
                counterFrames++;
                if (counterFrames > 5) {
                    currentFrame = (currentFrame + 1) % frames.length;
                    counterFrames = 0;
                }
            }
        }
     
     
        public void draw(Graphics2D g2, int playerCenterX, int playerCenterY) {
            if (isDrawing) {
                int weaponX = playerCenterX + (int) (distanceFromPlayer * Math.cos(angle) + gp.tileSize);
                int weaponY = playerCenterY + (int) (distanceFromPlayer * Math.sin(angle)) + gp.tileSize/2; 
     
                AffineTransform originalTransform = g2.getTransform();
                AffineTransform weaponTransform = new AffineTransform();
                weaponTransform.translate(weaponX, weaponY); 
                weaponTransform.rotate(angle + Math.PI / 2, gp.tileSize / 2, gp.tileSize / 2); 
                g2.setTransform(weaponTransform);
     
                if (frames[currentFrame] != null) {
     
                    g2.drawImage(frames[currentFrame], 0, 0, gp.tileSize, gp.tileSize, null);}
     
                    g2.setTransform(originalTransform);
                }
        }
     
     
        public boolean isDrawing() {
            return isDrawing;
        }
     
        public int getWeaponTipY(int playerCenterY) {
            return playerCenterY + (int) (distanceFromPlayer * Math.sin(angle));
        }
     
        public void damageMonster(int i){
            if(i != 999) {
     
                if (gp.mon[i].invincible == false) {
                    gp.mon[i].life -= 1;
                    gp.mon[i].invincible = true;
     
                    if(gp.mon[i].life <= 0){
                        gp.mon[i] = null;
                    }
                }
            }
        }
    }

    draw manages the display of my sword, I use affineTransform to apply a rotation and translation to the sword when the player presses space, isDrawing becomes True.

    Update manages the animation from spriteSheet but it does not matter much in my problem. Update also manages the angle progress that the sword travels during its use.

    In StartAttack I define the starting angles according to the orientation of the player.

    damageMonster is not used here but I would like to use it to apply damage to monsters when the sword’s collision box comes into contact with the monster’s.

    --- Update ---

    Maybe I can provide some pictures to illustrate?

  4. #4
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,162
    Thanks
    65
    Thanked 2,725 Times in 2,675 Posts

    Default Re: Game hitboxes

    How can I compile the code and execute it for testing? It does not have a main method.
    Can you make and post minimum code for testing?
    If you don't understand my answer, don't ignore it, ask a question.

  5. #5
    Junior Member
    Join Date
    Dec 2024
    Posts
    1
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Re: Game hitboxes

    To fix your weapon hitbox issue, ensure that the hitbox coordinates and dimensions are updated consistently with the sword's position, rotation, and scale. Here's a general approach:

    Translate and Rotate the Hitbox: Use the same transformation logic applied to the sword's rendering for the hitbox. This includes translating the hitbox to the sword's position and rotating it accordingly.

    Update on Every Frame: Recalculate the hitbox in the update() method to keep it aligned with the sword's current position and rotation.

    Debugging: When using drawRect, ensure you're drawing it with the correct coordinates and dimensions. You can log or print the values to verify.

Similar Threads

  1. LWJGL Game: Odd behavior in game. Need help.
    By vividMario52 in forum What's Wrong With My Code?
    Replies: 3
    Last Post: March 2nd, 2013, 05:43 PM
  2. Replies: 3
    Last Post: March 1st, 2013, 11:01 PM
  3. Help with Snake Game Java Code: It's Impossible to Lose the Game
    By haruspex_icis in forum What's Wrong With My Code?
    Replies: 20
    Last Post: December 17th, 2012, 12:21 PM
  4. Game Maker Language and Game Maker and Zelda Classic thread
    By Fira in forum Other Programming Languages
    Replies: 3
    Last Post: April 17th, 2012, 08:59 AM
  5. Simple game that requires me to load game settings from a file
    By 14fenix in forum Java Theory & Questions
    Replies: 5
    Last Post: December 1st, 2011, 09:21 PM

Tags for this Thread