Рубрики
Без рубрики

Создание приложения TIC-TAC-TOE с реактивным нативным и толкателем

В этом уроке мы будем реализовывать классическую игру Tic-Tac-Tac-носок с реактивным родным и толкателем.

Автор оригинала: Wern Ancheta.

В этом уроке мы будем реализовывать классическую игру Tic-Tac-Tac-носок с реактивным родным и толкателем. В этом руководстве предполагается, что у вас уже есть базовые знания оригинального родного.

Предпосылки

  • Учетная учетная запись – Нужна учетная запись PUSHER для создания экземпляра топирования, который мы будем использовать в этом руководстве. Если у вас еще нет аккаунта, вы можете Зарегистрируйтесь здесь Отказ После создания учетной записи вы можете пойти дальше и создать новое приложение Pusher.

  • Android SDK – Мы будем конкретно развертывать приложение в качестве приложения для Android, поэтому вам нужен Android SDK для запуска приложения на устройстве или эмуляторе Android.

  • Машина, которая готова к реагированию нативного развития – Если у вас еще нет ваша машина для реагирования на родных, вы можете следовать за Начало работы Руководство на официальных документах. Обязательно следуйте инструкциям в вкладке «Строительные проекты с нативным кодом».

  • Генимот или эмулятор Android – Это необязательно, так как вы всегда можете использовать настоящее устройство для тестирования.

Что мы собираемся построить

Вот что приложение будет выглядеть по умолчанию:

На главном экране Tic Tic Tac Tac

Когда пользователь решил создать комнату, идентификатор комнаты будет сгенерирован приложением. Идентификатор этого номера должен быть введен другим пользователем, поэтому игра может начать. На протяжении всего этого учебника я буду ссылаться на пользователя, кроме текущего пользователя, как «соперник».

Номер комнаты

Как только кто-то присоединился к комнате, будет показан доска Tic-Tac-Toe. На данный момент любой из игроков может начать первый ход.

Игра начинается

После того, как последний шаг используется для заполнения доски, будет отображаться предупреждение в Comment Creator, спрашивая, хотят ли они перезапустить игру (опустошить доску и запускать) или завершить игру. Если создатель комнаты решил закончить игру, состояние приложения будет сброшено, а экран по умолчанию будет показан.

Игра закончена

Вы можете найти полный исходный код приложения в его Github Repo Отказ

Кодирование компонента сервера

Компонент сервера аутентифицирует запросы, которые будут приходить из приложения. Это необходимо, потому что мы будем использовать События клиента отправлять данные от клиента клиенту. Компонент сервера аутентифицирует запрос всякий раз, когда приложение пытается подключиться с использованием ключа API приложенного вами созданного ранее. Таким образом, вы можете проверить, был ли запрос действительно пришел из вашего приложения.

Начните с помощью инициализации Package.json файл:

npm init

Установите зависимости:

npm install --save express body-parser pusher dotenv

Создать .env Файл в той же папке, что и Package.json Файл и добавьте детали приложения PUSHER:

APP_ID="YOUR PUSHER APP ID"
APP_KEY="YOUR PUSHER APP KEY"
APP_SECRET="YOUR PUSHER APP SECRET"
APP_CLUSTER="YOUR PUSHER APP CLUSTER"

Создать server.js Файл и добавьте следующий код:

var express = require('express'); // for running a server
var bodyParser = require('body-parser'); // for processing JSON submitted in the request body
var Pusher = require('pusher'); // for connecting to Pusher

require('dotenv').config();

var app = express();
app.use(bodyParser.json()); // for parsing JSON strings passed in the request body
app.use(bodyParser.urlencoded({ extended: false })); // for parsing URL encoded request body

var pusher = new Pusher({ // connect to pusher
  appId: process.env.APP_ID, // load the Pusher app settings from the .env file
  key: process.env.APP_KEY, 
  secret:  process.env.APP_SECRET,
  cluster: process.env.APP_CLUSTER, 
});

app.get('/', function(req, res){ // for testing if the server is running
  res.send('everything is good...');
});

app.post('/pusher/auth', function(req, res) { // authenticate user's who's trying to connect
  var socketId = req.body.socket_id;
  var channel = req.body.channel_name;
  var auth = pusher.authenticate(socketId, channel);
  res.send(auth);
});

