2017-04-11 61 views
0

我有本地服務器運行在box2d在零重力nodejs。和客戶端使用cocos2d-x。當我從客戶端發出一些移動數據時,服務器會獲取這些移動數據並將其應用到對象。問題是關於碰撞。當強制應用於動態對象(玩家)時,對象在零重力世界與另一個名爲B(球)的動態對象發生碰撞。 B對象在碰撞後不會漂浮。只需少量單位移動並突然停止。 (我試過設置線性衰減到0,它仍然突然停止。)Node.js box2d碰撞不起作用,因爲我預計在零重力?

服務器端代碼:

World.js

var Box2D = require('./box2d.js'); 
var s = require('./Server.js'); 

var b2Vec2 = Box2D.Common.Math.b2Vec2, 
    b2BodyDef = Box2D.Dynamics.b2BodyDef, 
    b2AABB = Box2D.Collision.b2AABB, 
    b2Body = Box2D.Dynamics.b2Body, 
    b2FixtureDef = Box2D.Dynamics.b2FixtureDef, 
    b2Fixture = Box2D.Dynamics.b2Fixture, 
    b2World = Box2D.Dynamics.b2World, 
    b2MassData = Box2D.Collision.Shapes.b2MassData, 
    b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape, 
    b2CircleShape = Box2D.Collision.Shapes.b2CircleShape, 
    b2DebugDraw = Box2D.Dynamics.b2DebugDraw, 
    b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef, 
    b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape; 

function World(world, gravity, velocity, name, room) { 

    this._room = room; 
    this._name = name; 
    this._world = world; 
    this._gravity = gravity; 
    this._velocity = velocity; 
    this._gameElements = {}; 
    this._scale = 30; 
    this._interval; 

    this._size = 50; 
    this._w = 900; 
    this._h = 500; 
    this._fps = 60; 
    this._inteval; 

    this._PI2 = Math.PI * 2; 
    this._D2R = Math.PI/180; 
    this._R2D = 180/Math.PI; 
    this._debug = false; 

} 

World.prototype.startEnv = function() { 

    this._world = new b2World(new b2Vec2(0, this._gravity), true); 

    this.createArea(0, 0, this._w, 5, true); 
    this.createArea(0, this._h, this._w, 5, true); 
    this.createArea(0, 0, 5, this._h, true); 
    this.createArea(this._w, 0, 5, this._h, true); 

    this.createBox(0.1,450, 250, 12, 12, false, true, 'ball','ball'); 
    this.createBox(1,250,250, 25, 25, false, true, 'blue','anilgulgor'); 
    //this.createBox(650, 250, 25, 25, false, true, 'red', username); 

    this._inteval = setInterval(() => { 

     this.update(); 

    }, 1000/this._fps); 

    this.update(); 

} 

World.prototype.update = function() { 

    this._world.Step(1/this._fps, this._gravity, this._velocity); 

    this._gameElements = this.gameStep(); 

    s.emitObjectsToClients(this._room.name, this._gameElements); 

    console.log(this._gameElements + "name : " + this._name); 

    this._world.ClearForces(); 

} 



World.prototype.gameStep = function() { 

    var elements = []; 
    var i = 0; 
    for (var b = this._world.m_bodyList; b; b = b.m_next) { 
     for (var f = b.m_fixtureList; f; f = f.m_next) { 

      if (f.m_body.m_userData) { 

       var x = Math.floor(f.m_body.m_xf.position.x * this._scale); 
       var y = Math.floor(f.m_body.m_xf.position.y * this._scale); 
       var r = Math.round(((f.m_body.m_sweep.a + this._PI2) % this._PI2) * this._R2D * 100)/100; 
       var width = f.m_body.m_userData.width; 
       var height = f.m_body.m_userData.height; 
       var static = f.m_body.m_userData.static; 
       var type = f.m_body.m_userData.type; 

       var gameObj = { 

        x: x, 
        y: y, 
        r: r, 
        w: width, 
        h: height, 
        s: static, 
        t: type 
       } 

       elements.push(gameObj); 

      } 

     } 
    } 

    console.log(elements); 

    return { elements: elements }; 

} 

