Итак, у меня проблема с выстрелами из игрока. Выстрелы всегда появляются из определенного места, а не перед игроком. Я поместил зеленый квадрат туда, откуда стреляют, но, конечно, в данном случае они должны стрелять с одной из коротких сторон синего прямоугольника.
Я знаю, что проблема вызвана преобразованием. По сути, положение выстреливаемого объекта не обновляется вместе с объектом игрока. Но я просто не знаю, как решить эту проблему.
Закомментированный код для рисования зеленого треугольника внутри преобразования игроков, по сути, будет делать то, что я делаю для объекта выстрела. Но я не уверен, как это сделать.
Класс основного/фрейма
public class Test extends JFrame {
public static void main(String argvs[]) {
Board board = new Board();
board.timer.start();
Test frame = new Test();
frame.add(board);
frame.setTitle("overflow");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
Класс платы
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import javax.swing.JComponent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Board extends JComponent implements ActionListener {
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
Player player = new Player();
Timer timer=new Timer(16, this);
public Board(){
//setFocusable(true);
add(player);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setPaintMode();
board(g);
player.draw(g);
for (int i = player.playerShot.size() - 1; i >=0 ; i--) {
Shot shot = player.playerShot.get(i);
if (shot.shotX < 0 || shot.shotY < 0 || shot.shotX > size.getWidth() || shot.shotY > size.getHeight()) {
player.playerShot.remove(i);
continue;
}
shot.collision();
shot.draw(g);
}
}
void board(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, (int)size.getWidth(), (int)size.getHeight());
}
@Override
public void actionPerformed(ActionEvent ev){
if (ev.getSource()==timer){
player.movement();
//shot.collision();
repaint();// this will call at every 1 second
}
}
}
Класс игрока
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
import java.awt.event.*;
public class Player extends JComponent {
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
int playerX; // Position of the player
int playerY;
private double rotationAngle; // Angle in radians
public Set<Integer> keysPressed; // Store the keys being pressed
boolean moving = false;
ArrayList<Shot> playerShot = new ArrayList<Shot>();
public Player() {
playerX = (int) (size.getWidth() / 2); // Initialize player position (you can set your own initial position)
playerY = (int) (size.getHeight() / 2);
rotationAngle = 0;
keysPressed = new HashSet<>();
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "moveForward");
getActionMap().put("moveForward", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.add(KeyEvent.VK_UP);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "forwardStop");
getActionMap().put("forwardStop", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.remove(KeyEvent.VK_UP);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "moveBack");
getActionMap().put("moveBack", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.add(KeyEvent.VK_DOWN);
// movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "backwardsStop");
getActionMap().put("backwardsStop", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.remove(KeyEvent.VK_DOWN);
// movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "rotateLeft");
getActionMap().put("rotateLeft", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.add(KeyEvent.VK_LEFT);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "leftRotateStop");
getActionMap().put("leftRotateStop", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.remove(KeyEvent.VK_LEFT);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "rotateRight");
getActionMap().put("rotateRight", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.add(KeyEvent.VK_RIGHT);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "rightRotateStop");
getActionMap().put("rightRotateStop", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.remove(KeyEvent.VK_RIGHT);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "Shoot");
getActionMap().put("Shoot", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.add(KeyEvent.VK_SPACE);
//movement();
}
});
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "stopShoting");
getActionMap().put("stopShoting", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
keysPressed.remove(KeyEvent.VK_SPACE);
//movement();
}
});
}
public void movement() {
//System.out.println("player is at " + playerX +" " +playerY);
int moveDistance = 4;
if (keysPressed.contains(KeyEvent.VK_UP)) {
// Move forward
playerX += moveDistance * Math.sin(rotationAngle);
playerY -= moveDistance * Math.cos(rotationAngle);
}
if (keysPressed.contains(KeyEvent.VK_DOWN)) {
// Move backward
playerX -= moveDistance * Math.sin(rotationAngle);
playerY += moveDistance * Math.cos(rotationAngle);
}
if (keysPressed.contains(KeyEvent.VK_LEFT)) {
rotationAngle -= Math.toRadians(2);
}
if (keysPressed.contains(KeyEvent.VK_RIGHT)) {
// Rotate left
rotationAngle += Math.toRadians(2);
}
if (keysPressed.contains(KeyEvent.VK_SPACE)) {
playerShot.add(shoot());
//shoot();
//Shot shot = new Shot();
//shot.collision(playerX,playerY);
// Rotate right
}
// System.out.println(keysPressed);
}
public Shot shoot() {
return new Shot(playerX + 6, playerY - 10,rotationAngle);
}
public void draw(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
Rectangle player = new Rectangle(playerX, playerY, 15, 50);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform oldTransform = g2d.getTransform(); // Save the current transform
AffineTransform rotationTransform = new AffineTransform();
rotationTransform.rotate(rotationAngle, playerX + player.getWidth() / 2, playerY + player.getHeight() / 2);
g2d.setTransform(rotationTransform);
g2d.fill(player);
//g2d.setColor(Color.green);
//g2d.fillRect(playerX+6, playerY-10, 5, 5);
g2d.setTransform(oldTransform); // Restore the original transform
g2d.setColor(Color.green);
g2d.fillRect(playerX+6, playerY-10, 5, 5);
}
}
Класс выстрела
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class Shot extends JComponent {
int shotX;
int shotY;
private double rotationAngle; // Angle in radians
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
public Shot(int shotX,int shotY,double rotationAngle) {
this.shotX = shotX;
this.shotY = shotY;
this.rotationAngle = rotationAngle;
}
public void draw(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.red);
Rectangle shot = new Rectangle(shotX, shotY, 5, 5);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform oldTransform = g2d.getTransform(); // Save the current transform
AffineTransform rotationTransform = new AffineTransform();
rotationTransform.rotate(rotationAngle, shotX + shot.getWidth() / 2, shotY + shot.getHeight() / 2);
g2d.setTransform(rotationTransform);
g2d.fill(shot);
g2d.setTransform(oldTransform); // Restore the original transform
}
public void collision(){
shotX += 4 * Math.sin(rotationAngle);
shotY -= 4 * Math.cos(rotationAngle);
/* if ((shotX <= -5)|| (shotX >= (int)(size.getWidth() + 5)) || (shotY <= -5 || shotY >= (int)(size.getHeight() + 5))){
System.out.println("aaaa");
} */
//shotX += 2;
// shotY -= 2;
}
}
@camickr Вы правы, я еще не добрался до этой части в то время. прямо сейчас я не могу понять, как заставить его работать.




