刘洪青 | 6266f99 | 2017-05-15 21:21:03 +0800 | [diff] [blame^] | 1 | <?xml version="1.0" encoding="UTF-8"?>
|
| 2 | <!--
|
| 3 | Licensed to the Apache Software Foundation (ASF) under one or more
|
| 4 | contributor license agreements. See the NOTICE file distributed with
|
| 5 | this work for additional information regarding copyright ownership.
|
| 6 | The ASF licenses this file to You under the Apache License, Version 2.0
|
| 7 | (the "License"); you may not use this file except in compliance with
|
| 8 | the License. You may obtain a copy of the License at
|
| 9 |
|
| 10 | http://www.apache.org/licenses/LICENSE-2.0
|
| 11 |
|
| 12 | Unless required by applicable law or agreed to in writing, software
|
| 13 | distributed under the License is distributed on an "AS IS" BASIS,
|
| 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 15 | See the License for the specific language governing permissions and
|
| 16 | limitations under the License.
|
| 17 | -->
|
| 18 | <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
| 19 | <head>
|
| 20 | <title>Apache Tomcat WebSocket Examples: Multiplayer Snake</title>
|
| 21 | <style type="text/css"><![CDATA[
|
| 22 | #playground {
|
| 23 | width: 640px;
|
| 24 | height: 480px;
|
| 25 | background-color: #000;
|
| 26 | }
|
| 27 |
|
| 28 | #console-container {
|
| 29 | float: left;
|
| 30 | margin-left: 15px;
|
| 31 | width: 300px;
|
| 32 | }
|
| 33 |
|
| 34 | #console {
|
| 35 | border: 1px solid #CCCCCC;
|
| 36 | border-right-color: #999999;
|
| 37 | border-bottom-color: #999999;
|
| 38 | height: 480px;
|
| 39 | overflow-y: scroll;
|
| 40 | padding-left: 5px;
|
| 41 | padding-right: 5px;
|
| 42 | width: 100%;
|
| 43 | }
|
| 44 |
|
| 45 | #console p {
|
| 46 | padding: 0;
|
| 47 | margin: 0;
|
| 48 | }
|
| 49 | ]]></style>
|
| 50 | </head>
|
| 51 | <body>
|
| 52 | <div class="noscript"><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable
|
| 53 | Javascript and reload this page!</h2></div>
|
| 54 | <div style="float: left">
|
| 55 | <canvas id="playground" width="640" height="480"/>
|
| 56 | </div>
|
| 57 | <div id="console-container">
|
| 58 | <div id="console"/>
|
| 59 | </div>
|
| 60 | <script type="application/javascript"><![CDATA[
|
| 61 |
|
| 62 | var Game = {};
|
| 63 |
|
| 64 | Game.fps = 30;
|
| 65 | Game.socket = null;
|
| 66 | Game.nextFrame = null;
|
| 67 | Game.interval = null;
|
| 68 | Game.direction = 'none';
|
| 69 | Game.gridSize = 10;
|
| 70 |
|
| 71 | function Snake() {
|
| 72 | this.snakeBody = [];
|
| 73 | this.color = null;
|
| 74 | }
|
| 75 |
|
| 76 | Snake.prototype.draw = function(context) {
|
| 77 | for (var id in this.snakeBody) {
|
| 78 | context.fillStyle = this.color;
|
| 79 | context.fillRect(this.snakeBody[id].x, this.snakeBody[id].y, Game.gridSize, Game.gridSize);
|
| 80 | }
|
| 81 | };
|
| 82 |
|
| 83 | Game.initialize = function() {
|
| 84 | this.entities = [];
|
| 85 | canvas = document.getElementById('playground');
|
| 86 | if (!canvas.getContext) {
|
| 87 | Console.log('Error: 2d canvas not supported by this browser.');
|
| 88 | return;
|
| 89 | }
|
| 90 | this.context = canvas.getContext('2d');
|
| 91 | window.addEventListener('keydown', function (e) {
|
| 92 | var code = e.keyCode;
|
| 93 | if (code > 36 && code < 41) {
|
| 94 | switch (code) {
|
| 95 | case 37:
|
| 96 | if (Game.direction != 'east') Game.setDirection('west');
|
| 97 | break;
|
| 98 | case 38:
|
| 99 | if (Game.direction != 'south') Game.setDirection('north');
|
| 100 | break;
|
| 101 | case 39:
|
| 102 | if (Game.direction != 'west') Game.setDirection('east');
|
| 103 | break;
|
| 104 | case 40:
|
| 105 | if (Game.direction != 'north') Game.setDirection('south');
|
| 106 | break;
|
| 107 | }
|
| 108 | }
|
| 109 | }, false);
|
| 110 | if (window.location.protocol == 'http:') {
|
| 111 | Game.connect('ws://' + window.location.host + '/examples/websocket/snake');
|
| 112 | } else {
|
| 113 | Game.connect('wss://' + window.location.host + '/examples/websocket/snake');
|
| 114 | }
|
| 115 | };
|
| 116 |
|
| 117 | Game.setDirection = function(direction) {
|
| 118 | Game.direction = direction;
|
| 119 | Game.socket.send(direction);
|
| 120 | Console.log('Sent: Direction ' + direction);
|
| 121 | };
|
| 122 |
|
| 123 | Game.startGameLoop = function() {
|
| 124 | if (window.webkitRequestAnimationFrame) {
|
| 125 | Game.nextFrame = function () {
|
| 126 | webkitRequestAnimationFrame(Game.run);
|
| 127 | };
|
| 128 | } else if (window.mozRequestAnimationFrame) {
|
| 129 | Game.nextFrame = function () {
|
| 130 | mozRequestAnimationFrame(Game.run);
|
| 131 | };
|
| 132 | } else {
|
| 133 | Game.interval = setInterval(Game.run, 1000 / Game.fps);
|
| 134 | }
|
| 135 | if (Game.nextFrame != null) {
|
| 136 | Game.nextFrame();
|
| 137 | }
|
| 138 | };
|
| 139 |
|
| 140 | Game.stopGameLoop = function () {
|
| 141 | Game.nextFrame = null;
|
| 142 | if (Game.interval != null) {
|
| 143 | clearInterval(Game.interval);
|
| 144 | }
|
| 145 | };
|
| 146 |
|
| 147 | Game.draw = function() {
|
| 148 | this.context.clearRect(0, 0, 640, 480);
|
| 149 | for (var id in this.entities) {
|
| 150 | this.entities[id].draw(this.context);
|
| 151 | }
|
| 152 | };
|
| 153 |
|
| 154 | Game.addSnake = function(id, color) {
|
| 155 | Game.entities[id] = new Snake();
|
| 156 | Game.entities[id].color = color;
|
| 157 | };
|
| 158 |
|
| 159 | Game.updateSnake = function(id, snakeBody) {
|
| 160 | if (typeof Game.entities[id] != "undefined") {
|
| 161 | Game.entities[id].snakeBody = snakeBody;
|
| 162 | }
|
| 163 | };
|
| 164 |
|
| 165 | Game.removeSnake = function(id) {
|
| 166 | Game.entities[id] = null;
|
| 167 | // Force GC.
|
| 168 | delete Game.entities[id];
|
| 169 | };
|
| 170 |
|
| 171 | Game.run = (function() {
|
| 172 | var skipTicks = 1000 / Game.fps, nextGameTick = (new Date).getTime();
|
| 173 |
|
| 174 | return function() {
|
| 175 | while ((new Date).getTime() > nextGameTick) {
|
| 176 | nextGameTick += skipTicks;
|
| 177 | }
|
| 178 | Game.draw();
|
| 179 | if (Game.nextFrame != null) {
|
| 180 | Game.nextFrame();
|
| 181 | }
|
| 182 | };
|
| 183 | })();
|
| 184 |
|
| 185 | Game.connect = (function(host) {
|
| 186 | if ('WebSocket' in window) {
|
| 187 | Game.socket = new WebSocket(host);
|
| 188 | } else if ('MozWebSocket' in window) {
|
| 189 | Game.socket = new MozWebSocket(host);
|
| 190 | } else {
|
| 191 | Console.log('Error: WebSocket is not supported by this browser.');
|
| 192 | return;
|
| 193 | }
|
| 194 |
|
| 195 | Game.socket.onopen = function () {
|
| 196 | // Socket open.. start the game loop.
|
| 197 | Console.log('Info: WebSocket connection opened.');
|
| 198 | Console.log('Info: Press an arrow key to begin.');
|
| 199 | Game.startGameLoop();
|
| 200 | setInterval(function() {
|
| 201 | // Prevent server read timeout.
|
| 202 | Game.socket.send('ping');
|
| 203 | }, 5000);
|
| 204 | };
|
| 205 |
|
| 206 | Game.socket.onclose = function () {
|
| 207 | Console.log('Info: WebSocket closed.');
|
| 208 | Game.stopGameLoop();
|
| 209 | };
|
| 210 |
|
| 211 | Game.socket.onmessage = function (message) {
|
| 212 | // _Potential_ security hole, consider using json lib to parse data in production.
|
| 213 | var packet = eval('(' + message.data + ')');
|
| 214 | switch (packet.type) {
|
| 215 | case 'update':
|
| 216 | for (var i = 0; i < packet.data.length; i++) {
|
| 217 | Game.updateSnake(packet.data[i].id, packet.data[i].body);
|
| 218 | }
|
| 219 | break;
|
| 220 | case 'join':
|
| 221 | for (var j = 0; j < packet.data.length; j++) {
|
| 222 | Game.addSnake(packet.data[j].id, packet.data[j].color);
|
| 223 | }
|
| 224 | break;
|
| 225 | case 'leave':
|
| 226 | Game.removeSnake(packet.id);
|
| 227 | break;
|
| 228 | case 'dead':
|
| 229 | Console.log('Info: Your snake is dead, bad luck!');
|
| 230 | Game.direction = 'none';
|
| 231 | break;
|
| 232 | case 'kill':
|
| 233 | Console.log('Info: Head shot!');
|
| 234 | break;
|
| 235 | }
|
| 236 | };
|
| 237 | });
|
| 238 |
|
| 239 | var Console = {};
|
| 240 |
|
| 241 | Console.log = (function(message) {
|
| 242 | var console = document.getElementById('console');
|
| 243 | var p = document.createElement('p');
|
| 244 | p.style.wordWrap = 'break-word';
|
| 245 | p.innerHTML = message;
|
| 246 | console.appendChild(p);
|
| 247 | while (console.childNodes.length > 25) {
|
| 248 | console.removeChild(console.firstChild);
|
| 249 | }
|
| 250 | console.scrollTop = console.scrollHeight;
|
| 251 | });
|
| 252 |
|
| 253 | Game.initialize();
|
| 254 |
|
| 255 |
|
| 256 | document.addEventListener("DOMContentLoaded", function() {
|
| 257 | // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
|
| 258 | var noscripts = document.getElementsByClassName("noscript");
|
| 259 | for (var i = 0; i < noscripts.length; i++) {
|
| 260 | noscripts[i].parentNode.removeChild(noscripts[i]);
|
| 261 | }
|
| 262 | }, false);
|
| 263 |
|
| 264 | ]]></script>
|
| 265 | </body>
|
| 266 | </html> |