您好,欢迎光临本网站![请登录][注册会员]  
文件名称: 球球大作战系列技术架构
  所属分类: Javascript
  开发工具:
  文件大小: 1mb
  下载次数: 0
  上传时间: 2016-10-07
  提 供 者: hanghang********
 详细说明: /*jslint bitwise: true, node: true */ 'use strict'; var express = require('express'); var app = express(); var http = require('http').Server(app); var io = require('socket.io')(http); var SAT = require('sat'); // Import game settings. var c = require('../../co nfig.json'); // Import utilities. var util = require('./lib/util'); // Import quadtree. var quadtree = require('simple-quadtree'); var tree = quadtree(0, 0, c.gameWidth, c.gameHeight); var users = []; var massFood = []; var food = []; var virus = []; var sockets = {}; var leaderboard = []; var leaderboardChanged = false; var V = SAT.Vector; var C = SAT.Circle; var initMassLog = util.log(c.defaultPlayerMass, c.slowBase); app.use(express.static(__dirname + '/../client')); function addFood(toAdd) { var radius = util.massToRadius(c.foodMass); while (toAdd--) { var position = c.foodUniformDisposition ? util.uniformPosition(food, radius) : util.randomPosition(radius); food.push({ // Make IDs unique. id: ((new Date()).getTime() + '' + food.length) >>> 0, x: position.x, y: position.y, radius: radius, mass: Math.random() + 2, hue: Math.round(Math.random() * 360) }); } } function addVirus(toAdd) { while (toAdd--) { var mass = util.randomInRange(c.virus.defaultMass.from, c.virus.defaultMass.to, true); var radius = util.massToRadius(mass); var position = c.virusUniformDisposition ? util.uniformPosition(virus, radius) : util.randomPosition(radius); virus.push({ id: ((new Date()).getTime() + '' + virus.length) >>> 0, x: position.x, y: position.y, radius: radius, mass: mass, fill: c.virus.fill, stroke: c.virus.stroke, strokeWidth: c.virus.strokeWidth }); } } function removeFood(toRem) { while (toRem--) { food.pop(); } } function movePlayer(player) { var x =0,y =0; for(var i=0; i 6.25) { player.cells[i].speed -= 0.5; } if (dist < (50 + player.cells[i].radius)) { deltaY *= dist / (50 + player.cells[i].radius); deltaX *= dist / (50 + player.cells[i].radius); } if (!isNaN(deltaY)) { player.cells[i].y += deltaY; } if (!isNaN(deltaX)) { player.cells[i].x += deltaX; } // Find best solution. for(var j=0; j new Date().getTime() - 1000 * c.mergeTimer) { if(player.cells[i].x < player.cells[j].x) { player.cells[i].x--; } else if(player.cells[i].x > player.cells[j].x) { player.cells[i].x++; } if(player.cells[i].y < player.cells[j].y) { player.cells[i].y--; } else if((player.cells[i].y > player.cells[j].y)) { player.cells[i].y++; } } else if(distance < radiusTotal / 1.75) { player.cells[i].mass += player.cells[j].mass; player.cells[i].radius = util.massToRadius(player.cells[i].mass); player.cells.splice(j, 1); } } } } if(player.cells.length > i) { var borderCalc = player.cells[i].radius / 3; if (player.cells[i].x > c.gameWidth - borderCalc) { player.cells[i].x = c.gameWidth - borderCalc; } if (player.cells[i].y > c.gameHeight - borderCalc) { player.cells[i].y = c.gameHeight - borderCalc; } if (player.cells[i].x < borderCalc) { player.cells[i].x = borderCalc; } if (player.cells[i].y < borderCalc) { player.cells[i].y = borderCalc; } x += player.cells[i].x; y += player.cells[i].y; } } player.x = x/player.cells.length; player.y = y/player.cells.length; } function moveMass(mass) { var deg = Math.atan2(mass.target.y, mass.target.x); var deltaY = mass.speed * Math.sin(deg); var deltaX = mass.speed * Math.cos(deg); mass.speed -= 0.5; if(mass.speed < 0) { mass.speed = 0; } if (!isNaN(deltaY)) { mass.y += deltaY; } if (!isNaN(deltaX)) { mass.x += deltaX; } var borderCalc = mass.radius + 5; if (mass.x > c.gameWidth - borderCalc) { mass.x = c.gameWidth - borderCalc; } if (mass.y > c.gameHeight - borderCalc) { mass.y = c.gameHeight - borderCalc; } if (mass.x < borderCalc) { mass.x = borderCalc; } if (mass.y < borderCalc) { mass.y = borderCalc; } } function balanceMass() { var totalMass = food.length * c.foodMass + users .map(function(u) {return u.massTotal; }) .reduce(function(pu,cu) { return pu+cu;}, 0); var massDiff = c.gameMass - totalMass; var maxFoodDiff = c.maxFood - food.length; var foodDiff = parseInt(massDiff / c.foodMass) - maxFoodDiff; var foodToAdd = Math.min(foodDiff, maxFoodDiff); var foodToRemove = -Math.max(foodDiff, maxFoodDiff); if (foodToAdd > 0) { //console.log('[DEBUG] Adding ' + foodToAdd + ' food to level!'); addFood(foodToAdd); //console.log('[DEBUG] Mass rebalanced!'); } else if (foodToRemove > 0) { //console.log('[DEBUG] Removing ' + foodToRemove + ' food from level!'); removeFood(foodToRemove); //console.log('[DEBUG] Mass rebalanced!'); } var virusToAdd = c.maxVirus - virus.length; if (virusToAdd > 0) { addVirus(virusToAdd); } } io.on('connection', function (socket) { console.log('A user connected!', socket.handshake.query.type); var type = socket.handshake.query.type; var radius = util.massToRadius(c.defaultPlayerMass); var position = c.newPlayerInitialPosition == 'farthest' ? util.uniformPosition(users, radius) : util.randomPosition(radius); var cells = []; var massTotal = 0; if(type === 'player') { cells = [{ mass: c.defaultPlayerMass, x: position.x, y: position.y, radius: radius }]; massTotal = c.defaultPlayerMass; } var currentPlayer = { id: socket.id, x: position.x, y: position.y, w: c.defaultPlayerMass, h: c.defaultPlayerMass, cells: cells, massTotal: massTotal, hue: Math.round(Math.random() * 360), type: type, lastHeartbeat: new Date().getTime(), target: { x: 0, y: 0 } }; socket.on('gotit', function (player) { console.log('[INFO] Player ' + player.name + ' connecting!'); if (util.findIndex(users, player.id) > -1) { console.log('[INFO] Player ID is already connected, kicking.'); socket.disconnect(); } else if (!util.validNick(player.name)) { socket.emit('kick', 'Invalid username.'); socket.disconnect(); } else { console.log('[INFO] Player ' + player.name + ' connected!'); sockets[player.id] = socket; var radius = util.massToRadius(c.defaultPlayerMass); var position = c.newPlayerInitialPosition == 'farthest' ? util.uniformPosition(users, radius) : util.randomPosition(radius); player.x = position.x; player.y = position.y; player.target.x = 0; player.target.y = 0; if(type === 'player') { player.cells = [{ mass: c.defaultPlayerMass, x: position.x, y: position.y, radius: radius }]; player.massTotal = c.defaultPlayerMass; } else { player.cells = []; player.massTotal = 0; } player.hue = Math.round(Math.random() * 360); currentPlayer = player; currentPlayer.lastHeartbeat = new Date().getTime(); users.push(currentPlayer); io.emit('playerJoin', { name: currentPlayer.name }); socket.emit('gameSetup', { gameWidth: c.gameWidth, gameHeight: c.gameHeight }); console.log('Total players: ' + users.length); } }); socket.on('pingcheck', function () { socket.emit('pongcheck'); }); socket.on('windowResized', function (data) { currentPlayer.screenWidth = data.screenWidth; currentPlayer.screenHeight = data.screenHeight; }); socket.on('respawn', function () { if (util.findIndex(users, currentPlayer.id) > -1) users.splice(util.findIndex(users, currentPlayer.id), 1); socket.emit('welcome', currentPlayer); console.log('[INFO] User ' + currentPlayer.name + ' respawned!'); }); socket.on('disconnect', function () { if (util.findIndex(users, currentPlayer.id) > -1) users.splice(util.findIndex(users, currentPlayer.id), 1); console.log('[INFO] User ' + currentPlayer.name + ' disconnected!'); socket.broadcast.emit('playerDisconnect', { name: currentPlayer.name }); }); socket.on('playerChat', function(data) { var _sender = data.sender.replace(/(<([^>]+)>)/ig, ''); var _message = data.message.replace(/(<([^>]+)>)/ig, ''); if (c.logChat === 1) { console.log('[CHAT] [' + (new Date()).getHours() + ':' + (new Date()).getMinutes() + '] ' + _sender + ': ' + _message); } socket.broadcast.emit('serverSendPlayerChat', {sender: _sender, message: _message.substring(0,35)}); }); socket.on('pass', function(data) { if (data[0] === c.adminPass) { console.log('[ADMIN] ' + currentPlayer.name + ' just logged in as an admin!'); socket.emit('serverMSG', 'Welcome back ' + currentPlayer.name); socket.broadcast.emit('serverMSG', currentPlayer.name + ' just logged in as admin!'); currentPlayer.admin = true; } else { console.log('[ADMIN] ' + currentPlayer.name + ' attempted to log in with incorrect password.'); socket.emit('serverMSG', 'Password incorrect, attempt logged.'); // TODO: Actually log incorrect passwords. } }); socket.on('kick', function(data) { if (currentPlayer.admin) { var reason = ''; var worked = false; for (var e = 0; e < users.length; e++) { if (users[e].name === data[0] && !users[e].admin && !worked) { if (data.length > 1) { for (var f = 1; f < data.length; f++) { if (f === data.length) { reason = reason + data[f]; } else { reason = reason + data[f] + ' '; } } } if (reason !== '') { console.log('[ADMIN] User ' + users[e].name + ' kicked successfully by ' + currentPlayer.name + ' for reason ' + reason); } else { console.log('[ADMIN] User ' + users[e].name + ' kicked successfully by ' + currentPlayer.name); } socket.emit('serverMSG', 'User ' + users[e].name + ' was kicked by ' + currentPlayer.name); sockets[users[e].id].emit('kick', reason); sockets[users[e].id].disconnect(); users.splice(e, 1); worked = true; } } if (!worked) { socket.emit('serverMSG', 'Could not locate user or user is an admin.'); } } else { console.log('[ADMIN] ' + currentPlayer.name + ' is trying to use -kick but isn\'t an admin.'); socket.emit('serverMSG', 'You are not permitted to use this command.'); } }); // Heartbeat function, update everytime. socket.on('0', function(target) { currentPlayer.lastHeartbeat = new Date().getTime(); if (target.x !== currentPlayer.x || target.y !== currentPlayer.y) { currentPlayer.target = target; } }); socket.on('1', function() { // Fire food. for(var i=0; i= c.defaultPlayerMass + c.fireFood) && c.fireFood > 0) || (currentPlayer.cells[i].mass >= 20 && c.fireFood === 0)){ var masa = 1; if(c.fireFood > 0) masa = c.fireFood; else masa = currentPlayer.cells[i].mass*0.1; currentPlayer.cells[i].mass -= masa; currentPlayer.massTotal -=masa; massFood.push({ id: currentPlayer.id, num: i, masa: masa, hue: currentPlayer.hue, target: { x: currentPlayer.x - currentPlayer.cells[i].x + currentPlayer.target.x, y: currentPlayer.y - currentPlayer.cells[i].y + currentPlayer.target.y }, x: currentPlayer.cells[i].x, y: currentPlayer.cells[i].y, radius: util.massToRadius(masa), speed: 25 }); } } }); socket.on('2', function(virusCell) { function splitCell(cell) { if(cell.mass >= c.defaultPlayerMass*2) { cell.mass = cell.mass/2; cell.radius = util.massToRadius(cell.mass); currentPlayer.cells.push({ mass: cell.mass, x: cell.x, y: cell.y, radius: cell.radius, speed: 25 }); } } if(currentPlayer.cells.length < c.limitSplit && currentPlayer.massTotal >= c.defaultPlayerMass*2) { //Split single cell from virus if(virusCell) { splitCell(currentPlayer.cells[virusCell]); } else { //Split all cells if(currentPlayer.cells.length < c.limitSplit && currentPlayer.massTotal >= c.defaultPlayerMass*2) { var numMax = currentPlayer.cells.length; for(var d=0; d 0 && z == m.num) return false; if(currentCell.mass > m.masa * 1.1) return true; } return false; } function check(user) { for(var i=0; i 10 && user.id !== currentPlayer.id) { var response = new SAT.Response(); var collided = SAT.testCircleCircle(playerCircle, new C(new V(user.cells[i].x, user.cells[i].y), user.cells[i].radius), response); if (collided) { response.aUser = currentCell; response.bUser = { id: user.id, name: user.name, x: user.cells[i].x, y: user.cells[i].y, num: i, mass: user.cells[i].mass }; playerCollisions.push(response); } } } return true; } function collisionCheck(collision) { if (collision.aUser.mass > collision.bUser.mass * 1.1 && collision.aUser.radius > Math.sqrt(Math.pow(collision.aUser.x - collision.bUser.x, 2) + Math.pow(collision.aUser.y - collision.bUser.y, 2))*1.75) { console.log('[DEBUG] Killing user: ' + collision.bUser.id); console.log('[DEBUG] Collision info:'); console.log(collision); var numUser = util.findIndex(users, collision.bUser.id); if (numUser > -1) { if(users[numUser].cells.length > 1) { users[numUser].massTotal -= collision.bUser.mass; users[numUser].cells.splice(collision.bUser.num, 1); } else { users.splice(numUser, 1); io.emit('playerDied', { name: collision.bUser.name }); sockets[collision.bUser.id].emit('RIP'); } } currentPlayer.massTotal += collision.bUser.mass; collision.aUser.mass += collision.bUser.mass; } } for(var z=0; z 0 && currentCell.mass > virus[virusCollision].mass) { sockets[currentPlayer.id].emit('virusSplit', z); } var masaGanada = 0; for(var m=0; m 0) moveMass(massFood[i]); } } function gameloop() { if (users.length > 0) { users.sort( function(a, b) { return b.massTotal - a.massTotal; }); var topUsers = []; for (var i = 0; i < Math.min(10, users.length); i++) { if(users[i].type == 'player') { topUsers.push({ id: users[i].id, name: users[i].name }); } } if (isNaN(leaderboard) || leaderboard.length !== topUsers.length) { leaderboard = topUsers; leaderboardChanged = true; } else { for (i = 0; i < leaderboard.length; i++) { if (leaderboard[i].id !== topUsers[i].id) { leaderboard = topUsers; leaderboardChanged = true; break; } } } for (i = 0; i < users.length; i++) { for(var z=0; z < users[i].cells.length; z++) { if (users[i].cells[z].mass * (1 - (c.massLossRate / 1000)) > c.defaultPlayerMass && users[i].massTotal > c.minMassLoss) { var massLoss = users[i].cells[z].mass * (1 - (c.massLossRate / 1000)); users[i].massTotal -= users[i].cells[z].mass - massLoss; users[i].cells[z].mass = massLoss; } } } } balanceMass(); } function sendUpdates() { users.forEach( function(u) { // center the view if x/y is undefined, this will happen for spectators u.x = u.x || c.gameWidth / 2; u.y = u.y || c.gameHeight / 2; var visibleFood = food .map(function(f) { if ( f.x > u.x - u.screenWidth/2 - 20 && f.x < u.x + u.screenWidth/2 + 20 && f.y > u.y - u.screenHeight/2 - 20 && f.y < u.y + u.screenHeight/2 + 20) { return f; } }) .filter(function(f) { return f; }); var visibleVirus = virus .map(function(f) { if ( f.x > u.x - u.screenWidth/2 - f.radius && f.x < u.x + u.screenWidth/2 + f.radius && f.y > u.y - u.screenHeight/2 - f.radius && f.y < u.y + u.screenHeight/2 + f.radius) { return f; } }) .filter(function(f) { return f; }); var visibleMass = massFood .map(function(f) { if ( f.x+f.radius > u.x - u.screenWidth/2 - 20 && f.x-f.radius < u.x + u.screenWidth/2 + 20 && f.y+f.radius > u.y - u.screenHeight/2 - 20 && f.y-f.radius < u.y + u.screenHeight/2 + 20) { return f; } }) .filter(function(f) { return f; }); var visibleCells = users .map(function(f) { for(var z=0; z u.x - u.screenWidth/2 - 20 && f.cells[z].x-f.cells[z].radius < u.x + u.screenWidth/2 + 20 && f.cells[z].y+f.cells[z].radius > u.y - u.screenHeight/2 - 20 && f.cells[z].y-f.cells[z].radius < u.y + u.screenHeight/2 + 20) { z = f.cells.lenth; if(f.id !== u.id) { return { id: f.id, x: f.x, y: f.y, cells: f.cells, massTotal: Math.round(f.massTotal), hue: f.hue, name: f.name }; } else { //console.log("Nombre: " + f.name + " Es Usuario"); return { x: f.x, y: f.y, cells: f.cells, massTotal: Math.round(f.massTotal), hue: f.hue, }; } } } }) .filter(function(f) { return f; }); sockets[u.id].emit('serverTellPlayerMove', visibleCells, visibleFood, visibleMass, visibleVirus); if (leaderboardChanged) { sockets[u.id].emit('leaderboard', { players: users.length, leaderboard: leaderboard }); } }); leaderboardChanged = false; } setInterval(moveloop, 1000 / 60); setInterval(gameloop, 1000); setInterval(sendUpdates, 1000 / c.networkUpdateFactor); // Don't touch, IP configurations. var ipaddress = process.env.OPENSHIFT_NODEJS_IP || process.env.IP || '127.0.0.1'; var serverport = process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || c.port; if (process.env.OPENSHIFT_NODEJS_IP !== undefined) { http.listen( serverport, ipaddress, function() { console.log('[DEBUG] Listening on *:' + serverport); }); } else { http.listen( serverport, function() { console.log('[DEBUG] Listening on *:' + c.port); }); } ...展开收缩
(系统自动生成,下载前可以参看下载内容)

下载文件列表

相关说明

  • 本站资源为会员上传分享交流与学习,如有侵犯您的权益,请联系我们删除.
  • 本站是交换下载平台,提供交流渠道,下载内容来自于网络,除下载问题外,其它问题请自行百度
  • 本站已设置防盗链,请勿用迅雷、QQ旋风等多线程下载软件下载资源,下载后用WinRAR最新版进行解压.
  • 如果您发现内容无法下载,请稍后再次尝试;或者到消费记录里找到下载记录反馈给我们.
  • 下载后发现下载的内容跟说明不相乎,请到消费记录里找到下载记录反馈给我们,经确认后退回积分.
  • 如下载前有疑问,可以通过点击"提供者"的名字,查看对方的联系方式,联系对方咨询.
 相关搜索: agario 源码
 输入关键字,在本站1000多万海量源码库中尽情搜索: