有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

仿射变换Java:使用仿射变换时游戏速度减慢

我想创建一个类似于太空入侵者的游戏,但是外星人并没有进入屏幕的底部,而是发射射弹。我想创造的一种外星人(在下面的代码中)变成了 到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) 个答案

  1. # 1 楼答案

    你的“核心”问题就在这里

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

    这会在每个绘制周期中创建大量短期对象,这会给GC带来额外的压力,降低程序的速度—更不用说创建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();
    
    }
    

    当我测试你的代码时,我看到了不均匀的帧速率。以远大于5毫秒的间隔调用ActionListener。当它执行30000次循环时,它的平均时间已经是75毫秒,并且在缓慢增加,这表明你还有一些问题要处理

    关注于{{CD7}}和对象的创建/处理,并考虑使用对象的“池”来进一步减少可能存在的

    的GC开销。

    你可以看看Swing animation running extremely slow作为例子

    PS@300000个周期,每次更新的平均周期为200毫秒:p