Ajutor NodeJS & socket.io

Salutare! Inainte de toate , doresc sa va urez un calduros “La multi ani!” si un an nou plin de realizari si impliniri.
Sunt nou ( sa zicem BUT , ca sa fiu sincer inca de la inceput ) in ceea ce priveste NodeJS-ul si am cateva nelamuriri in ceea ce il priveste.

Concret : Doresc (sau mai bine spus nu stiu alta varianta) sa folosesc socket.io pentru a putea conecta mai multi utilizatori intre ei.

  • Am un array cu 24 elemente pe care am aplicat un shuffle ( pentru a le amesteca de fiecare data la inceputul scriptu-lui ) si am 3 neclaritati :
  • In momentul in care dai refresh , scriptul o ia de la 0 , asta insemnand ca imi amesteca din nou vectorul ( iar eu nu vreau asta , vreau sa nu se intample nimic in momentul in care e actionat butonul de refresh ).
  • Vreau ca 12 elemente din array [0-11] sa ii revina unuia dintre utilizatorii conectati , iar celelalte 12 elemente sa ii revina celuilalt utilizator conectat [12-23].
  • Aici probabil seamana mult cu cea de a 2-a nedumerire. Doresc sa obtin o vedere precum intalnim la un joc multi-player de sah ( Am pus o poza sa observati mai bine despre ce vorbesc ).

Va multumesc mult pentru timpul acordat si va rog sa ma scuzati de deranj. :slightly_smiling:

1 Like

Nu stiu exact cum sa rezolv problema (in cod, ma refer), dar stiu care ar fi principalele lucruri de facut:

In primul rand, nu e nevoie neaparata de socket.io, dar pare suficient de intuitiva pentru a o aplica usor. Ce ai nevoie, insa, este un socket cu care te conectezi la fiecare utilizator. Librarii alternative pentru socket-uri.

Serverul node-js are piesele albe si negre in acelasi tabel, nu? (tabel cu valorile 0, 1, 2, spre exemplu, sau null, true, false, daca vrei sa folosesti mai putina memorie, deci un table de bool, ori “gol”, “alb”, “negru”, daca vrei sa folosesti ceva usor de inteles.)

Asta inseamna ca va trebui sa trimiti, dupa fiecare pas, echipei 1 si echipei 2 listele cu pozitiile, dupa fiecare schimbare. Apoi trebuie sa astepti player-ul al carui rand este sa trimita o mutare valida. Serverul trebuie sa verifice validitatea datelor si sa le respinga (si sa astepte alta mutare) daca sunt invalide. Plater-ul trebuie sa verifice validitatea datelor, pentru a nu trimite date invalide.

Va trebui sa fi conectat la toti playerii, in acelasi timp, cu socket-uri, iar ordinea sa o mentii cu un array si pozitia in array sa o mentii cu o variabila. Variabila ar trebui sa fie index-ul array-ului. Spre exemplu, indexul poate sa fie de la 0 la 9, iar functia pasUrmator() ar trebui sa fie asa:

var turn = 0;
function pasUrmator(){
   var++;
   if( turn == 10 )
      turn = 0;
}

Nu uita sa verifici datele primite, pe server! Asta e diferenta dintre un joc care poate fi hack-uit usor si unul care poate fi hackuit mai greu.

1 Like

Ai nevoie sa realizezi un demo sau vrei sa faci un joc?

Ceea ce ai mentionat se poate realiza cu sesiuni, fara Socket.io.

'use strict'

const koa = require('koa')
const session = require('koa-generic-session')


// generate simple id
const genID = () => ('u' + Math.floor(Math.random()*900) + 100)


// game state
const state = {
  // store players by ID
  players: {},
  points: [1,2,3,4,5,6,7,8]
}


const html = (content) => (`
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>Demo</title>
</head>
<body>
  <div id="content">
    ${content}
  </div>
</body>
</html>
`)