var port = process.env.PORT || 5000;
app.listen(port);

Вот что делает код выше:

  • Линия 1 Импорт [Express] (https://expressjs.com/) , веб-каркас для Node.js, которая позволяет нам создавать сервер и отвечать на определенные маршруты.

  • Линия 2 Импорт Тело-парсер , промежуточное программное обеспечение для анализа тела запроса, так что данные, передаваемые в тело запроса, могут быть доступны как объект. Например, в /pusher/auth Маршрут, это позволяет сделать следующее для доступа к идентификатору сокета из тела запроса: req.body.socket_id Отказ

  • Линия 3 Импортирует толкатель упаковка. Это позволяет нам взаимодействовать с приложением Pusher, которое вы создали ранее, чтобы аутентифицировать пользователя (строку 25).

  • Линия 5 Импортирует Доценв Пакет, который загружает конфигурацию в .env файл, который вы создали ранее. Вы можете видеть их доступ к в качестве переменных среды на линиях от 12 до 15.

  • Строки 7 до 9 Рассказывает экспресс использовать Тело-парсер Чтобы создать два разных завода промежуточного программного обеспечения, один для разборки строк JSON, а другой для разборки URL-кодированных строк. Расширенные Опция установлена на ложь Поскольку мы не очень ожидаем, что насыщенные объекты и массивы будут включены в тело запроса. Вместо этого мы только ожидаем пропущенные строки JSON в тело запроса.

  • Линии от 18 до 20 Для тестирования, если сервер работает, вы можете получить доступ к http://localhost: 5000 из вашего браузера. Если вы видите, что вывод строки «Все хорошо …», то он работает.

  • Строки 22 до 27 Для обработки запросов аутентификации, исходящие из приложения. Запрос аутентификации отправляется каждый раз, когда клиент подключается к Pusher от приложения, которую мы будем создавать. Обратите внимание, что код для аутентификации пользователей на самом деле не имеет никаких мер безопасности. Это означает, что кто-либо может просто использовать свое приложение Pusher, если они получают удержание ваших учетных данных приложений Pusher.

Кодирование приложения

Теперь мы готовы добавить код для приложения. Первый загрузчик новое нативное приложение raction:

react-native init RNPusherTicTacToe

Как только это будет сделано, вы теперь можете установить зависимости:

npm install --save lodash.range pusher-js react-native-prompt shortid react-native-spinkit@latest

Из этих зависимостей React Nature Spinkit имеет некоторые активы, которые должны быть связаны, поэтому выполните следующую команду, чтобы связать те:

react-native link

Вот как установлены пакеты, которые вы только что установили, используются в приложении:

  • PUSHER-JS – для использования толкателя. Это позволяет нам отправлять сообщения на каналы и получать сообщения из каналов в режиме реального времени.
  • Реагистративно-подсказка – Для отображения подсказки используется для получения пользовательского ввода.
  • React-Native-Spinkit – Чтобы показать спиннер, ожидая другого игрока, чтобы присоединиться к комнате.
  • lodash.range – для генерации массивов, которые имеют определенное количество предметов.
  • Подробнее – Для создания уникальных идентификаторов при создании комнаты.

Теперь мы готовы добавить код для приложения. Во-первых, откройте index.android.js Файл и замените код по умолчанию следующим образом:

import React, { Component } from 'react';
import {
  AppRegistry
} from 'react-native';

import Main from './components/Main';

export default class RNPusherTicTacToe extends Component {
  
  render() {
    return (
      
); } } AppRegistry.registerComponent('RNPusherTicTacToe', () => RNPusherTicTacToe);

Убедитесь, что Rnpushertictacteke Соответствует названию, которое вы дали приложению, когда вы создали его с помощью React - родной init Отказ

Далее создайте Компоненты/Main.js Файл и добавьте следующее:

import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  Button,
  Alert
} from 'react-native';

// include the dependencies
import Pusher from 'pusher-js/react-native';
import shortid  from 'shortid';
import Spinner from 'react-native-spinkit';

// include the components
import Header from './Header'; 
import Home from './Home'; // the default screen
import Board from './Board'; // the tic-tac-toe board and score UI

Внутри конструктора инициализируйте состояние и функции, которые будут использоваться по всему компоненту:

export default class Main extends Component {

