Home  >  Article  >  Web Front-end  >  Detailed explanation of an example of implementing a simple multiplayer airplane game in html5

Detailed explanation of an example of implementing a simple multiplayer airplane game in html5

零下一度
零下一度Original
2017-05-13 15:36:483254browse

I saw a multi-person chat room application more than a year ago. It was a socket.io tutorial written by teacher Zhang Dan (the original link cannot be opened, so I posted a repost). I thought sockets are very magical. Later, a project during my postgraduate period also used .Net sockets. The communication between multiple clients was very interesting. It was also that time that I fully understood and applied some concepts such as EventDelegation and so on. Recently, inspired by the enthusiasm for studying mapbox in the group and the help and inspiration from all the members of @开 Uncle, @老宇 @F3earth, I suddenly took some time to make an airplane war game based on mapbox gl js and socket.io! , although the functional interface is very simple. Moreover, the code is relatively primitive and has not been refactored properly. But I basically have a framework, and I simply write it down and analyze it. If you are interested in the source code or want to participate in development and optimization work, please visit the git repository: Jqmap2

Overall architecture

Simply put, the design idea of ​​the entire game is:

The server monitors any websocket connection request sent by the client from the beginning. After the connection (connection event) is established, the user name, the coordinates and the direction of the current aircraft sent by the client for the first time are added to the client data pool as a client. (Currently it is simply processed as clientsarray). Then the data of a client is synchronized to the server.

In the future, the client's aircraft coordinates, heading and other information will also be sent regularly (socket.send) to the server, so that the server can broadcast (broadcast) to all other clients at the same time. In fact, the server has made it clear, that is, it is responsible for relaying messages, and the purpose is to keep the status of the player aircraft in the field of view of all clients consistent.

Since websocket is a two-way communication, the client also needs to send messages to the server regularly, and more importantly, process various messages (message events) sent by the server to distinguish which messages welcome users online. , ordinary player position synchronization news, or news that A defeated B.

During this process, the front end and the server maintain a websocket connection and are constantly communicating. Compared with traditional polling and long poll, this saves traffic and performance. Generally speaking, the logic of the game is based on various message events. The connection event generates a socket connection, and the socket connection has message events and so on.

Backend websocket

Having said so much nonsense, let’s briefly look at how to implement some key codes.

// Back-end key process implementation

