0

标题最有可能令人困惑,但让我详细说明一下。

我正在制作一个视频游戏。我到处搜索这个问题的答案,但似乎我无法使用我的代码。我有两个类:一个用于主要方法,另一个用于 JFrame:

运行游戏.java:

package net.naprav.wardungeon;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

public class RunGame extends Canvas implements Runnable {
private static final long serialVersionUID = 1203994186653691379L;

private static final int WIDTH = WindowFrame.WIDTH;
private static final int HEIGHT = WindowFrame.HEIGHT;
private static final Dimension size = WindowFrame.size;

private Thread thread;
public boolean isRunning = false;

public static int FPS = 0; //Frames per second.
public static int TPS = 0; //Ticks per second. (Updates per second)

public static String frames;
public static String updates;

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] allPixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

//static Key key;
RenderSystem system;

/**
 * Added the main constructor.
 */ 
public RunGame() {
    this.setVisible(true);
    this.setSize(size);
    this.setPreferredSize(size);
    this.setMinimumSize(size);
    this.setMinimumSize(size);

    system = new RenderSystem(WIDTH, HEIGHT);
}

/**
 * Responsible for the logic behind the game.
 */
public void tick() {

}

/*
 * Responsible for the actual rendering behind the game.
 */
public void render() {
    BufferStrategy buffer = this.getBufferStrategy();

    //Clearing the screen to make room for the pixels! :D
    system.clearScreen();
    //Rendering the pixels in the RenderMechanism class.
    system.changePixels();
    for (int counter = 0; counter < allPixels.length; counter++) {
        //Setting the pixels in this class to the ones in RenderMechanism.java.
        allPixels[counter] = system.allPixels[counter];
    }

    //Buffer is automatically null, so we can create one to render a number of buffers. (3)
    if (buffer == null) {
        this.createBufferStrategy(3);
        return;
    }

    //Graphics setup.
    Graphics gfx = buffer.getDrawGraphics();
    gfx.setColor(new Color(146, 17, 189));
    gfx.fillRect(0, 0, this.getWidth(), this.getHeight());
    //Draw stuffs between here...
    gfx.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
    //and here.
    gfx.dispose();
    buffer.show();
}

/**
 * Used to start the thread and make it go! :D
 */
public synchronized void begin() {
    thread = new Thread(this);
    thread.start();
    isRunning = true;
}

/**
 * Used to end the thread and make it stop! :/
 */
public synchronized void finish() {
    if (isRunning == true) {
        isRunning = false;
        try {
            thread.join();
        } catch (InterruptedException exc) {
            System.out.println("Couldn't join thread! :(");
            exc.printStackTrace();
        }
    }
}   


/**
 * The run method is used to run the game itself in the thread.
 */
public void run() {
    long previousTime = System.nanoTime();
    long secondTimer = System.currentTimeMillis();

    final double nanoSeconds = 1000000000.0 / 60.0;
    double omega = 0;

    while (isRunning == true) {
        long currentTime = System.nanoTime();
        omega += (currentTime - previousTime) / nanoSeconds;
        previousTime = currentTime;

        while (omega >= 1) {
            this.tick();
            TPS++;
            omega--;
        }

        this.render();
        FPS++;

        if ((System.currentTimeMillis() - secondTimer) > 1000) {
            secondTimer += 1000;
            //Un-comment out below code for console output of frames and updates.
            frames = String.valueOf(FPS);
            updates = String.valueOf(TPS);
            System.out.println(frames + ", " + updates);
            FPS = 0;
            TPS = 0;
        }
    }
    this.finish();
}

/**
 * The Main method.
 * @param args
 */
public static void main(String[] args) {
    WindowFrame window = new WindowFrame("WarDungeon", FPS, TPS);
    //Get rid of '//' below to test the login screen!
    //LoginScreen login = new LoginScreen("WarDungeon Login");
}
}

上面的代码用于使用线程运行游戏。我将 RunGame.java 类(扩展 Canvas)添加到 WindowFramejava 类:

package net.naprav.wardungeon;

import java.awt.Dimension;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JFrame;

