こんにちは、みんな
Phaserでマルチプレイヤーゲームを作成しようとしています。 ゲームが作成されると、2人のプレーヤーがいます。 プレーヤーを動かすと(緑)、ブラウザーの新しいページでその動きを確認できます(緑ではありません)。
すべてが最善を尽くします。 しかし、動きの数が多いことを考えると、しばらくすると次のエラーが発生します。
VM2455:300 Uncaught DOMException: Failed to construct 'RTCPeerConnection': Cannot create so many PeerConnections
at new WrappedRTCPeerConnection (<anonymous>:300:28)
at Object.m._startPeerConnection (http://localhost/SP2P/lib/peer.js:1:33131)
at Object.m._getPeerConnection (http://localhost/SP2P/lib/peer.js:1:32849)
at Object.m.startConnection (http://localhost/SP2P/lib/peer.js:1:32216)
at new d (http://localhost/SP2P/lib/peer.js:1:2579)
at p.connect (http://localhost/SP2P/lib/peer.js:1:25072)
at PeerClient.conn (http://localhost/SP2P/P2P/PeerClient.js:100:27)
at Object.P2PMaze.send (http://localhost/SP2P/js/GameMultiplayer.js:42:29)
at P2PMaze.GameMultiplayer.update (http://localhost/SP2P/js/GameMultiplayer.js:236:21)
at Phaser.StateManager.update (http://localhost/SP2P/lib/phaser.js:31183:39)
Peerjsバージョン:0.3.9
Chromeバージョン:67.0.3396.62
たくさんの新しいつながりを作っているようです。 コードを見せてもらえますか?
また、ライブラリの縮小されていないバージョンを使用する場合は、dist /peer.jsにあります。
また、古いpeerjsバージョンを使用しているようです。最新のnpmバージョンは0.3.16です。
https://www.npmjs.com/package/peerjs
もちろん。 私のコードはこれです:
var P2PMaze = P2PMaze || {};
// global variable
var map;
var backgroudLayer;
var blockedLayer;
var player;
var toOpponentPlayer = [];
var cursor;
var items;
var logicalOrder = {};
var playerOrder = 1; // the player starts to 1 for compare the item to take
var createdOpponentPlayer = false;
var opponentPlayer;
var jump = false;
var hitPlatformO;
P2PMaze.send = function(data){
var id = P2PMaze.peer.getConnectTo().getId();
var conn = P2PMaze.peer.conn(id);
P2PMaze.peer.sendData(conn, data);
};
P2PMaze.GameMultiplayer = function(){
console.log("%cStarting GameMultiplayer", "color:black; background:yellow");
};
P2PMaze.GameMultiplayer.prototype = {
preload: function() {
this.game.load.tilemap('temp', 'assets/tilemaps/temp.json', null, Phaser.Tilemap.TILED_JSON);
this.game.load.image('tempImage', 'assets/images/tiles.png');
this.load.spritesheet('player', 'assets/images/dude.png',32,48);
this.load.image('redcup', 'assets/images/estintore_grande.png');
this.load.image('greycup', 'assets/images/greencup.png');
this.load.image('bluecup', 'assets/images/bluecup.png');
},
create: function() {
...
var keyPlayer = {"key": P2PMaze.peer.getId()};
var posx ={"posx":player.position.x};
var posy = {"posy":player.position.y}
var key = {"Key":player.key};
toOpponentPlayer.push(keyPlayer);
toOpponentPlayer.push(posx);
toOpponentPlayer.push(posy);
toOpponentPlayer.push(key);
P2PMaze.send(toOpponentPlayer);
// move player with cursor key
cursor = this.game.input.keyboard.createCursorKeys();
},
update: function(){
// creation opponent player
if(P2PMaze.dataReceived!=undefined && createdOpponentPlayer==false){
opponentPlayer = this.game.add.sprite(P2PMaze.dataReceived[1].posx, P2PMaze.dataReceived[2].posy, 'player');
// create the phisics body. Can be a single object (as in this case) or of array of Objects
this.game.physics.arcade.enable(opponentPlayer);
// Player physics properties. Give the little guy a slight bounce.
opponentPlayer.body.bounce.y = 0.2;
opponentPlayer.body.gravity.y = PLAYER.GRAVITY_Y;
opponentPlayer.body.collideWorldBounds = true;
// see image: 0, 1, 2, 3 is the frame for runring to left
// see image: 5, 6, 7, 8 is the frame for running to right
// 10 = frames per second
// the 'true' param tell the animation to loop
opponentPlayer.animations.add('left', [0, 1, 2, 3], 10, true);
opponentPlayer.animations.add('right', [5, 6, 7, 8], 10, true);
//the camera will follow the player in the world
this.game.camera.follow(opponentPlayer);
// the opponent player start to 4 frame
opponentPlayer.frame = 4;
createdOpponentPlayer=true;
}
// collisio to do
// https://phaser.io/docs/2.4.4/Phaser.Physics.Arcade.html#collide
var hitPlatform;
hitPlatform = this.game.physics.arcade.collide(player, blockedLayer);
if(opponentPlayer!=undefined){
hitPlatformO = this.game.physics.arcade.collide(opponentPlayer, blockedLayer);
}
// player movement
// NB: comment these to gain less control over the sprite
// player.body.velocity.y = 0;
player.body.velocity.x = PLAYER.VELOCITY_X_START;
if(opponentPlayer!=undefined){
opponentPlayer.body.velocity.x = PLAYER.VELOCITY_X_START;
}
if(this.game.input.activePointer.justPressed()){
// move on the direction of the input
this.game.physics.arcade.moveToPointer(player, 150);
// player.animations.play('left');
}
var updatePos = [];
if(cursor.left.isDown){
player.body.velocity.x = PLAYER.VELOCITY_X_LEFT;
player.animations.play('left');
// send to opponent player the left position of player
var keyupdating = {"key": "left"};
var updateX ={"updatePosx":player.x};
var updateY ={"updatePosy":player.y};
updatePos.push(keyupdating);
updatePos.push(updateX);
updatePos.push(updateY);
// SEND
P2PMaze.send(updatePos);
}else if(cursor.right.isDown){
player.body.velocity.x = PLAYER.VELOCITY_X_RIGHT;
player.animations.play('right');
var keyupdating = {"key": "right"};
var updateX ={"updatePosx":player.x};
var updateY ={"updatePosy":player.y};
updatePos.push(keyupdating);
updatePos.push(updateX);
updatePos.push(updateY);
P2PMaze.send(updatePos);
}
else{
// Stand still
player.animations.stop();
player.frame = 4;
}
// if(cursor.up.isDown && player.body.touching.down){
if(cursor.up.isDown && hitPlatform){
player.body.velocity.y = -250;
}
// move the opponent player to specific LEFT position
if(opponentPlayer!=undefined && P2PMaze.dataReceived[0].key=="left"){
var posx = P2PMaze.dataReceived[1].updatePosx;
var posy = P2PMaze.dataReceived[2].updatePosy;
// when the opponent player came to specific position + or - 1 (for avoid loop), stop the animation and set the frame to 4
if(Math.floor(opponentPlayer.x) === Math.floor(posx) ||
Math.floor(opponentPlayer.x) === (Math.floor(posx) +1) ||
Math.floor(opponentPlayer.x) === (Math.floor(posx) -1))
{
opponentPlayer.animations.stop();
opponentPlayer.frame = 4;
}else {
this.game.physics.arcade.moveToXY(opponentPlayer,Math.floor(posx),Math.floor(posy));
opponentPlayer.animations.play('left');
}
}
// move the opponent player to specific RIGHT position
if(opponentPlayer!=undefined && P2PMaze.dataReceived[0].key=="right"){
var posx = P2PMaze.dataReceived[1].updatePosx;
var posy = P2PMaze.dataReceived[2].updatePosy;
// when the opponent player came to specific position + or - 1 (for avoid loop), stop the animation and set the frame to 4
if(Math.floor(opponentPlayer.x) === Math.floor(posx) ||
Math.floor(opponentPlayer.x) === (Math.floor(posx) +1) ||
Math.floor(opponentPlayer.x) === (Math.floor(posx) -1))
{
opponentPlayer.animations.stop();
opponentPlayer.frame = 4;
}else {
this.game.physics.arcade.moveToXY(opponentPlayer,Math.floor(posx),Math.floor(posy));
opponentPlayer.animations.play('right');
}
}
// Checks for overlaps between two game objects.
// - The first object or array of objects to check.
// - The second object or array of objects to check.
// - An optional callback function that is called if the objects overlap.
// The two objects will be passed to this function in the same order in which you specified them,
// unless you are checking Group vs. Sprite, in which case Sprite will always be the first parameter.
// - A callback function that lets you perform additional checks against the two objects if
// they overlap. If this is set then overlapCallback will only be called if
// this callback returns true
// - The context in which to run the callbacks.
this.game.physics.arcade.overlap(player, items, this.collect, this.choiceItems, this);
if(opponentPlayer!=undefined){
this.game.physics.arcade.overlap(opponentPlayer, items, this.collect, this.choiceItems, this);
}
},
...
私は単一の接続を作成しようとします。 グローバル変数var conn = undefined
を作成し、更新で接続を割り当てます。
if(P2PMaze.dataReceived!=undefined && createdOpponentPlayer==false){
opponentPlayer = this.game.add.sprite(P2PMaze.dataReceived[1].posx, P2PMaze.dataReceived[2].posy, 'player');
....
var id = P2PMaze.peer.getConnectTo().getId();
conn = P2PMaze.peer.conn(id);
createdOpponentPlayer=true;
}
と
...
...
var updatePos = [];
if(cursor.left.isDown){
player.body.velocity.x = PLAYER.VELOCITY_X_LEFT;
player.animations.play('left');
// send to opponent player the left position of player
if(conn!=undefined){
var keyupdating = {"key": "left"};
var updateX ={"updatePosx":player.x};
var updateY ={"updatePosy":player.y};
updatePos.push(keyupdating);
updatePos.push(updateX);
updatePos.push(updateY);
P2PMaze.send(updatePos);
}
}else if(cursor.right.isDown){
player.body.velocity.x = PLAYER.VELOCITY_X_RIGHT;
player.animations.play('right');
// send to opponent player the right position of player
if(conn!=undefined){
var keyupdating = {"key": "right"};
var updateX ={"updatePosx":player.x};
var updateY ={"updatePosy":player.y};
updatePos.push(keyupdating);
updatePos.push(updateX);
updatePos.push(updateY);
P2PMaze.send(updatePos);
}
}
....
しかし、このように私のマルチプレイヤーは機能しません。 このために私は正しいアプローチは
var id = P2PMaze.peer.getConnectTo().getId();
var conn = P2PMaze.peer.conn(id);
P2PMaze.peer.sendData(conn, data);
P2PMaze.peer
は、フォームで行う割り当てです。
libディレクトリ内にある最小バージョンを使用しています。
私が間違っていない場合は、ここにあります:
P2PMaze.send = function(data){
var id = P2PMaze.peer.getConnectTo().getId();
var conn = P2PMaze.peer.conn(id);
P2PMaze.peer.sendData(conn, data);
};
メッセージを送信するたびに、新しい接続を開いています。 作成した接続をどこかに保存し、すべてのメッセージに使用する必要があります。たとえば、次のようになります。
P2PMaze.connect = function(){
var id = P2PMaze.peer.getConnectTo().getId();
P2PMaze.otherPlayer = P2PMaze.peer.conn(id);
};
P2PMaze.send = function(data){
P2PMaze.otherPlayer.send(data);
}
接続オブジェクトからsend
メソッドを使用します。
https://peerjs.com/docs/#dataconnection -send
そして、接続でdata
イベントをリッスンします。
https://peerjs.com/docs/#dataconnection -on-data
たぶん私はあなたのコードを理解していませんでした。 connはpeerjsであり、sendDataは接続オブジェクトから送信されると思いますか? そうでない場合は、それらの関数のコードも投稿してください。
conn
とsendData
は、私のクラスの2つのメソッドです。 :
`
/**
* Class that create a peer. The param are:
* <strong i="9">@param</strong> {string} id the id of my peer
* <strong i="10">@param</strong> {string} host the path of server
* <strong i="11">@param</strong> {int} port the number of port
* <strong i="12">@param</strong> {path} pht the app name of the server. It is useful for establish the connection
*/
class PeerClient {
constructor(id, h, p, pth){
this._id = id;
this._host = h;
this._port = p;
this._path = pth;
this._peerToConnect = undefined;
this._peer = new Peer(this._id, {
host: this._host, // 'localhost',
port: this._port, // 9000,
path: this._path // '/peerjs'
});
}
/**
* Return the id of my peer
*/
getId() {
return this._id;
}
/**
* Return the peer connected with me
*/
getConnectTo() {
return this._peerToConnect;
}
/**
* This metohd is used for setting the peer with i want connect. It used when I receive the request of
* connection by a specific peer.
* <strong i="13">@param</strong> {peer} peerToConnect
*/
setConnectTo(peerToConnect){
this._peerToConnect = new PeerClient(peerToConnect, this._host, this._port, this._path);
}
/**
* This allow to create the player
* <strong i="14">@param</strong> {*} x initial position x
* <strong i="15">@param</strong> {*} y initial position y
* <strong i="16">@param</strong> {*} identifierString the unique string by which we'll identify the image later in our code.
*/
createPlayer(x,y, identifierString){
return P2PMaze.game.add.sprite(x,y,identifierString)
}
/**
* Make the peer avilable for the connection
*/
openConnection() {
this._peer.on('open', function(id_peer) {
console.log('My peer ID is: ' + id_peer); //DEBUG
});
}
/**
* Closes the data connection gracefully, cleaning up underlying DataChannels and PeerConnections.
* REF:https://stackoverflow.com/questions/25797345/peerjs-manually-close-the-connection-between-peers
* <strong i="17">@param</strong> {object} conn i
*/
closeConnection(conn) {
conn.on('open', function(){
conn.close();
alert("connection close");
});
}
/**
* See the error of peer . * .
*/
seeError(){
this._peer.on('error', function(err){
alert(err.message);
});
}
/**
* This method is used for create a connection
* <strong i="18">@param</strong> {object} id_another_peer is the id of peer that I want to connect
*/
conn(id_another_peer) {
return this._peer.connect(id_another_peer);
}
/**
* Sharing data among peer. The first param is the value that return from the previusly method (conn)
* <strong i="19">@param</strong> {object} conn this is the connection
* <strong i="20">@param</strong> {object} data this is the data to send
*/
sendData(conn, data) {
conn.on('open', function(){
conn.send(data);
});
}
/**
* This method is used for receive data.
* <strong i="21">@param</strong> {method} callback return the data that arrived from sender
*/
enableReceptionData(callback) {
this._peer.on('connection', function(conn) {
conn.on('data', function(data){
console.log("--------------------------------");
console.log("MESSAGE RECEIVED : \n");
console.log(data);
console.log("--------------------------------");
callback(data);
});
});
}
}`
私はあなたが私に提案するこの解決策で試しましたが、それはうまくいきません。
言い換えれば、複数の接続を作成すると機能します。 単一の接続を作成すると、最初は機能しますが(他のピアの作成を確認できるため)、彼はデータの送信を停止します。 理由はわかりません。
私はpeerjsの最新(私は思う)最新バージョンを使用しています。 サイトが示す0.3.9。
sendData(conn, data) {
conn.on('open', function(){
conn.send(data);
});
}
ここでは、新しいリスナーを作成しており、イベント「open」が発生すると、データを送信します。 データを送信するだけです。
sendData(conn, data) {
conn.send(data);
}
Openイベントは、接続が確立されているかどうかを確認するためのものです。 それを確認することも、データを送信して接続がまだ開いていない場合は失敗させることもできます。
'open'イベントは、接続を開いた後に1回送信されるため、複数の接続でのみ機能します。 2回目にデータを送信するときは、「open」イベントを無期限に待機します。これは、前述したように、接続が確立されたときに1回だけ発行されます。
したがって、私が提案した変更を適用し、接続を1回だけ作成します。
とても良いです。 ありがとう。 理解できませんでした。 コードを試すと、結果を投稿します。 ありがとうありがとうありがとう。
動作しますが、データが届きません。
`
/ **
※この方法はデータの受信に使用します。
* @param {method}コールバックは、送信者から到着したデータを返します
* /
enableReceptionData(callback) {
this._peer.on('connection', function(conn) {
conn.on('data', function(data){
console.log("--------------------------------");
console.log("message received : \n");
console.log(data);
console.log("--------------------------------");
callback(data);
});
});
}`
コンソールから、データの接続と共有は問題ないことがわかりますが、この方法は機能しません。 理由を説明してもらえますか?
this._peer
は接続オブジェクトですか?
このようなもの?
this._peer = peer.connect('id')
また、enableReceptionDataをどこで呼び出しているのかわかりません。ローカルコンピューターでテストしている場合、接続が非常に高速であるため、 peer.connect(id)
を呼び出した直後に「connection」イベントが開始される可能性があることに注意してください。 。 したがって、次のようなことを行う必要があります。
this._peer = peer.connect('id');
enableReceptionData(callback);
接続の作成とリスナー(enableReceptionData)の間で他のことを行うと、「接続」イベントが欠落している可能性があります。
土地を取り消す場合、 conn.on('open', function(){ .. }
は省略できます。 しかし、コンソールで印刷する場合:
`
enableReceptionData(callback) {
console.log(conn); // IMPORTANT
this._peer.on('connection', function(conn) {
conn.on('data', function(data){
console.log("--------------------------------");
console.log("message received : \n");
console.log(data);
console.log("--------------------------------");
callback(data);
});
});
}
`
私はこのメッセージを取得します:
d {_events:{…}、options:{…}、open:false、type: "data"、peer: "zzz-6UsEonI"、…}
オープンが偽であることがわかります。
私の新しいPeerClassはこれです:
`/ **
*ピアを作成するクラス。 パラメータは次のとおりです。
* @param {string} id私のピアのID
* @param {string}はサーバーのパスをホストします
* @param {int} portポートの数
* @param {path} phtサーバーのアプリ名。 接続を確立するのに便利です
* /
クラスPeerClient {
constructor(id, h, p, pth){
this._id = id;
this._host = h;
this._port = p;
this._path = pth;
this._peerToConnect = undefined;
this._conn = undefined;
this._peer = new Peer(this._id, {
host: this._host, // 'localhost',
port: this._port, // 9000,
path: this._path // '/peerjs'
});
}
/**
* Return the id of my peer
*/
getId() {
return this._id;
}
/**
* Return the peer connected with me
*/
getConnectTo() {
return this._peerToConnect;
}
/**
* This metohd is used for setting the peer with i want connect. It used when I receive the request of
* connection by a specific peer.
* <strong i="28">@param</strong> {peer} peerToConnect
*/
setConnectTo(peerToConnect){
this._peerToConnect = new PeerClient(peerToConnect, this._host, this._port, this._path);
}
/**
* This allow to create the player
* <strong i="29">@param</strong> {*} x initial position x
* <strong i="30">@param</strong> {*} y initial position y
* <strong i="31">@param</strong> {*} identifierString the unique string by which we'll identify the image later in our code.
*/
createPlayer(x,y, identifierString){
return P2PMaze.game.add.sprite(x,y,identifierString)
}
/**
* Make the peer avilable for the connection
*/
open() {
this._peer.on('open', function(id_peer) {
console.log('My peer ID is: ' + id_peer); //DEBUG
});
}
openConnection(){
this._conn.on('open', function(data){
console.log(data);
});
}
/**
* Closes the data connection gracefully, cleaning up underlying DataChannels and PeerConnections.
* REF:https://stackoverflow.com/questions/25797345/peerjs-manually-close-the-connection-between-peers
* <strong i="32">@param</strong> {object} conn i
*/
closeConnection(conn) {
conn.on('open', function(){
conn.close();
alert("CONNESSIONE CHIUSA"); // TODO mettere un qualche messaggio
});
}
/**
* See the error of peer . * .
*/
seeError(){
this._peer.on('error', function(err){
alert(err.message);
});
}
/**
* This method is used for create a connection
* <strong i="33">@param</strong> {object} id_another_peer is the id of peer that I want to connect
*/
conn(id_another_peer) {
this._conn = this._peer.connect(id_another_peer);
return this._conn;
}
/**
* return the connection
*/
getConnection(){
return this._conn;
}
/**
* Sharing data among peer. The first param is the value that return from the previusly method (conn)
* <strong i="34">@param</strong> {object} conn this is the connection
* <strong i="35">@param</strong> {object} data this is the data to send
*/
// sendData(data) {
// this._conn.on('open', function(){
// this._conn.send(data);
// });
// }
sendData(data) {
this._conn.send(data);
}
/**
* This method is used for receive data.
* <strong i="36">@param</strong> {method} callback return the data that arrived from sender
*/
enableReceptionData(callback) {
this._peer.on('connection', function(conn) {
console.log(conn);
conn.on('data', function(data){
console.log("--------------------------------");
console.log("MESSAGE UPDATED : \n");
console.log(data);
console.log("--------------------------------");
callback(data);
});
});
}
}`
で接続を開くと:
conn(id_another_peer) {
this._conn = this._peer.connect(id_another_peer);
return this._conn;
}
すぐにイベントを聞き始める必要があるので、次のようにします。
conn(id_another_peer) {
this._conn = this._peer.connect(id_another_peer);
this.enableReceptionData();
return this._conn;
}
また、前に説明しなかった申し訳ありませんが、PeerServerに接続すると「open」イベントが発行されるため、他のピアに接続する前にそのイベントをリッスンする必要があります。新しいPeer( id):
var peer = new Peer();
peer.on('open', function(id) {
console.log('My peer ID is: ' + id);
// here you have your ID and you can start opening connections to other peers
});
したがって、 new Peer()
後にコンストラクターで「open」イベントをリッスンし、「open」イベントを取得すると、他のピアに接続できます。
'open'イベントの場合は、前に説明したとおりです。新しいPeer()の直後にリッスンする必要があります。そうしないと、リッスンするのに時間がかかりすぎるとイベントを見逃す可能性があります。
しばらくお待ちください。コードを実装したらすぐに結果を投稿します:+1:
いいえ、これは引き続き機能しません。
私は古い解決策で解決しました。
`
sendData(data) {
this._conn.on('open', function(){
this.send(data);
});
}`
これは良い妥協と見なすことができますか? このように、新しいリスナーを作成することはできませんが、同じ接続を使用します。 より洗練された解決策の1つは、この関数を1回だけ使用してから、でデータを送信することです。
`
sendData(data) {
this._conn.send(data);
}`
しかし、私は前にテストしたいです。 あなたは良い解決策だと思いますか?
明日も続ける必要があるのではないかと思います。 コードをhttps://gist.github.com/にアップロードし
だから私はもっとよく見ることができます、あなたはそれを非公開にして、他の人に見られたくないのであれば私に電子メールでリンクを送ることができます。
私のメールアドレス: [email protected]
機会をありがとうございました。 現在、私のコードはオープンな建設現場です。 手配次第、利用可能にします。 それまでの間、時間があれば、最後に示した解決策が問題への良いアプローチになるかどうか教えていただけますか?
もう一度ありがとう、また会いましょう:)
2番目の解決策が強く推奨されます。 最初のものは、メッセージごとに1つずつ、多くの接続を作成しているため、多くの問題を引き起こします。これにより、PeerJSから最初に発生したエラーが発生するだけでなく、リソース(CPU、RAM)も無効になります。 、 通信網)
2番目の解決策で、エラーを回避できることを確認します。 このため、今は2つの接続しかありません。
最も参考になるコメント
2番目の解決策で、エラーを回避できることを確認します。 このため、今は2つの接続しかありません。
他のデータ交換は同じ接続で実行されます。 @kidandcatにご支援いただきありがとうございます。 :+1: