[英]ActionListener executes twice on JPanel when called from JFrame
我希望為我的吃豆人精靈設置動畫,但是當我的計時器調用actionPerformed
來更新圖像時,它會執行兩次並跳過動畫。
下面是主類的代碼:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.concurrent.TimeUnit;
import javax.swing.Timer;
public class Pacman extends JFrame implements ActionListener, KeyListener{
public static Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
public static int FRAME_HEIGHT = (int)(dim.height-dim.height/5);
public static int FRAME_WIDTH = (int)(dim.width-dim.width/5);
public static Pacman frame = new Pacman();
public static Game gameInterface = new Game();
public static Timer timer;
public Pacman() {
super("Pac-man");
timer = new Timer(175, this);
timer.start();
addKeyListener(this);
}
public static void main(String[] args) {
ImageIcon frameIcon = new ImageIcon("Icon.png");
frame.setSize(FRAME_WIDTH,FRAME_HEIGHT);
frame.setIconImage(frameIcon.getImage());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.setContentPane(gameInterface);
gameInterface.requestFocus();
gameInterface.setFocusable(true);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int JframeX = (dim.width-FRAME_WIDTH)/2;
int JframeY = (dim.height-FRAME_HEIGHT)/2;
frame.setLocation(JframeX, JframeY);
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void paint(Graphics g) {
super.paint(g);
}
public void actionPerformed(ActionEvent ev){
repaint();
}
}
這是游戲類的代碼:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.concurrent.TimeUnit;
import javax.swing.Timer;
public class Game extends JPanel implements ActionListener, KeyListener{
public static Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
public static int FRAME_HEIGHT = (int)(dim.height-dim.height/5);
public static int FRAME_WIDTH = (int)(dim.width-dim.width/5);
public static Game gamePanel = new Game();
public static Timer timer;
public static boolean gameExit = false;
public static int animCounter = 0, imgPacmanX1 = 840, imgPacmanY1 = 0, imgPacmanX2 = 890, imgPacmanY2 = 50;
public Game() {
timer = new Timer(500, this);
timer.start();
addKeyListener(this);
}
public static void main(String[] args) {
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon animations = new ImageIcon("Pacman_Animations.png");
g.setColor(Color.BLUE);
g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
g.drawImage(animations.getImage(), 150, 200, 200, 250, imgPacmanX1, imgPacmanY1, imgPacmanX2, imgPacmanY2, null);
}
public void actionPerformed(ActionEvent ev){
if(animCounter == 2){
imgPacmanY1 = 0;
imgPacmanY2 = 50;
animCounter = 0;
}
else{
imgPacmanY1 += 50;
imgPacmanY2 += 50;
animCounter += 1;
}
repaint();
System.out.print(imgPacmanY1 + " " + imgPacmanY2 + " ");
}
}
如果我單獨運行游戲類,動作監聽器工作正常並且只執行一次,但是從我的主類調用動作監聽器執行兩次並且動畫開始跳幀。
你有兩個Timer
,每個都觸發repaint
和......歡迎來到你的架構錯誤的奇妙世界。
JFrame
這樣的頂級容器的繪制,事實上,通常不鼓勵從JFrame
擴展,因為您實際上並沒有向類添加新功能,而且它們已經是一堆組件。static
。 如果您發現您正在使用static
來允許您引用其他對象,那么您的設計是錯誤的。 您應該通過構造函數或 getter 將信息傳遞給您的類。 這就是“模型-視圖-控制器”之類的東西進來並且很重要的地方KeyListener
是一個糟糕的選擇,你應該使用Key bindings API來代替。 您應該關注的第一件事是將游戲核心邏輯與渲染工作流程分離。 這意味着您將有一個“主循環”(在本例中為 Swing Timer
),它將更新模式(或狀態),然后觸發一個繪制周期。 然后渲染工作流將使用當前“狀態”進行渲染。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.