user61349
user61349

Reputation: 13

Graphics in one object is influencing another object's graphics - JAVA

First post, so I'll try to be as clear as I can. Basically, what I'm trying to do is create a little game, where you have a ship, and you can shoot bullets from it. The ship rotates accordingly to the player's deltaX and deltaY using a tangent formula. I use a standard game loop like this one:

public void run() {
    long lastTime = System.nanoTime();
    double amountOfTicks = 60.0;
    double ns = 1000000000 / amountOfTicks;
    double delta = 0;
    long timer = System.currentTimeMillis();
    @SuppressWarnings("unused")
    int frames = 0;
    while(running){
        long now = System.nanoTime();
        delta += (now - lastTime) / ns;
        lastTime = now;
        while(delta >=1){
                tick();
                delta--;
            }
        if(running)
        repaint();
        frames++;

        if(System.currentTimeMillis() - timer > 1000)
        {
            timer += 1000;
            frames = 0;
        }
    }
    stop();
}

My "game" runs on a child of a JPanel, a class called Board. In the loop, I call the methods tick(), which updates the info, and repaint(), that works as a render method. This is my paintComponent(Graphics g) method:

public void paintComponent(Graphics g) {
    //This is for background
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.black);
    g2d.fill(new Rectangle(0, 0, Constants.width, Constants.height));

    //This is where actual game rendering occurs
    handler.render(g);
    g.dispose();
}

As can be seen, I dont render everything on my Board class. I do so on my handler. This is how I deal with the handler:

public void render(Graphics g) {
    for (int i = 0; i < handlerList.size(); i++) {
        //handlerList is a LinkedList
        handlerList.get(i).render(g);
    }
}

The LinkedList handlerList contains Entities. Entities is an abstract class, which is parent of Creature, which is parent of Player and Bullet. This is the code for the rendering of a Player instance:

public void render(Graphics g) {        
    float centerX = x + (width / 2);
    float centerY = y + (height / 2);

    double theta = findAngle(deltaX, deltaY);

    Graphics2D g2d = (Graphics2D) g;
    if(!stopped) g2d.rotate(theta, centerX, centerY);
    else g2d.rotate(stoppedTheta, centerX, centerY);
    g2d.drawImage(shipImage, (int)x, (int)y, (int)width, (int)height, null);
}

There is a boolean "stopped" which keeps track of the objects condition. I use Graphics2D instead of Graphics due to the fact that I wanna be able to rotate my ship.

Here's the code for the bullet's rendering:

public void render(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    g2d.setColor(Color.yellow);
    g2d.fillOval((int)x, (int)y, (int)width, (int)height);
 }

It looks right, as far as I'm aware. Whenever I don't have a bullet on, the game runs fine, as you can see in this GIF: DISCLAIMER: Sorry for low quality and the watermark, I've just formatted the computer and havent had time to install proper stuff....

When I add a bullet this happens:

The x and y position of the bullet doesn't change, but the bullet rotates with the ship. I'm assuming it has something to do with the misuse of the "dispose()" method, but I'm not sure what can be done to fix it.

Thank you in advance.

Upvotes: 1

Views: 43

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347274

  1. Don't ever call dispose on a Graphics context you did not explicitly create (or snapshot with create), this can cause issues further down the rendering pipeline.
  2. Graphics is a shared context, so you need to be mindful of the changes you make to it and undo any "significant" changes you make, especially transformations

If it was me, I'd create a snapshot of the Graphics context before each call to render and the dispose of it after, for example

public void render(Graphics g) {
    for (int i = 0; i < handlerList.size(); i++) {
        //handlerList is a LinkedList
        Graphics2D g2d = (Graphics2D)g.create();
        handlerList.get(i).render(g2d);
        g2d.dispose();
    }
}

This ensures that what ever changes that render makes to the Graphics context are undone before the next element is rendered

If the changes are compounding, then I'd make the snapshot before the start of the loop and dispose of it after it.

In either case, it means you control the changes been made and how they affect other elements down the line.

Also, remember, transformations are compounding

Upvotes: 1

Related Questions