プレイヤー中心視点の2Dゲーム
前回の2Dゲームプログラムの考え方を拡張し、自分のキャラクターを中心として、ゲームのワールドを移動できるようなプログラムを考えてみましょう。 前回と同様にJSONを利用してゲームの状態を送受信します。 プレイヤーは、矢印キーによってキャラクターを上下左右に移動させることができるようにします。 そのキー入力をクライアントからサーバーに送ります。 サーバープログラムは、クライアントからの入力を受け取り、各プレイヤーごとに、現在の座標とその周囲に存在する他プレイヤーの情報をクライアントに送ります。
通信方向 | 送信内容 | 例 |
---|---|---|
クライアント→サーバー | プレイヤーの操作(上下左右への移動) | {"direction": "up"} |
クライアント←サーバー | 現在のゲームの状態(表示座標と周囲のプレイヤーの座標) | {"players": [{"id": 2, "x": 100, "y": 200}]} |
サーバープログラム
import processing.net.*;
int screenWidth = 400;
int screenHeight = 400;
int gameWidth = 2000;
int gameHeight = 2000;
class Player {
int id;
float cx, cy;
Player(int id) {
this.id = id;
this.cx = random(gameWidth);
this.cy = random(gameHeight);
}
void move(float dx, float dy) {
this.cx += dx;
this.cy += dy;
if (this.cx > gameWidth) {
this.cx -= gameWidth;
}
if (this.cx < 0) {
this.cx += gameWidth;
}
if (this.cy > gameHeight) {
this.cy -= gameHeight;
}
if (this.cy < 0) {
this.cy += gameHeight;
}
}
JSONObject toJSON() {
JSONObject item = new JSONObject();
item.setInt("id", this.id);
item.setFloat("x", this.cx);
item.setFloat("y", this.cy);
return item;
}
}
Server server;
int idOffset = 0;
HashMap<Client, Player> players = new HashMap();
void setup() {
server = new Server(this, 5204);
}
void draw() {
for (Client client : players.keySet()) {
Player player = players.get(client);
JSONArray playerArray = new JSONArray();
for (Player p : players.values()) {
if (player.cx - screenWidth / 2 <= p.cx
&& p.cx <= player.cx + screenWidth / 2
&& player.cy - screenHeight / 2 <= p.cy
&& p.cy <= player.cy + screenHeight / 2) {
playerArray.append(p.toJSON());
}
}
JSONObject message = new JSONObject();
message.setJSONArray("players", playerArray);
message.setFloat("cx", player.cx);
message.setFloat("cy", player.cy);
client.write(message.toString());
client.write('\0');
}
}
void clientEvent(Client client) {
float d = 10;
String payload = client.readStringUntil('\0');
if (payload != null) {
JSONObject message = parseJSONObject(payload.substring(0, payload.length() - 1));
Player player = players.get(client);
switch (message.getString("direction")) {
case "left":
player.move(-d, 0);
break;
case "right":
player.move(d, 0);
break;
case "up":
player.move(0, -d);
break;
case "down":
player.move(0, d);
break;
}
}
}
void serverEvent(Server server, Client client) {
Player player = new Player(idOffset++);
players.put(client, player);
}
void disconnectEvent(Client client) {
players.remove(client);
}
クライアントプログラム
import processing.net.*;
int playerSize = 20;
int gameWidth = 2000;
int gameHeight = 2000;
class Player {
int id;
float cx, cy, angle;
Player(int id, float cx, float cy, float angle) {
this.id = id;
this.cx = cx;
this.cy = cy;
this.angle = angle;
}
void draw() {
}
}
Client client;
JSONObject status = new JSONObject();
void setup() {
size(400, 400);
client = new Client(this, "127.0.0.1", 5204);
}
void draw() {
background(255);
if (status.getJSONArray("players") == null) {
return;
}
synchronized(status) {
pushMatrix();
float cx = status.getFloat("cx");
float cy = status.getFloat("cy");
translate(-cx + width / 2, -cy + height / 2);
drawField();
JSONArray players = status.getJSONArray("players");
for (int i = 0; i < players.size(); ++i) {
JSONObject player = players.getJSONObject(i);
int playerId = player.getInt("id");
float playerX = player.getFloat("x");
float playerY = player.getFloat("y");
stroke(0);
fill(255);
ellipse(playerX, playerY, playerSize, playerSize);
fill(0);
textAlign(CENTER, CENTER);
text(playerId, playerX, playerY);
}
popMatrix();
}
}
void drawField() {
int size = 100;
int n = gameWidth / size;
stroke(0);
for (int i = 0; i <= n; ++i) {
line(0, size * i, gameWidth, size * i);
}
for (int j = 0; j <= n; ++j) {
line(size * j, 0, size * j, gameHeight);
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
fill(0);
textAlign(CENTER, CENTER);
text(i * n + j, size * j + size / 2, size * i + size / 2);
}
}
}
void keyPressed() {
if (key == CODED) {
JSONObject message = new JSONObject();
switch (keyCode) {
case RIGHT:
message.setString("direction", "right");
break;
case LEFT:
message.setString("direction", "left");
break;
case UP:
message.setString("direction", "up");
break;
case DOWN:
message.setString("direction", "down");
break;
default:
return;
}
client.write(message.toString());
client.write('\0');
}
}
void clientEvent(Client client) {
String payload = client.readStringUntil('\0');
if (payload != null) {
synchronized(status) {
status = parseJSONObject(payload.substring(0, payload.length() - 1));
}
}
}