キー入力クラスとコントローラークラスの役割分担に重点を置いてサンプルコードを書いてみました。
とりあえずシンプルに、コントローラーのメソッドと定義を使って情報を読み取る形にしました。
► スポイラーを表示
コード:
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
import isle.videogame.*;
interface Task
{
public void Update();
public void Render(Graphics g);
}
class KeyInput implements Task, KeyListener
{
private int[] vkeymap;
private int keystates;
public KeyInput(int[] vkeymap) {
this.vkeymap = vkeymap;
}
public int getKeyStates() {
return keystates;
}
@Override
public void Update() {
}
@Override
public void Render(Graphics g) {
}
@Override
public void keyPressed(KeyEvent e) {
int mask = 1;
for (int vkey : vkeymap) {
if (e.getKeyCode() == vkey) {
keystates |= mask;
}
mask <<= 1;
}
}
@Override
public void keyReleased(KeyEvent e) {
int mask = 1;
for (int vkey : vkeymap) {
if (e.getKeyCode() == vkey) {
keystates &= ~mask;
}
mask <<= 1;
}
}
@Override
public void keyTyped(KeyEvent e) {}
}
class Controller implements Task, KeyListener
{
public static final int RIGHT = (1<<0);
public static final int UP = (1<<1);
public static final int LEFT = (1<<2);
public static final int DOWN = (1<<3);
private int padstates;
private KeyInput[] keyInput = new KeyInput[2];
private boolean turnLeft = false;
public Controller() {
keyInput[0] = new KeyInput(new int[]{
KeyEvent.VK_RIGHT,
KeyEvent.VK_UP,
KeyEvent.VK_LEFT,
KeyEvent.VK_DOWN
});
keyInput[1] = new KeyInput(new int[]{
KeyEvent.VK_D,
KeyEvent.VK_W,
KeyEvent.VK_A,
KeyEvent.VK_S
});
}
public int getPadStates() {
return padstates;
}
@Override
public void Update() {
for (KeyInput ki : keyInput) ki.Update();
padstates = 0;
for (KeyInput ki : keyInput) padstates |= ki.getKeyStates();
if (turnLeft) {
int sb = (padstates & 1) << (4-1);
padstates = (padstates >>> 1) | sb;
}
}
@Override
public void Render(Graphics g) {
for (KeyInput ki : keyInput) ki.Render(g);
}
@Override
public void keyPressed(KeyEvent e) {
for (KeyInput ki : keyInput) ki.keyPressed(e);
if (e.getKeyCode() == KeyEvent.VK_Z) {
turnLeft = !turnLeft;
}
}
@Override
public void keyReleased(KeyEvent e) {
for (KeyInput ki : keyInput) ki.keyReleased(e);
}
@Override
public void keyTyped(KeyEvent e) {
for (KeyInput ki : keyInput) ki.keyTyped(e);
}
}
class Player implements Task
{
private int pos_x = 640/2;
private int pos_y = 480/2;
private Controller ctrlr;
public Player(Controller ctrlr) {
this.ctrlr = ctrlr;
}
@Override
public void Update() {
int padstates = ctrlr.getPadStates();
if ((padstates & Controller.LEFT) != 0) pos_x--;
if ((padstates & Controller.RIGHT) != 0) pos_x++;
if ((padstates & Controller.UP) != 0) pos_y--;
if ((padstates & Controller.DOWN) != 0) pos_y++;
}
@Override
public void Render(Graphics g) {
g.setColor(Color.CYAN);
int[] ptx = { pos_x+20, pos_x-20, pos_x-20 };
int[] pty = { pos_y+ 0, pos_y-10, pos_y+10 };
g.fillPolygon(ptx, pty, 3);
}
}
public class Sample extends VGCanvas
{
private LinkedList<Task> listTask = new LinkedList<Task>();
private Controller ctrlr;
public Sample()
{
ctrlr = new Controller();
addKeyListener(ctrlr);
listTask.add(ctrlr);
listTask.add(new Player(ctrlr));
}
protected void frameUpdate(int skipped)
{
for (Task task : listTask) {
task.Update();
}
}
protected void frameRender(Graphics g)
{
g.setColor(Color.BLACK);
g.fillRect(0, 0, 640, 480);
for (Task task : listTask) {
task.Render(g);
}
}
public static void main(String[] args)
{
new VGFrame(new Sample(), 640, 480, "サンプル");
}
}
キー入力クラス(KeyInput)は、仮想キーコードの配列を与え、各キーの押下状態をビットに反映したint値を取得します。
サンプルではキー入力クラスのインスタンスを2つ作り、カーソルキー以外にAWSDキーでも操作できるようにしています。
仮想キーコードの配列を書き換えたり配列ごと差し替えることでキーコンフィグを実装できます。
コントローラークラス(Controller)は、キー入力クラスから取得した情報をゲーム本体で使う情報に変換します。
サンプルではコントローラーの定義とキー配置が合致するのでそのまま論理和を取って使っています。
サンプルには含めませんでしたが、反対方向同時押しを消去するなど情報の正規化をここで行います。
Zキーを押すと、モニタを左に回転した場合の操作体系に変わります。
コントローラー内部で完結しているのでゲーム本体のプログラムには影響を与えません。
もう一度Zキーを押すと元に戻ります。