  constructor() {
    super();
    this.state = {
      username: '', // the name of the user
      piece: '', // the piece assigned to the user
      rival_username: '', // the name of the rival player
      is_playing: false, // whether the user is currently playing or not 
      show_prompt: false, // whether the prompt box for entering the room name is visible
      is_waiting: false, // whether the user is currently waiting for another player (rival) or not
      is_room_creator: false // whether the user is the room's creator
    }
  
    this.game_channel = null; // the Pusher channel where data regarding the game will be sent
    this.is_channel_binded = false; // whether a channel has already been binded or not
  
    this.onChangeUsername = this.onChangeUsername.bind(this); // executes when the value of the username text field changes
    this.onPressCreateRoom = this.onPressCreateRoom.bind(this); // executes when user creates a room
    this.onPressJoinRoom = this.onPressJoinRoom.bind(this); // executes when user taps on the join room button
    this.joinRoom = this.joinRoom.bind(this); // the function for joining a room
    this.onCancelJoinRoom = this.onCancelJoinRoom.bind(this); // executes when user cancels joining a room
    this.endGame = this.endGame.bind(this); // the function for ending the game

  }
}

Перед установленным компонентом подключитесь к тошеру с помощью учетных данных, которые вам дали, когда вы создали приложение PUSHER:

componentWillMount() {
  this.pusher = new Pusher('YOUR PUSHER API KEY', {
    authEndpoint: 'YOUR AUTH ENDPOINT',
    cluster: 'YOUR PUSHER APP CLUSTER',
    encrypted: true
  });
}

Когда компонент обновляется, нам нужно проверить, уже ожидает, что пользователь уже ждет соперника и что канал толкателя еще не связан ни на какие события. Если это так, мы слушаем Клиент, присоединенный к мероприятие. Когда это произойдет, обновите состояние, чтобы пользовательский интерфейс показывает игровую доску. Если пользователь является создателем комнаты, срабатывайте одинаковое событие, чтобы соперник (тот, кто присоединился к комнате), сообщается, что игра уже может начать.

componentDidUpdate() {
  if(this.state.is_waiting && !this.is_channel_binded){
    
    this.game_channel.bind('client-joined', (data) => {
      this.setState({
        is_waiting: false,
        is_playing: true,
        rival_username: data.username
      });

      if(this.state.is_room_creator){
        // inform the one who joined the room that the game can begin
        this.game_channel.trigger('client-joined', {
          username: this.state.username // send the name of the room creator to the one who joined
        });
      }
    });

    this.is_channel_binded = true;
  }
}

В оказывать Метод, Главная Компонент отображается по умолчанию. Он отображает пользовательский интерфейс, чтобы позволить пользователю ввести их имя и присоединиться или создать новую комнату. Как только соперник присоединяется к комнате, игровая доска будет показана. Спиннер Компонент используется в качестве состояния перехода между двумя в ожидании того, чтобы соперник присоединиться к комнате.

render() {
  return (
    
      
{ !this.state.is_playing && !this.state.is_waiting && } { this.state.is_playing && }
); }

Вот функция, которая выполняется, когда текстовое поле для ввода имени пользователя меняется:

onChangeUsername(username) {
  this.setState({username});
}

Когда пользователь нажал на Создать комнату Кнопка, генерируйте уникальный идентификатор для комнаты и подпишитесь на новый канал толкателя, используя этот идентификатор. Здесь мы используем Частный канал Так что мы можем отправлять сообщения прямо из приложения:

onPressCreateRoom() {
 
  let room_id = shortid.generate(); // generate a unique ID for the room
  this.game_channel = this.pusher.subscribe('private-' + room_id); // subscribe to a channel
  
  // alert the user of the ID that the friend needs to enter 
  Alert.alert(
    'Share this room ID to your friend',
    room_id,
    [
      {text: 'Done'},
    ],
    { cancelable: false }
  );

  // show loading state while waiting for someone to join the room
  this.setState({
    piece: 'X', // room creator is always X
    is_waiting: true,
    is_room_creator: true
  });

}

Когда конкурентные краны на Присоединяйтесь к комнате Кнопка, окно приглашения отображается:

onPressJoinRoom() {
  this.setState({
    show_prompt: true
  });
}

