| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> |
| <head> |
| <title>Apache Tomcat WebSocket Examples: Multiplayer Snake</title> |
| <style type="text/css"><![CDATA[ |
| #playground { |
| width: 640px; |
| height: 480px; |
| background-color: #000; |
| } |
| |
| #console-container { |
| float: left; |
| margin-left: 15px; |
| width: 300px; |
| } |
| |
| #console { |
| border: 1px solid #CCCCCC; |
| border-right-color: #999999; |
| border-bottom-color: #999999; |
| height: 480px; |
| overflow-y: scroll; |
| padding-left: 5px; |
| padding-right: 5px; |
| width: 100%; |
| } |
| |
| #console p { |
| padding: 0; |
| margin: 0; |
| } |
| ]]></style> |
| </head> |
| <body> |
| <div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable |
| Javascript and reload this page!</h2></div> |
| <div style="float: left"> |
| <canvas id="playground" width="640" height="480"/> |
| </div> |
| <div id="console-container"> |
| <div id="console"/> |
| </div> |
| <script type="application/javascript"><![CDATA[ |
| "use strict"; |
| |
| var Game = {}; |
| |
| Game.fps = 30; |
| Game.socket = null; |
| Game.nextFrame = null; |
| Game.interval = null; |
| Game.direction = 'none'; |
| Game.gridSize = 10; |
| |
| function Snake() { |
| this.snakeBody = []; |
| this.color = null; |
| } |
| |
| Snake.prototype.draw = function(context) { |
| for (var id in this.snakeBody) { |
| context.fillStyle = this.color; |
| context.fillRect(this.snakeBody[id].x, this.snakeBody[id].y, Game.gridSize, Game.gridSize); |
| } |
| }; |
| |
| Game.initialize = function() { |
| this.entities = []; |
| var canvas = document.getElementById('playground'); |
| if (!canvas.getContext) { |
| Console.log('Error: 2d canvas not supported by this browser.'); |
| return; |
| } |
| this.context = canvas.getContext('2d'); |
| window.addEventListener('keydown', function (e) { |
| var code = e.keyCode; |
| if (code > 36 && code < 41) { |
| switch (code) { |
| case 37: |
| if (Game.direction != 'east') Game.setDirection('west'); |
| break; |
| case 38: |
| if (Game.direction != 'south') Game.setDirection('north'); |
| break; |
| case 39: |
| if (Game.direction != 'west') Game.setDirection('east'); |
| break; |
| case 40: |
| if (Game.direction != 'north') Game.setDirection('south'); |
| break; |
| } |
| } |
| }, false); |
| if (window.location.protocol == 'http:') { |
| Game.connect('ws://' + window.location.host + '/examples/websocket/snake'); |
| } else { |
| Game.connect('wss://' + window.location.host + '/examples/websocket/snake'); |
| } |
| }; |
| |
| Game.setDirection = function(direction) { |
| Game.direction = direction; |
| Game.socket.send(direction); |
| Console.log('Sent: Direction ' + direction); |
| }; |
| |
| Game.startGameLoop = function() { |
| if (window.webkitRequestAnimationFrame) { |
| Game.nextFrame = function () { |
| webkitRequestAnimationFrame(Game.run); |
| }; |
| } else if (window.mozRequestAnimationFrame) { |
| Game.nextFrame = function () { |
| mozRequestAnimationFrame(Game.run); |
| }; |
| } else { |
| Game.interval = setInterval(Game.run, 1000 / Game.fps); |
| } |
| if (Game.nextFrame != null) { |
| Game.nextFrame(); |
| } |
| }; |
| |
| Game.stopGameLoop = function () { |
| Game.nextFrame = null; |
| if (Game.interval != null) { |
| clearInterval(Game.interval); |
| } |
| }; |
| |
| Game.draw = function() { |
| this.context.clearRect(0, 0, 640, 480); |
| for (var id in this.entities) { |
| this.entities[id].draw(this.context); |
| } |
| }; |
| |
| Game.addSnake = function(id, color) { |
| Game.entities[id] = new Snake(); |
| Game.entities[id].color = color; |
| }; |
| |
| Game.updateSnake = function(id, snakeBody) { |
| if (typeof Game.entities[id] != "undefined") { |
| Game.entities[id].snakeBody = snakeBody; |
| } |
| }; |
| |
| Game.removeSnake = function(id) { |
| Game.entities[id] = null; |
| // Force GC. |
| delete Game.entities[id]; |
| }; |
| |
| Game.run = (function() { |
| var skipTicks = 1000 / Game.fps, nextGameTick = (new Date).getTime(); |
| |
| return function() { |
| while ((new Date).getTime() > nextGameTick) { |
| nextGameTick += skipTicks; |
| } |
| Game.draw(); |
| if (Game.nextFrame != null) { |
| Game.nextFrame(); |
| } |
| }; |
| })(); |
| |
| Game.connect = (function(host) { |
| if ('WebSocket' in window) { |
| Game.socket = new WebSocket(host); |
| } else if ('MozWebSocket' in window) { |
| Game.socket = new MozWebSocket(host); |
| } else { |
| Console.log('Error: WebSocket is not supported by this browser.'); |
| return; |
| } |
| |
| Game.socket.onopen = function () { |
| // Socket open.. start the game loop. |
| Console.log('Info: WebSocket connection opened.'); |
| Console.log('Info: Press an arrow key to begin.'); |
| Game.startGameLoop(); |
| setInterval(function() { |
| // Prevent server read timeout. |
| Game.socket.send('ping'); |
| }, 5000); |
| }; |
| |
| Game.socket.onclose = function () { |
| Console.log('Info: WebSocket closed.'); |
| Game.stopGameLoop(); |
| }; |
| |
| Game.socket.onmessage = function (message) { |
| var packet = JSON.parse(message.data); |
| switch (packet.type) { |
| case 'update': |
| for (var i = 0; i < packet.data.length; i++) { |
| Game.updateSnake(packet.data[i].id, packet.data[i].body); |
| } |
| break; |
| case 'join': |
| for (var j = 0; j < packet.data.length; j++) { |
| Game.addSnake(packet.data[j].id, packet.data[j].color); |
| } |
| break; |
| case 'leave': |
| Game.removeSnake(packet.id); |
| break; |
| case 'dead': |
| Console.log('Info: Your snake is dead, bad luck!'); |
| Game.direction = 'none'; |
| break; |
| case 'kill': |
| Console.log('Info: Head shot!'); |
| break; |
| } |
| }; |
| }); |
| |
| var Console = {}; |
| |
| Console.log = (function(message) { |
| var console = document.getElementById('console'); |
| var p = document.createElement('p'); |
| p.style.wordWrap = 'break-word'; |
| p.innerHTML = message; |
| console.appendChild(p); |
| while (console.childNodes.length > 25) { |
| console.removeChild(console.firstChild); |
| } |
| console.scrollTop = console.scrollHeight; |
| }); |
| |
| Game.initialize(); |
| |
| |
| document.addEventListener("DOMContentLoaded", function() { |
| // Remove elements with "noscript" class - <noscript> is not allowed in XHTML |
| var noscripts = document.getElementsByClassName("noscript"); |
| for (var i = 0; i < noscripts.length; i++) { |
| noscripts[i].parentNode.removeChild(noscripts[i]); |
| } |
| }, false); |
| |
| ]]></script> |
| </body> |
| </html> |