const fmtPlayersView = (player_id) => {
  let view = Object.keys(state.players).map((id) => {
    let who = (id == player_id ? 'You' : 'Him')
    let points = state.players[id].points.map(point => `<b>${point}</b>`)

    return `<div>${who}: ${points}</div>`
  }).join('\n')

  return html(view)
}


// handle path: '/'
function index () {
  // check for player
  if (!this.session.player_id) {
    // check how many players connected
    if (Object.keys(state.players).length >= 2) {
      this.body = '2 players already connected'
    }
    else {
      let player_id = genID()
      let player = {
        // remove values from game state and add them to the player
        points: state.points.splice(0, 4)
      }

      // save player to state
      state.players[player_id] = player

      // set player id to session
      this.session.player_id = player_id

      // return values
      this.body = fmtPlayersView(player_id)
    }
  }
  else {
    let player_id = this.session.player_id

    this.body = fmtPlayersView(player_id)
  }
}


// handle path: '/disconnect'
function disconnect () {
  let player_id = this.session.player_id

  // player is connected
  if (player_id) {
    // put values back into game state
    state.points = state.points.concat(state.players[player_id].set)

    this.body = 'Player disconnected.'
  }
  // no player to disconnect
  else {
    this.redirect('/')
  }
}


// http://koajs.com/#application
const app = koa();

// app config
app.keys = ['1234', '4321']
app.use(session());

app.use(function * () {
  // simple path router
  switch (this.path) {
    case '/':
      index.call(this)
    break

    case '/disconnect':
      disconnect.call(this)
    break

    default:
      this.redirect('/')
  }
})

app.listen(9000)

Salveaza fisierul intr-un index.js apoi:

> npm install koa koa-generic-session
> node index.js

In browser: http://localhost:9000

2 Likes

Multumesc mult Sapioit si Navaru ! :slightly_smiling:
In principiu , as vrea sa fac un joc (dar numai asa , pentru consolidarea cunostintelor mele). Problema e ca , desi nu as avea probleme in realizarea lui (offline/single player) , m-au bagat in ceata total aceste conexiuni intre utilizatori si transmiterea de date intre ei. Ceea ce mi-ai dat tu , navaru ( si iti multumesc pentru timpul acordat ) arata bine , dar am cateva dubii ( nu spun ca e greseala ta , poate nu am verificat eu bine ) :

  • pare ca nu functioneaza shuffle-ul asa cum ar trebui , adica in loc sa afiseze valorile array[0],array[1],array[2],array[3] (care multumita shuffle-ului ar trebui sa fie diferite la fiecare initiere a scriptului. / ex 1,4,7,5 / 2 3 1 6 , etc ) , scriptul afiseaza valorile 1 , 2 , 3 , 4. ( oricum asta ma gandesc ca e ceva minor oricum )
  • dar ce ma framanta cu adevarat e faptul ca in momentul in care se conecteaza doi utilizatori , efectele acestui lucru devin vizibile doar dupa actionarea butonului de refresh ( ceea ce nu mi se pare o fluiditate prea buna ).

Cred ca totusi nu pot face ceea ce mi-am propus fara folosirea unui socket , probabil ar da rezultate mai bune ( doar imi dau si eu cu parerea ). Insa nu am gasit o documentatie prea buna in ceea ce priveste socket-urile si nu reusesc sa le inteleg principiul de functionare in totalitate ( principala resursa/principalul exemplu care impanzeste internetul , fiind acel chat , care iti lasa o gaura in ceea ce priveste intelegerea lor )

Probabil spun prostii , dar chiar daca o fac , o fac din necunostinta si nu din rautate. :slightly_smiling:

1 Like

Eu am prezentat un Proof Of Concept pt. sessions, nu neaparat un working demo, nu stiam ce vrei sa realizezi defapt. Socket.io e destul de simplu ca si concept, un articol light.

desi nu as avea probleme in realizarea lui

