Előadást letölteni
Az előadás letöltése folymat van. Kérjük, várjon
1
Multiplayer böngészőben
Szoftverfejlesztés laboratórium 2. IIT1 mérés
2
Technológiák szerver kliens kommunikáció Node.js
HTML5, JavaScript, WebGL kommunikáció sockets.io
3
Kiindulási állapot node.js szerver csak fileokat szolgáltat
minden lokálisan zajlik
4
Vezérlés App.prototype.registerEventHandlers = function() {
let theApp = this; document.onkeydown = function(event) { if(keyboardMap[event.keyCode] === 'W') { // LABTODO: üzenet a szervernek theApp.scene.setThrust(1);
5
Kilépésre eseményfigyelés
window.addEventListener('beforeunload', function() { // LABTODO: üzenet a szervernek });
6
Mesh betöltés let addMesh = function(textureFileName, animTileSize) {
let material = new Material(gl, theScene.texturedProgram); material.colorTexture.set( new Texture2D(gl, 'media/' + textureFileName + '.png') ); material.texScale.set(animTileSize); theScene[textureFileName + 'Mesh'] = new Mesh(theScene.quadGeometry, material); };
7
GameState - Fizikai állapotváltozók
this.positionPool = new Vec2Array(1024); this.orientationPool = new Vec1Array(1024); this.velocityPool = new Vec2Array(1024); this.angVelocityPool = new Vec1Array(1024); this.invMassPool = new Vec1Array(1024); this.invAngMassPool = new Vec1Array(1024); this.backDragPool = new Vec1Array(1024); this.sideDragPool = new Vec1Array(1024); this.angDragPool = new Vec1Array(1024); this.thrustPool = new Vec1Array(1024); this.torquePool = new Vec1Array(1024);
8
GameState - Fizikai számításokhoz memória
this.forcePool = new Vec2Array(1024); this.aheadPool = new Vec2Array(1024); this.aheadSpeedPool = new Vec1Array(1024); this.aheadVelocityPool = new Vec2Array(1024); this.sideVelocityPool = new Vec2Array(1024); this.backDragFactorPool = new Vec1Array(1024); this.sideDragFactorPool = new Vec1Array(1024); this.angDragFactorPool = new Vec1Array(1024);
9
GameState – objektumok, avatarok
this.dynamicObjects = []; this.avatars = {}; this.resizeArrays();
10
GameState – resizeArrays
GameState.prototype.resizeArrays = function() { this.positions = this.positionPool.subarray(0, this.dynamicObjects.length); ...
11
GameState – addPlayer GameState.prototype.addPlayer = function(playerId){ this.avatars[playerId] = {}; };
12
GameState – addObject GameState.prototype.addObject = function(playerId, isAvatar, meshName){ let i = this.dynamicObjects.length; this.dynamicObjects.push({ playerId:playerId, isAvatar:isAvatar, meshName:meshName, role:role}); if(isAvatar){ this.avatars[playerId].objectIndex = i; } this.positionPool.at(i).setRandom(0, 5); ...
13
GameState – dropPlayer
GameState.prototype.dropPlayer = function(playerId){ // remove objects with a certain player id this.dynamicObjects = this.dynamicObjects.filter(function(obj){ return obj.playerId !== playerId; });
14
GameState – dropPlayer
// refresh avatar indices delete this.avatars[playerId]; for(var i=0; i<this.dynamicObjects.length; i++){ let obj = this.dynamicObjects[i]; if(obj.isAvatar){ this.avatars[obj.playerId].objectIndex = i; } this.resizeArrays();
15
GameState update – Euler integrálás Newton egyenletekre
this.aheads.cossin(this.orientations); this.forces.mulWithVec1s(this.aheads, this.thrusts); this.velocities.addScaled(this.velocities, this.forces, dt); this.angVelocities.addScaled(this.angVelocities, this.torques, dt); this.positions.addScaled(this.positions, this.velocities, dt); this.orientations.addScaled(this.orientations, this.angVelocities, dt); this.aheadSpeeds.dotVec2s(this.velocities, this.aheads); this.aheadVelocities.mulWithVec1s(this.aheads, this.aheadSpeeds); this.sideVelocities.sub(this.velocities, this.aheadVelocities); this.backDragFactors.exp(this.backDrags, dt); this.aheadVelocities.mulWithVec1s(this.aheadVelocities, this.backDragFactors); this.sideDragFactors.exp(this.sideDrags, dt); this.sideVelocities.mulWithVec1s(this.sideVelocities, this.sideDragFactors); this.velocities.add(this.aheadVelocities, this.sideVelocities); this.angDragFactors.exp(this.angDrags, dt); this.angVelocities.mul(this.angVelocities, this.angDragFactors);
16
Ütközésdetektálás és válasz
let relativeVelocity = new Vec2(); let diff = new Vec2(); for(let i=0; i<this.dynamicObjects.length; i++) { for(let j=i+1; j<this.dynamicObjects.length; j++) { diff.set(this.positions.at(i)).sub(this.positions.at(j)); let dist2 = diff.dot(diff); if(dist2 < 4) { diff.mul( 1.0 / Math.sqrt(dist2) ); this.positions.at(i).addScaled(0.05, diff); this.positions.at(j).addScaled(-0.05, diff); var tangent = new Vec2(-diff.y, diff.x); var vi = this.velocities.at(i); var bi = this.angVelocities.at(i); var vj = this.velocities.at(j); var bj = this.angVelocities.at(j); relativeVelocity.set(vi).sub(vj).addScaled(bi.x - bj.x, tangent); let impulseLength = diff.dot(relativeVelocity); diff.mul( impulseLength * 1.5 /*restitution*/ ); let frictionLength = tangent.dot(relativeVelocity); tangent.mul(frictionLength * 0.5 /*friction*/); vi.sub(diff).sub(tangent); vj.add(diff).add(tangent); bi.add(frictionLength /* *radius*/ ); bj.add(frictionLength /* *radius*/ ); }
17
Kameramozgatás this.camera.position.set(
this.gameState.positions.at(this.avatarIndex)); this.camera.updateViewProjMatrix();
18
Feladat ütközésválasz a statikus objektumokra
minden ugyanaz, kivéve, hogy a statikusnak nulla a sebessége és a szögsebessége, valamint nem mozdul el
19
Feladat fizikai szimuláció a szerveren (is)
szinkronizáció a kliensekke multiplayer játék az egyes lépésekhez segítenek a következő diák
20
Indítás most nem az index.html játszik már hanem az index.js
package.json-ban van minden node shell / linux shell npm start csatlakozás: böngészőbe: localhost:8082
21
Szerver lehetőségek localhost cg.iit.bme.hu windows standalone node.js
nodejs-portable.exe 2-es menüopció cd arena npm start cg.iit.bme.hu user/pass: sw2/node.js a home-ba mindenki gyárthat NEPTUN kód könyvtárat npm a pathban van, npm start működik
22
Debuggolás kliens: szerver (localhoston) chrome, jobb klikk, inspect
chrome: about:inspect ha fut a szerver, kell itt lennie egy linknek a debuggolásához
23
Kapcsolódás a kliensből (App.js)
//this.socket = io.connect('localhost'); // VAGY //this.socket = io.connect('
24
Socket.io szerveren (index.js)
let io = require('socket.io')(server);
25
fogadás a szerveren io.on('connection', function(client) {
let clientId = lastClientId++; console.log('User connected, id: ' + clientId); });
26
Próbáljuk ki
27
Kilépés client.on('leave', function(){
console.log('Client left. Id: ' + clientId); });
28
Page unloadkor a kliens
theApp.socket.emit('leave', {});
29
Próbáljuk ki
30
Feladat néhány frameenként 'reqState' üzenet küldése a kliensről
App update-ből üres objektumot elég átküldni írjuk ki, hogy az üzenet megjött próbáljuk ki
31
GameState objektum szerveroldalon
let game = new GameState();
32
Szerveren: új játékos belépésekor objektumok létrehozása
új játékos hozzáadása (gameState) új avatar objektum hozzáadása (gameState) syncObject küldése mindenkinek üzenet része a kliensId (tudja meg a kliens, hogy hányas) ha broadcastolunk, ne legyen benne kliensId (legyen null) plusz küldjük át a gameState objektumot client.broadcast.emit('syncObjects', { clientId:null, state:game });
33
App.js: üzenetfogadás a kliensen példa
this.socket.on('syncObjects', function(data){ theScene.syncObjects(data.clientId, data.state); });
34
syncObjects példa Scene.prototype.syncObjects = function(clientId, serverState) { let theScene = this; var i = 0; this.dynamicObjects = serverState.dynamicObjects.map( function(obj){ return new GameObject( theScene[obj.meshName + 'Mesh'] ); }); this.gameState.dynamicObjects = serverState.dynamicObjects; this.gameState.resizeArrays(); this.syncState(clientId, serverState); };
35
syncState példa Scene.prototype.syncState = function(clientId, serverState) { if(clientId !== null) { this.playerId = clientId; } this.gameState.set(serverState); };
36
Próbáljuk ki új belépő esetén az új objektum és a játékállapot mindenkinek el lesz küldve
37
Szerveren: játékos kilépésekor
játékos kidobása a gameStateből syncObjects küldése mindenkinek
38
Próbáljuk ki kilépés esetén sync
39
Game loop a szerveren var timeAtStart = new Date().getTime();
var timeAtLastFrame = 0.0; setInterval(function(){ let time = (new Date().getTime() - timeAtStart) / ; let dt = time - timeAtLastFrame; timeAtLastFrame = time; game.update(dt); }, 16);
40
Feladat legyen az avataroknak valamilyen kezdősebessége
néhány frameenként 'reqState' üzenet küldése a kliensről válasz a szerverről: 'syncState' üzenetek
41
Próbáljuk ki sodródó, de szinkronizált hajók
42
Feladat setThrust és setTorque üzenetek küldése a kliensről, feldolgozása a szerveren game.avatars[clientId].objectIndex-et ne felejtsük
43
Próbáljuk ki multiplayer lökdösődés
44
További lehetőségek más objektumok ütközéskor típusfüggő reakció
pickupok, lövedékek célszerű őket előre, kapcsolódáskor létrehozni a GameState dynamicObjectsben lehet tárolni, hogy az objektum miféle (role) ütközéskor típusfüggő reakció ha az egyik avatar, a másik meg pickup: avatar tulajdonságok változtatása ehhez lehet avatarleíróba új property-t felvenni az objectIndex mellé pl. tolóerő függjön attól, hány pickupot szedtük fel pickup respawn (random helyre ugrik) lövedék: ha talál, frag++, eltalált respawn
Hasonló előadás
© 2024 SlidePlayer.hu Inc.
All rights reserved.