Gemini said
This implementation uses Java Swing, Graphics2D, and KeyBindings (which are more robust than KeyListeners for GUI applications). It features a Submarine class to handle the geometry and a Missile class for the projectiles.
The Submarine Code
Copy this code into a file named SubmarineGame.java.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
public class SubmarineGame extends JPanel {
// Submarine position
private double subX = 100, subY = 200;
private double speed = 5.0;
// Animation state
private double propAngle = 0;
private List<Missile> missiles = new ArrayList<>();
public SubmarineGame() {
setBackground(new Color(0, 105, 148)); // Deep Sea Blue
setFocusable(true);
setupControls();
// Animation Timer (~60 FPS)
Timer timer = new Timer(16, e -> {
propAngle += 0.3; // Spin the propeller
updateMissiles();
repaint();
});
timer.start();
}
private void setupControls() {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
// WASD Movement
im.put(KeyStroke.getKeyStroke('w'), "up");
im.put(KeyStroke.getKeyStroke('s'), "down");
im.put(KeyStroke.getKeyStroke('a'), "left");
im.put(KeyStroke.getKeyStroke('d'), "right");
im.put(KeyStroke.getKeyStroke("SPACE"), "fire");
am.put("up", new AbstractAction() { public void actionPerformed(ActionEvent e) { subY -= speed; } });
am.put("down", new AbstractAction() { public void actionPerformed(ActionEvent e) { subY += speed; } });
am.put("left", new AbstractAction() { public void actionPerformed(ActionEvent e) { subX -= speed; } });
am.put("right", new AbstractAction() { public void actionPerformed(ActionEvent e) { subX += speed; } });
am.put("fire", new AbstractAction() { public void actionPerformed(ActionEvent e) { launchMissile(); } });
}
private void launchMissile() {
missiles.add(new Missile(subX + 60, subY + 15));
}
private void updateMissiles() {
for (int i = missiles.size() - 1; i >= 0; i--) {
missiles.get(i).move();
if (missiles.get(i).x > getWidth()) missiles.remove(i);
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawSubmarine(g2);
drawMissiles(g2);
}
private void drawSubmarine(Graphics2D g2) {
AffineTransform old = g2.getTransform();
g2.translate(subX, subY);
// 1. Draw Body (Ellipse)
g2.setColor(Color.DARK_GRAY);
Ellipse2D body = new Ellipse2D.Double(0, 0, 80, 30);
g2.fill(body);
// 2. Draw Tower (Rectangle)
Rectangle2D tower = new Rectangle2D.Double(30, -10, 20, 15);
g2.fill(tower);
// 3. Draw Propeller (The "4 strokes" spinning)
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(3));
g2.translate(0, 15); // Move to back-center of sub
g2.rotate(propAngle);
for (int i = 0; i < 4; i++) {
g2.rotate(Math.PI / 2); // 90 degree increments
g2.draw(new Line2D.Double(0, 0, 10, 0));
}
g2.setTransform(old);
}
private void drawMissiles(Graphics2D g2) {
g2.setColor(Color.YELLOW);
for (Missile m : missiles) {
g2.fill(new Ellipse2D.Double(m.x, m.y, 15, 5));
}
}
// Missile Helper Class
class Missile {
double x, y;
Missile(double x, double y) { this.x = x; this.y = y; }
void move() { x += 10; }
}
public static void main(String[] args) {
JFrame frame = new JFrame("Submarine 2D Graphics");
frame.add(new SubmarineGame());
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Key Features Explained
java.awt.geom:We use
Ellipse2Dfor the hull andRectangle2Dfor the conning tower.The propeller is created using
Line2Dinside a loop that rotates the coordinate system.
The "4-Stroke" Animation:
In the
drawSubmarinemethod, I useg2.rotate(propAngle). By looping 4 times and rotating byMath.PI / 2(90 degrees) each time, we draw four distinct blades. BecausepropAngleincreases in the Timer, it creates a spinning effect.
Movement (WASD):
I used KeyBindings (
getInputMapandgetActionMap). Unlike aKeyListener, KeyBindings don't require the component to have focus manually and are less prone to "glitching" when multiple keys are pressed.
Missile Logic:
An
ArrayListstores active missiles. Every frame, they move to the right. To prevent memory leaks, they are removed from the list once they exit the screen boundaries.
How to run it in NetBeans
Create a new Java Project.
Create a new Java Class named
SubmarineGame.Paste the code above.
Right-click the file and select Run File.

Tidak ada komentar:
Posting Komentar