После того, как соперник присоединяется к комнате, выполняется следующая функция. Room_id Предоставляется окном приглашения, поэтому мы просто используем его, чтобы подписаться на тот же канал, что и для создателя комнаты. Это позволяет двум пользователям взаимодействовать напрямую использовать этот канал. Обратите внимание, что код ниже не обрабатывается, если присоединиться к комнате третьего человека. Вы можете добавить функциональность для проверки количества пользователей в комнате, если хотите. Таким образом, приложение отклонит его, если в комнате уже есть два пользователя.

joinRoom(room_id) {
  this.game_channel = this.pusher.subscribe('private-' + room_id);
  // inform the room creator that a rival has joined
  this.game_channel.trigger('client-joined', {
    username: this.state.username
  });
  
  this.setState({
    piece: 'O', // the one who joins the room is always O
    show_prompt: false,
    is_waiting: true // wait for the room creator to confirm
  });
}

Когда пользователь отменяет присоединение к комнате, просто скрыть окно приглашения:

onCancelJoinRoom() {
  this.setState({
    show_prompt: false
  });
}

Когда создатель комнаты решает завершить игру, приложение обратно обратно в состояние по умолчанию:

endGame() {
  // reset to the default state
  this.setState({
    username: '',
    piece: '',
    rival_username: '',
    is_playing: false,
    show_prompt: false,
    is_waiting: false,
    is_room_creator: false
  });
  // reset the game channel
  this.game_channel = null;
  this.is_channel_binded = false;
}

Наконец, добавьте стили:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#F5FCFF',
  },
  spinner: {
    flex: 1,
    alignSelf: 'center',
    marginTop: 20,
    marginBottom: 50
  }
});

Далее – Заголовок составная часть. Создать Компоненты/header.js Файл и добавьте следующее:

import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class Header extends Component {

  render() {
    return (
      
        {this.props.title}
      
    );
  }

}

const styles = StyleSheet.create({
  title_container: {
    flex: 1,
  },
  title: {
    alignSelf: 'center',
    fontWeight: 'bold',
    fontSize: 30
  }
});

Все этот компонент делает это отображение заголовка приложения в заголовке.

Далее создайте Компоненты/home.js файл. Как упоминалось ранее, это компонент по умолчанию, который отображается в первый раз, когда пользователь открывает приложение или когда создатель комнаты заканчивается игрой.

import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  TextInput,
  Button
} from 'react-native';

import Prompt from 'react-native-prompt';

export default class Home extends Component {

  render() {

    return (        
      
        
          
        

        
          
          
        

        
      
    );
  }
}

const styles = StyleSheet.create({
  content_container: {
    flex: 1
  },
  input_container: {
    marginBottom: 20
  },
  button_container: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    alignItems: 'center'
  },
  text_input: {
    backgroundColor: '#FFF',
    height: 40,
    borderColor: '#CCC', 
    borderWidth: 1
  },
  button: {
    flex: 1
  }
});

Далее создайте Компоненты/Board.js файл. Этот компонент служит главным мясом приложения, потому что это там, где происходит игра.

Во-первых, включите компоненты и пакеты, которые нам понадобится:

import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  TextInput,
  Button,
  TouchableHighlight,
  Alert
} from 'react-native';

import range from 'lodash.range'; 

В конструкторе свяжите методы для создания контента для доски (доска 3×3). Возможные комбинации для получения оценки также объявлены. IDS используются в качестве идентификаторов для ссылки на отдельные блоки. Как видите, это массив, который имеет в ней три массива. Каждая из этих массивов относится к рядам в доске, и его предметы относятся к отдельным блокам. Поэтому при обращении к второму столбцу в первой строке доски вы можете получить идентификатор для этого, используя Это. [0] [1] Отказ Это тогда вернется 1 Отказ Идентификатор будет использоваться позже, чтобы определить оценки на основе Возможные_combinations множество.

export default class Board extends Component {

