diff --git a/client/src/components/Game.vue b/client/src/components/Game.vue index cbe50fd..87f50ef 100644 --- a/client/src/components/Game.vue +++ b/client/src/components/Game.vue @@ -53,13 +53,13 @@ export default { this.players.forEach(player => { this.renderPlayer(player) - this.renderWalls(player.walls, player.color) + this.renderWalls(player) }) - this.renderDebug() + this.renderDebug(this.player) - this.checkPlayerColision() - this.updatePlayer() + // this.checkPlayerColision() + this.updatePlayer(this.player) }, renderBorders () { this.context.strokeStyle = 'black' @@ -80,19 +80,19 @@ export default { this.context.restore() }, - renderWalls (walls, color) { + renderWalls (player) { this.context.beginPath() this.context.lineWidth = this.settings.wallSize - this.context.strokeStyle = color - walls.forEach(wall => { + this.context.strokeStyle = player.color + player.walls.forEach(wall => { const canvasX = this.canvas.width / 2 + wall.x - this.player.x const canvasY = this.canvas.height / 2 + wall.y - this.player.y this.context.lineTo(canvasX, canvasY) }) - this.context.lineTo(this.canvas.width / 2, this.canvas.height / 2) + this.context.lineTo(this.canvas.width / 2 + player.x - this.player.x, this.canvas.height / 2 + player.y - this.player.y) this.context.stroke() }, - renderDebug () { + renderDebug (player) { this.context.beginPath() const canvasX = this.canvas.width / 2 const canvasY = this.canvas.height / 2 @@ -102,8 +102,8 @@ export default { this.context.strokeStyle = 'blue' this.context.stroke() - const x = canvasX + 30 * Math.cos(this.player.angle) * 2 - const y = canvasY + 30 * Math.sin(this.player.angle) * 2 + const x = canvasX + 30 * Math.cos(player.angle) * 2 + const y = canvasY + 30 * Math.sin(player.angle) * 2 this.context.beginPath() this.context.lineTo(canvasX, canvasY) this.context.lineTo(x, y) @@ -125,10 +125,10 @@ export default { this.context.strokeStyle = 'purple' this.context.stroke() - this.context.fillText('player x: ' + this.player.x + ' y:' + this.player.y, 10, 10) - this.context.fillText('a:' + this.player.angle + ' a_t' + this.player.targetAngle, 10, 20) + this.context.fillText('player x: ' + player.x + ' y:' + player.y, 10, 10) + this.context.fillText('a:' + player.angle + ' a_t' + player.targetAngle, 10, 20) this.context.fillText('canvasX: ' + canvasX + ' canvasY:' + canvasY, 10, 30) - this.context.fillText('walls: ' + this.player.walls.length, 10, 40) + this.context.fillText('walls: ' + player.walls.length, 10, 40) }, mouseEvent (event) { var rect = this.canvas.getBoundingClientRect() @@ -141,17 +141,19 @@ export default { this.player.targetAngle = Math.atan2(dy, dx) send({ message: this.player, type: 'update' }) }, - updatePlayer () { + updatePlayer (player) { + /* this.player.lastWall++ if (this.player.lastWall > this.settings.wallUpdate) { this.player.walls.push({ x: this.player.x, y: this.player.y }) this.player.lastWall = 0 } + */ - this.player.x += this.settings.playerSpeed * Math.cos(this.player.angle) - this.player.y += this.settings.playerSpeed * Math.sin(this.player.angle) + player.x += this.settings.playerSpeed * Math.cos(player.angle) + player.y += this.settings.playerSpeed * Math.sin(player.angle) - this.player.angle = this.player.targetAngle + player.angle = player.targetAngle // angle lag /* if (this.player.targetAngle !== this.player.angle) { diff --git a/client/src/store/gameModule.js b/client/src/store/gameModule.js index 364f7df..937f3bf 100644 --- a/client/src/store/gameModule.js +++ b/client/src/store/gameModule.js @@ -4,8 +4,6 @@ const state = { y: 100, angle: 0, targetAngle: 0, - walls: [], - lastWall: 0, color: 'red' }, players: { @@ -37,8 +35,10 @@ const actions = { commit('SET_SETTINGS', settings) }, update ({ commit }, update) { + commit('SET_PLAYERS', update) }, - dead ({ commit }) { + dead ({ commit }, player) { + commit('SET_PLAYER', player) }, error ({ commit }, error) { alert('Error: ' + error) @@ -49,6 +49,9 @@ const mutations = { SET_PLAYER (state, player) { state.player = player }, + SET_PLAYERS (state, players) { + state.players = players + }, SET_SETTINGS (state, settings) { state.settings = settings }, diff --git a/client/src/store/socketPlugin.js b/client/src/store/socketPlugin.js index cc36243..73a0f45 100644 --- a/client/src/store/socketPlugin.js +++ b/client/src/store/socketPlugin.js @@ -33,7 +33,7 @@ export default function createSocketPlugin () { store.dispatch('game/update', data.message) break case 'gamePlayerDead': - store.dispatch('game/dead') + store.dispatch('game/dead', data.message) break default: break diff --git a/server/.factorypath b/server/.factorypath index 30583c9..2e7aef0 100644 --- a/server/.factorypath +++ b/server/.factorypath @@ -14,7 +14,6 @@ - @@ -36,4 +35,5 @@ + diff --git a/server/pom.xml b/server/pom.xml index 7ca1408..60e8c9e 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -50,6 +50,12 @@ json 20200518 + + com.fasterxml.jackson.core + jackson-core + 2.11.2 + + diff --git a/server/src/main/java/gltronic/tronio/TronIoApplication.java b/server/src/main/java/gltronic/tronio/TronIoApplication.java index 781e7e4..a14c5c4 100644 --- a/server/src/main/java/gltronic/tronio/TronIoApplication.java +++ b/server/src/main/java/gltronic/tronio/TronIoApplication.java @@ -2,10 +2,15 @@ package gltronic.tronio; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @SpringBootApplication +@EnableScheduling @ComponentScan(basePackages = "gltronic.tronio") @PropertySource("classpath:application.properties") public class TronIoApplication { @@ -14,4 +19,15 @@ public class TronIoApplication { SpringApplication.run(TronIoApplication.class, args); } + @Bean + public TaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + + scheduler.setPoolSize(2); + scheduler.setThreadNamePrefix("scheduled-task-"); + scheduler.setDaemon(true); + + return scheduler; + } + } diff --git a/server/src/main/java/gltronic/tronio/business/GameManager.java b/server/src/main/java/gltronic/tronio/business/GameManager.java index a2d51ae..7dab49a 100644 --- a/server/src/main/java/gltronic/tronio/business/GameManager.java +++ b/server/src/main/java/gltronic/tronio/business/GameManager.java @@ -4,8 +4,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Random; -import org.json.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.socket.WebSocketSession; @@ -24,14 +27,17 @@ public class GameManager implements IGameManager { SocketUtils.sendMessage(session, "error", "cant login twice"); return; } - + Player player = initPlayer(new Player()); game.getSessions().put(session.getId(), session); game.getPlayers().put(session.getId(), player); - SocketUtils.forwardMessage(session, "login", new JSONObject(player)); - SocketUtils.forwardMessage(session, "gameSettings", new JSONObject(game.getSettings())); + System.out.println("[GAME] Player " + session.getId() + " logged in | status: " + player.getX() + " " + player.getY() + " " + player.getColor()); + + SocketUtils.sendObject(session, "login", new ObjectMapper().writeValueAsString(player)); + SocketUtils.sendObject(session, "gameSettings", new ObjectMapper().writeValueAsString(game.getSettings())); + SocketUtils.sendObject(session, "gameUpdate", new ObjectMapper().writeValueAsString(game.getPlayers().values())); } @Override @@ -48,14 +54,16 @@ public class GameManager implements IGameManager { } @Override + @Scheduled(fixedDelay = 1000 / 60) public void step() throws InterruptedException, IOException { // CHECK OUT OF BORDERS & COLISIONS game.getPlayers().forEach((id, player) -> { // OUT OF BORDERS - if (player.getX() - game.getSettings().getPlayerSize() < 0 || - player.getX() + game.getSettings().getPlayerSize() > game.getSettings().getArenaSize() || - player.getY() - game.getSettings().getPlayerSize() < 0 || - player.getY() + game.getSettings().getPlayerSize() > game.getSettings().getArenaSize()) { + if (player.getX() - game.getSettings().getPlayerSize() < 0 + || player.getX() + game.getSettings().getPlayerSize() > game.getSettings().getArenaSize() + || player.getY() - game.getSettings().getPlayerSize() < 0 + || player.getY() + game.getSettings().getPlayerSize() > game.getSettings().getArenaSize()) { + System.out.println("[GAME] border"); killPlayer(id); return; } @@ -65,8 +73,12 @@ public class GameManager implements IGameManager { for (var i = 0; i < player2.getWalls().size() - 2; i++) { Wall wallA = player2.getWalls().get(i); Wall wallB = player2.getWalls().get(i + 1); - if (isCloseToWall(wallA.getX(), wallA.getY(), wallB.getX(), wallB.getY(), player.getX(), player.getY(), game.getSettings().getPlayerSize())) { - if (this.isCrossingLine(wallA.getX(), wallA.getY(), wallB.getX(), wallB.getY(), player.getX(), player.getY(), game.getSettings().getPlayerSize())) { + if (isCloseToWall(wallA.getX(), wallA.getY(), wallB.getX(), wallB.getY(), player.getX(), player.getY(), + game.getSettings().getPlayerSize())) { + System.out.println("[GAME] close to wall"); + if (this.isCrossingLine(wallA.getX(), wallA.getY(), wallB.getX(), wallB.getY(), player.getX(), + player.getY(), game.getSettings().getPlayerSize())) { + System.out.println("[GAME] touch da wall"); killPlayer(id); return; } @@ -88,12 +100,21 @@ public class GameManager implements IGameManager { player.setX(player.getX() + game.getSettings().getPlayerSpeed() * Math.cos(player.getAngle())); player.setY(player.getY() + game.getSettings().getPlayerSpeed() * Math.sin(player.getAngle())); }); + + SocketUtils.broadcast(game, "gameUpdate", new ObjectMapper().writeValueAsString(game.getPlayers().values())); } - private void killPlayer (String id) { + private void killPlayer(String id) { Player player = game.getPlayers().get(id); initPlayer(player); - SocketUtils.sendMessage(game.getSessions().get(id), "gamePlayerDead", "yo dead"); + System.out.println("[GAME] Player " + id + " is dead | status: " + player.getX() + " " + player.getY() + " " + player.getColor()); + try { + SocketUtils.sendObject(game.getSessions().get(id), "gamePlayerDead", + new ObjectMapper().writeValueAsString(player)); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } private boolean isCloseToWall (double xa, double ya, double xb, double yb, double xc, double yc, double radius) { @@ -120,8 +141,8 @@ public class GameManager implements IGameManager { double x = game.getSettings().getArenaSize() * (0.25 + Math.random() * 0.5); double y = game.getSettings().getArenaSize() * (0.25 + Math.random() * 0.5); - player.setAngle(0); - player.setTargetAngle(0); + // player.setAngle(0); + // player.setTargetAngle(0); player.setLastWall(0); player.setWalls(new ArrayList()); player.setColor(String.format("#%06x", rand.nextInt(0xffffff + 1))); diff --git a/server/src/main/java/gltronic/tronio/business/SocketUtils.java b/server/src/main/java/gltronic/tronio/business/SocketUtils.java index d070d46..0fb79cd 100644 --- a/server/src/main/java/gltronic/tronio/business/SocketUtils.java +++ b/server/src/main/java/gltronic/tronio/business/SocketUtils.java @@ -2,7 +2,6 @@ package gltronic.tronio.business; import java.io.IOException; -import org.json.JSONObject; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; @@ -17,17 +16,17 @@ public class SocketUtils { } } - public static void forwardMessage(WebSocketSession session, String type, JSONObject message) { + public static void sendObject(WebSocketSession session, String type, String object) { try { - session.sendMessage(new TextMessage("{\"type\":\"" + type + "\",\"message\": " + message.toString() + " }")); + session.sendMessage(new TextMessage("{\"type\":\"" + type + "\",\"message\": " + object + " }")); } catch (IOException e) { e.printStackTrace(); } } - public static void broadcast(Game game, String type, JSONObject message) { + public static void broadcast(Game game, String type, String message) { game.getSessions().forEach((id, session) -> { - forwardMessage(session, type, message); + sendObject(session, type, message); }); } } \ No newline at end of file diff --git a/server/src/main/java/gltronic/tronio/model/Player.java b/server/src/main/java/gltronic/tronio/model/Player.java index 7b4150c..64ee2d3 100644 --- a/server/src/main/java/gltronic/tronio/model/Player.java +++ b/server/src/main/java/gltronic/tronio/model/Player.java @@ -2,6 +2,8 @@ package gltronic.tronio.model; import java.util.ArrayList; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -9,13 +11,20 @@ import lombok.Setter; @Getter @Setter @NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) public class Player { - private double x; - private double y; - private double angle; - private double targetAngle; - private ArrayList walls; - private int lastWall; + private String color; + private double x; + + private double y; + + private double angle; + + private double targetAngle; + + private ArrayList walls; + + private int lastWall; } \ No newline at end of file diff --git a/server/src/main/java/gltronic/tronio/web/SocketHandler.java b/server/src/main/java/gltronic/tronio/web/SocketHandler.java index 1d2222f..6e7bec8 100644 --- a/server/src/main/java/gltronic/tronio/web/SocketHandler.java +++ b/server/src/main/java/gltronic/tronio/web/SocketHandler.java @@ -2,6 +2,8 @@ package gltronic.tronio.web; import java.io.IOException; +import com.fasterxml.jackson.databind.ObjectMapper; + import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -23,15 +25,17 @@ public class SocketHandler extends TextWebSocketHandler { @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException { - System.err.println("[WS] message :" + message.getPayload()); + // System.err.println("[WS] message :" + message.getPayload()); String payload = message.getPayload(); - JSONObject jsonObject = new JSONObject(payload); + JSONObject rootObject = new JSONObject(payload); - String type = (String) jsonObject.get("type"); + String type = rootObject.getString("type"); switch (type) { case "update": - gameManager.updatePlayer(session, (Player) jsonObject.get("message")); + Player player = new ObjectMapper().readValue(rootObject.get("message").toString(), Player.class); + + gameManager.updatePlayer(session, player); break; default: SocketUtils.sendMessage(session, "error", "unknow command"); diff --git a/server/target/classes/gltronic/tronio/TronIoApplication.class b/server/target/classes/gltronic/tronio/TronIoApplication.class index 43c49f2..6bd2fe1 100644 Binary files a/server/target/classes/gltronic/tronio/TronIoApplication.class and b/server/target/classes/gltronic/tronio/TronIoApplication.class differ diff --git a/server/target/classes/gltronic/tronio/business/GameManager.class b/server/target/classes/gltronic/tronio/business/GameManager.class index a1ae6b7..5202f6d 100644 Binary files a/server/target/classes/gltronic/tronio/business/GameManager.class and b/server/target/classes/gltronic/tronio/business/GameManager.class differ diff --git a/server/target/classes/gltronic/tronio/business/SocketUtils.class b/server/target/classes/gltronic/tronio/business/SocketUtils.class index df04686..6619551 100644 Binary files a/server/target/classes/gltronic/tronio/business/SocketUtils.class and b/server/target/classes/gltronic/tronio/business/SocketUtils.class differ diff --git a/server/target/classes/gltronic/tronio/model/Player.class b/server/target/classes/gltronic/tronio/model/Player.class index a7ccc47..f3042f6 100644 Binary files a/server/target/classes/gltronic/tronio/model/Player.class and b/server/target/classes/gltronic/tronio/model/Player.class differ diff --git a/server/target/classes/gltronic/tronio/web/SocketHandler.class b/server/target/classes/gltronic/tronio/web/SocketHandler.class index 9dfba34..888b790 100644 Binary files a/server/target/classes/gltronic/tronio/web/SocketHandler.class and b/server/target/classes/gltronic/tronio/web/SocketHandler.class differ diff --git a/test.json b/test.json new file mode 100644 index 0000000..0c35ed8 --- /dev/null +++ b/test.json @@ -0,0 +1,19 @@ +{ + "type":"gameUpdate", + "message": [ + { + "color":"#0deeff", + "x":361.69764869823257, + "y":427.9410817135364, + "angle":0.0, + "targetAngle":0.0, + "walls":[ + {"x":323.69764869823257,"y":427.9410817135364}, + {"x":335.69764869823257,"y":427.9410817135364}, + {"x":347.69764869823257,"y":427.9410817135364}, + {"x":359.69764869823257,"y":427.9410817135364} + ], + "lastWall":0 + } + ] +} \ No newline at end of file