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

Java加速度物理引擎无法减速/停止问题求助

物理引擎减速逻辑不执行问题排查与修复

我开发了一款带加速度功能的物理引擎,但尝试让物体停止时,它既不减速也不停止。排查后发现if(deaccelerating) {...}代码块从未执行,试了多种方法都解决不了。相关代码如下:

原始Acceleration类代码

public class Acceleration {
    
    public float rateOfVelocity = 0.125f;
    public float rateOfAcceleration = 2;
    
    public int alternateRateOfVelocity = 1;
    public int alternateRateOfAcceleration = 2;

    public boolean accelerating;
    public boolean deaccelerating;
    
    public boolean alternateAccelerating;
    public boolean alternateDeaccelerating;
    
    public boolean loopedOnce;
    
    public void accelerate(float max, float min) {
        if(accelerating) {
            if(rateOfVelocity < max) {
                while(rateOfVelocity < max && !loopedOnce) {
                    rateOfVelocity*=rateOfAcceleration;
                    System.out.println(":)");
                    loopedOnce=true;                
                }
            }
            if(rateOfVelocity >= max || !accelerating){
                deaccelerating=true;
                System.out.println(deaccelerating);
            }
        }
        if(deaccelerating) {
            if(rateOfVelocity > min) {
                while(rateOfVelocity < min && !loopedOnce) {
                    rateOfVelocity/=rateOfAcceleration;
                    loopedOnce=true;
                }
            }
        else if(rateOfVelocity <= min) {
                deaccelerating=false;
            }
        }
    }
    public void alternateAccelerate(float max, float min) {
        if(alternateAccelerating) {
            if(alternateRateOfVelocity < max) {
                while(alternateRateOfVelocity < max && !loopedOnce) {
                    alternateRateOfVelocity*=rateOfAcceleration;
                    loopedOnce=true;
                }
            }
        }
        else if(alternateDeaccelerating) {
            while(rateOfVelocity > min && !loopedOnce) {
                alternateRateOfVelocity/=alternateRateOfAcceleration;
                loopedOnce=true;
            }
        }
    }
}

原始调用代码(DisplayContents类)

public class DisplayContents extends JPanel implements Runnable{
    Thread run;
    Acceleration a = new Acceleration();

    float x=0,y=0;
    public boolean updateSpeed;
    
    public void startThread() {
        run = new Thread(this);
        run.start();
    }
    public DisplayContents() {
        
        this.setBackground(Color.DARK_GRAY);
        this.setDoubleBuffered(true);
        this.setFocusable(true);
        this.addKeyListener(new KeyListener() {
            
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_D) {
                    a.accelerating=true;
                    updateSpeed=true;
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_D) {
                    a.accelerating=false;
                }
            }
            @Override
            public void keyTyped(KeyEvent e) {}
            });
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D draw = (Graphics2D) g;
        draw.setColor(Color.WHITE);
        draw.fillRect((int)x, 0, 100, 100);
        draw.dispose();
    }

    @Override
    public void run() {
        boolean loopedOnce = false;
        while(run != null) {
            repaint();
            a.accelerate(4, 0.125f);
            a.loopedOnce=false;
            while(updateSpeed&&!loopedOnce) {
                x+=a.rateOfVelocity;
                loopedOnce=true;
            }
            loopedOnce=false;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {e.printStackTrace();}
        }
    }
}

问题根源分析

  1. 减速触发逻辑被嵌套死:deaccelerating=true的判断放在if(accelerating)代码块内部,只有当accelerating为true时才会执行这个分支。但松开按键后accelerating会被设为false,根本进不去这个代码块,永远无法激活减速状态。
  2. 减速循环条件完全写反:while(rateOfVelocity < min && !loopedOnce)——减速需要速度从大于最小值降到阈值内,但这个条件要求速度已经低于最小值才执行循环,逻辑完全颠倒。
  3. loopedOnce重置时机错误:调用a.accelerate()之后才重置loopedOnce,导致每次执行加速逻辑时,loopedOnce还是上一次的true状态,直接跳过循环,逻辑无法运行。

修复后的代码

Acceleration类修改版

public class Acceleration {
    
    public float rateOfVelocity = 0.125f;
    public float rateOfAcceleration = 2;
    