  constructor() {
    super();
    this.generateRows = this.generateRows.bind(this); // bind the method for generating the rows for the board
    this.generateBlocks = this.generateBlocks.bind(this); // bind the method for generating individual blocks for each row
    
    // the possible combinations for getting a score in a 3x3 tic-tac-toe board 
    this.possible_combinations = [
      [0, 3, 6],
      [1, 4, 7],
      [0, 1, 2],
      [3, 4, 5],
      [2, 5, 8],
      [6, 7, 8],
      [0, 4, 8],
      [2, 4, 6]
    ];
    
    // the IDs of the individual blocks
    this.ids = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8]
    ];
    
    // the individual rows
    this.rows = [
      range(3).fill(''), // make an array with 3 elements and set each item to an empty string
      range(3).fill(''),
      range(3).fill('')
    ];

    this.state = {
      moves: range(9).fill(''), // the pieces (X or O) used on each block
      x_score: 0, // score of the room creator
      o_score: 0 // score of the rival
    }

}

Прямо под объявлением для Это Является ли массив, который будет использоваться для генерации строк в доске.

Как только компонент установлен, мы тогда хотим слушать Client-Make-Move событие произошло. Это событие срабатывает каждый раз, когда пользователь помещает их кусок (либо «X», либо «O») на плате. Обратите внимание, что это будет запущено только на соперниках, а не пользователю, который отправил мероприятие.

componentDidMount() {
  this.props.channel.bind('client-make-move', (data) => {
    let moves = this.state.moves;
    let id = this.ids[data.row_index][data.index]; // get the ID based on the row index and block index
    moves[id] = data.piece; // set the piece
    
    // update the UI
    this.setState({
      moves
    });
    
    this.updateScores.call(this, moves); // update the user scores
  });
}

Каждый раз сделан движение, UpdateScores Функция выполняется. Это петли через все возможные комбинации. Он использует каждый () Метод проверки, использовался ли удельный кусок на каждом из предметов для возможной комбинации. Например, если «X» используется для блоков 0, 1 и 2, то 1 точка награждается пользователю, у которого есть «X» как их кусок.

updateScores(moves) {

  var pieces = {
    'X': 0,
    'O': 0
  }

  function isInArray(moves, piece, element, index, array){
    return moves[element] && moves[element] == piece; // check if there's a piece assigned to a specific block and that piece is the piece we're looking for (either "X" or "O")
  }

  this.possible_combinations.forEach((p_row) => {
    if(p_row.every(isInArray.bind(null, moves, 'X'))){
      pieces['X'] += 1;
    }else if(p_row.every(isInArray.bind(null, moves, 'O'))){
      pieces['O'] += 1;
    }
  });

  this.setState({
    x_score: pieces['X'],
    o_score: pieces['O']
  });
        
}

Вот …| Render () метод. Он использует nechanterwows () Способ генерирования контента для доски. Ниже приведен дисплей баллов для двух пользователей.

render() {
  return (
    
      
      {this.generateRows()}
      
    
      
        
          {this.state.x_score}
          {this.props.username} (x)
        
    
        
          {this.state.o_score}
          {this.props.rival_username} (o)
        
      
    
  );
}

Вот …| nechanterwows () Метод:

generateRows() {
  return this.rows.map((row, index) => {
    return (
      
        {this.generateBlocks(row, index)}
      
    );
  });
}

GenerateBlocks () Метод используется для генерации отдельных блоков на каждой строке. Он использует Touchablehighlight Компонент для создания представления, который может быть подключен пользователем. Каждый блок отображает часть пользователя, который сначала постучал на него. Нажатие на блок выполняет OnMakemove () Метод, который помещает кусок пользователя на этот блок.

generateBlocks(row, row_index) {
  return row.map((block, index) => {
    let id = this.ids[row_index][index];
    return (
      
          
          {this.state.moves[id]}
          
              
    );
  });
}

OnMakemove () Метод получает ROW_INDEX и блок индекс Отказ Они позволяют нам получить блок ID который используется для установки части на определенный блок. После этого UpdateScores () Также называется обновление результатов пользователей. Чтобы обновить UI соперника, детали движения отправляются с помощью Client-Make-Move мероприятие.

onMakeMove(row_index, index) {
  let moves = this.state.moves;
  let id = this.ids[row_index][index];

  if(!moves[id]){ // nobody has occupied the space yet
    moves[id] = this.props.piece;
    this.setState({
      moves
    });

    this.updateScores.call(this, moves);
    
    // inform the rival that a move is made
    this.props.channel.trigger('client-make-move', {
      row_index: row_index,
      index: index,
      piece: this.props.piece
    });   
  }
}

