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