preface

Always wanted to do an online game, before also use socket. IO to do a few demo, but don’t know at that time in the frame synchronization, so when I am with all players by data (location, blood), and shot all of the data is forwarded to all players (except yourself), then other players by judging whether to have this data, If it doesn’t, it generates one, and if it does, it overwrites.

But this approach above super card, matchless card, abnormal card, forced, baidu how to do online games.

On the network, there are two ways to do online games, one is state synchronization, the other is frame synchronization.

Here is a brief introduction to the difference between the two methods, but it is not much to say. (Because I still know a little about it.)

The most important aspect of online gaming is that all clients display uniformly.

State synchronization

In this case, the server takes care of all the calculations and returns the same data to all the players, who use this data to render the game interface. (This method is similar to what I did before = =)

This is safe because all the data is on the server, and no matter how much the client changes the data, it still executes the data on the server.

Frame synchronization

This is the focus of this article, how to search baidu did not see js/node/socket. IO online tutorial, so only their own hard to learn (blind writing).

The way I’m doing frame synchronization right now is that the actions sent by the client are not processed locally, but are uploaded to the server and the server saves all the player actions and sends them to all the clients at a fixed time. The client then processes these operations at a fixed frequency to achieve a synchronous effect.

And the frame sync saves the player’s actions, so it’s easy to replay and watch.

So let me just briefly explain the two demos that we did. (Code is too bad, can learn ideas, but can’t copy, will die.)

Demo1 – Ball drawing

This demo mainly realizes the midway to join the game players can see the players already in the game, game playback, all players operation unified.

Demo2 – Ball ball battle

This is mainly to implement a whole room system, create private room, join room, room list, kick out of room. The game just wrote a move.

I also made a simple chat room with two channels, one world channel (for all to see) and one room channel (for all to see within the room).

Train of thought

In this case, I parse the actions sent to both sides using the front and back action.js:

Server:

const actions = {
  // Player adds action to the game
  'player.add': (player, package) = >{},// Create a room
  'room.create': (player, package) = >{},// Join the room
  'room.add': (player, package) = >{},// Leave the room
  'room.leave': (player, package) = >{},// Kick out of the room
  'room.shit': (player, package) = >{},// Room list
  'room.list': (player, package) = >{},// Prepare the game in the room
  'room.ready': (player, package) = >{},// Create a game
  'game.create': (player, package) = >{},// The action of the game
  'game.action': (player, package) = >{},// System information distribution
  'message': (player, package) = >{}}// Process the packet
module.exports = function (data) {
  if(! data.action) {console.warn('Unprocessed packets', data);
    return;
  }
  let action = actions[data.action];
  if(! action) {console.warn('Unprocessed action:' + data.action);
    return;
  }
  actions[data.action](this, data);
}

Emit ('all'), emit('all'), emit('all'), emit('all'), emit('all'
this.socket.on('all', data => {
  action.call(this, data)
});
Copy the code

The front end then sends the packet like this:

on(name, fn) {
  if (!this.io) {
    console.error('not connect socket server.');
    return;
  }
  this.io.on(name, fn);
},
emit(name, data) {
  if (!this.io) {
    console.error('not connect socket server.');
    return;
  }
  this.io.emit(name, data);
},
// Send the packet here
action(name, data) {
  this.emit('all', {
    data,
    action: name,
    time: new Date().getTime()
  });
},
Copy the code

The client also has an action to parse the packet sent by the backend, so I won’t paste the code here (it’s the same)

Now let’s talk about what the player does in the game

The way I’m doing it right now is that the server sends all the player actions it receives to all the clients at a fixed frequency.

class G{
  constructor(room){
    this.room = room;
    // This is to save all actions of the entire game
    this.frames = [];
    // This saves the client action for each frame
    this.actions = {};
    // The frequency, that is, the frame, is sent in each frame to save all the actions of the client
    this.packageNum = global.option.gameFrame;
    this.interval = null;

    this.start();
  }

  start(){
    this.interval = setInterval((a)= > {
      // Send the actions of all players in the room to everyone in the room
      global.Core.socket.emit('game.action'.this.actions, null.this.room.key);
      // Save the action of this frame, and you can use it to make a replay later.
      this.frames.push(this.actions);
      // Clear the operation
      this.room.playerList.forEach(item= > {
        this.actions[item.id] = [];
      });
    }, 1000 / this.packageNum); }}Copy the code

The client can then parse game.action by:

// action.js
'game.action': package= > {
    game.complite(package.data);
},

// game.js
complite(action) {
    // Give the action to the player's instance
    Object.keys(action).forEach(key= > {
      action[key].forEach(ac= > {
        this.playerList[key].action(ac); })});// When the action frame is received from the back end, each player instance will move, so that all clients can display the same
    Object.keys(this.playerList).forEach(key= > {
      this.playerList[key].move(); })}Copy the code

The client sending game action looks like this:

// This code is so simple = = that I am too lazy to comment 2333.
let prev = null;

function action(key, flag) {
  let action = key + (flag ? '_up' : ' ');
  if (action == prev) return;
  app.action('game.action', {
    action
  });
  prev = action;
}

let event = {
  '0'(flag) {
    action('left', flag);
  },
  '1'(flag) {
    action('top', flag);
  },
  '2'(flag) {
    action('right', flag);
  },
  '3'(flag) {
    action('bottom', flag);
  },
  '- 5'(flag){
    action('speed', flag); }}document.body.onkeydown = ev= > {
  if (!this.playStatus) return;
  let code = ev.keyCode - 37;
  event[code] && event[code]();
}
document.body.onkeyup = ev= > {
  if (!this.playStatus) return;
  let code = ev.keyCode - 37;
  event[code] && event[code](true);
}
Copy the code

The game play

If a player needs to see a replay, he can accept the set and then iterate through all the actions = = (is that easy).

this.io.on('getGameLog', data => {
  this.logs = data;
  this.play();
})

play() {
  // Exit if you've seen all the actions
  if (this.playLog >= this.logs.length) {
    this.playStatus = false;
    return;
  }
  this.playStatus = true;
  let item = this.logs[this.playLog];
  game.complete(item);

  // Parse each frame
  this.playLog++;
  // Here is the play multiplier
  setTimeout(this.play.bind(this), 1000 / (20 * this.playX));
}
Copy the code

The code address

Yards cloud

The last

Because my writing style is limited, there may be misspelled words, train of thought is not clear content, but also please bear a lot = =(may not understand what I write is a ghost thing)

Also, is this idea may not be very good… Because this is my own thinking, there will be a lot of problems, here as a brick to draw jade.

Scatter flowers, in the first article of the Nuggets ~