我正在使用NodeJS和MongoDB编写在线多人游戏。我有文件app.js,index.html,entity.js和inventory.js。每次我开始运行我的服务器时都会收到错误引用错误:文档未定义,它引用了库存中的refreshRender()以及我在实体中使用它的位置,所以这显然是这个函数的错误,但我无法弄清楚是什么。
app.js:
var mongojs = require("mongojs");
require('./entity');
require('./client/inventory');
//Connect to database
var db = mongojs('localhost:27017/myGame', ['users','progress']);
var express = require('express');
var app = express();
var serv = require('http').Server(app);
app.get('/',function(req, res) {
res.sendFile(__dirname + '/client/index.html');
});
app.use('/client',express.static(__dirname + '/client'));
serv.listen(8080);
console.log("Server started.");
var SOCKET_LIST = {};
var isValidPassword = function(data,callBack){
db.users.find({username:data.username,password:data.password}, function(err,res){
if(res.length > 0)
callBack(true);
else
callBack(false);
})
};
//Test to see if username already exists]
var isUsernameTaken = function(data,callBack){
db.users.find({username:data.username}, function(err,res){
if(res.length > 0)
callBack(true);
else
callBack(false);
})
};
//Add user
var addUser = function(data,callBack){
db.users.insert({username:data.username,password:data.password}, function(err){
callBack();
})
};
var io = require('socket.io')(serv,{});
io.sockets.on('connection', function(socket){
socket.id = Math.random();
SOCKET_LIST[socket.id] = socket;
socket.on('logIn',function(data){
isValidPassword(data,function(res){
if(res){
Player.onConnect(socket, data.username);
socket.emit('signInResponse',{success:true});
} else {
socket.emit('signInResponse',{success:false});
}
});
});
socket.on('signUp',function(data){
isUsernameTaken(data,function(res){
if(res){
socket.emit('signUpResponse',{success:false});
} else {
addUser(data,function(){
socket.emit('signUpResponse',{success:true});
});
}
});
});
socket.on('disconnect',function(){
delete SOCKET_LIST[socket.id];
Player.onDisconnect(socket);
});
});
setInterval(function(){
var packs = Entity.getFrameData();
for(var i in SOCKET_LIST){
var socket = SOCKET_LIST[i];
socket.emit('init',packs.initPack);
socket.emit('update',packs.updatePack);
socket.emit('remove',packs.removePack);
}
},1000/25);
的index.html:
<div id="signDiv">
Username: <input id="signDiv-username" type="text"></input><br>
Password: <input id="signDiv-password" type="password"></input>
<button id="signDiv-logIn">Log in</button>
<button id="signDiv-signUp">Sign up</button>
</div>
<div id="gameDiv" style="display:none;">
<div id="game" style="position:absolute;width:500px;height:500px">
<canvas id="ctx" width="500" height="500" style="position:absolute;border:1px solid #000000;"></canvas>
<canvas id="ctx-ui" width="500" height="500" style="position:absolute;border:1px solid #000000;"></canvas>
<div id="ui" style="position:absolute;width:500px;height:500px;">
<button onclick="changeMap()" style="position:absolute;bottom:0px;left:0px">
Change Map
</button>
</div>
</div>
<div id="belowGame" style="margin-top:520px">
<div id="chat-text" style="width:500px;height:100px;overflow-y:scroll">
<div>Hello!</div>
</div>
<div id="inventory"></div>
<form id="chat-form">
<input id="chat-input" type="text" style="width:500px"></input>
</form>
</div>
</div>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="/client/inventory.js"></script>
<script>
var WIDTH = 500;
var HEIGHT = 500;
var socket = io();
//log in and sign up for game
var signDiv = document.getElementById('signDiv');
var signDivUsername = document.getElementById('signDiv-username');
var signDivLogIn = document.getElementById('signDiv-logIn');
var signDivSignUp = document.getElementById('signDiv-signUp');
var signDivPassword = document.getElementById('signDiv-password');
signDivLogIn.onclick = function(){
socket.emit('logIn', {username:signDivUsername.value, password:signDivPassword.value});
};
signDivSignUp.onclick = function(){
socket.emit('signUp', {username:signDivUsername.value, password:signDivPassword.value});
};
socket.on('signInResponse', function(data){
if(data.success){
signDiv.style.display = 'none';
gameDiv.style.display = 'inline-block';
} else
alert("Log in unsuccessful")
});
socket.on('signUpResponse', function(data){
if(data.success){
alert("Sing up successful")
} else
alert("Sign up unsuccessful")
});
//Game chat, get elements
var chatText = document.getElementById('chat-text');
var chatInput = document.getElementById('chat-input');
var chatForm = document.getElementById('chat-form');
//Socket on for chat
socket.on('addToChat', function(data){
chatText.innerHTML += '<div>' + data + '</div>';
});
chatForm.onsubmit = function(e){
e.preventDefault();
if(chatInput.value[0] === '/')
socket.emit('evalServer',chatInput.value.slice(1));
else if (chatInput.value[0] === '@'){
//@username,message
socket.emit('sendPrivToServer', {
username:chatInput.value.slice(1, chatInput.value.indexOf(',')),
message:chatInput.value.slice(chatInput.value.indexOf(',')+1)
})
}
else
socket.emit('sendMsgToServer',chatInput.value);
chatInput.value = '';
};
//UI
var changeMap = function(){
socket.emit('changeMap');
};
var inventory = new Inventory(socket, false);
socket.on('updateInventory', function(items){
inventory.items = items;
inventory.refreshRender();
});
//Game
//Game images
var Img = {};
Img.player = new Image();
Img.player.src = '/client/image/player.png';
Img.bullet = new Image();
Img.bullet.src = '/client/image/bullet.png';
Img.map = {};
Img.map['default'] = new Image();
Img.map['default'].src = '/client/image/map.png';
Img.map['second'] = new Image();
Img.map['second'].src = '/client/image/rocks.png';
var ctx = document.getElementById("ctx").getContext("2d");
var ctxUi = document.getElementById("ctx-ui").getContext("2d");
ctxUi.font = '30px Arial';
var Player = function(initPack){
var self = {};
self.id = initPack.id;
self.number = initPack.number;
self.x = initPack.x;
self.y = initPack.y;
self.hp = initPack.hp;
self.hpMax = initPack.hpMax;
self.sheild = initPack.sheild;
self.sheildMax = initPack.sheildMax;
self.score = initPack.score;
self.map = initPack.map;
self.draw = function() {
if(Player.list[selfId].map !== self.map)
return;
var x = self.x - Player.list[selfId].x + WIDTH/2;
var y = self.y - Player.list[selfId].y + HEIGHT/2;
var hpWidth = 30 * self.hp/self.hpMax;
ctx.fillStyle = 'green';
ctx.fillRect(x - hpWidth/2, y - 40, hpWidth, 4);
var sheildWidth = 30 * self.sheild/self.sheildMax;
ctx.fillStyle = 'purple';
ctx.fillRect(x - sheildWidth/2, y - 40, sheildWidth, 4);
var width = Img.player.width; //may need to be smaller
var height = Img.player.height;
ctx.drawImage(Img.player,
0,0,Img.player.width,Img.player.height,
x-width/2,y-height/2,width,height);
//ctx.fillText(self.score, self.x, self.y-60);
};
Player.list[self.id] = self;
return self;
};
Player.list= {};
var Bullet = function(initPack){
var self = {};
self.id = initPack.id;
self.x = initPack.x;
self.y = initPack.y;
self.map = initPack.map;
self.draw = function () {
if(Player.list[selfId].map !== self.map)
return;
var width = Img.bullet.width/2;
var height = Img.bullet.height/2;
var x = self.x - Player.list[selfId].x + WIDTH/2;
var y = self.y - Player.list[selfId].y + HEIGHT/2;
ctx.drawImage(Img.bullet,
0,0,Img.bullet.width,Img.bullet.height,
x-width/2,y-height/2,width,height);
};
Bullet.list[self.id] = self;
return self;
};
Bullet.list = {};
var selfId = null;
//Initialisation package
socket.on('init', function(data){
if(data.selfId)
selfId = data.selfId;
for(var i = 0 ; i < data.player.length; i++){
new Player(data.player[i]);
}
for(var i = 0 ; i < data.bullet.length; i ++){
new Bullet(data.bullet[i])
}
});
//Update package
socket.on('update', function(data){
for(var i = 0 ; i < data.player.length; i++){
var pack = data.player[i];
var p = Player.list[pack.id];
if(p){
if(pack.x !== undefined)
p.x = pack.x;
if(pack.y !== undefined)
p.y = pack.y;
if(pack.hp !== undefined)
p.hp = pack.hp;
if(pack.score !== undefined)
p.score = pack.score;
if(pack.sheild !== undefined)
p.sheild = pack.sheild;
if(pack.map !== undefined)
p.map = pack.map;
}
}
for(var i = 0 ; i < data.bullet.length; i++){
var pack = data.bullet[i];
var b = Bullet.list[data.bullet[i].id];
if(b){
if(pack.x !== undefined)
b.x = pack.x;
if(pack.y !== undefined)
b.y = pack.y;
}
}
});
//Remove package
socket.on('remove',function(data){
for(var i = 0 ; i < data.player.length; i++){
delete Player.list[data.player[i]];
}
for(var i = 0 ; i < data.bullet.length; i++){
delete Bullet.list[data.bullet[i]];
}
});
setInterval(function(){
if(!selfId)
return;
ctx.clearRect(0,0,500,500);
drawMap();
drawScore();
for(var i in Player.list)
Player.list[i].draw();
for(var i in Bullet.list)
Bullet.list[i].draw();
},40);
var drawMap = function () {
var player = Player.list[selfId];
var x = player.x;
var y = player.y;
ctx.drawImage(Img.map[player.map],x,y);
};
var drawScore = function () {
if(lastScore === Player.list[selfId].score)
return;
lastScore = Player.list[selfId].score;
ctxUi.clearRect(0,0,500,500);
ctxUi.fillStyle = 'red';
ctxUi.fillText(Player.list[selfId].score,0,40);
};
var lastScore = null;
document.onkeydown = function(event){
if(event.keyCode === 68) //d
socket.emit('keyPress',{inputId:'right',state:true});
else if(event.keyCode === 83) //s
socket.emit('keyPress',{inputId:'down',state:true});
else if(event.keyCode === 65) //a
socket.emit('keyPress',{inputId:'left',state:true});
else if(event.keyCode === 87) // w
socket.emit('keyPress',{inputId:'up',state:true});
};
document.onkeyup = function(event){
if(event.keyCode === 68) //d
socket.emit('keyPress',{inputId:'right',state:false});
else if(event.keyCode === 83) //s
socket.emit('keyPress',{inputId:'down',state:false});
else if(event.keyCode === 65) //a
socket.emit('keyPress',{inputId:'left',state:false});
else if(event.keyCode === 87) // w
socket.emit('keyPress',{inputId:'up',state:false});
};
document.onmousedown = function(event){
socket.emit('keyPress', {inputId:'shoot', state:true});
};
document.onmouseup = function (event){
socket.emit('keyPress', {inputId:'shoot', state:false});
};
document.onmousemove = function(event){
var x = -250 + event.clientX - 8;
var y = -250 + event.clientY -8;
var angle = Math.atan2(y,x)/Math.PI*180;
socket.emit('keyPress', {inputId:'mouseAngle', state:angle});
};
document.oncontextmenu = function(event){
event.preventDefault();
};
</script>
inventory.js:
Inventory = function(items, socket, server){
var self = {
items:items, //{id:"itemId",amount:1}
socket:socket,
server:server
}
self.refreshRender = function(){
//server
if(self.server){
self.socket.emit('updateInventory',self.items);
return;
}
self.addItem = function(id,amount){
for(var i = 0 ; i < self.items.length; i++){
if(self.items[i].id === id){
self.items[i].amount += amount;
self.refreshRender();
return;
}
}
self.items.push({id:id,amount:amount});
self.refreshRender();
}
self.removeItem = function(id,amount){
for(var i = 0 ; i < self.items.length; i++){
if(self.items[i].id === id){
self.items[i].amount -= amount;
if(self.items[i].amount <= 0)
self.items.splice(i,1);
self.refreshRender();
return;
}
}
}
self.hasItem = function(id,amount){
for(var i = 0 ; i < self.items.length; i++){
if(self.items[i].id === id){
return self.items[i].amount >= amount;
}
}
return false;
}
var inventory = document.getElementById("inventory");
inventory.innerHTML = "";
var addBtn = function(data) {
let item = Item.list[data.id];
let button = document.createElement('button');
button.onclick = function(){
self.socket.emit("useItem", item.id);
}
button.innerText = item.name + " x" + data.amount;
inventory.appendChild(button);
}
for(var i = 0 ; i < self.items.length; i++){
addBtn(self.items[i]);
}
if(self.server){}
self.socket.on("useItem", function(itemId){
if (!self.hasItem(itemId, 1)){
console.log("You dont have the item");
return;
}
let item = Item.list[itemId];
item.event(Player.list[self.socket.id]);
})
}
return self;
}
Item = function(id,name,event){
var self = {
id:id,
name:name,
event:event,
}
Item.list[self.id] = self;
return self;
}
Item.list = {};
Item("potion","Potion",function(player){
player.sheild = 10;
player.inventory.removeItem("potion",1);
});
Item("newGun", "New Gun", function(player){
player.inventory.removeItem("newGun", 1);
player.inventory.addItem("newAttack", 1);
})
Item("newAttack","New Attack",function(player){
for(var i = 0; i < 360; i++)
player.shootBullet(i);
});
entity.js:
var initPack = {player:[],bullet:[]};
var removePack = {player:[],bullet:[]};
Entity = function(param){
var self = {
x:250,
y:250,
spdX:0,
spdY:0,
id:"",
map:'default'
};
if(param){
if(param.x)
self.x = param.x;
if(param.y)
self.y = param.y;
if(param.map)
self.map = param.map;
if(param.id)
self.id = param.id;
}
self.update = function(){
self.updatePosition();
};
self.updatePosition = function(){
self.x += self.spdX;
self.y += self.spdY;
};
self.getDistance = function(pt){
return Math.sqrt(Math.pow(self.x-pt.x,2) + Math.pow(self.y-pt.y,2));
};
return self;
};
Entity.getFrameData = function () {
var pack = {
initPack:{
player:initPack.player,
bullet:initPack.bullet
},
removePack:{
player:removePack.player,
bullet:removePack.bullet
},
updatePack:{
player:Player.update(),
bullet:Bullet.update(),
}
};
initPack.player = [];
initPack.bullet = [];
removePack.player = [];
removePack.bullet = [];
return pack;
};
Player = function(param){
var self = Entity(param);
self.number = "" + Math.floor(10 * Math.random());
self.username = param.username;
self.pressingRight = false;
self.pressingLeft = false;
self.pressingUp = false;
self.pressingDown = false;
self.pressingShoot = false;
self.mouseAngle = 0;
self.maxSpd = 10;
self.hp = 100;
self.hpMax = 100;
self.sheild = 0;
self.sheildMax = 100;
self.score = 0;
self.inventory = new Inventory(param.socket, true);
var super_update = self.update;
self.update = function(){
self.updateSpd();
super_update();
if(self.pressingShoot){
self.shootBullet(self.mouseAngle);
}
};
self.shootBullet = function(angle){
if(Math.random() <0.1)
self.inventory.addItem("potion",1);
Bullet({
parent:self.id,
angle:angle,
x:self.x,
y:self.y,
map:self.map
})
};
self.updateSpd = function(){
if(self.pressingRight)
self.spdX = self.maxSpd;
else if(self.pressingLeft)
self.spdX = -self.maxSpd;
else
self.spdX = 0;
if(self.pressingUp)
self.spdY = -self.maxSpd;
else if(self.pressingDown)
self.spdY = self.maxSpd;
else
self.spdY = 0;
};
self.getInitPack = function(){
return{
id:self.id,
x:self.x,
y:self.y,
number:self.number,
hp:self.hp,
hpMax:self.hpMax,
shield:self.sheild,
shieldMax:self.sheildMax,
score:self.score,
map:self.map
}
};
self.getUpdatePack = function(){
return{
id:self.id,
x:self.x,
y:self.y,
hp:self.hp,
shield:self.sheild,
score:self.score,
map:self.map
}
};
Player.list[self.id] = self;
initPack.player.push(self.getInitPack());
return self;
};
Player.list = {};
Player.onConnect = function(socket,username){
var map = 'default';
if(Math.random() < 0.2)
map = 'second';
var player = Player({
username:username,
id:socket.id,
map:map,
socket:socket
});
player.inventory.self.refreshRender();
socket.on('keyPress',function(data){
if(data.inputId === 'left')
player.pressingLeft = data.state;
else if(data.inputId === 'right')
player.pressingRight = data.state;
else if(data.inputId === 'up')
player.pressingUp = data.state;
else if(data.inputId === 'down')
player.pressingDown = data.state;
else if(data.inputId === 'shoot')
player.pressingShoot = data.state;
else if(data.inputId === 'mouseAngle')
player.mouseAngle = data.state;
});
socket.on('changeMap',function(data){
if(player.map === 'default')
player.map = 'second';
else
player.map = 'default';
});
socket.on('sendMsgToServer', function(data){
for(var i in SOCKET_LIST){
SOCKET_LIST[i].emit('addToChat', player.username + ": " + data);
}
});
socket.on('sendPrivToServer', function(data){
var recipientSocket = null;
for(var i in Player.list)
if(Player.list[i].username === data.username)
recipientSocket = SOCKET_LIST[i];
if(recipientSocket === null){
socket.emit('addToChat', 'Player not online');
} else {
recipientSocket.emit('addToChat', 'From ' + player.username + ': ' + data.message);
socket.emit('addToChat', 'To ' + data.username + ': ' + data.message);
}
});
socket.emit('init', {
selfId:socket.id,
player:Player.getAllInitPack(),
bullet:Bullet.getAllInitPack()
})
};
Player.getAllInitPack = function () {
var players = [];
for(var i in Player.list)
players.push(Player.list[i].getInitPack());
return players;
};
Player.onDisconnect = function(socket){
delete Player.list[socket.id];
removePack.player.push(socket.id);
};
Player.update = function(){
var pack = [];
for(var i in Player.list){
var player = Player.list[i];
player.update();
pack.push(player.getUpdatePack());
}
return pack;
};
Bullet = function(param){
var self = Entity(param);
self.id = Math.random();
self.angle = param.angle;
self.spdX = Math.cos(param.angle/180*Math.PI) * 10;
self.spdY = Math.sin(param.angle/180*Math.PI) * 10;
self.parent = param.parent;
self.timer = 0;
self.toRemove = false;
var super_update = self.update;
self.update = function(){
if(self.timer++ > 100)
self.toRemove = true;
super_update();
for(var i in Player.list){
var p = Player.list[i];
if(self.map === p.map && self.getDistance(p) < 32 && self.parent !== p.id) {
if (p.sheild > 0) {
p.sheild -= 1
} else {
p.hp -= 1;
if (p.hp <= 0) {
var shooter = Player.list[self.parent];
if (shooter) {
shooter.score += 1;
p.hp = p.hpMax;
p.x = Math.random() * 500;
p.y = Math.random() * 500;
}
}
self.toRemove = true;
}
}
}
};
self.getInitPack = function(){
return{
id:self.id,
x:self.x,
y:self.y,
map:self.map
}
};
self.getUpdatePack = function(){
return{
id:self.id,
x:self.x,
y:self.y,
}
};
Bullet.list[self.id] = self;
initPack.bullet.push(self.getInitPack());
return self;
};
Bullet.list = {};
Bullet.update = function(){
var pack = [];
for(var i in Bullet.list) {
var bullet = Bullet.list[i];
bullet.update();
if (bullet.toRemove){
delete Bullet.list[i];
removePack.bullet.push(bullet.id);
}else
pack.push(bullet.getUpdatePack());
}
return pack;
};
Bullet.getAllInitPack = function () {
var bullets = [];
for(var i in Bullet.list)
bullets.push(Bullet.list[i].getInitPack());
return bullets;
};