Incepe cu versiunea single player si te ajutam sa-l faci multi-player. Pune codul pe github si contribui cu idei / cod.

1 Like

În primul rând trebuie să-ți stabilești flowul aplicației. Poate tu îl ai în minte deja, dar nu l-ai explicat foarte bine în primul post.

Să descriu eu cum am înțeles că vrei să meargă aplicația:

  1. deschizi siteul și se conectează la server și trebuie să aștepte pentru următorul player
  2. întra al doilea player pe site și se conectează la server, iar în acest moment când sunt 2 playeri conectați trebuie să primească arrayurile cum ai explicat tu

ce se întâmplă când intră mai mulți playeri? ce se întâmplă când iese un player după ce s-au conectat?

Eu am stabilit următoarele reguli:

  1. când pe site este doar un jucător conectat, îi apare mesajul “așteaptă”
  2. când pe site sunt doi jucători conectați jocul începe instant
  3. când pe site se conecteaza > 2 player îi apare msajul ca este full
  4. dacă părăsește siteul când este în joc, la celalalt player îi apare un mesaj că jocul s-a oprit și așteaptă din nou pentru alt player.

Ideea este că pe server trebuie să ai toate datele, câti jucători ai, în ce poziție sunt respectivii jucători, și absolut tot trebuie să treacă prin server. Cum faci chestia asta? prin evenimente stabilite de tine.

Îți stabilești niște evenimente cheie precum “join”, “start”, “stop”, “end”, “full”, "wait’ de la server la client și de la client la server. Pentru fiecare eveniment trebuie să știi exact ce să faci.

Spre exemplu codul scris de mine are următoarea logică:

  • pe server țin tot timpul numărul de useri conectați (0, 1, 2, sau mai mulți)
  • când se conectează un player verific dacă: este singurul jucător și îi trimit evenimentul WAIT, dacă este al doilea jucător înseamnă ca jocul poate să înceapă și amestec arrayul și trimit evenimentul START + arrayul de date, daca este al treilea jucător îi trimit evenimentul FULL
  • dacă unul din jucător iese trimit la celălalt jucător evenimentul STOP

astea sunt evenimente de la server la client. Toate aceste evenimente le implementez pe client și pentru fiecare din ele se întampla o anumită acțiune.

În jocul nostru clientul nu are nici o acțiune de trimis la server, că momentan nu poate să facă nimic.

Aici ai codul: https://github.com/micku7zu/SocketIOExample/tree/master/FirstExample
Aici ai un screenrecord: https://drive.google.com/open?id=0BxktHhMrAobWeG5PelA4RkExSkk (nu este foarte explicativ, dar poate te ajută mai mult decât codul gata scris. Recomand să downloadezi videoul de pe drive că nu a fost procesat încă și nu se vede full hd)




După ce te uiți peste ce ți-am dat mai sus și ÎNȚELEGI tot ce am făcut, poți să treci la urmățorul exemplu.
Am făcut și unul puțin mai avansat decât primul, care poate să țina oricâti jucători și fiecare jucător poate să joace cu oricare altul.

Cod: https://github.com/micku7zu/SocketIOExample/tree/master/SecondExample
Demo: https://drive.google.com/file/d/0BxktHhMrAobWejJlbk5EZGxxa0k/view

Amândouă am încercat să le scriu cât mai simplu și să nu le complic ca să le poți întelege cât mai bine.
Să-mi pui întrebari unde nu ai înteles.

3 Likes

Multumesc Eugen , Sergiu , e exact ce imi doream !
Nu am explicat in primul post foarte bine , deoarece nu am dat toate detaliile cu privire la cum vreau sa arate jocul , fiindca nu-i pretind nimanui sa mi-l dea pe tot gata facut. :slightly_smiling: Exact asta imi doream , sa vad mecanismul de functionare la un nivel asa mai schematic :smiley: .

Revin cu intrebari in cazul in care ma impotmolesc undeva. Multumesc mult !

1 Like