4
\$\begingroup\$

I'm developing a 2D game in Java using Java Swing, and I've run into an issue with my player character's attack animation. The player has both movement and attack animations:

Movement sprites: 16x16 pixels Attack sprites: 80x80 pixels The movement animations work perfectly, and the player displays at the correct size. However, when I trigger the attack animation, the player sprite becomes very small, even though the attack sprites are larger than the movement sprites. The player goes through the complete axe attack animation however he becomes extremely small during the animation. Any insight would be greatly appreciated thanks !

Here's the relevant code from my Player class: package entity;

import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import main.GamePanel; import main.KeyHandler; import object.Axe_Object; import object.SuperObject; public class Player extends Entity{ public BufferedImage spriteSheet; public BufferedImage spriteSheetAxe; GamePanel gp; KeyHandler keyH; public int screenX; public int screenY; public SuperObject currentWeapon; // Player inventory and Game Mechanics private Inventory inventory; // Arrays to hold animation frames for each direction public BufferedImage[] upFrames = new BufferedImage[8]; public BufferedImage[] downFrames = new BufferedImage[8]; public BufferedImage[] leftFrames = new BufferedImage[8]; public BufferedImage[] rightFrames = new BufferedImage[8]; // Arrays to hold attacks animations public BufferedImage[] upAxeFrames = new BufferedImage[12]; public BufferedImage[] downAxeFrames = new BufferedImage[12]; public BufferedImage[] leftAxeFrames = new BufferedImage[12]; public BufferedImage[] rightAxeFrames = new BufferedImage[6]; private int frameIndex = 0; // To track the current frame private int frameCounter = 0; // control fame rate of animation private int frameDelay = 5; // How many game loops before switching frame public int numberOfKeys = 0; public Player(GamePanel gp, KeyHandler keyH) { this.gp = gp; this.keyH = keyH; screenX = gp.screenWidth / 2 - (gp.tileSize / 2); screenY = gp.screenHeight / 2 - (gp.tileSize / 2); solidArea = new Rectangle(8, 16, 16, 16); // x, y, width, height solidAreaDefaultX = solidArea.x; solidAreaDefaultY = solidArea.y; inventory = new Inventory(); setDefaultValues(); loadSpriteSheet(); loadPlayerImages(); loadPlayerAxeAttackImages(); } private void loadSpriteSheet() { try { spriteSheet = ImageIO.read(getClass().getResourceAsStream("/player/walk.png")); spriteSheetAxe = ImageIO.read(getClass().getResourceAsStream("/player/axesprite.png")); } catch (IOException e) { System.out.println("There was an error in loading the spritesheet"); e.printStackTrace(); } } private void loadPlayerImages() { int x = 3; int upY = 18; int downY = 13; int rightY = 3; int leftY = 8; for (int i = 0; i < 8; i++) { upFrames[i] = grabImage(x, upY, gp.originalTileSize, gp.originalTileSize); downFrames[i] = grabImage(x, downY, gp.originalTileSize, gp.originalTileSize); rightFrames[i] = grabImage(x, rightY, gp.originalTileSize, gp.originalTileSize); leftFrames[i] = grabImage(x, leftY, gp.originalTileSize, gp.originalTileSize); x += 5; } } // THIS IS THE PART CAUSING PROBLEMS private void loadPlayerAxeAttackImages() { int x = 3; int upY = 18; int downY = 13; int rightY = 3; int leftY = 8; // Load all up frames images for right swing rightAxeFrames[0] = grabImageAxeAttack(1, 1, 80, 80 ); rightAxeFrames[1] = grabImageAxeAttack(2, 1, 80, 80 ); rightAxeFrames[2] = grabImageAxeAttack(3, 1, 80, 80 ); rightAxeFrames[3] = grabImageAxeAttack(4, 1, 80, 80); rightAxeFrames[4] = grabImageAxeAttack(5, 1, 80, 80 ); rightAxeFrames[5] = grabImageAxeAttack(6, 1, 80, 80 ); } public void setDefaultValues() { worldX = gp.tileSize * 10; worldY = gp.tileSize * 10; speed = 7; direction = "down"; // PLAYER STATUS level = 1; maxNumberOfHP = 6; currentHp = maxNumberOfHP ; strength = 1; // The more strenght he has, the more damage he gives. dexterity = 1; // The more dexterity he has, the less damage he receives. attack = 4; defense = 1; exp = 0; nextLevelExp = 5; coin = 0; currentWeapon = new Axe_Object(); } public BufferedImage grabImage(int col, int row, int width, int height) { int x = (col * 16) - 16; int y = (row * 16) - 16; //System.out.printf("X coordinates: " + x + ", Y coordinates:", y); //System.out.println("Width: " + width + ", Height: " + height); return spriteSheet.getSubimage(x, y, width, height); } public BufferedImage grabImageAxeAttack(int col, int row, int width, int height) { int x = (col * 80) - 80; int y = (row * 80) - 80; //System.out.printf("X coordinates: " + x + ", Y coordinates:", y); //System.out.println("Width: " + width + ", Height: " + height); return spriteSheetAxe.getSubimage(x, y, width, height); } public void checkForObject() { for (int i = 0; i < gp.obj.length; i++) { if (gp.obj[i] != null) { if (this.gp.cChecker.objectCollision(this, gp.obj[i])) { // System.out.println("INTERSECTION BETWEEN PLAYER OBJECT"); pickUpObject(gp.obj[i]); // Pick up object if collided gp.obj[i] = null; // Remove object from the map break; } } } } private void pickUpObject(SuperObject obj) { // TODO Auto-generated method stub if (obj != null) { String objName = obj.name; switch (objName) { case "Key": gp.playSoundEffect(1); numberOfKeys++; break; } inventory.addItem(obj); System.out.println(obj.name + " picked up!"); } } public void update() { if (keyH.showInventory == true) { inventory.showInventory(); } if (keyH.upPressed == true || keyH.downPressed == true || keyH.leftPressed == true || keyH.rightPressed == true) { if (keyH.upPressed == true) { direction = "up"; //worldY -= speed; } else if (keyH.downPressed == true) { direction = "down"; //worldY += speed; } else if (keyH.leftPressed == true) { direction = "left"; // worldX -= speed; } else if (keyH.rightPressed == true) { direction = "right"; //worldX += speed; } // Check tile collision collisionOn = false; gp.cChecker.checkTile(this); if (collisionOn == false) { switch(direction) { case "up": worldY -= speed; break; case "down": worldY += speed; break; case "left": worldX -= speed; break; case "right": worldX += speed; break; } } checkForObject(); // Update animation frame if player is moving frameCounter++; if (frameCounter >= frameDelay) { // Pass to next state of animation frameCounter = 0; frameIndex++; if (frameIndex >= 6) { frameIndex = 0; } } } else { frameIndex =0; } } public void draw(Graphics2D g2) { //g2.fillRect(screenX, screenY, gp.tileSize, gp.tileSize); BufferedImage image = null; switch (direction) { case "up": image = upFrames[frameIndex]; if (attack()) { System.out.println("The player just attacked up"); image = upAxeFrames[frameIndex]; } break; case "down": image = downFrames[frameIndex]; if (attack()) { System.out.println("The player just attacked down"); image = downAxeFrames[frameIndex]; } break; case "left": image = leftFrames[frameIndex]; if (attack()) { System.out.println("The player just attacked left"); image = leftAxeFrames[frameIndex]; } break; case "right": image = rightFrames[frameIndex]; if (attack()) { System.out.println("The player just attacked right"); image = rightAxeFrames[frameIndex]; } break; } g2.drawImage(image, screenX, screenY, gp.tileSize, gp.tileSize, null); } @Override public boolean attack() { // TODO Auto-generated method stub if (keyH.weaponAttack) { return true; } return false; } } 
\$\endgroup\$

1 Answer 1

19
\$\begingroup\$

This is the line where you actually draw the player:

g2.drawImage(image, screenX, screenY, gp.tileSize, gp.tileSize, null); 

As you can see in the documentation, there are several versions of this method. You've picked the one that takes 6 arguments, (Image img, int x, int y, int width, int height, ImageObserver observer). And for the width and height parameters, you passed gp.tileSize. That means "Take this image and scale it to this size before you draw it". So your 80x80 attack frames get scaled down to your tile size of (I assume) 16x16.

However, there is also a version of drawImage which doesn't take an image size. Try this:

g2.drawImage(image, screenX, screenY, null); 

Now every frame will be drawn in its original size.

However, you might now see a different problem: The frame is not where it should be. The larger sprites are too far to the right and too far down. That's because the coordinates we pass are the top-left corner of the sprite. So when you have spritesheets of non-uniform size, then you need to define a pivot point for each frame and take that into account when calculating the screen position. You didn't show us your sprites, so I don't know where their pivot points are. If they are always in the center of the frame, you could do this:

g2.drawImage(image, screenX - image.getWidth() / 2, screenY - image.getHeight() / 2, null); 

Now every frame will be drawn centered on the screenX:screenY point.

\$\endgroup\$
0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.