Дмитрий
Дмитрий
Developer Python, PHP, Javascript
23.08.2019

Создание карточной игры Blackjack

Дмитрий
Дмитрий
Developer Python, PHP, Javascript
23.08.2019
23.08.2019
5.0
6870
25 минут
0

Задача заключается в создании многопользовательской карточной онлайн-игры в «очко», где игрокам поочередно предлагается брать карты. Выигрывает тот, кто набрал больше очков но не более чем 21. При выигрыше, сумма ставки прибавляется к счету игрока, который победил и отнимается у того, кто проиграл.

Наше приложение будет состоять из 2-х частей: серверной и клиентской. Создадим каркас приложения ангуляр для клиентской части. Для этого воспользуемся библиотекой командной строки angular-cli, которую желательно установить глобально в систему.

sudo npm install -g @angular/cli

Итак, создаем приложение следующим образом:

ng new client

При установке соглашаемся на использование роутинга, он нам пригодится. После чего получим каталог client с необходимой структурой папок. Нас больше всего будет интересовать каталог src/app, в котором и будет код нашего приложения. Игра будет содержать три роутинга и соответственно – три страницы и привязанных к ним компонента.

  1. Страница с формой авторизации.
  2. Страница со списком пользователей онлайн.
  3. Станица комнаты с игрой между двумя пользователями.

Поэтому создадим эти три компонента следующими командами:

ng g c login;
ng g c online;
ng g c room.

Вот так должен выглядеть результат, при котором создались 3 одноименных каталога с компонентами, которые также были включены в корневой модуль app.module.ts, о чем свидетельствует строка:

UPDATE src/app/app.module.ts

Если мы откроем этот файл, то заметим что в него добавился импорт каждого компонента и включен в секцию декларации.

import { LoginComponent } from './login/login.component';
import { OnlineComponent } from './online/online.component';
import { RoomComponent } from './room/room.component';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    OnlineComponent,
    RoomComponent
  ],

Привяжем эти компоненты к маршрутизатору, создав 3 маршрута (на самом деле их 4 но один используется для редиректа).

import { LoginComponent } from './login/login.component';
import { OnlineComponent } from './online/online.component';
import { RoomComponent } from './room/room.component';
 
const routes: Routes = [
  {
    path: '',
    redirectTo: 'login',
    pathMatch: 'full'
  },
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: 'online',
    component: OnlineComponent
  },
  {
    path: 'room/:uuid',
    component: RoomComponent
  }
];

В первом роутинге мы делаем редирект на форму авторизации (LoginComponent) на главной странице. Т.е. теперь, когда мы запустим сервер разработки командой:

ng serve

Потом, когда перейдем по адресу http://localhost:4200 нас автоматически перебросит на адрес http://localhost:4200/login и мы увидим такую картину:

В последнем роутинге мы определили переменную :uuid при указании шаблона пути, эта переменная будет изменятся и содержать уникальный идентификатор игровой комнаты.

Теперь осталось открыть шаблон корневого компонента app.component.html, убрать все лишнее от приветствия и вставить ссылки на каждый роут вот так:

Принято использовать специальную директиву [routerLink] для указания пути роутинга. Вместо параметра :uuid в роутинге игровой комнаты мы пока вставим тестовое значение room_id. В теге router-outlet будет выводится содержимое шаблонов компонентов, соответствующих пути роута.

Вот что должно получится:

Теперь предлагаю оформить интерфейс в лучших традициях bootstrap и подключить библиотеку ngx-bootstrap такой командой:

ng add ngx-bootstrap

Далее необходимо перезагрузить сервер разработки и применить в шаблоне разметку bootstrap.

Вот что у нас получилось:

Создадим форму для логина в шаблоне login/login.component.html.

Теперь необходимо привязать сабмит формы к методу компонента. Для этого откроем код компонента login/login.component.ts и добавим переменную с логином и метод.

export class LoginComponent implements OnInit {
 
  login: string;
  constructor() { }
 
