mirror of
https://github.com/OpenLiberty/liberty-bikes.git
synced 2025-01-30 10:40:13 +08:00
Transmit player locations more efficiently
Instead of sending each individual player location update to each client on every game tick, instead send all player locations as an array in a single message. This cuts down the amount of messages per game tick from 16messages to 4 (when 4 players are involved). Also, fix a bug that would allow players to move backwards on themselves if they change direction more than once per game tick.
This commit is contained in:
parent
93082f3d59
commit
e5177c652f
@ -52,9 +52,7 @@ export class GameWebsocket {
|
||||
location.reload();
|
||||
}
|
||||
if (json.playerlocs) {
|
||||
console.log(`Drawing player locations...`);
|
||||
for (let playerLoc of json.playerlocs) {
|
||||
console.log(`Got playerloc ${playerLoc}`);
|
||||
this.whiteboard.drawSquare(playerLoc);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
*/
|
||||
package org.libertybikes.game.core;
|
||||
|
||||
import javax.json.bind.Jsonb;
|
||||
import javax.json.bind.JsonbBuilder;
|
||||
import javax.json.bind.annotation.JsonbProperty;
|
||||
|
||||
/**
|
||||
@ -11,6 +13,8 @@ import javax.json.bind.annotation.JsonbProperty;
|
||||
*/
|
||||
public class ClientMessage {
|
||||
|
||||
private static final Jsonb jsonb = JsonbBuilder.create();
|
||||
|
||||
public static enum GameEvent {
|
||||
GAME_START,
|
||||
GAME_PAUSE,
|
||||
@ -27,7 +31,7 @@ public class ClientMessage {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ direction=" + direction + ", playerjoined=" + playerJoinedId + ", event=" + event + " }";
|
||||
return jsonb.toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,21 +21,20 @@ public class GameRound implements Runnable {
|
||||
OPEN, FULL, RUNNING, FINISHED
|
||||
}
|
||||
|
||||
public static final int GAME_TICK_SPEED = 50;
|
||||
public static final int GAME_SIZE = 600;
|
||||
public static final int GAME_SPEED = 50;
|
||||
|
||||
private static final Random r = new Random();
|
||||
|
||||
public final String id;
|
||||
public final String nextRoundId;
|
||||
|
||||
public Set<Player> players = new HashSet<Player>();
|
||||
|
||||
public State state = State.OPEN;
|
||||
|
||||
boolean[][] board = new boolean[121][121];
|
||||
AtomicBoolean gameRunning = new AtomicBoolean(false);
|
||||
AtomicBoolean paused = new AtomicBoolean(false);
|
||||
|
||||
private static final Random r = new Random();
|
||||
private boolean[][] board = new boolean[121][121];
|
||||
private AtomicBoolean gameRunning = new AtomicBoolean(false);
|
||||
private AtomicBoolean paused = new AtomicBoolean(false);
|
||||
|
||||
// Get a string of 6 random uppercase letters (A-Z)
|
||||
private static String getRandomId() {
|
||||
@ -57,45 +56,55 @@ public class GameRound implements Runnable {
|
||||
public void addPlayer(Player p) {
|
||||
players.add(p);
|
||||
System.out.println("Player " + players.size() + " has joined.");
|
||||
for (Player cur : players)
|
||||
broadcastLocation(cur);
|
||||
broadcastPlayerList(players);
|
||||
broadcastPlayerLocations();
|
||||
broadcastPlayerList();
|
||||
}
|
||||
|
||||
public void removePlayer(Player p) {
|
||||
p.disconnect();
|
||||
System.out.println(p.playerName + " disconnected.");
|
||||
broadcastPlayerList(players);
|
||||
broadcastPlayerList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < GAME_SIZE / Player.PLAYER_SIZE + 1; i++) {
|
||||
for (int i = 0; i < GAME_SIZE / Player.PLAYER_SIZE + 1; i++)
|
||||
Arrays.fill(board[i], true);
|
||||
}
|
||||
gameRunning.set(true);
|
||||
System.out.println("Starting round: " + id);
|
||||
|
||||
while (gameRunning.get()) {
|
||||
while (!paused.get()) {
|
||||
delay(GAME_SPEED);
|
||||
for (Player p : players) {
|
||||
if (p.isAlive) {
|
||||
if (p.movePlayer()) {
|
||||
broadcastLocation(p);
|
||||
} else {
|
||||
// Since someone died, check for winning player
|
||||
checkForWinner(p);
|
||||
broadcastPlayerList(players);
|
||||
}
|
||||
}
|
||||
}
|
||||
delay(GAME_TICK_SPEED);
|
||||
gameTick();
|
||||
}
|
||||
delay(500); // don't thrash for pausing
|
||||
delay(500); // don't thrash when game is paused
|
||||
}
|
||||
System.out.println("Finished round: " + id);
|
||||
}
|
||||
|
||||
private void gameTick() {
|
||||
// Move all living players forward 1
|
||||
boolean playerStatusChange = false;
|
||||
boolean playersMoved = false;
|
||||
for (Player p : players) {
|
||||
if (p.isAlive) {
|
||||
if (p.movePlayer(board)) {
|
||||
playersMoved = true;
|
||||
} else {
|
||||
// Since someone died, check for winning player
|
||||
checkForWinner(p);
|
||||
playerStatusChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (playersMoved)
|
||||
broadcastPlayerLocations();
|
||||
if (playerStatusChange)
|
||||
broadcastPlayerList();
|
||||
}
|
||||
|
||||
private void delay(long ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
@ -103,13 +112,16 @@ public class GameRound implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastLocation(Player p) {
|
||||
String json = p.toJson();
|
||||
for (Player player : players)
|
||||
player.sendTextToClient(json);
|
||||
private void broadcastPlayerLocations() {
|
||||
JsonArrayBuilder arr = Json.createArrayBuilder();
|
||||
for (Player p : players)
|
||||
arr.add(p.toJson());
|
||||
String playerLocations = Json.createObjectBuilder().add("playerlocs", arr).build().toString();
|
||||
for (Player client : players)
|
||||
client.sendTextToClient(playerLocations);
|
||||
}
|
||||
|
||||
private void broadcastPlayerList(Set<Player> players) {
|
||||
private void broadcastPlayerList() {
|
||||
JsonArrayBuilder array = Json.createArrayBuilder();
|
||||
for (Player p : players) {
|
||||
array.add(Json.createObjectBuilder()
|
||||
@ -144,7 +156,7 @@ public class GameRound implements Runnable {
|
||||
for (Player p : players)
|
||||
if (STATUS.Connected == p.getStatus())
|
||||
p.setStatus(STATUS.Alive);
|
||||
broadcastPlayerList(players);
|
||||
broadcastPlayerList();
|
||||
if (!gameRunning.get()) {
|
||||
try {
|
||||
ExecutorService exec = InitialContext.doLookup("java:comp/DefaultManagedExecutorService");
|
||||
|
@ -28,24 +28,23 @@ public class Player {
|
||||
}
|
||||
|
||||
public static final int PLAYER_SIZE = 5;
|
||||
private final GameRound game;
|
||||
|
||||
private Session client;
|
||||
public final String color;
|
||||
public DIRECTION direction = DIRECTION.RIGHT;
|
||||
private DIRECTION lastDirection = null;
|
||||
public int x;
|
||||
public int y;
|
||||
public String playerName;
|
||||
public boolean isAlive = true;
|
||||
private STATUS playerStatus = STATUS.Connected;
|
||||
|
||||
public Player(GameRound g, Session client, String color) {
|
||||
this.game = g;
|
||||
public Player(Session client, String color) {
|
||||
this.color = color;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public Player(GameRound g, Session client, String color, int xstart, int ystart) {
|
||||
this.game = g;
|
||||
public Player(Session client, String color, int xstart, int ystart) {
|
||||
this.color = color;
|
||||
this.client = client;
|
||||
x = xstart;
|
||||
@ -53,8 +52,8 @@ public class Player {
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
// {"shape":"square","color":"#FF0000","coords":{"x":251,"y":89}}
|
||||
StringBuffer sb = new StringBuffer("{\"shape\":\"square\",\"color\":\"");
|
||||
// {"color":"#FF0000","coords":{"x":251,"y":89}}
|
||||
StringBuffer sb = new StringBuffer("{\"color\":\"");
|
||||
sb.append(this.color);
|
||||
sb.append("\",\"coords\":{\"x\":");
|
||||
sb.append(this.x);
|
||||
@ -64,22 +63,35 @@ public class Player {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void setDirection(DIRECTION dir) {
|
||||
direction = dir;
|
||||
public void setDirection(DIRECTION newDirection) {
|
||||
// Make sure the player doesn't move backwards on themselves
|
||||
if (lastDirection != null) {
|
||||
if (newDirection == DIRECTION.UP && lastDirection == DIRECTION.DOWN)
|
||||
return;
|
||||
else if (newDirection == DIRECTION.DOWN && lastDirection == DIRECTION.UP)
|
||||
return;
|
||||
else if (newDirection == DIRECTION.LEFT && lastDirection == DIRECTION.RIGHT)
|
||||
return;
|
||||
else if (newDirection == DIRECTION.RIGHT && lastDirection == DIRECTION.LEFT)
|
||||
return;
|
||||
}
|
||||
|
||||
direction = newDirection;
|
||||
}
|
||||
|
||||
public DIRECTION getDrirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
private boolean checkPosition(int x, int y) {
|
||||
int realXPosition = x / PLAYER_SIZE;
|
||||
int realYPosition = y / PLAYER_SIZE;
|
||||
return game.board[realXPosition][realYPosition];
|
||||
}
|
||||
/**
|
||||
* Move a player forward one space in whatever direction they are facing currently.
|
||||
*
|
||||
* @return True if the player is still alive after moving forward one space. False otherwise.
|
||||
*/
|
||||
public boolean movePlayer(boolean[][] board) {
|
||||
// Consume the space the player was in before the move
|
||||
board[x / PLAYER_SIZE][y / PLAYER_SIZE] = false;
|
||||
|
||||
public boolean movePlayer() {
|
||||
game.board[x / PLAYER_SIZE][y / PLAYER_SIZE] = false;
|
||||
switch (direction) {
|
||||
case UP:
|
||||
if (y - PLAYER_SIZE >= 0)
|
||||
@ -98,11 +110,14 @@ public class Player {
|
||||
x -= PLAYER_SIZE;
|
||||
break;
|
||||
}
|
||||
boolean checkResult = checkPosition(x, y);
|
||||
if (!checkResult) {
|
||||
|
||||
// Check if the player is now dead after moving
|
||||
boolean spaceAvailable = board[x / PLAYER_SIZE][y / PLAYER_SIZE];
|
||||
if (!spaceAvailable) {
|
||||
setStatus(STATUS.Dead);
|
||||
}
|
||||
return checkResult;
|
||||
lastDirection = direction;
|
||||
return isAlive;
|
||||
}
|
||||
|
||||
public void sendTextToClient(String message) {
|
||||
|
@ -38,7 +38,7 @@ public class PlayerFactory {
|
||||
|
||||
public static Player initNextPlayer(GameRound g, Session client, String name) {
|
||||
PlayerData data = startingData[g.players.size()];
|
||||
Player p = new Player(g, client, data.color, data.x, data.y);
|
||||
Player p = new Player(client, data.color, data.x, data.y);
|
||||
p.direction = data.dir;
|
||||
p.playerName = name;
|
||||
return p;
|
||||
|
Loading…
Reference in New Issue
Block a user