var app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server); // 引入socket.io 库
io.on('connection', function(socket) { // 开始监听客户端的websocket连接请求,connection事件产生 socket 对象
    socket.emit('open'); // 向该客户端发送open事件.
    // init client drone obj for each connection !!
    var client = {
        name: false,
        color: getColor(),
        direction: 0,
        coordinates: [0, 0]
    }
    // message from client.
    socket.on('message', function(msg) {
        if (!client.name && msg.name) { // 如果是第一次连接,把用户的名字存储起来,并且广播给所有客户端。
          var obj  = { }; // 构建发送给其他客户端的消息
          obj = msg;
          clients.push(client); // 加入后台维持的客户端数组
          socket.broadcast.emit('message', obj); // 广播欢迎语给其他客户端
        } else if ( client.name == msg.name ) { // 客户端发来的飞机状态消息
            // 广播给其他客户端
          socket.broadcast.emit('message', obj);
        }
    }
}

The background processing process is relatively simple. Basically, you only need to accept the message sent by a client and forward it to other clients (randomly I won’t go into details about the location of the enemy aircraft. Of course, it will be changed later so that all clients share a set of enemy aircraft information, so that they can fight the same BOSS together). However, the front-end needs to process the messages from the server separately according to business needs

Front-end socket and aircraftModel

The front-end business is relatively complex. In addition to dealing with In addition to websocket messages, a set of aircraft data models need to be constructed, including position, speed, orientation, blood volume, weapons and equipment, etc. (it can be very complex, so we will handle it simply for now).

var socket;
try {
    socket = io.connect("http://123.206.201.245:3002");
    socket.on('open', function(){  // 当服务端确认连接后,开始发送第一次数据。
        statusBar.innerText = "已经连上服务器..";
        var askName = prompt("来,取个名字", "");
    }
    socket.on("message", function(json) { // 其实收到的是js 对象,这一点很牛逼。因为双向通信过程中传递的是 Binary 形式的数据,不需要再次解析了。
      if (json.type === "welcome" && json.text.name) {
          // .. 显示其他用户登录消息
      } else if (json.type === "defeat") {
          // .. 在前端的敌机数据模型中移除空血槽的飞机
      } else if (drone && json.text.name != drone.name) {
          // .. 传来的其他客户端飞机消息
          featureCol.features.forEach(function(drone) {
          // featureCol 是所有敌机数据集合,根据用户名check是更新还是新增.
          }
      }
   }

Other issues include:

Aircraft data involves changing at any time uploading to the server and rendering. The rendering uses the geojson object as the source data in the mapbox api, so is it necessary to redraw all aircraft positions as soon as the server-side message is received? Here, the setData() method of the source is called regularly through setInterval to implement redrawing.

The trajectory calculation of the aircraft bullet involves the position and orientation of the aircraft at the moment when the user presses the space bar. An animation is made based on the set bullet flight time to display the collision between the bullet and the enemy aircraft. Detection and simplified processing: Set a constant as the volume of the aircraft, and calculate the distance between the bullet and the enemy aircraft in real time during the flight of the bullet. When the map is at a small scale, the detection radius is increased, and when the map is at a large scale, the detection radius is correspondingly reduced.

At present, it is possible that the calculation amount of collision detection during the flight of the bullet is too large, there will be stuck problems, the CPU usage is high, and the entire application consumes about 100~130Mb of memory... There are many small problems that I won’t mention. . It really took some brains out.

Choose one or two points to analyze, one is the flight process of the bullet, and the other is the random behavior control of the Robot enemy aircraft

// setPostion is to update Mydrone position.
function setPosition() {
    // direction in Rad. Generally, 1 Rad stands for 100km
    var current_rotate = map.getBearing(); 
    if (!manual && Math.random() > 0.95) { // 这边有意思,在每秒50帧的情况下,不是每一帧都会随机微调飞机的方向。而是5%的概率。
        direction += (Math.random() - 0.5) /5;
    }    
    // 根据飞机朝向和速度更新位置。
    point.coordinates[0] += speed * Math.sin(direction) / 100;
    point.coordinates[1] += speed * Math.cos(direction) / 100;
    // 校正飞机的朝向显示。因为默认情况下mapbox是根据你的视角随时调整图标方向。但实际上飞机图标的朝向必须和飞机运行方向一致,而不是简单的和标注一样。
    current_rotate = (-current_rotate) + direction * (180 / Math.PI);
}

The following is the calculation process of the bullet flight.

// start: fire location, target: bullet destination, duration: total animation time
function renderBulvar(start, target, direction, duration) {
    // target is geojson POINT, add Temp point in layer.. 
    var interval = 20, ratio = interval/duration, real_point = start, range = 0.4, count = 0, hitted = false;
    if (target.coordinates) {
        var targetSource = map.getSource('drone-target');
        window.setInterval(function(){
            if (count > duration/interval) { // 到达终点,不计算了
            } else {
                // 子弹每一帧跑一定比例的路程,最终到达指定终点
                real_point.coordinates[0] += Math.sin(direction)*ratio*range;
                real_point.coordinates[1] += Math.cos(direction)*ratio*range;
                targetSource.setData(real_point);
                if (!hitted){
                    hitted = testCrash(real_point.coordinates); // 感觉这里的hitted 有问题.
                }
                count += 1;
            }
        }, interval);
    }

到这里其实基本介绍了这个游戏的制作过程,经历了一些不成熟的想法,总共花了近十个小时完成目前的开发。还没有严谨地考虑过代码结构和 函数复杂程序,特别是子弹飞行和碰撞等部分,碰撞到后就终结子弹飞行等等。各位如果感兴趣,愿意完成 To DO list中的事情或者有何建议,请访问git仓库: Jqmap2 。请各位大神多提修改意见!

喜欢的同学请关注、收藏相关专题,会不断更新文章。希望和大家分享!!

【相关推荐】

1. 特别推荐“php程序员工具箱”V0.1版本下载

2. 免费h5在线视频教程

3. php.cn原创html5视频教程

The above is the detailed content of Detailed explanation of an example of implementing a simple multiplayer airplane game in html5. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn