如何在JavaSwing中将逻辑与表单分离?

如何在JavaSwing中将逻辑与表单分离?,java,forms,swing,model-view-controller,logic,Java,Forms,Swing,Model View Controller,Logic,我很难将游戏的逻辑从视图中分离出来。视图应该是哑视图,并且只渲染模型的当前状态。但我不知道该怎么做。你能帮我简化代码,把逻辑和形式分开吗?因为我想扩展游戏和添加新的东西,但我不能因为混乱的代码形式。我是java新手 import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.*; pub

我很难将游戏的逻辑从视图中分离出来。视图应该是哑视图,并且只渲染模型的当前状态。但我不知道该怎么做。你能帮我简化代码,把逻辑和形式分开吗?因为我想扩展游戏和添加新的东西,但我不能因为混乱的代码形式。我是java新手

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.*;

public class ProjectileShooterTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(600, 600);
        final ProjectileShooter projectileShooter = new ProjectileShooter();
        ProjectileShooterPanel projectileShooterPanel = new ProjectileShooterPanel(
                projectileShooter);
        projectileShooter.setPaintingComponent(projectileShooterPanel);
        JPanel controlPanel = new JPanel(new GridLayout(1, 0));
        controlPanel.add(new JLabel("Angle"));
        final JSlider angleSlider = new JSlider(0, 90, 45);
        controlPanel.add(angleSlider);
        controlPanel.add(new JLabel("Power"));
        final JSlider powerSlider = new JSlider(0, 100, 50);
        controlPanel.add(powerSlider);
        JButton shootButton = new JButton("Shoot");
        shootButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int angleDeg = angleSlider.getValue();
                int power = powerSlider.getValue();
                projectileShooter.setAngle(Math.toRadians(angleDeg));
                projectileShooter.setPower(power);
                projectileShooter.shoot();
            }
        });
        controlPanel.add(shootButton);
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(controlPanel, BorderLayout.NORTH);
        f.getContentPane().add(projectileShooterPanel, BorderLayout.CENTER);
        f.setVisible(true);
    }
}

class ProjectileShooter {
    private double angleRad = Math.toRadians(45);
    private double power = 50;
    private Projectile projectile;
    private JComponent paintingComponent;

    void setPaintingComponent(JComponent paintingComponent) {
        this.paintingComponent = paintingComponent;
    }

    void setAngle(double angleRad) {
        this.angleRad = angleRad;
    }

    void setPower(double power) {
        this.power = power;
    }

    void shoot() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                executeShot();
            }
        });
        t.setDaemon(true);
        t.start();
    }

    private void executeShot() {
        if (projectile != null) {
            return;
        }
        projectile = new Projectile();
        Point2D velocity = AffineTransform.getRotateInstance(angleRad).transform(
                new Point2D.Double(1, 0), null);
        velocity.setLocation(velocity.getX() * power * 0.5, velocity.getY() * power * 0.5);
        projectile.setVelocity(velocity);
        long prevTime = System.nanoTime();
        while (projectile.getPosition().getY() >= 0) {
            long currentTime = System.nanoTime();
            double dt = 3 * (currentTime - prevTime) / 1e8;
            projectile.performTimeStep(dt);
            prevTime = currentTime;
            paintingComponent.repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
        projectile = null;
        paintingComponent.repaint();
    }

    Projectile getProjectile() {
        return projectile;
    }
}

class Projectile {
    private final Point2D ACCELERATION = new Point2D.Double(0, -9.81 * 0.1);
    private final Point2D position = new Point2D.Double();
    private final Point2D velocity = new Point2D.Double();

    public Point2D getPosition() {
        return new Point2D.Double(position.getX(), position.getY());
    }

    public void setPosition(Point2D point) {
        position.setLocation(point);
    }

    public void setVelocity(Point2D point) {
        velocity.setLocation(point);
    }

    void performTimeStep(double dt) {
        scaleAddAssign(velocity, dt, ACCELERATION);
        scaleAddAssign(position, dt, velocity);
    }

    private static void scaleAddAssign(Point2D result, double factor, Point2D addend) {
        double x = result.getX() + factor * addend.getX();
        double y = result.getY() + factor * addend.getY();
        result.setLocation(x, y);
    }
}

class ProjectileShooterPanel extends JPanel {
    private final ProjectileShooter projectileShooter;

    public ProjectileShooterPanel(ProjectileShooter projectileShooter) {
        this.projectileShooter = projectileShooter;
    }

    @Override
    protected void paintComponent(Graphics gr) {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D) gr;
        Projectile projectile = projectileShooter.getProjectile();
        if (projectile != null) {
            g.setColor(Color.RED);
            Point2D position = projectile.getPosition();
            int x = (int) position.getX();
            int y = getHeight() - (int) position.getY();
            Ellipse2D.Double gerd = new Ellipse2D.Double(x - 01, y - 10, 20, 20);
            g.draw(gerd);
            // g.fillOval(x-01, y-10, 20, 20);
        }
        Rectangle hadaf1 = new Rectangle(450, 450, 50, 50);
        Rectangle hadaf2 = new Rectangle(500, 450, 50, 50);
        Rectangle hadaf3 = new Rectangle(475, 400, 50, 50);
        g.draw(hadaf1);
        g.draw(hadaf2);
        g.draw(hadaf3);
    }
}

我会非常感激的。

基本上,你是在问我。对于每一段代码,您需要问自己它负责什么。如果它负责管理游戏状态并对状态做出决定,那么它应该属于模型,如果它是关于改变状态(可能通过键盘或鼠标),那么它应该在控制器中,如果它负责绘制状态,然后它应该在视图中。您应该能够获取一个或多个部分,并用不同的实现替换它,而无需重新编码其他部分。还需要注意的是,有时,您需要关于程序的一部分的信息,而该部分实际上不属于另一部分(责任/管理方面),例如容器的当前大小。这就是代理可以发挥作用的地方,它只是向程序的另一部分提供一条关键信息,同时保持对它的责任。您还应该更喜欢接口而不是实现,以进一步解耦您的代码。请有人演示如何做?