World.prototype.createBox = function (d,x, y, w2, h2, static, circle, type, username) { 

    var bodyDef = new b2BodyDef; 
    bodyDef.type = static ? b2Body.b2_staticBody : b2Body.b2_dynamicBody; 
    bodyDef.position.x = x/this._scale; 
    bodyDef.position.y = y/this._scale; 
    bodyDef.userData = { width: w2, height: h2, static: static, type: type, userName: username }; 
    bodyDef.allowSleep = false; 
    bodyDef.linearDamping = 0.5; 
    bodyDef.fixedRotation = true; 

    var fixDef = new b2FixtureDef; 
    fixDef.density = d; 
    fixDef.friction = 0.1; 
    fixDef.restitution = 1; 

    if (circle) { 
     var circleShape = new b2CircleShape; 
     circleShape.m_radius = w2/this._scale; 
     fixDef.shape = circleShape; 
    } else { 
     fixDef.shape = new b2PolygonShape; 
     fixDef.shape.SetAsBox(w2/this._scale, h2/this._scale); 
    } 

    return this._world.CreateBody(bodyDef).CreateFixture(fixDef); 

} 

World.prototype.applyForce = function (username, force) { 

    for (var b = this._world.m_bodyList; b; b = b.m_next) { 

     for (var f = b.m_fixtureList; f; f = f.m_next) { 

      if(f.m_body.m_userData){ 

      if (f.m_body.m_userData.userName == username) { 

       var forceVec = JSON.parse(force); 

       f.m_body.ApplyForce(new b2Vec2(forceVec.forceX, forceVec.forceY) , f.m_body.m_xf.position); 

       //f.m_body.SetLinearVelocity(new b2Vec2(forceVec.forceX, forceVec.forceY)); 

       console.log(forceVec.forceX + " " + forceVec.forceY); 

      } 

      } 

     } 

    } 

} 

World.prototype.createArea = function (x, y, w2, h2, static) { 

    var bodyDef = new b2BodyDef; 
    bodyDef.type = static ? b2Body.b2_staticBody : b2Body.b2_dynamicBody; 
    bodyDef.position.x = x/this._scale; 
    bodyDef.position.y = y/this._scale; 

    var fixDef = new b2FixtureDef; 
    fixDef.density = 1.5; 
    fixDef.friction = 0.2; 
    fixDef.restitution = 1.0; 

    fixDef.shape = new b2PolygonShape; 
    fixDef.shape.SetAsBox(w2/this._scale, h2/this._scale); 

    return this._world.CreateBody(bodyDef).CreateFixture(fixDef); 

} 

module.exports = World; 

Server.js

const http = require('http'); 
const express = require('express'); 
const socketIO = require('socket.io'); 
const World = require('./World.js'); 

var usernames = []; 
var roomToJoin; 

//port 
const port = process.env.PORT || 3000; 

var app = express(); 
var server = http.createServer(app); 
var io = socketIO(server); 

//server listen 
server.listen(port,() => { 

    console.log(`Server is on port ${port}`); 

}); 