После того, как доска была заполнена кусочками, спросите комнату создателя, если они хотят перезапустить или завершить игру. Если создатель комнаты решает перезапустить игру, что доска просто сбрасывается в состояние по умолчанию, в противном случае приложение сбрасывается в состояние по умолчанию (так же, как когда приложение впервые открывается).

if(this.props.is_room_creator && moves.indexOf('') == -1){
  Alert.alert(
    "Restart Game", 
    "Do you want to restart the game?",
    [
      {
        text: "Nope. Let's call it quits.", 
        onPress: () => {
          this.setState({
            moves: range(9).fill(''),
            x_score: 0,
            o_score: 0
          });
          this.props.endGame();
        },
        style: 'cancel'
      },
      {
        text: 'Heck yeah!', 
        onPress: () => {
          this.setState({
            moves: range(9).fill(''),
            x_score: 0,
            o_score: 0
          });
        }  
      },
    ],
    { cancelable: false } 
  );
}

Наконец, добавьте стили:

const styles = StyleSheet.create({
  board_container: {
    flex: 9
  },
  board: {
    flex: 7,
    flexDirection: 'column'
  },
  row: {
    flex: 1,
    flexDirection: 'row',
    borderBottomWidth: 1,
  },
  block: {
    flex: 1,
    borderRightWidth: 1,
    borderColor: '#000',
    alignItems: 'center',
    justifyContent: 'center'
  },
  block_text: {
    fontSize: 30,
    fontWeight: 'bold'
  },
  scores_container: {
    flex: 2,
    flexDirection: 'row',
    alignItems: 'center'
  },
  score: {
    flex: 1,
    alignItems: 'center'
  },
  user_score: {
    fontSize: 25,
    fontWeight: 'bold'
  },
  username: {
    fontSize: 20
  }
});

Тестирование приложения

Теперь, когда вы построили приложение, сейчас время попробовать его. Первое, что вам нужно сделать, это запустить сервер:

node server.js

Вы можете запустить приложение со следующей командой:

react-native run-android

Убедитесь, что у вас уже есть подключенное устройство или эмулятор, открытый при выполнении этого.

Если вы используете Wenymotion или эмулятор Android, и вы не хотите тестировать на реальном устройстве, вы можете использовать браузер для имитации соперника.

Как только это сделано, запустите приложение и создайте новую комнату. Затем скопируйте идентификатор комнаты, показанного в поле оповещения.

Далее перейдите на приборную панель приложения Pusher и нажмите на Отладка консоли вкладка Нажмите на Показать Создатель событий и введите Частный номер_Ид для Канал Отказ Обязательно замените Room_id с фактическим идентификатором комнаты, затем установить Клиент, присоединенный к как ценность Мероприятие. Значение для Данные является:

{
  "username": "doraemon"
}

Используйте скриншот ниже в качестве ссылки:

Тестовые события от отладочной консоли

Как только это сделано, нажмите на Отправить событие кнопка. Это должно вызвать приложение для изменения своего UI на фактическую игровую доску. Чтобы вызвать некоторые ходы, установите Событие Имя на Client-Make-Move Затем добавьте детали перемещения на Данные поле:

{
  "row_index": 0,
  "index": 0,
  "piece": "O"
}

Это поместит штуку «O» на первом поле в игровой доске.

Оттуда вы можете разместить другое значение для индекс и ROW_INDEX Эмулировать игру игры.

Развертывание сервера

Метод, который я показал вам выше, отлично, если вы хотите только тестировать в свою местную сеть. Но что, если вы хотите проверить его с друзьями за пределами сети? Для этого вы могли бы использовать Сейчас Отказ Я не собираюсь вспомнить детали о том, как развернуть сервер, но вы можете проверить их Документы Отказ Сейчас Свободно использовать, единственный недостаток в том, что ваш код будет доступен публично.

Заключение

Это оно! В этом руководстве вы узнали, как повторно создать TIC-TAC-TAC, используя толкатель. Как вы видели, Pusher действительно позволяет легко реализовать функции в реальном времени в играх. В то время как Tic-Tac-Toe – очень простая игра, это не означает, что толкатель может использоваться только в простых играх. Вы можете в значительной степени использовать Pusher в любой игре в режиме реального времени, о которой вы можете подумать.

Первоначально опубликовано на Душерный блог .