Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
ゲームパッド入力とキーボード入力を使って宇宙船からビームを発射する。(Java JInputサンプル)
/*
* ゲームパッド入力とキーボード入力を使って宇宙船からビームを発射する。
*/
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import net.java.games.input.*;
import net.java.games.input.Component.Identifier;
import net.java.games.input.Component;
import net.java.games.input.EventQueue;
/**
* メインプログラム。
*/
public final class App {
static final int SCREEN_WIDTH = 400;
static final int SCREEN_HEIGHT = 500;
GameScreen screen;
ControllerInput keyboardInput;
ControllerInput gamepadInput;
Starship starship;
App() {
this.starship = new Starship();
this.gamepadInput = new GamepadControllerInput();
this.keyboardInput = new KeyboardControllerInput();
this.screen = new GameScreen(starship);
}
void startGame() {
// ゲームパッド入力
if (gamepadInput.available()) {
ForkJoinPool.commonPool().execute(() -> {
while (true) {
gamepadInput.getState().ifPresent(this::changeState);
sleep(15L);
}
});
}
// キーボード入力
if (keyboardInput.available()) {
ForkJoinPool.commonPool().execute(() -> {
while (true) {
keyboardInput.getState().ifPresent(this::changeState);
sleep(15L);
}
});
}
// 状態更新
ForkJoinPool.commonPool().execute(() -> {
while (true) {
starship.updateState();
screen.repaint();
sleep(15L);
}
});
}
/**
* コントローラー入力の状態をゲームの状態に反映する。
* @param controllerState コントローラ入力の状態
*/
void changeState(ControllerInput.State controllerState) {
starship.directionX = controllerState.x;
starship.directionY = controllerState.y;
if (controllerState.attackButtonPushed) {
starship.fire();
}
}
static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Game");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
f.setLocationRelativeTo(null);
App app = new App();
f.add(app.screen, BorderLayout.CENTER);
f.setVisible(true);
app.startGame();
}
});
}
}
/**
* ゲーム画面。
*/
final class GameScreen extends JPanel {
Starship starship;
GameScreen(Starship starship) {
this.starship = starship;
setBackground(Color.BLACK);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(starship.image, starship.x, starship.y, this);
g.setColor(Color.CYAN);
for (Beam beam : starship.beams) {
if (beam.fired) {
g.fill3DRect(beam.x - 10, beam.y, 4, 8, true);
g.fill3DRect(beam.x + 10, beam.y, 4, 8, true);
}
}
}
}
/**
* 宇宙船。
*/
final class Starship {
static final int WIDTH = 48;
static final int HEIGHT = 48;
static final int MOVE_DISTANCE = 12;
static final int MAX_X = App.SCREEN_WIDTH - (WIDTH - 8) * 2;
static final int MIN_X = 10;
static final int MAX_Y = App.SCREEN_HEIGHT - HEIGHT * 2;
static final int MIN_Y = 10;
BufferedImage image;
int directionX;
int directionY;
int x;
int y;
List<Beam> beams;
Starship() {
try {
this.image = ImageIO.read(getClass().getResource("starship.png"));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
this.directionX = 0;
this.directionY = 0;
this.x = MAX_X / 2 - 10;
this.y = MAX_Y - 30;
// ビーム同時発射は最大5発
this.beams = IntStream.range(0, 5).mapToObj(x -> new Beam()).collect(Collectors.toList());
}
void move(int directionX, int directionY) {
this.directionX = directionX;
this.directionY = directionY;
}
void fire() {
Collections.rotate(beams, 1);
Beam beam = beams.get(0);
if (!beam.fired) {
beam.fire(x, y);
}
}
void updateState() {
int x = this.x;
int y = this.y;
if (directionX > 0) {
x += MOVE_DISTANCE;
x = Math.min(x, MAX_X);
}
else if (directionX < 0) {
x -= MOVE_DISTANCE;
x = Math.max(x, MIN_X);
}
if (directionY > 0) {
y += MOVE_DISTANCE;
y = Math.min(y, MAX_Y);
}
else if (directionY < 0) {
y -= MOVE_DISTANCE;
y = Math.max(y, MIN_Y);
}
this.x = x;
this.y = y;
for (Beam beam : beams) {
beam.updateState();
}
this.directionX = 0;
this.directionY = 0;
}
}
/**
* ビーム。
*/
final class Beam {
static final int MOVE_DISTANCE = 18;
boolean fired;
int x;
int y;
void fire(int x, int y) {
this.fired = true;
this.x = x + Starship.WIDTH / 2;
this.y = y;
}
void fadeOut() {
this.fired = false;
}
void updateState() {
if (fired) {
y -= MOVE_DISTANCE;
if (y < -20) {
fadeOut();
}
}
}
}
/**
* コントローラー入力。
*/
interface ControllerInput {
Optional<ControllerInput.State> getState();
boolean available();
static Controller detectController(Controller.Type type) {
Controller[] controllers = ControllerEnvironment.getDefaultEnvironment().getControllers();
for (Controller controller : controllers) {
if (controller != null && controller.getType() == type) {
return controller;
}
}
return NullController.INSTANCE;
}
/**
* コントローラー入力の状態。
*/
static final class State {
int x;
int y;
boolean attackButtonPushed;
State(int x, int y, boolean attackButtonPushed) {
this.x = x;
this.y = y;
this.attackButtonPushed = attackButtonPushed;
}
}
}
/**
* コントローラーが無効な場合のスタブ。
*/
final class NullController implements Controller {
static final Controller INSTANCE = new NullController();
@Override
public Controller[] getControllers() {
return new Controller[0];
}
@Override
public Type getType() {
return Controller.Type.UNKNOWN;
}
@Override
public Component[] getComponents() {
return new Component[0];
}
@Override
public Component getComponent(Identifier id) {
return null;
}
@Override
public Rumbler[] getRumblers() {
return new Rumbler[0];
}
@Override
public boolean poll() {
return false;
}
@Override
public void setEventQueueSize(int size) {
}
@Override
public EventQueue getEventQueue() {
return null;
}
@Override
public PortType getPortType() {
return Controller.PortType.UNKNOWN;
}
@Override
public int getPortNumber() {
return -1;
}
@Override
public String getName() {
return "NullController";
}
}
/**
* ゲームパッドコントローラー入力。
*/
final class GamepadControllerInput implements ControllerInput {
final Controller controller;
volatile boolean button3Released;
GamepadControllerInput() {
this.controller = ControllerInput.detectController(Controller.Type.GAMEPAD);
this.button3Released = true;
}
@Override
public boolean available() {
return controller != NullController.INSTANCE;
}
@Override
public Optional<ControllerInput.State> getState() {
if (controller.poll()) {
float x0 = controller.getComponent(Identifier.Axis.X).getPollData();
float y0 = controller.getComponent(Identifier.Axis.Y).getPollData();
int x = x0 > 0.0f
? 1
: x0 < -0.1f
? -1
: 0;
int y = y0 > 0.0f
? 1
: y0 < -0.1f
? -1
: 0;
// Button._2はボタン3(0オリジン)
boolean button3Pushed = controller.getComponent(Identifier.Button._2).getPollData() > 0.0f;
boolean attackButtonPushed = button3Released && button3Pushed;
button3Released = !button3Pushed;
if (x != 0 || y != 0 || attackButtonPushed) {
return Optional.of(new ControllerInput.State(x, y, attackButtonPushed));
}
}
return Optional.empty();
}
}
/**
* キーボードコントローラー入力。
*/
final class KeyboardControllerInput implements ControllerInput {
final Controller controller;
volatile boolean spaceKeyReleased;
KeyboardControllerInput() {
this.controller = ControllerInput.detectController(Controller.Type.KEYBOARD);
this.spaceKeyReleased = true;
}
@Override
public boolean available() {
return controller != NullController.INSTANCE;
}
@Override
public Optional<ControllerInput.State> getState() {
if (controller.poll()) {
int x = controller.getComponent(Identifier.Key.LEFT).getPollData() > 0.0f
? -1
: controller.getComponent(Identifier.Key.RIGHT).getPollData() > 0.0f
? 1
: 0;
int y = controller.getComponent(Identifier.Key.UP).getPollData() > 0.0f
? -1
: controller.getComponent(Identifier.Key.DOWN).getPollData() > 0.0f
? 1
: 0;
// Spaceキー
boolean spaceKeyPushed = controller.getComponent(Identifier.Key.SPACE).getPollData() > 0.0f;
boolean attackButtonPushed = spaceKeyReleased && spaceKeyPushed;
spaceKeyReleased = !spaceKeyPushed;
if (x != 0 || y != 0 || attackButtonPushed) {
return Optional.of(new ControllerInput.State(x, y, attackButtonPushed));
}
}
return Optional.empty();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment