Search the Community

Showing results for tags 'socket.io'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • HTML5 Game Coding
    • News
    • Game Showcase
    • Facebook Instant Games
    • Coding and Game Design
  • Frameworks
    • Phaser 3
    • Phaser 2
    • Pixi.js
    • Babylon.js
    • Panda 2
    • melonJS
    • Haxe JS
    • Kiwi.js
  • General
    • General Talk
  • Business
    • Collaborations (un-paid)
    • Jobs (Hiring and Freelance)
    • Services Offered

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Website URL


Twitter


Skype


Location


Interests

Found 45 results

  1. I have problems writing a multiplayer game with phaser 3 and socket.io I’ll explain it using a simple example: 2 players P1 and P2, try to kill each other using bullets B1 and B2. Scenario A: Use Pure Javascript and socket.io, without any game engine. A1. The socket.io server calculates the position of all players and bullets, and send these information to all players for every 30ms. A2. Each player send [inputs] to the server on real time basis. Of course, those inputs may arrive the server later then expected. A3. Each player show objects in screen only according to the information provided by the server, without calculating the objects’ position on the client side. A4. The game runs without any BIG problem since the Unique Game State is only calculated on the server side. A5. However, without using game engine, I need to calculate the [Physics] of all objects by myself on the server side. Scenario B: Use Javascript with phaser 3 and socket.io B1. At time 0.000 second, the server ask both players start the game at the same time. B2. At time 0.030 and 0.040, both players start the game accordingly. (As you can see, the network of player P1 is faster) B3. At time 0.200, player P1 fires a bullet B1 and starts to update screen using the phaser 3 engine’s [Physics]. B4. At time 0.280 (here the server takes 10ms to transfer this action from P1 to P2), P2 gets this action from the server, and starts to update screen using the game engine’s [Physics]. (You may probably notice that at this moment, the screens of P1 and P2 are different!) B5. Suppose the bullet B1 is able to hit P2 at time 1.000. At time 0.950, P2 moves away from the bullet and continues playing the game. B6. As you may already figure out, the action that P2 moves away, arrives P1 at time 1.030, at that time, P1 already win the game! At this moment, in P1’s screen, P1 win the game, but in P2’s screen, P2 is still playing the game! It seems that phaser 3 is not suitable for multiplayer games. Did I miss anything? Thanks in advance for your help.
  2. Hello! We made an IO game called PirateBattle.io and you can play it here: http://piratebattle.io/ Mobile app version here: https://play.google.com/store/apps/details?id=com.jettigames.piratebattle IOS coming soon You are a pirate ship and you shall collect coins and shoot other ships. Coins are used to upgrade your boat. Controls: Use mouse to move Use left click to shoot Use space to boost Use 1, 2, 3 and 4 to upgrade your ship if you have enough money This game is made using Phaser, socketIO, NodeJS backend and Nginx for serving the static files. PLAY IT HERE: http://piratebattle.io/
  3. mla

    Images disappearing

    My game is build for 6 players. Each player loads the game in a browser is assigned a unique room that displays a personal card and is represented by an avatar. The game works well, the images all load, however for some reason as more players access the game, some images may disappear. The player is actually still logged into the game and can even play the game, however their avatar image may have disappeared or their personal card may have disappeared. There is no consistency to which image may vanish and it doesn't always happen, but in most cases it does. Would anyone know why this may be? Thanks!
  4. Kipfocks

    Using Socket.io in phaser3

    Hi there! I'm relatively new...ok very new to coding with phaser and I'm having a tough time finding tutorials that can help guide me through a few of the basics for what I'm looking for. I've been trying to use this tutorial: How to make a multiplayer online game with Phaser, Socket.io and Node.js And this one: How to create a multiplayer game with Phaser, Node, Socket.io and Express. However, it seems that both tutorials were made using Phaser2 and there are a few fundamental differences that don't function well using the newer code. The biggest part I'm having trouble with is the differences between game states in the old Phaser and how they are different from the scenes the new version uses. game.state.add('Game',Game); game.state.start('Game'); These functions specifically seem to break my game every time I try and use them. Is the new phaser designed to be run entirely through the index.html file? Or is there a way to execute most of my game's code in a separate game.js file? Currently I have at least a functioning game where I can move around on a map, but the entire thing is contained inside a single index.html file. You can see my game's code here: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Top Down Multiplayer Test Game</title> <script src="//cdn.jsdelivr.net/npm/phaser@3.1.1/dist/phaser.js"></script> <script src="/node_modules/socket.io-client/dist/socket.io.js"></script> <style type="text/css"> body { margin: 0; } </style> </head> <body> <script type="text/javascript"> var config = { type: Phaser.Auto, width: 960, height: 960, physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, create: create, update: update } }; var player; var blocked; var game = new Phaser.Game(config); function preload () { //assets to use in the loading screen this.load.image('preloadbar', 'assets/images/preloader-bar.png'); //load game assets this.load.image('level1', 'assets/tilemaps/level1.png'); this.load.image('gameTiles', 'assets/images/Outside_A2.png'); this.load.image('gameTiles', 'assets/images/Outside_B.png'); this.load.image('emptypot', 'assets/images/emptypot.png'); this.load.image('filledbucket', 'assets/images/filledbucket'); this.load.image('player', 'assets/images/player.png'); this.load.image('doorleft', 'assets/images/doorleft.png'); this.load.image('doorright', 'assets/images/doorright.png'); this.load.image('tent', 'assets/images/tent.png'); this.load.image('sign', 'assets/images/sign.png'); this.load.image('campfire', 'assets/images/campfire.png'); this.load.image('woodpile', 'assets/images/woodpile.png'); this.load.image('tree', 'assets/images/tree.png'); this.load.image('rock', 'assets/images/rock.png'); this.load.image('grapes', 'assets/images/grapes.png'); this.load.image('log', 'assets/images/log.png'); this.load.spritesheet('dude', 'assets/spritesheets/dude.png',{frameWidth: 32, frameHeight: 48}); } function create () { this.add.image(480, 480, 'level1'); blocked = this.physics.add.staticGroup(); blocked.create(456, 216, 'sign'); blocked.create(648, 168, 'woodpile'); blocked.create(648, 216, 'campfire'); blocked.create(744, 168, 'tent'); blocked.create(840, 216, 'filledbucket'); blocked.create(600, 400, 'rock'); blocked.create(648, 448, 'rock'); blocked.create(600, 448, 'grapes'); blocked.create(214, 720, 'tree'); blocked.create(214, 552, 'tree'); blocked.create(214, 384, 'tree'); blocked.create(214, 286, 'log'); blocked.create(214, 192, 'tree'); blocked.create(358, 192, 'tree'); player = this.physics.add.sprite(480, 480, 'dude'); player.setBounce(0.2); player.setCollideWorldBounds(true); cursors = this.input.keyboard.createCursorKeys(); this.physics.add.collider(player, blocked); this.anims.create({ key: 'left', frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3}), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'turn', frames: [ { key: 'dude', frame: 4 } ], frameRate: 20 }) this.anims.create({ key: 'right', frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }), frameRate: 10, repeat: -1 }); } function update () { if (cursors.left.isDown) { player.setVelocityX(-160); player.anims.play('left', true); } else if (cursors.right.isDown) { player.setVelocityX(160); player.anims.play('right', true) } else if (cursors.up.isDown) { player.setVelocityY(-160); player.anims.play('right', true) } else if (cursors.down.isDown) { player.setVelocityY(160); player.anims.play('left', true) } else{ player.setVelocityX(0); player.setVelocityY(0); player.anims.play('turn'); } } </script> </body> </html> I'm also having a few issues adapting what I see in these tutorials around using a server to keep track of my player's position and report back locations. Some examples start with something as basic as referencing socket.io in my code as a source. In all the tutorials I can find they say to use this line of code in my index.html file: <script src="/socket.io/socket.io.js"></script> However this doesn't work, as you can see at the top of my game file above, I had to reference the full file path, going in through the node_modules folder and finding the socket.io.js file. Am I doing something wrong? Or am I supposed to reference the full file path and the tutorial is not accurate? Finally when trying to implement some of the code in the tutorials into the game file itself to tell the game to ask the server when a new client is connected, I get an error saying the code is invalid. I'm not sure if this is because I am putting the code in the incorrect place, or if it's because the code doesn't work in Phaser3 the way it did in version 2. Client.askNewPlayer(); The tutorial says to put this "at the end of game.create()" however because I don't have game states, I have nothing I can find as the equivalent. Just for the sake of testing it out, I tried placing this code inside the "function create ()" of my game if only because of the word create, and then also in the "function update ()" of my game because I figured this is where the game is always looping and checking for updates. But both gave me errors saying that "client is not defined" Again I'm sure you can probably tell this is my first time doing this sort of thing with real code, I've been messing around with RPG maker before this, but I really think I can get the hang of it if I can just get a few pointers or tips to get me going in the right direction! Any help or advice would be greatly appreciated!
  5. It seems that to send a private message to a player, you are supposed to use socket.to(socket.id).emit. I need to emit an image to a specific player so am using this concept, however it doesn't seem to work. Would anyone know how to emit an image to a specific client? Thanks!
  6. I want to design a multiplayer phaser game that has a lobby, you can review your information or talk with friends via chat while you are waiting until you are matched with another player (is a fight game, pokemon style). -How do I get this? should I develop everything like a normal socket.io/chat project and then start the game when you find a match? -Should I start the game instance since the beginning, and the lobby would be a state, the fight another state and then back to the lobby? I'm very new to this but I'm excited to start developing, I'll appreciate any guidance, thanks
  7. Sentinel

    Pixi.js renderer not working

    So basically I have a big project ongoing. Instead of having nested constructors that passed down all the game data such as renderer, resources and so on, I decided in my Game.js file to make it static and then require that in every other file and directly get the required data through there. It is quite a big project, so I am not going to include files, instead I'll be linking to my git repository. The issue is that nothing gets rendered on the screen and no errors are shown at all. I've tried 2 different browsers aswell. I've tried with both the CanvasRenderer and WebGLRenderer yet the same error still occurs. And I've checked the PIXI Container that gets rendered, and it does contain children of other DisplayObjects. https://github.com/marcus-sa/StormEngine/tree/dev/client
  8. Kiro705

    Super Asteroid Battle

    Join the Super Asteroid Battle! Bring your friends to fight the asteroids, collect ore, upgrade your spaceship, and shoot for the high score in this now multiplayer version of the classic Asteroids game. Built as a collaboration between Elisabeth Seite and Jackson Sui. We used the phaser.io framework and socket.io for multiplayer. We think the game turned out very well and hope you enjoy it! Try playing it here! Github Link
  9. pyre

    [Phaser] Infinitris.io

    Hi, Infinitris.io - A massively multiplayer online falling block puzzle game, created using the Phaser game engine. Controls: Arrow keys and spacebar. Current Features: Instant join - only specify your nickname and you're ready to play. Multiplayer. No player limit. Dynamically sized grid with horizontal wrapping. Mistake detection. Sabotage other players by dropping on them. Phase shift into gaps directly below you (hold the down key while your block is being placed). Ingame chat [Enter]. Scoreboard. Facebook: https://www.facebook.com/infinitris Twitter: https://twitter.com/infinitris_io Blog: https://infinitrisblog.wordpress.com/ Please give it a try and let me know what you think! Pyre
  10. Hello! I have been making this small puzzle prototype-game on my free time. It is called Numeropeli online. (Numeropeli means numbergame in Finnish.) I'm pretty sure there are real name for this type of game, (like chess, GO, backgammon) but i haven't found the one using google, so that's why the name of the game is kinda dumb. It is using node.js on backend, and it's using socket.io to connect to the server. It currently supports playing against random people, invite/host -game and playing against AI. I have been having fun playing with friends, it is kinda addicting too. The idea is, that players play in turns. The first player chooses the tile where the game begins. At each round, the players has to choose a tile from the line that the opponent has chosen. When you select a tile on your turn, the opponent must choose the next tile from the same column where the last picked tile were. The player with the most points wins. The next version contains: UX and UI updates, maybe whole rework (It feels bit wrong still) bug fixes (I'm pretty sure there are still bugs :D) Sounds (maybe) Stats system (wins, losses, avg, best points, game history, etc.) Leave button for games, if you dont want to play. Support for 5x5 tile games. Translations for other languages. Maybe make this an Windows Phone/Android application I would like to know what you guys think about it, are there some bad things, what should i change in the web design? Can you see any bugs? It looks like this on mobile Try it!
  11. It is regularly ask so I suggest that I use as server NodeJS + socket.IO. this therefore create a master server and workers according to the number of heart of the machine. This solution allows to distribute the load. Here is the Serveur.js var cluster = require('cluster'), _portSocket = 8080, _portRedis = 6379, _HostRedis = 'localhost'; if (cluster.isMaster) { var server = require('http').createServer(), socketIO = require('socket.io').listen(server), redis = require('socket.io-redis'); socketIO.adapter(redis({ host: _HostRedis, port: _portRedis })); var numberOfCPUs = require('os').cpus().length; for (var i = 0; i < numberOfCPUs; i++) { cluster.fork(); } cluster.on('fork', function(worker) { console.log('Travailleur %s créer', worker.id); }); cluster.on('online', function(worker) { console.log('Travailleur %s en ligne', worker.id); }); cluster.on('listening', function(worker, addr) { console.log('Travailleur %s écoute sur %s:%d', worker.id, addr.address, addr.port); }); cluster.on('disconnect', function(worker) { console.log('Travailleur %s déconnecter', worker.id); }); cluster.on('exit', function(worker, code, signal) { console.log('Travailleur %s mort (%s)', worker.id, signal || code); if (!worker.suicide) { console.log('Nouveau travailleur %s créer', worker.id); cluster.fork(); } }); } if (cluster.isWorker) { var http = require('http'); http.globalAgent.maxSockets = Infinity; var app = require('express')(), ent = require('ent'), fs = require('fs'), server = http.createServer(app).listen(_portSocket), socketIO = require('socket.io').listen(server), redis = require('socket.io-redis'); socketIO.adapter(redis({ host: _HostRedis, port: _portRedis })); app.get('/', function (req, res) { res.emitfile(__dirname + '/interface.php');}); socketIO.sockets.on('connection', function(socket, pseudo) { socket.setNoDelay(true); socket.on('nouveau_client', function(pseudo) { pseudo = ent.encode(pseudo); socket.pseudo = pseudo; try { socket.broadcast.to(socket.room).emit('nouveau_client', pseudo); } catch(e) { socket.to(socket.room).emit('nouveau_client', pseudo); } console.log('L\'utilisateur : '+socket.pseudo+' s\'est connecter'); }); socket.on('message', function(data) { socket.broadcast.to(socket.room).emit('dispatch', data); }); socket.on('exit', function(data) { socket.close();}); socket.on('room', function(newroom) { socket.room = newroom; socket.join(newroom); console.log('Le membre '+socket.pseudo+' a rejoint le domaine '+socket.room); socket.broadcast.to(socket.room).emit('dispatch', 'L\'utilisateur : '+socket.pseudo+' a rejoint le domaine : '+socket.room); }); }); } And to install Node: and install Redis server: and modules: The server runs. ------------------------ Client: <head> <script type="text/javascript" src="http://localhost:8080/socket.io/socket.io.js"></script> </head> <body> <script> var socket = null; try { socket = io.connect(); console.log("socket: Ok!"); } catch(err) { console.error("Socket is out of service!"); } if(socket != null) { socket.emit('new_client', 'admin'); // use variable php (COOKIES, SESSION...) socket.on('message', function(data) { $('#zone_chat').prepend('' + data.pseudo + ': ' + data.message + '<br />'); }); socket.on('new_client', function(pseudo) { $('#zone_chat').prepend('<em>' + pseudo + ' a rejoint le chat !</em><br />'); }); socket.on('moveObjet', function(data) { mesh = scene.getMeshByName(data.name); mesh.position = new BABYLON.Vector3(data.position); mesh.rotation = new BABYLON.Vector3(data.rotation); }); } </script> </body> The client runs.
  12. GodsVictory

    Multiplayer desync

    What am I doing wrong here. Normal movement is fine, but when boost is applied, there is rubber banding at the end. I'm using client/server model to implement movement. pseudo code: Client sends inputs to server Client process inputs and displays locally Server receives inputs and calculates where client should be Server emit client coordinates Client receives update and applies coordinates Client reapply all inputs made after the last server update Player class: https://github.com/GodsVictory/SuperOnRoad/blob/wip/public/js/player.js Server code: https://github.com/GodsVictory/SuperOnRoad/blob/wip/server.js
  13. GodsVictory

    Properly syncing multiplayer movement

    Currently, when a client moves, the inputs are processed on both the client and the server which use the same calculation to process the movement. When the client receives an update from the server, the servers position will override the clients position. I would hope that the client and the server would calculate the same positions, but that is not the case. I believe timing is the culprit. What is the best practice when syncing movement? Current flow: Source: https://github.com/GodsVictory/SuperOnRoad
  14. Jadegames

    Monitise .io Games

    I've created a few HTML5 games and want to push myself further and try to make a multiplayer game. It got me thinking about monitising .io games and how other people monitise their multiplayer games, if at all. It would be nice if the multiplayer game I made covered it's own expenses. I've not seen any adverts for something like slither.io and video ads would just ruin the flow of the game. So I wanted to ask the community: how do you monitise your multiplayer games?
  15. Hello everybody! I can create single player games with phaser and now I want to start making multiplayer games using socket.io + node.js So unfortunately I haven't found any tutorials about how to create games on phaser with phaser. I have never had projects with serverpart(so I have no experience in it) So that's all I could understand and write myself :[ SERVER PART var express = require('express'); var app = express(); var serv = require('http').Server(app); var counter = 0; app.get('/', function(req, res) { res.sendFile(__dirname + '/client/index.html'); }); app.use('/client', express.static('/client')); serv.listen(2000); console.log('server started'); var io = require('socket.io')(serv); io.sockets.on('connection', function(socket) { counter++; console.log('connection #' + counter); }); Client <script> var socket = io(); var sendInfo = function() { socket.emit('objAppear'); } </script> <button id="btn" onclick="sendInfo();">Appear</button> Of course that's the simplest thing to create using node + socket.io So now I want to create multiplayer in games I've already created. But how?!?! I can't find any tutorials. Can you please help me. Server part is too hard for me
  16. Greetings! I see quite often around these parts and in further fields, that there are constantly people who are just starting out asking how to add networked multiplayer functionality to their HTML5 games. I was one of them, and I hated the near absence of practical explanations that were written in concise, plain-English, yet still detailed, of how to get started. So, I made a simple game example/template using Socket.io and Phaser, and documented the hell out of it. Almost everything gets a few lines of comments to explain what is doing what, and I haven't assumed any prior knowledge, aside from core JavaScript and being able to set up NodeJS and how to view the game in a browser. The main focal point is using Socket.io, as the game framework can be easily interchanged to one of your preference. Hopefully this will save a few hours and headaches for people who don't have a clue what they are doing. https://github.com/Arcanorum/basic-networked-multiplayer-game
  17. Jerorx

    Phaser Quest

    I'm happy to present to you Phaser Quest, a top-down real-time multiplayer adventure made with Phaser and Socket.io. Explore the map, find better equipment, fight monsters and defeat the final boss, alone or with friends! It was for me a practice project, and is a reproduction of Mozilla's Browserquest. Hopefully the source code will interest you, as the project integrates of a lot of Phaser features together (such as tiled maps, text input, tweens, animations, sound, click handling, camera management, etc.), as well as pathfinding using Easystar.js. It is also an example of how a Phaser client can be made to interact with a Node.js server using Socket.io. On my website, I have written a few articles about some aspects of the game. They are mostly concerned with networking for the moment. If you'd like me to write an article explaining how I accomplished this or that in the development of this game, feel free to ask, I'm always happy to help. In addition, I'm interested in any feedback you might have, it's always valuable, especially with future multiplayer projects in mind.
  18. thatnoobguy

    PVP matchmaking system

    Hey everyone, Sorry for that rookie question. I'm trying to develop this 1vs1 RPG multiplayer game and have a hard time implementing player matchmaking mechanism. For testing purposes, I'm creating a player when the client connects to the server. // Client side: const socket = io(); socket.on('connect', () => { socket.emit('create player', data => console.log(data)) }) // Server side: let players = []; const playerFactory = () => { return { state: 'idle', // idle, searching, fightInProgress lvl: getRandomArbitrary(1, 10), // Get random number from 1 - 10 winRatio: getRandomArbitrary(0, 100) } }; io.on('connection', socket => { socket.on('create player', fn => { console.log('Player created'); const player = playerFactory(name); player.id = socket.id; players.push(player); //returning acknowledgement to client fn(player); }) }) Assuming there is a 'Find opponent' button. How do I watch and match players with 'searching' statuses and appropriate levels? Also, how would I match players by their win/loss ratio? Any information or code examples, libraries or frameworks would help a lot. Thank you in advance!
  19. JasperCherry

    Shipwrecked

    Hey there, I just finished my first multiplayer project based on node.js. Some features of game below: - earning upgrades during the game - up to 10 players + 5 constant AIs on the map - can play with friends or against them - in build chat and map to communicate with others - optional voice control Have fun https://shipwrecked.herokuapp.com/
  20. primrose93

    Node.js Multiplayer Simple Game

    https://drive.google.com/folderview?id=0Bwl58NPLObeIWEQ3YlNlTV9KNWs Here's a sharable link to the directory where my files are located. There's no node_modules, so it's necessary to install before express and socket.io. The problem is I can't create and render the balls which need to bounce all the time. The server is responsible for creating my players and balls. I did successfully the creation and movement of my players with the arrow keys and that's synchronised to all the clients. But I can't do the part with bouncing balls. It seems simple game but as far as I am new to this stuff, I can't figure it out. I provide a link to the directory of my files. The command to start the game is: node server.js. If anyone could help me, I would be very happy. Thanks in advance guys.
  21. hunts

    socket.io

    hello to all multiplayer experts, i'm on a project using socket.io, but i want to update the position of the local player to the other players, e.g when a forward or backward key is pressed.
  22. Hi all! I'm newbie to game development. I just complete my first game, a simple game using HTML5 canvas, socket.io and express. I have NodeJS npm installed and i run my game locally in my PC as npm game.js. The question is that now i want this game to upload to a server where different users from different devices play the game. Is it works like we upload normal sites to domains or different. Please help! Thanks.
  23. Ranger Steve is a web (phaser) based realtime 2d shooter that let's you have instant lan parties with your friends. Ranger Steve: Buffalo Invasion YouTube Teaser Trailer Fast paced, intense shooter, explosions This is a realtime, "shoot em up", explosive multiplayer game that makes playing with your friends as simple as sharing a link. Made with: Phaser.io, ReactJS, NodeJS, Socket.io, and Redux.
  24. Ray

    PressBall

    Hi guys, I'd like to show my last game: PressBall. Yo can see the game info and play here: Info and Play Game available for exclusive or non-exclusive licensing. If you are interested, feel free to write via: contact@ninjabitsgames.com It's my first time using socket.io and phaser, any feedback is welcome!
  25. As I don't have an external server at the moment, I'm trying to fake a bit of latency using SetTimeout. The code is based on Gabriel Gambetta's code for handling an authoritative server: http://www.gabrielgambetta.com/fpm_live.html And yeah. I know the code is very ugly and prototypish, no handling of multiple users, etc. etc.. I am sending inputs as well as the time the key is pressed, as a way of making it time-independent, but I have no sanity checks. If I keep the networkLatency at 0, it seems to run very smoothly, and both reconciliation and prediction works very well. However, if I add a delay, of say, 200 ms, it behaves strangely, and I can't really see why. This is the code handling the updating of the position, and the prediction based on previously saved inputs, and as far as I can see, this should work: iosocket.on('updatePOS', function(message) { setTimeout(function () { sphereBody.position.x = message.x; sphereBody.position.y = message.y; sphereBody.position.z = message.z; ghostSphere.position.x = message.x; ghostSphere.position.y = message.y; ghostSphere.position.z = message.z; lastSequence = message.last; console.log(lastSequence); for (var x in pending_inputs){ if (x <= lastSequence){ console.log(x); delete pending_inputs[x]; pending_inputs.splice(x, 1); delete inputsToSend[x]; inputsToSend.splice(x, 1); } else { //console.log(x); // console.log(pending_inputs[x]); applyInputs(pending_inputs[x]); } } }, networkLatency); }); Even with a delay/latency, the function should still take into consideration the saved inputs, and apply these when the new positional updates are received. So even when apllying updates as old as 200ms, the result should be the same as the predicted state. If someone can spot where the issue is, that would be awesome. If someone has a VPS with some real latency, a test of that woulld be appreciated too. index.html: <!doctype html> <html> <head> <meta charset="utf-8"> <title>Babylon - Basic scene</title> <style> html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; } #renderCanvas { width: 100%; height: 100%; touch-action: none; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/babylonjs/2.4.0/babylon.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.8/socket.io.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.js"></script> <!-- optional physics engine --> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> </head> <body> <canvas id="renderCanvas"></canvas> <script type="text/javascript"> var sphere, inputs = []; var globalGravity = new CANNON.Vec3(0,-30,0); var camera; var lastSequence = 0; var client = {}; client.left = false; client.right = false; client.forward = false; client.back = false; pending_inputs = []; inputsToSend = []; input_sequence_number = -1; var networkLatency = 0; // var keys; // keys.left=1; this.playerDirection = [0,0,0,0]; quat = new CANNON.Quaternion(); var iosocket = io.connect("http://localhost:8080"); iosocket.on('connect', function () { console.log("connect"); iosocket.on('message', function(message) { // console.log(message); }); iosocket.on('updatePOS', function(message) { setTimeout(function () { sphereBody.position.x = message.x; sphereBody.position.y = message.y; sphereBody.position.z = message.z; ghostSphere.position.x = message.x; ghostSphere.position.y = message.y; ghostSphere.position.z = message.z; lastSequence = message.last; console.log(lastSequence); for (var x in pending_inputs){ if (x <= lastSequence){ console.log(x); delete pending_inputs[x]; pending_inputs.splice(x, 1); delete inputsToSend[x]; inputsToSend.splice(x, 1); } else { //console.log(x); // console.log(pending_inputs[x]); applyInputs(pending_inputs[x]); } } }, networkLatency); }); iosocket.on('spawnPlayer', function(player) { console.log("Spawning Player"); }); iosocket.on('disconnect', function() { }); }); var canvas = document.querySelector("#renderCanvas"); var engine = new BABYLON.Engine(canvas, true); // setTimeout(sendInput, 2000); function sendInput(){ console.log("2 sek"); for (var x in inputsToSend){ iosocket.emit('input', inputsToSend[x]); } setTimeout(sendInput, 2000); } var createScene = function () { this.playerDirection = [0,0,0,0]; // Now create a basic Babylon Scene object var scene = new BABYLON.Scene(engine); scene.debugLayer.show(); // Change the scene background color to green. scene.clearColor = new BABYLON.Color3(0, 1, 0); // This creates and positions a free camera camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene); // This targets the camera to scene origin camera.setTarget(BABYLON.Vector3.Zero()); // This attaches the camera to the canvas camera.attachControl(canvas, false); // This creates a light, aiming 0,1,0 - to the sky. var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene); // Dim the light a small amount light.intensity = .5; // Let's try our built-in 'sphere' shape. Params: name, subdivisions, size, scene this.sphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene); this.sphere.quaternion = new CANNON.Quaternion(0,0,0,0); this.box = BABYLON.MeshBuilder.CreateBox("box", {height: 5}, scene); // Move the sphere upward 1/2 its height this.sphere.position.y = 2; this.box.position.y = 2.5; this.box.position.z = 2; this.box.parent = this.sphere; ghostSphere = BABYLON.Mesh.CreateSphere("ghost", 16, 2, scene); var ghostMat = new BABYLON.StandardMaterial("texture1", scene); ghostMat.diffuseColor = new BABYLON.Color3(0.5, 0.2, 0.7); ghostMat.alpha = 0.6; ghostSphere.material = ghostMat; // Let's try our built-in 'ground' shape. Params: name, width, depth, subdivisions, scene this.ground = BABYLON.Mesh.CreateGround("ground1", 6, 6, 2, scene); this.ground.rotation = new CANNON.Vec3(-0,0,0); BABYLON.SceneLoader.ImportMesh("", "https://raw.githubusercontent.com/RaggarDK/Baby/baby/", "height.babylon", scene, function (newMeshes) { setTimeout(function () { ground = newMeshes[1]; var material = new BABYLON.StandardMaterial("texture1", scene); //window.ground = ground; //ground.parent = undefined; ground.scaling.copyFromFloats(.3, .3, .3); ground.bakeCurrentTransformIntoVertices(); material.diffuseTexture = new BABYLON.Texture("https://raw.githubusercontent.com/RaggarDK/Baby/baby/plan.png", scene); ground.material = material; //ground.physicsImpostor = new BABYLON.PhysicsImpostor(ground, BABYLON.PhysicsEngine.HeightmapImpostor, { mass: 0 }, scene); createHeightmap(newMeshes[1]); }, 2000) }); // window.addEventListener("keydown", handleKeyDown, false); // window.addEventListener("keyup", handleKeyUp, false); window.addEventListener("mousemove", function(e) { // console.log("mouse"); event = e; var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; //this.sphereBody.quaternion.y += movementX * 0.002; // this.sphereBody.quaternion.x += movementY * 0.002; sphereBody.rotation.y += movementX * 0.008; sphereBody.rotation.x += movementY * 0.008; }); seq = 0; function handleKeyDown(evt){ seq += 1; if (evt.keyCode==16){ if(inputs){ console.log(inputs); } } if (evt.keyCode==65){ inputs[seq] = {left:1, rot:sphereBody.rotation}; this.playerDirection[0] = 1; applyInput(seq, "left", sphereBody.rotation); console.log(seq); // iosocket.emit('input', { left:1, rot:sphereBody.rotation}); // shootBullet(sphereBody.rotation.y, sphereBody.position); } if (evt.keyCode==68){ sphereBody.position.x += .1; inputs[seq] = {right:1, rot:sphereBody.rotation}; this.playerDirection[1] = 1; //applyInput(seq, "right", sphereBody.rotation); //iosocket.emit('input', { right:1, rot:sphereBody.rotation}); } if (evt.keyCode==87){ inputs[seq] = {forward:1, rot:sphereBody.rotation}; applyInput(seq, "forward", sphereBody.rotation); this.playerDirection[2] = 1; // iosocket.emit('input', { forward:1, rot:sphereBody.rotation}); } if (evt.keyCode==83){ inputs[seq] = {back:1, rot:sphereBody.rotation}; this.playerDirection[3] = 1; applyInput(seq, "back", sphereBody.rotation); // iosocket.emit('input', { back:1, rot:sphereBody.rotation}); } } function handleKeyUp(evt){ if (evt.keyCode==65){ this.playerDirection[0] = 0; // iosocket.emit('input', { left:0}); } if (evt.keyCode==68){ // iosocket.emit('input', { right:0}); this.playerDirection[1] = 0; } if (evt.keyCode==87){ // iosocket.emit('input', { forward:0}); this.playerDirection[2] = 0; } if (evt.keyCode==83){ // iosocket.emit('input', { back:0}); this.playerDirection[3] = 0; } } var keyHandler = function(e) { e = e || window.event; if (e.keyCode == 65) { console.log("Lefty"); client.left = (e.type == "keydown"); } if (e.keyCode == 68) { console.log("righty"); client.right = (e.type == "keydown"); } if (e.keyCode == 87) { console.log("forward"); client.forward = (e.type == "keydown"); } else if (e.keyCode == 83) { client.back = (e.type == "keydown"); console.log("back"); } }; window.addEventListener("keydown", keyHandler, false); window.addEventListener("keyup", keyHandler, false); return scene; }; var createPhysics = function(){ console.log("createPhysicsFunction Called!"); world = new CANNON.World(); world.gravity.set(0,-30,0); world.broadphase = new CANNON.NaiveBroadphase(); var mass = 5, radius = 1; sphereShape = new CANNON.Sphere(radius); // Step 1 sphereBody = new CANNON.Body({mass: 1, shape: sphereShape}); // Step 2 sphereBody.position.set(0,2,2); sphereBody.rotation = new CANNON.Vec3(); world.add(sphereBody); // Step 3 console.log("sphereBodyPosition0: " + sphereBody.position); sphereBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); groundShape = new CANNON.Plane(); groundBody = new CANNON.Body({ mass: 0, shape: groundShape }); console.log(groundBody.rotation); groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); console.log(groundBody.quaternion); world.add(groundBody); timeStep = 1.0 / 60.0; // seconds velocity = sphereBody.velocity; sphereBody.velocity = new CANNON.Vec3(0,0,0); return world; } var scene = createScene(); this.world = createPhysics(); var zeroVel = new CANNON.Vec3(0,0,0); var inputVelocity = new CANNON.Vec3(); var lastTime = (new Date()).getTime(); var currentTime = 0; var delta = 0; engine.runRenderLoop(function () { currentTime = (new Date()).getTime(); delta = (currentTime - lastTime) / 1000; // console.log(delta); processInputs(); scene.render(); world.step(1.0 / 60.0); velocity = sphereBody.velocity; this.sphere.position = sphereBody.position; this.sphere.rotation = sphereBody.rotation; moveSpeed = .1; // camera.position.x = sphereBody.position.x // camera.position.z = sphereBody.position.z // camera.rotation = sphereBody.rotation; //sphereBody.position.z += moveSpeed; //console.log(sphereBody.position.x); velocity.x = inputVelocity.x; velocity.z = inputVelocity.z; lastTime = currentTime; }); window.addEventListener("resize", function () { engine.resize(); }); function processInputs() { // Compute delta time since last update. var now_ts = +new Date(); var last_ts = this.last_ts || now_ts; var dt_sec = (now_ts - last_ts) / 1000.0; this.last_ts = now_ts; // Package player's input. var input; if (client.right) { input = {dir:"right", press_time: dt_sec }; }else if (client.forward && client.left) { input = {dir:"sfLeft", press_time: dt_sec }; } else if (client.left) { input = {dir:"left", press_time: dt_sec }; }else if (client.forward) { input = {dir:"forward", press_time: dt_sec }; }else if (client.back) { input = {dir:"back", press_time: dt_sec }; } else { // Nothing interesting happened. return; } // Send the input to the server. input.input_sequence_number = input_sequence_number++; console.log(input.input_sequence_number); // input.entity_id = this.entity_id; applyInputs(input); inputsToSend.push(input); iosocket.emit('input', input); // Save this input for later reconciliation. pending_inputs.push(input); } function applyInputs(input) { // console.log(input.dir); if (input.dir == "left"){ sphereBody.position.x += -input.press_time*5; } if (input.dir == "right"){ sphereBody.position.x += input.press_time*5; } if (input.dir == "forward"){ sphereBody.position.z += input.press_time*5; } if (input.dir == "back"){ sphereBody.position.z += -input.press_time*5; } if (input.dir == "sfLeft"){ sphereBody.position.z += input.press_time*2.5; sphereBody.position.x += -input.press_time*2.5; } } function createHeightmap (object, pointDepth) { var pos = object.getVerticesData(BABYLON.VertexBuffer.PositionKind); var matrix = []; //For now pointDepth will not be used and will be automatically calculated. //Future reference - try and find the best place to add a reference to the pointDepth variable. var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1); var dim = Math.min(object.getBoundingInfo().boundingBox.extendSize.x, object.getBoundingInfo().boundingBox.extendSize.z); var elementSize = dim * 2 / arraySize; var minY = object.getBoundingInfo().boundingBox.extendSize.y; for (var i = 0; i < pos.length; i = i + 3) { var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2); var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1); var y = pos[i + 1] + minY; if (!matrix[x]) { matrix[x] = []; } if (!matrix[x][z]) { matrix[x][z] = y; } matrix[x][z] = Math.max(y, matrix[x][z]); } for (var x = 0; x <= arraySize; ++x) { if (!matrix[x]) { var loc = 1; while (!matrix[(x + loc) % arraySize]) { loc++; } matrix[x] = matrix[(x + loc) % arraySize].slice(); } for (var z = 0; z <= arraySize; ++z) { if (!matrix[x][z]) { var loc = 1; var newValue; while (newValue === undefined) { newValue = matrix[x][(z + loc++) % arraySize]; } matrix[x][z] = newValue; } } } var shape = new CANNON.Heightfield(matrix, { elementSize: elementSize }); console.log(elementSize); //Output Matrix Info for Node.js console.log(matrix.length); for (i=0;i<matrix.length;i++){ //GET MATRIX DATA //console.info(JSON.stringify(matrix[0], null, ' ')) console.log("\n" + "matrix2[" + i + "] = " + JSON.stringify(matrix[i], null, ' ')) } heightBody = new CANNON.Body({mass: 0, shape: shape}); // Step 2 heightBody.position.y = -4.5; heightBody.position.x = -30; heightBody.position.z = 30; heightBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); console.log(heightBody.position); world.add(heightBody); }; </script> </body> </html> server.js: /* Copyright (c) 2012 Sven "FuzzYspo0N" Bergström http://underscorediscovery.com MIT Licensed. See LICENSE for full license. Usage : node simplest.app.js */ var gameport = process.env.PORT || 4004, CANNON = require('cannon'), io = require('socket.io'), socketio = require('socket.io'), express = require('express'), UUID = require('node-uuid'), fs = require('fs'), gameloop = require('node-gameloop'), verbose = false; var fs = require('fs') , http = require('http') , socketio = require('socket.io'); var server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html'}); res.end(fs.readFileSync(__dirname + '/index.html')); }).listen(8080, function() { console.log('Listening at: http://localhost:8080'); }); timeStep = 1.0 / 60.0; moveSpeed = .1; lastProcessedInput = -1; socketio.listen(server).on('connection', function (socket) { socket.emit('spawnPlayer'); var testLat = 0; var networkLoop = gameloop.setGameLoop(function(delta) { //socket.emit('news', { x: sphereBody.position.x, y: sphereBody.position.y, z: sphereBody.position.z, last:lastProcessedInput}); socket.emit('updatePOS', { x: sphereBody.position.x, y: sphereBody.position.y, z: sphereBody.position.z, last:lastProcessedInput}); }, 1000 / 10); socket.on('input', function (inp) { applyInput(inp); console.log(inp.input_sequence_number); }); sphereBody.velocity = new CANNON.Vec3(0,0,0); /*socket.on('arrayInput', function (ainput) { for (var input in ainput){ if (ainput.input_sequence_number > lastProcessedInput){ applyInput(ainput[input]); } } }); */ }); function applyInput(inp){ sphereBody.velocity.x = 0; if (inp.dir == "right"){ sphereBody.position.x += inp.press_time*5; } if (inp.dir == "sfLeft"){ sphereBody.position.z += inp.press_time*2.5; sphereBody.position.x += -inp.press_time*2.5; } if (inp.dir == "left"){ sphereBody.position.x += -inp.press_time*5; } if (inp.dir == "forward"){ sphereBody.position.z += inp.press_time*5; } if (inp.dir == "back"){ sphereBody.position.z += -inp.press_time*5; } lastProcessedInput = inp.input_sequence_number; console.log(lastProcessedInput); } var initPhysics = function() { world = new CANNON.World(); world.gravity.set(0,-30,0); world.broadphase = new CANNON.NaiveBroadphase(); var mass = 5, radius = 1; sphereShape = new CANNON.Sphere(radius); sphereBody = new CANNON.Body({mass: 1, shape: sphereShape}); sphereBody.position.set(0,2,2); sphereBody.rotation = new CANNON.Vec3(); world.add(sphereBody); sphereBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); createHeightfield(); } var frameCount = 0; var mainLoop = gameloop.setGameLoop(function(delta) { // console.log('Hi there! (frame=%s, delta=%s)', frameCount++, delta); world.step(timeStep); // console.log(sphereBody.position); if (sphereBody){ velocity = sphereBody.velocity; //sphereBody.velocity.z = 0; var inputVelocity = new CANNON.Vec3(); sphereBody.velocity.x = 0; sphereBody.velocity.z = 0; velocity.x = inputVelocity.x; velocity.z = inputVelocity.z; } }, 1000 / 60); function createHeightfield(){ matrix2 = []; elementSize = 2.9999426007270813; matrix2[0] = [ 10.294134842548655, 10.294077302543254, 10.294019762537854, 10.293962222532453, 10.293904682527053, 10.293847142521653, 10.293789602516252, 10.293732062510852, 10.293674522505452, 10.293616982500051, 10.29355944249465, 10.29350190248925, 10.29344436248385, 10.29338682247845, 10.29332928247305, 10.293271742467649, 10.293214202462249, 10.293156662456848, 10.293099122451448, 10.293041582446047, 10.292984042440647 ]; matrix2[1] = [ 10.294134842548655, 10.294077302543254, 10.294019762537854, 10.293962222532453, 10.293904682527053, 10.293847142521653, 10.293789602516252, 10.293732062510852, 10.293674522505452, 10.293616982500051, 10.29355944249465, 10.29350190248925, 10.29344436248385, 10.29338682247845, 10.29332928247305, 10.293271742467649, 10.293214202462249, 10.293156662456848, 10.293099122451448, 10.293041582446047, 10.292984042440647 ]; matrix2[2] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[3] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[4] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[5] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 1.260629979194317, 1.2605724391889166, 1.2605148991835162, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[6] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 1.260629979194317, 1.2605724391889166, 1.2605148991835162, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[7] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 1.260629979194317, 1.2605724391889166, 1.2605148991835162, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[8] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[9] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 4.516292111633966, 4.516234571628566 ]; matrix2[10] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 4.516292111633966, 4.516234571628566 ]; matrix2[11] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 4.516292111633966, 4.516234571628566 ]; matrix2[12] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[13] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[14] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 7.674529389168344, 7.674471849162944, 7.674414309157544, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[15] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 7.674529389168344, 7.674471849162944, 7.674414309157544, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[16] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 7.674529389168344, 7.674471849162944, 7.674414309157544, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[17] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[18] = [ 10.294134842548655, 10.294077302543254, 4.517270291725772, 4.517212751720372, 4.517155211714972, 4.517097671709571, 4.517040131704171, 4.5169825916987705, 4.51692505169337, 4.51686751168797, 4.516809971682569, 4.516752431677169, 4.516694891671769, 4.516637351666368, 4.516579811660968, 4.5165222716555675, 4.516464731650167, 4.516407191644767, 4.516349651639366, 10.293041582446047, 10.292984042440647 ]; matrix2[19] = [ 10.294134842548655, 10.294077302543254, 10.294019762537854, 10.293962222532453, 10.293904682527053, 10.293847142521653, 10.293789602516252, 10.293732062510852, 10.293674522505452, 10.293616982500051, 10.29355944249465, 10.29350190248925, 10.29344436248385, 10.29338682247845, 10.29332928247305, 10.293271742467649, 10.293214202462249, 10.293156662456848, 10.293099122451448, 10.293041582446047, 10.292984042440647 ]; matrix2[20] = [ 10.294134842548655, 10.294077302543254, 10.294019762537854, 10.293962222532453, 10.293904682527053, 10.293847142521653, 10.293789602516252, 10.293732062510852, 10.293674522505452, 10.293616982500051, 10.29355944249465, 10.29350190248925, 10.29344436248385, 10.29338682247845, 10.29332928247305, 10.293271742467649, 10.293214202462249, 10.293156662456848, 10.293099122451448, 10.293041582446047, 10.292984042440647 ]; shape = new CANNON.Heightfield(matrix2, { elementSize: elementSize }); heightBody = new CANNON.Body({mass: 0, shape: shape}); // Step 2 heightBody.position.y = -4.5; heightBody.position.x = -30; heightBody.position.z = 30; heightBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); console.log(heightBody.position); world.add(heightBody); } initPhysics(); Node.js for the server.js Chrome for the index.html WASD to move around.