您现在的位置是:主页 > news > wordpress 3.9.1/seo管理是什么
wordpress 3.9.1/seo管理是什么
admin2025/6/15 23:33:21【news】
简介wordpress 3.9.1,seo管理是什么,加载wordpress外部文件路径,极速微网站建设cmswebsocket实战(1) 入门websocket实战(2) 信息处理发送、接收和编码websocket实战(3) 错误处理及配置管理通过前面3篇的阐述,相信可以构建一个简单的socket应用了。当然,也会遗漏了许…
websocket实战(1) 入门
websocket实战(2) 信息处理发送、接收和编码
websocket实战(3) 错误处理及配置管理
通过前面3篇的阐述,相信可以构建一个简单的socket应用了。当然,也会遗漏了许多知识点,相信会在以后分享的实例中捎带说明下。
本文的主要是分析下tomcat官方自带的贪食蛇游戏。为什么选择分析这个项目呢。
贪食蛇游戏规则,人人明白,业务方面不需要过多解释(当然这款websocket版的游戏规则也有一定特色)。
游戏设计简单,一个对象足以完成游戏,但不涉及到一些复杂的逻辑算法。
通过游戏,有很好的代入感
1.游戏规则介绍
1.能够实现贪吃蛇自动向前移动,一旦贪食蛇选择了方向,贪食蛇就按所选方向开始运动,可以任意。移动方向为贪吃蛇当前行走方向。
2.游戏通过键盘的上下左右四个方向控制贪吃蛇当前行走方向。(没有可以吃的食物)。
3.支持对战功能,如果发生碰撞情况,后蛇会自杀,重置信息,重新来玩。
4.如果移动出画布外,从对立方向进入,移动方向不变。
界面是"群蛇乱舞”界面。
2.贪食蛇设计
贪食蛇状态快照
贪食蛇类图
贪食蛇:有几个重要属性。颜色,头(head),身体(tail),行动方向。
颜色:随机生成。
头&身体:决定蛇的长度,在画布中的位置。还有决定是否发生碰撞。有(x,y)坐标说明。
行动方向:东西南北四个方向。
重点说一下和websocket相关的信息。贪食蛇的session属性。
session主要负责贪食蛇状态信息的传播,将自己的颜色和位置信息传递到前端。
传播时机
状态变化要传播(kill,join,..)
位置变化要传播(包括方向,其实也是状态变化)
重置要传播(也是状态变化)
分析序列图得知,其实作为游戏的websocket的EndPoint,做的事情很简单。两件事
有新需求:创建贪食蛇,发送渲染命令(join)
响应客户端的命令(方向命令)
不难分析,游戏贪食蛇的移动,是应该有定时器驱动的,所有贪食蛇位置的变化,都是通过SnakeTimer驱动的。然后更新位置信息,最后调用贪食蛇,将自己信息传递到前端。所以定时器,需要维护贪食蛇的聚合信息。
1.贪食蛇聚合信息维护(CRD,没有更新,贪食蛇信息的更新不属于聚合信息范畴)
protected static synchronized void addSnake(Snake snake) {if (snakes.size() == 0) {startTimer();}snakes.put(Integer.valueOf(snake.getId()), snake);
}protected static Collection<Snake> getSnakes() {return Collections.unmodifiableCollection(snakes.values());
}protected static synchronized void removeSnake(Snake snake) {snakes.remove(Integer.valueOf(snake.getId()));if (snakes.size() == 0) {stopTimer();}
}
2. 消息广播(将贪食蛇最新状态信息,实时广播到前端)
就是调用snake自动发送,不难猜,调用session相关的方法。
//SnakeTimer.java
protected static void broadcast(String message) {for (Snake snake : SnakeTimer.getSnakes()) {try {snake.sendMessage(message);} catch (IllegalStateException ise) {// An ISE can occur if an attempt is made to write to a// WebSocket connection after it has been closed. The// alternative to catching this exception is to synchronise// the writes to the clients along with the addSnake() and// removeSnake() methods that are already synchronised.}}
}
//Snake.java
protected void sendMessage(String msg) {try {session.getBasicRemote().sendText(msg);} catch (IOException ioe) {CloseReason cr =new CloseReason(CloseCodes.CLOSED_ABNORMALLY, ioe.getMessage());try {session.close(cr);} catch (IOException ioe2) {// Ignore}}
}
实时更新位置信息
websocket.snake.SnakeTimer.tick()
protected static void tick() {StringBuilder sb = new StringBuilder();for (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator();iterator.hasNext();) {Snake snake = iterator.next();snake.update(SnakeTimer.getSnakes());sb.append(snake.getLocationsJson());if (iterator.hasNext()) {sb.append(',');}}broadcast(String.format("{'type': 'update', 'data' : [%s]}",sb.toString()));
}
按方向计算贪食蛇头下一个的位置
websocket.snake.Location. getAdjacentLocation(Direction direction)
没有方向,不变化位置。
public Location getAdjacentLocation(Direction direction) {switch (direction) {case NORTH:return new Location(x, y - SnakeAnnotation.GRID_SIZE);case SOUTH:return new Location(x, y + SnakeAnnotation.GRID_SIZE);case EAST:return new Location(x + SnakeAnnotation.GRID_SIZE, y);case WEST:return new Location(x - SnakeAnnotation.GRID_SIZE, y);case NONE:// fall throughdefault:return this;}
}
websocket.snake.Snake. update(Collection<Snake> snakes)
public synchronized void update(Collection<Snake> snakes) {Location nextLocation = head.getAdjacentLocation(direction);if (nextLocation.x >= SnakeAnnotation.PLAYFIELD_WIDTH) {nextLocation.x = 0;}if (nextLocation.y >= SnakeAnnotation.PLAYFIELD_HEIGHT) {nextLocation.y = 0;}if (nextLocation.x < 0) {nextLocation.x = SnakeAnnotation.PLAYFIELD_WIDTH;}if (nextLocation.y < 0) {nextLocation.y = SnakeAnnotation.PLAYFIELD_HEIGHT;}if (direction != Direction.NONE) {tail.addFirst(head);if (tail.size() > length) {tail.removeLast();//这一步很关键,实现动态位置变化,否则蛇就无限增长了}head = nextLocation;}//处理蛇是否发生碰撞 handleCollisions(snakes);
}
判断是否发生碰撞
判断和其他,是否发生重叠。是否迎头碰撞,还是头尾碰撞。
private void handleCollisions(Collection<Snake> snakes) {for (Snake snake : snakes) {boolean headCollision = id != snake.id && snake.getHead().equals(head);boolean tailCollision = snake.getTail().contains(head);if (headCollision || tailCollision) {kill();//牺牲自己,触发dead类型信息if (id != snake.id) {snake.reward();//成全别人,让别人长度增加1.触发kill类型信息}}}
}
主要业务逻辑就分析完毕了。有对canvas感兴趣的,可以关注前端js.
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 = [];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 + '/wsexample/websocket/snake');} else {Game.connect('wss://' + window.location.host + '/wsexample/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) {// _Potential_ security hole, consider using json lib to parse data in production.var packet = eval('(' + 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 XHTMLvar noscripts = document.getElementsByClassName("noscript");for (var i = 0; i < noscripts.length; i++) {noscripts[i].parentNode.removeChild(noscripts[i]);} }, false);
结论
通过阅读一些官方文档的代码,学习人家的编码风格,细节。比如线程安全方面。js的面向对象编写,很优雅。不像笔者遇到的经常看到的一个方法,一个方法式的嵌套调用,不考虑性能,就阅读起来就特别费劲。
转载于:https://blog.51cto.com/dba10g/1856234