简体   繁体   中英

Java: game slowing down while using affine transform

I want to create a game similar to SpaceInvaders, but instead of getting to the bottom of the screen, the aliens shoot projectiles. One type of aliens I wanted to create(in the code below), turns to 45 degree and back. I tried it with affine transform, but everytime they turn the game slows down to half of the speed. The player and the projectiles are moving at half the speed then. The code below is the class that creates a JPanel and draws everything.

import javax.swing.Timer;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import java.util.*;
import javax.swing.JPanel;
import javax.imageio.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.io.IOException;
import javax.swing.*;

public class WELTZEICHNER2 extends JPanel implements  ActionListener , 
KeyListener
{
Player p;
Timer t = new Timer (5, this);
ArrayList<ANGRIFF> ziele = new ArrayList<ANGRIFF>();
ArrayList<ANGRIFF> ziele2 = new ArrayList<ANGRIFF>();
ArrayList<ALIEN1> aliens1 = new ArrayList<ALIEN1>();
private boolean left,right,space;
private int lastshot = 100;
private int score =0;
BufferedImage image;
BufferedImage image2;
BufferedImage image3;
BufferedImage image4;
int count = 0;
int count2 = 0;
int d = 0;

public WELTZEICHNER2()
{
    setDoubleBuffered(true);
    p = new Player(500,900,100000);
    t.start();
    addKeyListener(this);
    setFocusable(true);

    URL resource = getClass().getResource("alien2.png");
    URL resource2 = getClass().getResource("background.png");  
    URL resource3 = getClass().getResource("raumschifftest.png"); 
    URL resource4 = getClass().getResource("kreislertest.png");

    try {
        image = ImageIO.read(resource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        image2 = ImageIO.read(resource2);
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        image3 = ImageIO.read(resource3);
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        image4 = ImageIO.read(resource4);
    } catch (IOException e) {
        e.printStackTrace();
    }
    for (int i= 0;i < 20;i++)
    {
        for (int j =0;j <5;j++)
        {

            aliens1.add(new ALIEN1(70+i*90,80+j*70,1));

        }
    }

}

public void erzeugeANGRIFF()
{
    ANGRIFF b = new ANGRIFF(p.getxN() + 11, p.getyN(),true);
    ziele2.add(b);

}

public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    g.drawImage(image2,1,1,this); //background image
    g.drawImage(image3,p.getxN(),p.getyN(),this); //player image

    for (ANGRIFF b : ziele)
    {
        g2.setColor(Color.RED);
        g2.fill( new Ellipse2D.Double(b.getxN(),b.getyN(),5,10)); //alien´s projectiles
    }
    for (ANGRIFF b : ziele2)
    {
        g2.setColor(Color.GREEN);
        g2.fill( new Ellipse2D.Double(b.getxN(),b.getyN(),5,10)); // player´s projectiles
    }

    for (ALIEN1 i : aliens1) //draw alien images
    {

        if(count2 > 10000)
        {
            AffineTransform trans = new AffineTransform();
            trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
            BufferedImage rotated = new BufferedImage(image4.getWidth(),
                    image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D g3 = rotated.createGraphics();
            g3.drawImage(image4, trans, null);
            g2.drawImage(rotated,i.getxN(),i.getyN(),null);

        }
        else
        {
            g.drawImage(image4,i.getxN(),i.getyN(),this);
        }

    }
    g2.setColor(Color.RED);
    g2.drawString("Score:"+ score,5,15);
    g2.drawString("Health:"+ p.health,5,30);
    g2.drawString("Count:"+ count,5,45);

    if(p.health == 0) //Game Over screen
    {
        g2.setColor(Color.BLACK);
        g2.fill(new Rectangle2D.Double(1,1,1920,1080));
        g2.setColor(Color.RED);
        String text = "Game Over";
        Font endtext = new Font("TimesNewRoman",Font.PLAIN, 200 );
        g2.setFont(endtext);
        g2.drawString(text,450,540);
    }

}

public void actionPerformed(ActionEvent e)
{   
    if ( right == true)
    {
        p.right();
    }
    if (left == true)
    {
        p.left();
    }

    if(space == true && lastshot < 0)
    {
        erzeugeANGRIFF();
        lastshot = 100;
    }

    lastshot -=1;
    int bulletCount =ziele.size();
    int bulletCount2 =ziele2.size();

    int Alien1Count = aliens1.size();
    ArrayList<Integer> remANGRIFF= new ArrayList<Integer>();
    ArrayList<Integer> remANGRIFF2= new ArrayList<Integer>();
    ArrayList<Integer>remAlien1=new ArrayList<Integer>();

    for( int i = 0; i < bulletCount2;i++)
    {
        ANGRIFF b = ziele2.get(i);
        b.bewegeANGRIFF();
        if (b.getyN() >1000 )
        {
            remANGRIFF2.add(i);
        }

        for (int j =0;j< Alien1Count;j++ )
        {

            ALIEN1 n = aliens1.get(j);
            if (b.checkCollision(n) && b.player == true)
            {

                n.health -=1;
                score +=50;
                if (n.health <= 0)
                {
                    remAlien1.add(j);
                    score +=100;

                }
                remANGRIFF2.add(i);
            }
        }

    }
    for( int i = 0; i < bulletCount;i++)
    {
        ANGRIFF b = ziele.get(i);
        b.bewegeANGRIFF();
        if (b.getyN() < -100 )
        {
            remANGRIFF.add(i);
        }
        if (b.checkCollision(p) && b.player == false)
        {

            p.health -=50;

            if (p.health <= 0)
            {
                p.health = 0;

            }
            remANGRIFF.add(i);
        }
    }

    for (ALIEN1 i : aliens1)
    {
        // i.Bewegungsmuster();
        count2++;
        if(count2 > 20000)
        {
            count2 = 0;
        }
        if (i.newANGRIFF())
        {
            ziele.add(new ANGRIFF(i.getxN()+50,i.getyN()+50,false));
        }

    }
    for (int i: remANGRIFF)
    {
        if(i < ziele.size())
        {
            ziele.remove(i);
        }
    }
    for (int i: remANGRIFF2)
    {
        if(i < ziele2.size())
        {
            ziele2.remove(i);
        }
    }

    for (int i: remAlien1)
    {
        if (i<aliens1.size())
        {
            aliens1.remove(i);
        }

    }

    repaint();
}

public void keyPressed(KeyEvent e)
{
    int code = e.getKeyCode();

    if ( code == KeyEvent.VK_RIGHT)
    {
        right = true;
    }
    if ( code == KeyEvent.VK_LEFT)
    {
        left = true;
    }

    if ( code == KeyEvent.VK_SPACE)
    {
        space = true;
    }
}

public void keyReleased(KeyEvent e)
{
    int code = e.getKeyCode();

    if ( code == KeyEvent.VK_RIGHT)
    {
        right = false;
    }
    if ( code == KeyEvent.VK_LEFT)
    {
        left = false;
    }
    if ( code == KeyEvent.VK_SPACE)
    {
        space = false;
        lastshot =0;
    }
}

public void keyTyped(KeyEvent e)
{
    int code = e.getKeyCode();
    if ( code == KeyEvent.VK_SPACE)
    {
        erzeugeANGRIFF();
    }

}

}

This is the class that starts the game.

import javax.swing.*;

public class start
{

  public static void main(String[] args)
  {
    //System.setProperty("sun.java2d.d3d", "true");
    //System.setProperty("sun.java2d.noddraw", "false");
    //-Dsun.java2d.noddraw=false;
    JFrame f = new JFrame();
    WELTZEICHNER2 d = new WELTZEICHNER2();
    f.setSize(1920,1080);
    f.setTitle("BlueJ Space Invader");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     f.add(d);
    f.setVisible(true);


  }   
}

Any help is appreciated.

You're "core" problem is here...

if(count2 > 10000)
{
    AffineTransform trans = new AffineTransform();
    trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
    BufferedImage rotated = new BufferedImage(image4.getWidth(),
            image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
    Graphics2D g3 = rotated.createGraphics();
    g3.drawImage(image4, trans, null);
    g2.drawImage(rotated,i.getxN(),i.getyN(),null);

}

This is creating a number of short lived objects on every paint cycle, which is putting extra strain one the GC, slowing down your program - not to mention the time it takes to create a BufferedImage

A better solution is to simply rotate the current Graphics context. The problem with this is, it can become very complex very quickly.

So, basically what I would do, is I would use the AffineTransform to translate the origin point/offset to the position of the object you are painting. The rotation then becomes as simple as rotating about the centre point of the image and then painting the image at 0x0 .

The trick is reseting the transform when you're finished. This is where creating another copy of the Graphics context before hand, applying the transform to it, painting the image and then disposing of the copy comes in very, very handy.

if (count2 > 10000) {
    AffineTransform trans = new AffineTransform();
    trans.translate(i.getxN(), i.getyN());
    trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
    //BufferedImage rotated = new BufferedImage(image4.getWidth(),
    //image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
    Graphics2D g3 = (Graphics2D) g2.create();
    g3.setTransform(trans);
    //g3.drawImage(image4, trans, null);
    g3.drawImage(image4, 0, 0, null);
    g3.dispose();

}

When I was testing your code, I had witnessed an uneven frame rate. The ActionListener was been called at intervals in far greater values of 5 milliseconds. By the time it had performed 30, 000 cycles, it was already at an average of 75 milliseconds and slowly increasing, which suggest that you have some more issues to deal with.

Focus on the ArrayList and the creation/disposal of your objects and consider using "pools" of objects to further reduce the GC overhead where possible

You could have a look at Swing animation running extremely slow for an example.

PS @ about 300, 000 cycles, the update cycle is up to an average of 200 milliseconds per update :P

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM