每个客户端的 Meteor 同步内容
Meteor synchronus content for each client
我正在尝试用 meteor 在 three.js 中制作一条多人游戏蛇,一个玩家只能控制一条蛇的效果很好(尽管我们只有 3 个指定的用户可以控制 3 条蛇中的一条目前)
现在的问题是,你在你的屏幕上看不到其他玩家的动作,他们也看不到你的,就像每个人都有自己的游戏一样。
我的 HTML 看起来像这样:(client.html)
<div>
{{> loginButtons align="right"}}
{{> spiel}}
<div id="msg">
{{> messages}}
</div>
<div id="inp">
{{> input}}
</div>
</div>
里面有游戏的div就是模板'spiel'
<template name="spiel">
<div id="container"></div>
</template>
我用(main.js 在我的客户端文件夹中填充容器)
Template.spiel.rendered = function(){
init();
addSchlange();
addSchlange2();
addSchlange3();
animate();
}
我在那里调用的代码看起来像这样(test.js 在我的客户端文件夹的 lib 文件夹中)
我不知道是什么导致了这个问题,所以我将 post 整个代码(不要因此而恨我 ^^)
var camera, scene, renderer;
init =function (){
//Allgemeines
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xbbbbbb, 2000, 10000 );
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.y =50;
camera.rotation.x=-1.571;
renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true});
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setClearColor( scene.fog.color, 1 );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.getElementById("container");
container.appendChild( renderer.domElement );
var ggeometry = new THREE.PlaneBufferGeometry( 500, 500 );
var gmaterial = new THREE.MeshPhongMaterial( { emissive: 0xbbbbbb } );
var ground = new THREE.Mesh( ggeometry, gmaterial );
ground.position.set( 0, -250, 0 );
ground.rotation.x = -Math.PI/2;
scene.add( ground );
ground.receiveShadow = true;
// LIGHTS
var ambient = new THREE.AmbientLight( 0x222222 );
scene.add( ambient );
var light = new THREE.DirectionalLight( 0xebf3ff, 1.6 );
light.position.set( 0, 140, 500 ).multiplyScalar( 1.1 );
scene.add( light );
light.castShadow = true;
light.shadowMapWidth = 1024;
light.shadowMapHeight = 2048;
var d = 390;
light.shadowCameraLeft = -d;
light.shadowCameraRight = d;
light.shadowCameraTop = d * 1.5;
light.shadowCameraBottom = -d;
light.shadowCameraFar = 3500;
light.shadowCameraVisible = true;
var light = new THREE.DirectionalLight( 0x497f13, 1 );
light.position.set( 0, -1, 0 );
scene.add( light );
}
addSchlange = function () {
var loader = new THREE.JSONLoader();
var callbackModel = function( geometry, materials ) {
Kopf1 = new THREE.Mesh (geometry, new THREE.MeshFaceMaterial(materials));
Kopf1.scale.set( 1.5,1.5, 1.5 );
Kopf1.position.set(-1.5,0,0);
var xDirection = Kopf1.position.x;
var yDirection = Kopf1.position.y;
pivot1 = new THREE.Object3D();
pivot1.add(Kopf1);
scene.add(pivot1);
};
loader.load( 'SchlangeKOPFnoTEX.js', callbackModel );
Schlange1 = new Array();
}
addSchlange2 = function () {
var loader = new THREE.JSONLoader();
var callbackModel = function( geometry, materials ) {
Kopf2 = new THREE.Mesh (geometry, new THREE.MeshFaceMaterial(materials));
Kopf2.scale.set( 1.5,1.5, 1.5 );
Kopf2.position.set(-3,0,-9.75);
var xDirection = Kopf2.position.x;
var yDirection = Kopf2.position.y;
pivot2 = new THREE.Object3D();
pivot2.add(Kopf2);
scene.add(pivot2);
};
loader.load( 'SchlangeKOPF2.js', callbackModel );
Schlange2 = new Array();
Change2 = new Array();
}
addSchlange3 = function(){
var loader = new THREE.JSONLoader();
var callbackModel = function( geometry, materials ) {
Kopf3 = new THREE.Mesh (geometry, new THREE.MeshFaceMaterial(materials));
Kopf3.scale.set( 1.5,1.5, 1.5 );
Kopf3.position.set(-3.25,0,9.5);
var xDirection = Kopf2.position.x;
var yDirection = Kopf2.position.y;
pivot3 = new THREE.Object3D();
pivot3.add(Kopf3);
scene.add(pivot3);
};
loader.load( 'SchlangeKOPF3.js', callbackModel );
}
var changeDirection = "D";
var lastPOS = "D";
var changeDirection2 = "D";
var lastPOS2 = "D";
var changeDirection3 = "D";
var lastPOS3 = "D";
animate = function(){
renderer.render( scene, camera );
$(window).bind('keyup', function (event) {
var keycode;
keycode = event.keyCode;
// SCHLANGE 1
if(Meteor.user().username == 'Babsi'){
if(keycode == 65){
lastPOS = changeDirection;
if(lastPOS !="D"){
changeDirection = "A";
}
}
if(keycode == 83){
lastPOS = changeDirection;
if(lastPOS != "W"){
changeDirection = "S";
}
}
if(keycode == 68){
lastPOS = changeDirection;
if(lastPOS != "A"){
changeDirection = "D";
}
}
if(keycode == 87){
lastPOS = changeDirection;
if(lastPOS != "S"){
changeDirection = "W";
}
}
}
//SCHLANGE 2
if(Meteor.user().username == 'Jacky'){
if(keycode == 65){
lastPOS2 = changeDirection2;
if(lastPOS2 !="D"){
changeDirection2 = "A";
}
}
if(keycode == 83){
lastPOS2 = changeDirection2;
if(lastPOS2 != "W"){
changeDirection2 = "S";
}
}
if(keycode == 68){
lastPOS2 = changeDirection2;
if(lastPOS2 != "A"){
changeDirection2 = "D";
}
}
if(keycode == 87){
lastPOS2 = changeDirection2;
if(lastPOS2 != "S"){
changeDirection2 = "W";
}
}
}
//SCHLANGE 3
if(Meteor.user().username == 'Manu'){
if(keycode == 65){
lastPOS3 = changeDirection3;
if(lastPOS3 !="D"){
changeDirection3 = "A";
}
}
if(keycode == 83){
lastPOS3 = changeDirection3;
if(lastPOS3 != "W"){
changeDirection3 = "S";
}
}
if(keycode == 68){
lastPOS3 = changeDirection3;
if(lastPOS3 != "A"){
changeDirection3 = "D";
}
}
if(keycode == 87){
lastPOS3 = changeDirection3;
if(lastPOS3 != "S"){
changeDirection3 = "W";
}
}
}
});
if(typeof pivot1 !='undefined') {
if(changeDirection == "A"){
pivot1.position.x -= 0.2;
pivot1.rotation.y = 1.571*2;
if(pivot1.position.x<=-37){
pivot1.position.x=40;
pivot1.position.x -= 0.2;
}
}
if(changeDirection == "D"){
pivot1.position.x += 0.2;
pivot1.rotation.y = 0;
if(pivot1.position.x>=37){
pivot1.position.x=-40;
pivot1.position.x -= 0.2;
}
}
if(changeDirection == "S"){
pivot1.position.z += 0.2;
pivot1.rotation.y = -1.571;
if(pivot1.position.z>=38){
pivot1.position.z=-38;
pivot1.position.z -= 0.2;
}
}
if(changeDirection == "W"){
pivot1.position.z -= 0.2;
pivot1.rotation.y = 1.571;
if(pivot1.position.z<=-38){
pivot1.position.z=38;
pivot1.position.z -= 0.2;
}
}
}
if(typeof pivot2 !='undefined') {
if(changeDirection2 == "W"){
pivot2.position.z -= 0.2;
pivot2.rotation.y = 1.571;
if(pivot2.position.z<=-38){
pivot2.position.z=38;
pivot2.position.z -= 0.2;
}
}
if(changeDirection2 == "S"){
pivot2.position.z += 0.2;
pivot2.rotation.y = -1.571;
if(pivot2.position.z>=38){
pivot2.position.z=-38;
pivot2.position.z -= 0.2;
}
}
if(changeDirection2 == "D"){
pivot2.position.x += 0.2;
pivot2.rotation.y = 0;
if(pivot2.position.x>=37){
pivot2.position.x=-40;
pivot2.position.x -= 0.2;
}
}
if(changeDirection2 == "A"){
pivot2.position.x -= 0.2;
pivot2.rotation.y = 1.571*2;
if(pivot2.position.x<=-37){
pivot2.position.x=40;
pivot2.position.x -= 0.2;
}
}
}
if(typeof pivot3 !='undefined') {
if(changeDirection3 == "W"){
pivot3.position.z -= 0.2;
pivot3.rotation.y = 1.571;
if(pivot3.position.z<=-38){
pivot3.position.z=38;
pivot3.position.z -= 0.2;
}
}
if(changeDirection3 == "S"){
pivot3.position.z += 0.2;
pivot3.rotation.y = -1.571;
if(pivot3.position.z>=38){
pivot3.position.z=-38;
pivot3.position.z -= 0.2;
}
}
if(changeDirection3 == "D"){
pivot3.position.x += 0.2;
pivot3.rotation.y = 0;
if(pivot3.position.x>=37){
pivot3.position.x=-40;
pivot3.position.x -= 0.2;
}
}
if(changeDirection3 == "A"){
pivot3.position.x -= 0.2;
pivot3.rotation.y = 1.571*2;
if(pivot3.position.x<=-37){
pivot3.position.x=40;
pivot3.position.x -= 0.2;
}
}
}
requestAnimationFrame( animate );
}
Meteor 跨客户端同步 数据。如果您希望每个客户端都看到其他客户端的蛇的位置,您需要将这些位置存储在所有客户端都订阅的集合中。
常用代码:
Snakes = new Meteor.Collection('snakes');
然后在 rendered
回调中,您需要在 Snakes
中插入或更新文档。将该文档的 _id
设置为一个变量,然后在您的动画代码中您应该调用类似 Snakes.update(_id, {position: newPosition})
的内容。不要每秒调用 60 次;每秒一次或两次可能是连接可以处理的最多。这些更新会自动同步到其他客户端;使用 observeChanges
侦听器来处理其他客户端的更新,并告诉 Three.js 如何更新蛇的位置。
另请参阅 Meteor Streams 包。它使您可以做基本相同的事情,但无需写入数据库; “更新”实际上只是成为在所有连接的客户端上触发的事件。因此,对于您的用例来说,它的性能可能要高得多,我想这将是一个首要考虑因素。尽管网站上说该项目已被放弃,但我已经在当前(Meteor 1.0.3.2)项目中使用了 Meteor Streams,并且运行良好。
我正在尝试用 meteor 在 three.js 中制作一条多人游戏蛇,一个玩家只能控制一条蛇的效果很好(尽管我们只有 3 个指定的用户可以控制 3 条蛇中的一条目前)
现在的问题是,你在你的屏幕上看不到其他玩家的动作,他们也看不到你的,就像每个人都有自己的游戏一样。
我的 HTML 看起来像这样:(client.html)
<div>
{{> loginButtons align="right"}}
{{> spiel}}
<div id="msg">
{{> messages}}
</div>
<div id="inp">
{{> input}}
</div>
</div>
里面有游戏的div就是模板'spiel'
<template name="spiel">
<div id="container"></div>
</template>
我用(main.js 在我的客户端文件夹中填充容器)
Template.spiel.rendered = function(){
init();
addSchlange();
addSchlange2();
addSchlange3();
animate();
}
我在那里调用的代码看起来像这样(test.js 在我的客户端文件夹的 lib 文件夹中) 我不知道是什么导致了这个问题,所以我将 post 整个代码(不要因此而恨我 ^^)
var camera, scene, renderer;
init =function (){
//Allgemeines
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xbbbbbb, 2000, 10000 );
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.y =50;
camera.rotation.x=-1.571;
renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true});
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setClearColor( scene.fog.color, 1 );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.getElementById("container");
container.appendChild( renderer.domElement );
var ggeometry = new THREE.PlaneBufferGeometry( 500, 500 );
var gmaterial = new THREE.MeshPhongMaterial( { emissive: 0xbbbbbb } );
var ground = new THREE.Mesh( ggeometry, gmaterial );
ground.position.set( 0, -250, 0 );
ground.rotation.x = -Math.PI/2;
scene.add( ground );
ground.receiveShadow = true;
// LIGHTS
var ambient = new THREE.AmbientLight( 0x222222 );
scene.add( ambient );
var light = new THREE.DirectionalLight( 0xebf3ff, 1.6 );
light.position.set( 0, 140, 500 ).multiplyScalar( 1.1 );
scene.add( light );
light.castShadow = true;
light.shadowMapWidth = 1024;
light.shadowMapHeight = 2048;
var d = 390;
light.shadowCameraLeft = -d;
light.shadowCameraRight = d;
light.shadowCameraTop = d * 1.5;
light.shadowCameraBottom = -d;
light.shadowCameraFar = 3500;
light.shadowCameraVisible = true;
var light = new THREE.DirectionalLight( 0x497f13, 1 );
light.position.set( 0, -1, 0 );
scene.add( light );
}
addSchlange = function () {
var loader = new THREE.JSONLoader();
var callbackModel = function( geometry, materials ) {
Kopf1 = new THREE.Mesh (geometry, new THREE.MeshFaceMaterial(materials));
Kopf1.scale.set( 1.5,1.5, 1.5 );
Kopf1.position.set(-1.5,0,0);
var xDirection = Kopf1.position.x;
var yDirection = Kopf1.position.y;
pivot1 = new THREE.Object3D();
pivot1.add(Kopf1);
scene.add(pivot1);
};
loader.load( 'SchlangeKOPFnoTEX.js', callbackModel );
Schlange1 = new Array();
}
addSchlange2 = function () {
var loader = new THREE.JSONLoader();
var callbackModel = function( geometry, materials ) {
Kopf2 = new THREE.Mesh (geometry, new THREE.MeshFaceMaterial(materials));
Kopf2.scale.set( 1.5,1.5, 1.5 );
Kopf2.position.set(-3,0,-9.75);
var xDirection = Kopf2.position.x;
var yDirection = Kopf2.position.y;
pivot2 = new THREE.Object3D();
pivot2.add(Kopf2);
scene.add(pivot2);
};
loader.load( 'SchlangeKOPF2.js', callbackModel );
Schlange2 = new Array();
Change2 = new Array();
}
addSchlange3 = function(){
var loader = new THREE.JSONLoader();
var callbackModel = function( geometry, materials ) {
Kopf3 = new THREE.Mesh (geometry, new THREE.MeshFaceMaterial(materials));
Kopf3.scale.set( 1.5,1.5, 1.5 );
Kopf3.position.set(-3.25,0,9.5);
var xDirection = Kopf2.position.x;
var yDirection = Kopf2.position.y;
pivot3 = new THREE.Object3D();
pivot3.add(Kopf3);
scene.add(pivot3);
};
loader.load( 'SchlangeKOPF3.js', callbackModel );
}
var changeDirection = "D";
var lastPOS = "D";
var changeDirection2 = "D";
var lastPOS2 = "D";
var changeDirection3 = "D";
var lastPOS3 = "D";
animate = function(){
renderer.render( scene, camera );
$(window).bind('keyup', function (event) {
var keycode;
keycode = event.keyCode;
// SCHLANGE 1
if(Meteor.user().username == 'Babsi'){
if(keycode == 65){
lastPOS = changeDirection;
if(lastPOS !="D"){
changeDirection = "A";
}
}
if(keycode == 83){
lastPOS = changeDirection;
if(lastPOS != "W"){
changeDirection = "S";
}
}
if(keycode == 68){
lastPOS = changeDirection;
if(lastPOS != "A"){
changeDirection = "D";
}
}
if(keycode == 87){
lastPOS = changeDirection;
if(lastPOS != "S"){
changeDirection = "W";
}
}
}
//SCHLANGE 2
if(Meteor.user().username == 'Jacky'){
if(keycode == 65){
lastPOS2 = changeDirection2;
if(lastPOS2 !="D"){
changeDirection2 = "A";
}
}
if(keycode == 83){
lastPOS2 = changeDirection2;
if(lastPOS2 != "W"){
changeDirection2 = "S";
}
}
if(keycode == 68){
lastPOS2 = changeDirection2;
if(lastPOS2 != "A"){
changeDirection2 = "D";
}
}
if(keycode == 87){
lastPOS2 = changeDirection2;
if(lastPOS2 != "S"){
changeDirection2 = "W";
}
}
}
//SCHLANGE 3
if(Meteor.user().username == 'Manu'){
if(keycode == 65){
lastPOS3 = changeDirection3;
if(lastPOS3 !="D"){
changeDirection3 = "A";
}
}
if(keycode == 83){
lastPOS3 = changeDirection3;
if(lastPOS3 != "W"){
changeDirection3 = "S";
}
}
if(keycode == 68){
lastPOS3 = changeDirection3;
if(lastPOS3 != "A"){
changeDirection3 = "D";
}
}
if(keycode == 87){
lastPOS3 = changeDirection3;
if(lastPOS3 != "S"){
changeDirection3 = "W";
}
}
}
});
if(typeof pivot1 !='undefined') {
if(changeDirection == "A"){
pivot1.position.x -= 0.2;
pivot1.rotation.y = 1.571*2;
if(pivot1.position.x<=-37){
pivot1.position.x=40;
pivot1.position.x -= 0.2;
}
}
if(changeDirection == "D"){
pivot1.position.x += 0.2;
pivot1.rotation.y = 0;
if(pivot1.position.x>=37){
pivot1.position.x=-40;
pivot1.position.x -= 0.2;
}
}
if(changeDirection == "S"){
pivot1.position.z += 0.2;
pivot1.rotation.y = -1.571;
if(pivot1.position.z>=38){
pivot1.position.z=-38;
pivot1.position.z -= 0.2;
}
}
if(changeDirection == "W"){
pivot1.position.z -= 0.2;
pivot1.rotation.y = 1.571;
if(pivot1.position.z<=-38){
pivot1.position.z=38;
pivot1.position.z -= 0.2;
}
}
}
if(typeof pivot2 !='undefined') {
if(changeDirection2 == "W"){
pivot2.position.z -= 0.2;
pivot2.rotation.y = 1.571;
if(pivot2.position.z<=-38){
pivot2.position.z=38;
pivot2.position.z -= 0.2;
}
}
if(changeDirection2 == "S"){
pivot2.position.z += 0.2;
pivot2.rotation.y = -1.571;
if(pivot2.position.z>=38){
pivot2.position.z=-38;
pivot2.position.z -= 0.2;
}
}
if(changeDirection2 == "D"){
pivot2.position.x += 0.2;
pivot2.rotation.y = 0;
if(pivot2.position.x>=37){
pivot2.position.x=-40;
pivot2.position.x -= 0.2;
}
}
if(changeDirection2 == "A"){
pivot2.position.x -= 0.2;
pivot2.rotation.y = 1.571*2;
if(pivot2.position.x<=-37){
pivot2.position.x=40;
pivot2.position.x -= 0.2;
}
}
}
if(typeof pivot3 !='undefined') {
if(changeDirection3 == "W"){
pivot3.position.z -= 0.2;
pivot3.rotation.y = 1.571;
if(pivot3.position.z<=-38){
pivot3.position.z=38;
pivot3.position.z -= 0.2;
}
}
if(changeDirection3 == "S"){
pivot3.position.z += 0.2;
pivot3.rotation.y = -1.571;
if(pivot3.position.z>=38){
pivot3.position.z=-38;
pivot3.position.z -= 0.2;
}
}
if(changeDirection3 == "D"){
pivot3.position.x += 0.2;
pivot3.rotation.y = 0;
if(pivot3.position.x>=37){
pivot3.position.x=-40;
pivot3.position.x -= 0.2;
}
}
if(changeDirection3 == "A"){
pivot3.position.x -= 0.2;
pivot3.rotation.y = 1.571*2;
if(pivot3.position.x<=-37){
pivot3.position.x=40;
pivot3.position.x -= 0.2;
}
}
}
requestAnimationFrame( animate );
}
Meteor 跨客户端同步 数据。如果您希望每个客户端都看到其他客户端的蛇的位置,您需要将这些位置存储在所有客户端都订阅的集合中。
常用代码:
Snakes = new Meteor.Collection('snakes');
然后在 rendered
回调中,您需要在 Snakes
中插入或更新文档。将该文档的 _id
设置为一个变量,然后在您的动画代码中您应该调用类似 Snakes.update(_id, {position: newPosition})
的内容。不要每秒调用 60 次;每秒一次或两次可能是连接可以处理的最多。这些更新会自动同步到其他客户端;使用 observeChanges
侦听器来处理其他客户端的更新,并告诉 Three.js 如何更新蛇的位置。
另请参阅 Meteor Streams 包。它使您可以做基本相同的事情,但无需写入数据库; “更新”实际上只是成为在所有连接的客户端上触发的事件。因此,对于您的用例来说,它的性能可能要高得多,我想这将是一个首要考虑因素。尽管网站上说该项目已被放弃,但我已经在当前(Meteor 1.0.3.2)项目中使用了 Meteor Streams,并且运行良好。