  ngOnInit() {
  }
 
  doLogin(){
    console.log(this.login);
  }

}

Для проверки в методе doLogin мы выводим в консоль значение переменной login, объявленной в классе перед конструктором.

Эта переменная будет связана со значением поля input в шаблоне следующим образом:

Обратите внимание на обязательное присутствие атрибута name в теге input. Однако, для связывание переменной login директивой [(ngModel)] необходимо подключить модуль FormsModule в корневом модуле, иначе вы увидите следующую ошибку в консоле браузера:

Can't bind to 'ngModel' since it isn't a known property of 'input'.

Поэтому импортируем этот модуль и включим в секцию imports корневого модуля app.module.ts.

import from '@angular/forms';

@NgModule({

  imports: [
   ...
    FormsModule
  ],

Осталось вызвать метод doLogin при сабмите нашей формы.

Результат работы:

Теперь нам предстоит задействовать веб-сокеты и по ним передать логин пользователя на сервер. Мы будем использовать библиотеку socket.io, и для нее есть обертка под Ангуляр, устанавливаем.

npm i ngx-socket-io --save

Далее ее необходимо импортировать в корневом модуле приложения, сконфигурировать и добавить в секцию imports.

import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io';
const config: SocketIoConfig = { url: 'http://localhost:3000', options: {} };

@NgModule({

  imports: [
    ...
    SocketIoModule.forRoot(config)
  ],

Как видно, мы планируем запустить сокет-сервер на порту 3000 локальной машины.

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

А пока создадим такой сервис в новом файле socket.service.ts.

import { Injectable } from '@angular/core';
import { Socket } from 'ngx-socket-io';

@Injectable({
  providedIn: 'root'
})
export class SocketService {

  constructor(private socket: Socket) { }

  sockLogin(login: string) {
    console.log(`emmiting login $ to server`);
    this.socket.emit('LoginEvent', );
  }
}

Декоратором @Injectable мы делаем сервис способным к применению внутри компонентов. Функцией emit объекта socket мы передаем информацию на сервер.

Применим этот сервис в компоненте, пока просто импортировав его класс и добавив приватную переменную socket_service в конструктор класса компонента LoginComponent:

import { SocketService } from './../socket.service';
...
export class LoginComponent implements OnInit {

  constructor(private socket_service: SocketService) { }
  ...
}

После этого наш компонент попытается создать сокет-соединение с сервером, которого пока еще нет. Об этом будет свидетельствовать сообщение об ошибке в консоле.

Причем попытки соединится продолжаются не прекращаясь, это позволяет восстанавливать сокет-соединение при падении сервера.

Но несмотря на то, что рабочего сервера пока нет, все же реализуем отправку сообщения, вызвав метод sockLogin нашего сервиса из компонента LoginComponent, и передадим в нее переменную login.

doLogin(){
  this.socket_service.sockLogin(this.login);
}

Выводы

В этой статье рассмотрен процесс создания приложения Angular с использованием системы маршрутизации. Также описан процесс работы с компонентами, их шаблонами и сервисами на примере формы авторизации. Затронуто использование сокет-соединения на базе библиотеки ngx-socket-io.

В следующей статье будет рассмотрен процесс создания серверной части и взаимодействие его с клиентской.

Как вам статья?
5.0
Проголосовало: 3
Давайте обсудим Ваш проект
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее
Комментарии
(0)
Будьте первыми, кто оставит комментарий
wezom logo
Остались вопросы?
Оставьте ваши контактные данные. Наш менеджер свяжется и проконсультирует вас.
Подписывайтесь на рассылку Айтыжблог
blog subscriber decor image
Хотите получать интересные статьи?
Нажимая на кнопку “Отправить”, вы даете согласие на обработку личных данных. Подробнее
Следите за нами в социальных сетях
Этот сайт использует cookie-файлы для более комфортной работы пользователя. Продолжая просматривать сайт, Вы соглашаетесь на использование cookie.