Java: игра замедляется при использовании аффинного преобразования - PullRequest
0 голосов
/ 01 июля 2018

Я хочу создать игру, похожую на SpaceInvaders, но вместо того, чтобы добраться до нижней части экрана, инопланетяне стреляют снарядами. Один тип пришельцев, который я хотел создать (в коде ниже), превращает до 45 градусов и обратно. Я пробовал это с аффинным преобразованием, но каждый раз, когда они поворачивают, игра замедляется до половины скорости. Игрок и снаряды движутся в два раза быстрее. Код ниже - это класс, который создает JPanel и рисует все.

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();
    }

}

}

Это класс, который запускает игру.

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);


  }   
}

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 01 июля 2018

Вы здесь "основная" проблема ...

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);

}

Это создание нескольких недолговечных объектов в каждом цикле рисования, что создает дополнительную нагрузку на ГХ, замедляя вашу программу - не говоря уже о времени, которое требуется для создания BufferedImage

Лучшее решение - просто повернуть текущий контекст Graphics. Проблема в том, что она может очень быстро стать очень сложной.

Итак, в основном я бы использовал AffineTransform для перевода исходной точки / смещения в положение объекта, который вы рисуете. Вращение становится таким же простым, как вращение вокруг центральной точки изображения, а затем раскрашивание изображения в 0x0.

Хитрость в том, чтобы сбросить преобразование, когда вы закончите. Здесь очень удобно создать еще одну копию контекста Graphics, применить к нему преобразование, нарисовать изображение и затем удалить копию.

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();

}

Когда я тестировал ваш код, я наблюдал неравномерную частоту кадров. ActionListener был вызван с интервалами в гораздо больших значениях 5 миллисекунд. К тому времени, когда он выполнил 30 000 циклов, он уже составлял в среднем 75 миллисекунд и медленно увеличивался, что говорит о том, что у вас есть еще некоторые проблемы, с которыми нужно иметь дело.

Сосредоточьтесь на ArrayList и создании / удалении ваших объектов и подумайте об использовании «пулов» объектов для дальнейшего снижения накладных расходов ГХ, где это возможно

Например, Анимация Swing работает очень медленно .

PS @ около 300 000 циклов, цикл обновления составляет в среднем до 200 миллисекунд на обновление: P

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...