Я скопировал ваш код в свою IDE и запустил его.
У вас есть корабль (игрок), который может вращаться, двигаться вперед и назад, а также может стрелять лазерным лучом. Клавиша со стрелкой вверх перемещает корабль вперед, клавиша со стрелкой вниз перемещает корабль назад, клавиша со стрелкой влево вращает корабль против часовой стрелки, клавиша со стрелкой вправо вращает корабль по часовой стрелке, а пробел стреляет лазерным лучом. Удерживание пробела делает лазерный луч длиннее.
Корабль не имеет импульса. Он движется только до тех пор, пока вы удерживаете одну или несколько клавиш со стрелками.
Все идет нормально. Вот как это выглядит, когда я запускаю приложение и стреляю парой лазеров
В ходе тестирования я обнаружил, что могу вывести корабль за пределы экрана. Я не уверен, какую игру вы пытаетесь подражать, так как вы не сказали.
Все четыре ваших класса являются расширениями компонента Java Swing. Это не способ создать сложную игру. Вы столкнетесь с проблемами, как вы уже обнаружили.
@camickr прокомментировал ваш метод рисования. Организация кода в классы и методы помогает изолировать проблемы при отладке кода.
Когда я создаю графический интерфейс Swing, я использую шаблон модель-представление-контроллер (MVC). Этот шаблон позволяет мне разделить свои задачи и сосредоточиться на одной части приложения за раз.
В Java Swing модель приложения состоит из одного или нескольких простых классов получения/установки Java. Представление приложения состоит из компонентов Swing. Контроллер приложения состоит из одного или нескольких действий или слушателей.
Модель приложения хранит состояние игры.
Представление приложения показывает состояние игры. Период. Ничего больше.
Контроллеры приложений изменяют модель приложения и обновляют или перерисовывают представление.
Я создал три класса моделей: GameModel, Ship и Shot.
Класс GameModel — это простой класс получателя/установщика Java, который содержит экземпляр Ship и List экземпляров Shot.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
public class GameModel {
private final Dimension drawingPanelSize;
private final List<Shot> shots;
private final Ship ship;
public GameModel() {
this.drawingPanelSize = new Dimension(400, 400);
Point2D p = new Point2D.Double(drawingPanelSize.width / 2,
drawingPanelSize.height / 2);
this.ship = new Ship(p, 0.0, Color.BLUE);
this.shots = new ArrayList<>();
}
public void addShot(Shot shot) {
this.shots.add(shot);
}
public void removeShot(Shot shot) {
this.shots.remove(shot);
}
public Dimension getDrawingPanelSize() {
return drawingPanelSize;
}
public Ship getShip() {
return ship;
}
public List<Shot> getShots() {
return shots;
}
}
Класс Ship — это простой класс получения/установки Java, который содержит положение, направление и скорость корабля. Этот класс также рисует изображение корабля. Я сделал изображение треугольником, но вы можете изменить код, чтобы сделать корабль любой комбинацией форм, которую вы хотите.
Каждый класс Java расширяет Object и может реализовать toString метод для отображения или отладки.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
public class Ship {
private final BufferedImage image;
/**
* The direction in radians. Zero is north. Positive values rotate
* clockwise. Negative values rotate counterclockwise. The velocity
* is pixels per frame.
*/
private double direction, velocity;
private Point2D location;
public Ship(Point2D location, double degrees, Color color) {
this.location = location;
this.direction = Math.toRadians(degrees);
this.velocity = 0.0;
this.image = createShipImage(color);
}
private BufferedImage createShipImage(Color color) {
BufferedImage image = new BufferedImage(25, 40,
BufferedImage.TYPE_INT_ARGB);
int width = image.getWidth();
int height = image.getHeight();
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, width, height);
Polygon p = new Polygon();
p.addPoint(width / 2, 0);
p.addPoint(0, height);
p.addPoint(width, height);
g2d.setColor(color);
g2d.fillPolygon(p);
g2d.dispose();
return image;
}
public void moveShip(Dimension drawingPanelSize) {
double dx = velocity * Math.sin(direction);
double dy = velocity * Math.cos(direction);
double x = location.getX() + dx;
double y = location.getY() - dy;
x = Math.max(0.0, x);
x = Math.min(drawingPanelSize.width, x);
y = Math.max(0.0, y);
y = Math.min(drawingPanelSize.height, y);
location.setLocation(x, y);
}
public double getDirection() {
return direction;
}
public void incrementDirection(double degrees) {
this.direction += Math.toRadians(degrees);
}
public void setVelocity(double velocity) {
this.velocity = velocity;
}
public Point2D getLocation() {
return location;
}
public BufferedImage getImage() {
return image;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("The ship is located at ");
String display = String.format("%.2f", location.getX());
builder.append(display);
builder.append(", ");
display = String.format("%.2f", location.getY());
builder.append(display);
builder.append(" and facing ");
double angle = Math.toDegrees(direction);
display = String.format("%.1f", angle);
builder.append(display);
builder.append(" degrees");
return builder.toString();
}
}
Класс Shot — это простой класс получения/установки Java, который содержит положение, направление и скорость выстрела. Этот класс также рисует изображение кадра.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
public class Shot {
private final BufferedImage image;
/**
* The direction in radians. Zero is north. Positive values rotate
* clockwise. Negative values rotate counterclockwise. The velocity is
* pixels per frame.
*/
private double direction, velocity;
private Point2D location;
public Shot(Point2D location, double direction, Color color) {
this.location = location;
this.direction = direction;
this.velocity = 5.0;
this.image = createShotImage(color);
}
private BufferedImage createShotImage(Color color) {
BufferedImage image = new BufferedImage((int) velocity, (int) velocity,
BufferedImage.TYPE_INT_RGB);
int width = image.getWidth();
int height = image.getHeight();
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
g2d.fillRect(0, 0, width, height);
g2d.dispose();
return image;
}
public boolean moveShot(Dimension drawingPanelSize) {
double dx = velocity * Math.sin(direction);
double dy = velocity * Math.cos(direction);
double x = location.getX() + dx;
double y = location.getY() - dy;
if (x < 0.0 || x > drawingPanelSize.width) {
return false;
}
if (y < 0.0 || y > drawingPanelSize.height) {
return false;
}
location.setLocation(x, y);
return true;
}
public double getDirection() {
return direction;
}
public Point2D getLocation() {
return location;
}
public BufferedImage getImage() {
return image;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("The shot is located at ");
String display = String.format("%.2f", location.getX());
builder.append(display);
builder.append(", ");
display = String.format("%.2f", location.getY());
builder.append(display);
builder.append(" and facing ");
double angle = Math.toDegrees(direction);
display = String.format("%.1f", angle);
builder.append(display);
builder.append(" degrees");
return builder.toString();
}
}
Я создал JFrame and a drawing JPanel`. Поскольку я создал модель, представление стало намного проще.
Вместо того, чтобы вращать всевозможные компоненты Swing, я создал BufferedImage корабля и каждого кадра. Таким образом, я мог написать один метод вращения на рисунке JPanel и использовать его для всех изображений.
Вот класс Game.
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Game implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Game());
}
private final DrawingPanel drawingPanel;
private final GameKeyBindings gameKeyBindings;
private final GameModel model;
public Game() {
this.model = new GameModel();
this.drawingPanel = new DrawingPanel(model);
this.gameKeyBindings = new GameKeyBindings(drawingPanel);
}
@Override
public void run() {
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
Timer timer = new Timer(20, new GameListener(this, model));
timer.start();
}
public GameKeyBindings getGameKeyBindings() {
return gameKeyBindings;
}
public Dimension getDrawingPanelSize() {
return drawingPanel.getSize();
}
public void repaint() {
drawingPanel.repaint();
}
}
Вот класс DrawingPanel.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final GameModel model;
public DrawingPanel(GameModel model) {
this.model = model;
this.setPreferredSize(model.getDrawingPanelSize());
this.setBackground(Color.BLACK);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Ship ship = model.getShip();
BufferedImage image = ship.getImage();
Point2D p = ship.getLocation();
double rotation = ship.getDirection();
drawRotatedImage(g2d, image, p, rotation);
for (Shot shot : model.getShots()) {
image = shot.getImage();
p = shot.getLocation();
rotation = shot.getDirection();
drawRotatedImage(g2d, image, p, rotation);
}
}
private void drawRotatedImage(Graphics2D g2d, BufferedImage image,
Point2D p, double rotation) {
BufferedImage rotatedImage = rotateImage(image, rotation);
int x = (int) Math.round(p.getX()) - rotatedImage.getWidth() / 2;
int y = (int) Math.round(p.getY()) - rotatedImage.getHeight() / 2;
g2d.drawImage(rotatedImage, x, y, this);
}
/**
* <p>
* This method will rotate an image on its center point.
* </p>
* <p>
* First, the image is copied to an image large enough to hold the rotated
* image at any angle. Then, the copied image is rotated.
* </p>
*
* @param image - The image to be rotated.
* @param rotation - The rotation angle in radians. A positive value rotates
* the image clockwise. A negative value rotates the image
* counterclockwise.
* @return The rotated image
*/
private BufferedImage rotateImage(BufferedImage image, double rotation) {
double newWidthD = getNewImageWidth(image);
double halfWidthD = newWidthD / 2.0;
int newWidthI = (int) newWidthD;
BufferedImage newImage = translateImage(image, newWidthI);
BufferedImage outputImage = new BufferedImage(newWidthI, newWidthI,
image.getType());
AffineTransform tx = AffineTransform.getRotateInstance(rotation,
halfWidthD, halfWidthD);
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_BILINEAR);
op.filter(newImage, outputImage);
return outputImage;
}
/**
* This method calculates the width of the new image. Basically, calculate
* the hypotenuse of the width and height of the image.
*
* @param image - The original image
* @return The width and height of the square that can hold the image
* rotated at any angle.
*/
private double getNewImageWidth(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
double newWidth = width * width + height * height;
newWidth = Math.ceil(Math.pow(newWidth, 0.5));
return newWidth;
}
/**
* This method copies the image to a new image. The original image is placed
* in the center of the new image. The rest of the image is filled with
* transparent pixels.
*
* @param image - The original image.
* @param newWidth - the width and height of the new image.
* @return The translated image
*/
private BufferedImage translateImage(BufferedImage image, int newWidth) {
BufferedImage newImage = new BufferedImage(newWidth, newWidth,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) newImage.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, newWidth, newWidth);
int x = (newWidth - image.getWidth()) / 2;
int y = (newWidth - image.getHeight()) / 2;
g2d.drawImage(image, x, y, null);
g2d.dispose();
return newImage;
}
}
Я выделил привязки клавиш в отдельный класс, главным образом для того, чтобы упростить организацию кода. Я создал два частных класса Action, которые я мог бы использовать повторно.
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class GameKeyBindings {
private final Set<Integer> keysPressed;
public GameKeyBindings(JPanel panel) {
this.keysPressed = new HashSet<>();
defineKeyBindings(panel);
}
private void defineKeyBindings(JPanel panel) {
InputMap inputMap = panel.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = panel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false),
"moveForward");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true),
"forwardStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false),
"moveBack");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true),
"backwardsStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false),
"rotateLeft");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true),
"leftRotateStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false),
"rotateRight");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true),
"rightRotateStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false),
"shoot");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true),
"stopShooting");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false),
"moveForward");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true),
"forwardStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false),
"moveBack");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true),
"backwardsStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false),
"rotateLeft");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true),
"leftRotateStop");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false),
"rotateRight");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true),
"rightRotateStop");
actionMap.put("moveForward", new KeyAdditionAction(KeyEvent.VK_UP));
actionMap.put("forwardStop", new KeyRemovalAction(KeyEvent.VK_UP));
actionMap.put("moveBack", new KeyAdditionAction(KeyEvent.VK_DOWN));
actionMap.put("backwardsStop", new KeyRemovalAction(KeyEvent.VK_DOWN));
actionMap.put("rotateLeft", new KeyAdditionAction(KeyEvent.VK_LEFT));
actionMap.put("leftRotateStop", new KeyRemovalAction(KeyEvent.VK_LEFT));
actionMap.put("rotateRight", new KeyAdditionAction(KeyEvent.VK_RIGHT));
actionMap.put("rightRotateStop", new KeyRemovalAction(KeyEvent.VK_RIGHT));
actionMap.put("shoot", new KeyAdditionAction(KeyEvent.VK_SPACE));
actionMap.put("stopShooting", new KeyRemovalAction(KeyEvent.VK_SPACE));
}
public Set<Integer> getKeysPressed() {
return keysPressed;
}
private class KeyAdditionAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final int keyEvent;
public KeyAdditionAction(int keyEvent) {
this.keyEvent = keyEvent;
}
@Override
public void actionPerformed(ActionEvent event) {
Integer value = Integer.valueOf(keyEvent);
keysPressed.add(value);
}
}
private class KeyRemovalAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final int keyEvent;
public KeyRemovalAction(int keyEvent) {
this.keyEvent = keyEvent;
}
@Override
public void actionPerformed(ActionEvent event) {
Integer value = Integer.valueOf(keyEvent);
keysPressed.remove(value);
}
}
}
Я создал один отдельный класс контроллера. Я уже упоминал два закрытых класса Action для привязки клавиш.
Класс GameListener — это игровой цикл. Перемещайте корабль, перемещайте кадры и перекрашивайте рисунок JPanel.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.util.List;
import java.util.Set;
public class GameListener implements ActionListener {
private final Game view;
private final GameModel model;
public GameListener(Game view, GameModel model) {
this.view = view;
this.model = model;
}
@Override
public void actionPerformed(ActionEvent event) {
double velocity = 4.0;
double degreesRotated = 2.0;
GameKeyBindings gameKeyBindings = view.getGameKeyBindings();
Set<Integer> keysPressed = gameKeyBindings.getKeysPressed();
Ship ship = model.getShip();
model.getShip().setVelocity(0.0);
if (keysPressed.contains(KeyEvent.VK_UP)) {
ship.setVelocity(velocity);
}
if (keysPressed.contains(KeyEvent.VK_DOWN)) {
ship.setVelocity(-velocity);
}
if (keysPressed.contains(KeyEvent.VK_LEFT)) {
ship.incrementDirection(-degreesRotated);
}
if (keysPressed.contains(KeyEvent.VK_RIGHT)) {
ship.incrementDirection(degreesRotated);
}
if (keysPressed.contains(KeyEvent.VK_SPACE)) {
// System.out.println(ship);
Point2D s = ship.getLocation();
Point2D p = new Point2D.Double(s.getX(), s.getY());
Shot shot = new Shot(p, ship.getDirection(), Color.RED);
model.addShot(shot);
}
Dimension drawingPanelSize = view.getDrawingPanelSize();
ship.moveShip(drawingPanelSize);
List<Shot> shots = model.getShots();
for (int index = shots.size() - 1; index >= 0; index--) {
Shot shot = shots.get(index);
// System.out.println(shot);
boolean valid = shot.moveShot(drawingPanelSize);
if (!valid) {
model.removeShot(shot);
}
}
view.repaint();
}
}
Вот изображение пересмотренного графического интерфейса. Я сделал его намного меньше, чтобы он лучше вписывался в этот ответ.
В Windows вы можете щелкнуть поле в правом верхнем углу, чтобы графический интерфейс использовал весь дисплей.
Ого, не думал, что получу ответ по этому поводу. Но вау, ты действительно приложил усилия. Поскольку вам удалось решить проблему, я знаю, что у меня есть много кода для изучения и изучения, спасибо.
Не связано с вашим вопросом, но метод рисования должен рисовать только текущее состояние компонента, а не изменять состояние. Логика «удаления» НЕ должна быть в методе pantComponent(). Эта логика должна быть в методе «движения».