public class WindowFrame extends JFrame {
private static final long serialVersionUID = 1203994186653691379L;

public static final int WIDTH = 330;
public static final int HEIGHT = 200;
public static final int SCALE = 3;
public static final Dimension size = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);

private ImageIcon icon;

RunGame game;

public WindowFrame(String title) {
    this.setTitle(title);
    this.setSize(size);
    this.setVisible(true);
    this.setResizable(true);
    this.setLocationRelativeTo(null);

    icon = new ImageIcon("res/wardungeon_logo.png");
    this.setIconImage(icon.getImage());

    game = new RunGame();

    this.add(game);
    game.begin();

    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public WindowFrame(String title, int frame, int update) {
    this.setTitle(title + " | " + "FPS: " + frame + ", UPS: " + update);
    this.setSize(size);
    this.setVisible(true);
    this.setResizable(true);
    this.setLocationRelativeTo(null);

    icon = new ImageIcon("res/wardungeon_logo.png");
    this.setIconImage(icon.getImage());

    game = new RunGame();

    this.add(game);
    game.begin();

    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

我知道这是很多代码,我很抱歉。我仍然是 Java 编码的菜鸟,但如果你能帮我解决这个问题,那就太好了。我的主要问题是我无法在标题栏上显示 FPS 和 TPS。我不知道如何在不影响帧和更新的“每秒”的情况下更改该变量。

提前致谢。

4

2 回答 2

0

简短的回答:您需要以某种方式定期.setTitle(...)从该run()方法调用 JFrame(可能代替System.out.println您已经到达那里)。这是使标题栏保持最新的唯一方法。

仅从您的代码的粗略概述来看,您似乎需要进行一些重构,因为 RunGame 类中没有对 JFrame 的引用。与其让 JFrame 成为包含 RunGame 实例的“主”,不如将其反转,让 RunGame 控制 JFrame。

于 2013-09-27T00:24:05.393 回答
0

可能有几种方法可以做到这一点......

基本流程是...

  • 找到父窗口/框架
  • 解析当前标题
  • 创建新标题
  • 更新窗口标题...

例如...

while (isRunning == true) {
    /*...*/

    if ((System.currentTimeMillis() - secondTimer) > 1000) {
        frames = String.valueOf(FPS);
        updates = String.valueOf(TPS);
        /*...*/
        Window parent = SwingUtilities.windowForComponent(this);
        if (parent instanceof Frame) {
            Frame frame = (Frame)parent;
            String title = frame.getTitle();
            String title = value.substring(0, value.indexOf("|")).trim();
            title = title + " | " + "FPS: " + frame + ", UPS: " + update;
            frame.setTitle(title);
        }
    }
}

我对这种方法的问题是它突然将你RunGameFrame...

虽然这看起来没什么大不了的,但如果你想重用组件或以其他方式部署它,它可能会破坏应用程序

更好的解决方案是定义一个interface具有某种RunGame可以调用的方法(get/setTitle例如)...

例如...

public interface GameContainer {
    public String getTitle();
    public void setTitle();
}

然后WindowFrame可以实现这个接口...

public class WindowFrame extends JFrame implements GameContainer {...}

并且RunGame需要一个实例...

public class RunGame extends Canvas implements Runnable {
    /*...*/
    private GameContainer gameContainer;
    public RunGame(GameContainer gameContainer) {
        this.gameContainer = gameContainer;

然后,您将使用此实例进行更改...

    if ((System.currentTimeMillis() - secondTimer) > 1000) {
        frames = String.valueOf(FPS);
        updates = String.valueOf(TPS);
        /*...*/
        if (gameContainer != null) {
            String title = gameContainer.getTitle();
            String title = value.substring(0, value.indexOf("|")).trim();
            title = title + " | " + "FPS: " + frame + ", UPS: " + update;
            frame.setTitle(title);
        }
    }

最后,当您创建游戏时,您只需传递GameContainer对它的引用...

game = new RunGame(this);

现在,您可以自由定义GameContainer您认为合适的...

于 2013-09-27T00:26:12.193 回答