    public int alternateRateOfVelocity = 1;
    public int alternateRateOfAcceleration = 2;

    public boolean accelerating;
    public boolean deaccelerating;
    
    public boolean alternateAccelerating;
    public boolean alternateDeaccelerating;
    
    public boolean loopedOnce;
    
    public void accelerate(float max, float min) {
        if(accelerating) {
            deaccelerating = false; // 加速时强制关闭减速状态
            if(rateOfVelocity < max) {
                while(rateOfVelocity < max && !loopedOnce) {
                    rateOfVelocity *= rateOfAcceleration;
                    System.out.println("加速中:" + rateOfVelocity);
                    loopedOnce = true;                
                }
            }
            // 达到最大速度后自动切换减速
            if(rateOfVelocity >= max) {
                accelerating = false;
                deaccelerating = true;
                System.out.println("触发自动减速");
            }
        }
        // 把减速逻辑移到外部,确保松开按键后能触发
        if(deaccelerating || !accelerating) {
            if(!accelerating && !deaccelerating) {
                deaccelerating = true;
            }
            if(rateOfVelocity > min) {
                // 修正循环条件:速度大于最小值时才执行减速
                while(rateOfVelocity > min && !loopedOnce) {
                    rateOfVelocity /= rateOfAcceleration;
                    System.out.println("减速中:" + rateOfVelocity);
                    loopedOnce = true;
                }
            } else if(rateOfVelocity <= min) {
                deaccelerating = false;
                rateOfVelocity = min; // 固定到最小速度,避免过度减速
                System.out.println("已停止");
            }
        }
    }
    
    public void alternateAccelerate(float max, float min) {
        if(alternateAccelerating) {
            if(alternateRateOfVelocity < max) {
                while(alternateRateOfVelocity < max && !loopedOnce) {
                    alternateRateOfVelocity *= rateOfAcceleration;
                    loopedOnce = true;
                }
            }
        } else if(alternateDeaccelerating) {
            // 修正变量错误:使用alternateRateOfVelocity而非rateOfVelocity
            while(alternateRateOfVelocity > min && !loopedOnce) {
                alternateRateOfVelocity /= alternateRateOfAcceleration;
                loopedOnce = true;
            }
        }
    }
}

DisplayContents类修改版

public class DisplayContents extends JPanel implements Runnable{
    Thread run;
    Acceleration a = new Acceleration();

    float x=0,y=0;
    public boolean updateSpeed;
    
    public void startThread() {
        run = new Thread(this);
        run.start();
    }
    public DisplayContents() {
        this.setBackground(Color.DARK_GRAY);
        this.setDoubleBuffered(true);
        this.setFocusable(true);
        this.addKeyListener(new KeyListener() {
            
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_D) {
                    a.accelerating=true;
                    updateSpeed=true;
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_D) {
                    a.accelerating=false;
                    a.deaccelerating = true; // 松开按键直接触发减速
                }
            }
            @Override
            public void keyTyped(KeyEvent e) {}
            });
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D draw = (Graphics2D) g;
        draw.setColor(Color.WHITE);
        draw.fillRect((int)x, 0, 100, 100);
        // 移除手动dispose,交给Swing管理绘图资源
    }

    @Override
    public void run() {
        boolean loopedOnce = false;
        while(run != null) {
            repaint();
            // 先重置loopedOnce,再执行加速逻辑
            a.loopedOnce = false;
            a.accelerate(4, 0.125f);
            
            while(updateSpeed&&!loopedOnce) {
                x += a.rateOfVelocity;
                loopedOnce=true;
            }
            loopedOnce=false;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {e.printStackTrace();}
        }
    }
}

关键修复点总结

  • 将减速触发逻辑从if(accelerating)代码块中移出,确保松开按键后能进入减速判断
  • 修正减速循环条件,从rateOfVelocity < min改为rateOfVelocity > min
  • 调整loopedOnce的重置时机到accelerate方法调用之前,保证每次逻辑执行都是初始状态
  • 在按键松开时直接设置deaccelerating=true,让减速逻辑立刻触发
  • 移除paintComponent中的draw.dispose(),避免Swing绘图资源被提前释放

内容的提问来源于stack exchange,提问作者Grinding For Reputation

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:02:59