You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

按键移动矩形时run方法中repaint()与update()无效问题求助

问题描述

我需要让run方法(原描述误称loop())能够调用repaint(),但调用后无任何效果。此外,执行代码时run方法也未执行update()。尝试多种修改方式均无效,使用Eclipse作为开发IDE,因老师要求从零编写代码,不得使用游戏引擎。

相关代码

GamePanel类

package main;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable {

    private static final long serialVersionUID = 1L;
    final int originalTilesize=16;
    final int scale=3;
    final int tileSize=originalTilesize *scale;
    final int maxScreenRow=12;
    final int maxScreenCol=16;
    final int screenWidth=tileSize*maxScreenCol;
    final int screenHeight=tileSize*maxScreenRow;
    
    int FPS=60;
    KeyHandler keyH = new KeyHandler();
    Thread gameThread;

    int playerX=100;
    int playerY=100;
    int playerSpeed=4;

    public GamePanel()
    {
        this.setPreferredSize(new Dimension(screenWidth,screenHeight));
        this.setBackground(Color.black);
        this.setDoubleBuffered(true);
        this.addKeyListener(keyH);
        this.setFocusable(true);
    }
    public void startGameThread()
    {
        gameThread = new Thread(this);  
        gameThread.start();
    }


    public void run() {
        double drawInterval=1000000000/FPS;
        double nextDrawTime=System.nanoTime()+drawInterval;
        while (gameThread !=null) {
            update();
            repaint();
            
            try {
                double remainingTime=nextDrawTime-System.nanoTime();
                remainingTime=remainingTime/1000000;
                if (remainingTime<0)
                {
                    remainingTime=0;
                }
                Thread.sleep((long)remainingTime);
                nextDrawTime+=drawInterval;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };  
    }

    public void update()
    {
        if (keyH.upPressed == true)
        {
            playerY-=playerSpeed;
        }
        else if(keyH.downPressed==true)
        {
            playerY +=playerSpeed;  
        }
        else if(keyH.leftPressed==true)
        {
            playerX -=playerSpeed;  
        }
        else if(keyH.rightPressed==true)
        {
            playerX +=playerSpeed;  
        }
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2=(Graphics2D)g;
        g2.setColor(Color.white);
        g2.fillRect(playerX,playerY,tileSize,tileSize);
        g2.dispose();
    }
}

KeyHandler类

package main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyHandler implements KeyListener {
    public boolean upPressed,downPressed,leftPressed,rightPressed;

    public void keyTyped(KeyEvent e) {
        
    }

    public void keyPressed(KeyEvent e) {
        
        int code =e.getKeyCode();
        if (code==KeyEvent.VK_W) {
            upPressed = true;   
        }

        if (code==KeyEvent.VK_S) {
            downPressed=true;   
        }

        if (code==KeyEvent.VK_A) {
        leftPressed=true;
        }

        if (code==KeyEvent.VK_D) {
            rightPressed=true;  
        }

    }

    public void keyReleased(KeyEvent e) {
        int code=e.getKeyCode();
        if (code==KeyEvent.VK_W) {
            upPressed = false;  
        }

        if (code==KeyEvent.VK_S) {
            downPressed=false;  
        }

        if (code==KeyEvent.VK_A) {
            leftPressed=false;
        }

        if (code==KeyEvent.VK_D) {
            rightPressed=false; 
        }
    }
}
解决方法

1. 确保启动游戏线程

你的GamePanel类中startGameThread()方法负责启动线程,但如果没有在主类中调用这个方法,run()根本不会执行。需要添加一个主类来初始化窗口并启动线程:

package main;

import javax.swing.JFrame;

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        GamePanel gamePanel = new GamePanel();
        
        frame.add(gamePanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        // 必须调用此方法启动游戏线程
        gamePanel.startGameThread();
    }
}

2. 删除手动释放Graphics资源的代码

在paintComponent方法中调用g2.dispose()会提前释放绘制资源,导致内容无法正常显示。Swing会自动管理Graphics资源,删除这行代码即可:

public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2=(Graphics2D)g;
    g2.setColor(Color.white);
    g2.fillRect(playerX,playerY,tileSize,tileSize);
    // 移除下面这行
    // g2.dispose();
}

3. 优化线程循环(可选)

原run()方法的时间计算可能存在累积误差,可以改成更稳定的实现:

public void run() {
    long lastTime = System.nanoTime();
    double tickInterval = 1000000000.0 / FPS;
    double delta = 0;
    
    while(gameThread != null){
        long now = System.nanoTime();
        delta += (now - lastTime) / tickInterval;
        lastTime = now;
        
        if(delta >= 1){
            update();
            repaint();
            delta--;
        }
    }
}

完成以上修改后,run()方法会正常执行update(),repaint()也能正确绘制玩家方块。

内容的提问来源于stack exchange,提问作者299792458

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:25:25