io.on('connection', function (socket) { 

    //event fired when we get a new connection 
    console.log('user connected'); 

    socket.emit('connected', `connected to the server`); 

    //wait for addMe command with username parameter 
    socket.on('addMe', function (username) { 

     //Starting procedure of joining room 
     console.log(`${username} started addMe procedure to join room`); 

     //socket username is binded with client username 
     socket.username = username; 
     //socket room name is statically given. 
     socket.room = 'room1'; 
     //add username to the global username list 
     usernames.push(username); 



     if (roomToJoin != null) { 

      if (roomToJoin.length < 2) { 

       //room is available to join 

       //client join static room 
       socket.join(socket.room, (err) => { 

        if (!err) { 

         roomToJoin = io.sockets.adapter.rooms[socket.room]; 

         roomToJoin.name = socket.room; 

         console.log(roomToJoin.length + " clients in room"); 

         //join room sucessfully 
         socket.emit('connectedToRoom', `connected to the room name : ${socket.room}`); 

         //broadcast to another users in the room to warn that some user has connected 
         socket.broadcast.to(socket.room).emit('userConnectedToRoom', 'GameServer', `${username} has connected to the ${socket.room}`); 

         //room capacity is full right now 
         //we can start and emit world object positions to the clients 

         //startEmittingObjectPositionsToClients(roomToJoin); 

        } 
        else { 

         socket.emit('canNotConnectRoom', 'can not connect to the room'); 

        } 

       }); 

      } 

     } 
     else { 

      //there is no room name socket.room 

      socket.join(socket.room, (err) => { 

       if (!err) { 

        roomToJoin = io.sockets.adapter.rooms[socket.room]; 

        roomToJoin.name = socket.room; 

        console.log(roomToJoin.length + " clients in room"); 

        //world definition 
        var world; 
        var w = new World(world, 0, 100, `${socket.room} world`, roomToJoin); 
        // assign creator world to the roomToJoin.world 
        roomToJoin.world = w; 

        //join room sucessfully 
        socket.emit('connectedToRoom', `connected to the room name : ${socket.room}`); 

        //broadcast to another users in the room to warn that some user has connected 
        socket.broadcast.to(socket.room).emit('userConnectedToRoom', 'GameServer', `${username} has connected to the ${socket.room}`); 

        startEmittingObjectPositionsToClients(roomToJoin); 

       } 
       else { 

        socket.emit('canNotConnectRoom', 'can not connect to the room'); 

       } 

      }); 

     } 

    }); 

    socket.on('move', function(moveData) { 

     var room = io.sockets.adapter.rooms[socket.room]; 

     console.log(room); 

     room.world.applyForce('anilgulgor', moveData); 

     console.log(moveData); 

    }); 

}); 



function startEmittingObjectPositionsToClients(room) { 

    room.world.startEnv(); 

} 

function emitObjectsToClients(roomName, gameElements) { 

    console.log(roomName); 

    io.sockets.in(roomName).emit('worldStep', gameElements); 

    console.log('gönderdiiiiiiiiiiiim'); 

} 

module.exports.emitObjectsToClients = emitObjectsToClients; 

一切正常當我發出「移動」來自我的客戶的電話。但碰撞不能按我的預期工作。

+0

我想我找到了一個不可靠的解決方案。在Y軸上將重力設置爲0.0001。碰撞後對象的衝動現在就起作用。 –

回答

0

你的問題似乎基本上是:爲什麼碰撞後身體突然停下來?

由於速度閾值設置(b2_velocityThreshold值),可能會發生這種情況。此源代碼註釋(在基本2.3.2 Box2D C++代碼中)陳述了以下關於此設置的內容:

彈性碰撞的速度閾值。相對線速度低於此閾值的任何碰撞都將被視爲非彈性。

而在「無彈性」情況下,不應用恢復原則;只有位置分辨率 - 它可以消除兩個物體的重疊,但不會增加速度。

如果這是問題,那麼速度閾值設置可以降低到零,以看到越來越少的身體休息。如果速度閾值對於您的應用來說太高,確實是問題 - 並且聽起來確實如此 - 那麼設置一個小但非零重力不是解決它的正確方法。

注意,艾琳卡託 - 誰是Box2D的原作者 - raises the following point什麼人能降低速度閾值爲零期待:

如果將門檻設定爲零,非零恢復原狀會導致你的身體永遠反彈。

希望能回答你的問題。

+0

感謝路易斯,我的問題就像你上面提到的一樣,我通過在Y軸上設置重力0.0001來解決這個問題,這是微不足道的,並且對系統有任何影響。但我會嘗試將velocity_threshold設置爲零並讓您意識到。 –