frenneruruu
@frenneruruu
writer, game designer, java/kotlin/lua developer

Почему приложение на java тормозит?

Занимаюсь самообучением по программированию и пока ещё не всё понимаю.
В рамках изучения работы с графическим интерфейсом я делаю игру Сапёр. Однако система работает с задержкой. Я нажимаю на объект, а реакции нет. Приходиться нажимать несколько раз. Бывает, что с первого раза получается, но не часто.
Программа
package jsx;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class Minesweeper extends JPanel {

	List<Tile> field;
	Random random;
	boolean inGame;
	boolean isWin;

	public Minesweeper() {
		field = new ArrayList<Tile>();
		random = new Random();

		setPreferredSize(new Dimension(346, 368));
		setFocusable(true);
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					init();
				}
			}
		});
		addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (inGame) {
					if (e.getButton() == MouseEvent.BUTTON1) {
						Tile tile = getTile(e.getX(), e.getY());
						if (tile == null)
							return;

						clickLeft(tile);
					} else if (e.getButton() == MouseEvent.BUTTON3) {
						Tile tile = getTile(e.getX(), e.getY());
						if (tile == null)
							return;

						clickRight(tile);
					}
				} else {
					init();
				}
			}
		});
		init();
	}

	void init() {
		inGame = true;
		isWin = false;
		for (int x = 0; x < 9; x++) {
			for (int y = 0; y < 9; y++) {
				field.add(new Tile(x, y));
			}
		}
		for (int i = 0; i < 9; i++) {
			Tile t = field.get(random.nextInt(field.size()));
			if (t.isMined()) {
				i--;
			} else {
				t.setMined();
				for (Tile t0 : getNearby(t)) {
					t0.setValue(t0.getValue() + 1);
				}
			}
		}
		repaint();
	}

	List<Tile> getNearby(Tile t) {
		List<Tile> out = new ArrayList<Tile>();
		for (Tile tile : field) {
			if (t.isNear(tile)) {
				out.add(tile);
			}
		}
		return out;
	}

	int getInt(int i) {
		if (i < 18) {
			return -1;
		}
		for (int c = 1; c < 10; c++) {
			if (i < 18 + 32 * c) {
				return c - 1;
			}
		}
		return -1;
	}

	Tile getTile(int x, int y) {
		x = getInt(x);
		y = getInt(y);
		if (x > -1 && y > -1) {
			for (Tile t0 : field) {
				if (t0.getX() == x && t0.getY() == y) {
					return t0;
				}
			}
		}
		return null;
	}

	void clickRight(Tile tile) {
		if (tile.isFlag(Flag.NONE)) {
			tile.setFlag(Flag.MARKED);
		} else if (tile.isFlag(Flag.MARKED)) {
			tile.setFlag(Flag.NONE);
		}

		repaint();
	}

	void clickLeft(Tile tile) {
		if (!tile.isFlag(Flag.NONE))
			return;

		// losing
		if (tile.isMined()) {
			inGame = false;
			for (Tile t0 : field) {
				if (t0.isMined()) {
					if (t0.isFlag(Flag.MARKED)) {
						t0.setFlag(Flag.VERIFIED);
					} else {
						t0.setFlag(Flag.ERROR);
					}
				} else {
					t0.setFlag(Flag.CRUSHED);
				}
			}

		} else {
			tile.setFlag(Flag.OPEN);

			// TODO check win

		}

		repaint();
	}

	enum Flag {
		NONE, OPEN, MARKED, CRUSHED, ERROR, VERIFIED;
	}

	static class Tile {

		private boolean mined;
		private int value, x, y;
		private Flag flag;

		public Tile(int x, int y) {
			this.mined = false;
			this.value = 0;
			this.x = x;
			this.y = y;
			this.flag = Flag.NONE;
		}

		public boolean isNear(Tile t) {
			return Math.abs(x - t.getX()) < 2 && Math.abs(y - t.getY()) < 2;
		}

		public int getX() {
			return x;
		}

		public int getY() {
			return y;
		}

		public boolean isMined() {
			return mined;
		}

		public void setMined() {
			this.mined = true;
		}

		public int getValue() {
			return value;
		}

		public void setValue(int i) {
			this.value = i;
		}

		public boolean isFlag(Flag f) {
			return flag == f;
		}

		public Flag getFlag() {
			return flag;
		}

		public void setFlag(Flag f) {
			this.flag = f;
		}
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(new Color(255, 223, 94));
		g.fillRect(0, 0, 346, 368);
		for (Tile t : field) {
			drawTile(g, t);
		}
	}

	Color getTileTextColor(int i) {
		switch (i) {
		case 1:
			return new Color(0, 45, 183);
		case 2:
			return new Color(22, 122, 0);
		case 3:
			return new Color(183, 0, 0);
		case 4:
			return new Color(0, 10, 163);
		case 5:
			return new Color(183, 0, 0);
		case 6:
			return new Color(140, 184, 255);
		case 7:
			return new Color(183, 0, 0);
		case 8:
			return new Color(147, 0, 160);
		}
		return null;
	}

	void drawTile(Graphics gr, Tile tile) {
		Graphics2D g = ((Graphics2D) gr);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
		int oX = 18 + tile.getX() * 34;
		int oY = 18 + tile.getY() * 34;
		// 166, 0, 14

		if (tile.isFlag(Flag.OPEN)) {
			g.setColor(new Color(221, 234, 255));
			g.fillRect(oX, oY, 32, 32);

			if (tile.getValue() > 0) {
				g.setColor(getTileTextColor(tile.getValue()));
				Font font = new Font("Arial", Font.BOLD, 18);
				g.setFont(font);
				FontMetrics fm = getFontMetrics(font);
				int w = fm.stringWidth(String.valueOf(tile.getValue()));
				int h = -(int) fm.getLineMetrics(String.valueOf(tile.getValue()), g).getBaselineOffsets()[2];

				g.drawString(String.valueOf(tile.getValue()), oX + (32 - w) / 2, oY + 32 - (32 - h) / 2 - 2);
			}
		} else if (tile.isFlag(Flag.MARKED)) {
			g.setColor(new Color(43, 102, 196));
			g.fillRect(oX, oY, 32, 32);

			g.setColor(new Color(255, 255, 255));
			Font font = new Font("Arial", Font.BOLD, 18);
			g.setFont(font);
			FontMetrics fm = getFontMetrics(font);
			int w = fm.stringWidth("?");
			int h = -(int) fm.getLineMetrics("?", g).getBaselineOffsets()[2];

			g.drawString("?", oX + (32 - w) / 2, oY + 30 - (32 - h) / 2);

		} else if (tile.isFlag(Flag.CRUSHED)) {
			g.setColor(new Color(186, 37, 0));
			g.fillRect(oX, oY, 32, 32);
		} else if (tile.isFlag(Flag.VERIFIED)) {
			g.setColor(new Color(22, 188, 0));
			g.fillRect(oX, oY, 32, 32);
		} else if (tile.isFlag(Flag.ERROR)) {
			g.setColor(new Color(255, 251, 30));
			g.fillRect(oX, oY, 32, 32);
		} else if (tile.isFlag(Flag.NONE)) {
			g.setColor(new Color(43, 102, 196));
			g.fillRect(oX, oY, 32, 32);
		}

		if (!inGame) {
			g.setColor(new Color(255, 255, 255, 30));
			g.fillRect(0, 0, getWidth(), getHeight());
			g.setColor(new Color(44, 44, 44));
			g.setFont(new Font("Arial", Font.BOLD, 80));
			if (isWin) {
				g.drawString("Win!", 110, 201);
			} else {
				g.drawString("Lose!", 110, 201);
			}
		}
	}

	public static void main(String[] args) {
		JFrame game = new JFrame();
		game.setTitle("Minesweeper");
		game.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

		game.setSize(346, 368);
		game.setResizable(false);

		game.add(new Minesweeper());

		game.setLocationRelativeTo(null);
		game.setVisible(true);
	}

}

  • Вопрос задан
  • 749 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Shiftuia
Java-программист
Во первых попробуйте отдебажить программу, написав тестовый пример с тестовыми данными и запустив дебаг
Во вторых попробуйте написать тесте на все методы, протестировав их поведение. Это вам сильно пригодится в будущем
В третьих, если баг не найдете, сконфигурируйте JMX и посмотрите на потребляемые приложением ресурсы.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы