rubentd / tanks Goto Github PK
View Code? Open in Web Editor NEWTanks battle game prototype, for nodejs learning purposes
Tanks battle game prototype, for nodejs learning purposes
Hi,
I'm implementing a game with your project, which is mervellous ! But i still have a little problem, in fact, i would like to implement a system which allows each player to have differents lifepoints, damages, or ball speed. I've tried some things, but it didn't work. There is the code i've made, can someone edit it to make my project possible ? Thank's you very much !
`var express = require('express');
var app = express();
var counter = 0;
var WIDTH = 1100;
var HEIGHT = 580;
var BALL_SPEED;
var TANK_INIT_HP;
var TANK_DAMAGES;
//Static resources server
app.use(express.static(__dirname + '/'));
var server = app.listen(process.env.PORT || 8082, function () {
var port = server.address().port;
console.log('Server running at port %s', port);
});
var io = require('socket.io')(server);
/* Connection events */
io.on('connection', function(client) {
console.log('User connected');
client.on('joinGame', function(tank){
console.log(tank.id + ' joined the game');
var initX = getRandomInt(40, 900);
var initY = getRandomInt(40, 500);
client.emit('addTank', { id: tank.id, type: tank.type, isLocal: true, x: initX, y: initY, hp: TANK_INIT_HP });
client.broadcast.emit('addTank', { id: tank.id, type: tank.type, isLocal: false, x: initX, y: initY, hp: TANK_INIT_HP} );
game.addTank({ id: tank.id, type: tank.type, hp: TANK_INIT_HP});
});
client.on('initialize', function(tankdata){
var BALL_SPEED = tankdata.ballspeed;
var TANK_INIT_HP = tankdata.tankhp;
var TANK_DAMAGES = tankdata.tankdamages;
});
client.on('sync', function(data){
//Receive data from clients
if(data.tank != undefined){
game.syncTank(data.tank);
}
//update ball positions
game.syncBalls();
//Broadcast data to clients
client.emit('sync', game.getData());
client.broadcast.emit('sync', game.getData());
//I do the cleanup after sending data, so the clients know
//when the tank dies and when the balls explode
game.cleanDeadTanks();
game.cleanDeadBalls();
counter ++;
});
client.on('shoot', function(ball){
var ball = new Ball(ball.ownerId, ball.alpha, ball.x, ball.y );
game.addBall(ball);
});
client.on('chatMessage', function(message, tankname){
console.log('['+tankname+'] : '+message);
client.emit('recieveChatMessage', message, tankname);
client.broadcast.emit('recieveChatMessage', message, tankname);
});
client.on('leaveGame', function(tankId){
console.log(tankId + ' has left the game');
game.removeTank(tankId);
client.broadcast.emit('removeTank', tankId);
});
});
function Ball(ownerId, alpha, x, y){
this.id = game.lastBallId;
game.increaseLastBallId();
this.ownerId = ownerId;
this.alpha = alpha; //angle of shot in radians
this.x = x;
this.y = y;
this.out = false;
};
Ball.prototype = {
fly: function(){
//move to trayectory
var speedX = BALL_SPEED * Math.sin(this.alpha);
var speedY = -BALL_SPEED * Math.cos(this.alpha);
this.x += speedX;
this.y += speedY;
}
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function GameServer(){
this.tanks = [];
this.balls = [];
this.lastBallId = 0;
}
GameServer.prototype = {
addTank: function(tank){
this.tanks.push(tank);
},
addBall: function(ball){
this.balls.push(ball);
},
removeTank: function(tankId){
//Remove tank object
this.tanks = this.tanks.filter( function(t){return t.id != tankId} );
},
//Sync tank with new data received from a client
syncTank: function(newTankData){
this.tanks.forEach( function(tank){
if(tank.id == newTankData.id){
tank.x = newTankData.x;
tank.y = newTankData.y;
tank.baseAngle = newTankData.baseAngle;
tank.cannonAngle = newTankData.cannonAngle;
}
});
},
//The app has absolute control of the balls and their movement
syncBalls: function(){
var self = this;
//Detect when ball is out of bounds
this.balls.forEach( function(ball){
self.detectCollision(ball);
if(ball.x < 0 || ball.x > WIDTH
|| ball.y < 0 || ball.y > HEIGHT){
ball.out = true;
}else{
ball.fly();
}
});
},
//Detect if ball collides with any tank
detectCollision: function(ball){
var self = this;
this.tanks.forEach( function(tank){
if(tank.id != ball.ownerId
&& Math.abs(tank.x - ball.x) < 30
&& Math.abs(tank.y - ball.y) < 30){
//Hit tank
self.hurtTank(tank);
ball.out = true;
ball.exploding = true;
}
});
},
hurtTank: function(tank){
tank.hp -= TANK_DAMAGES;
},
getData: function(){
var gameData = {};
gameData.tanks = this.tanks;
gameData.balls = this.balls;
return gameData;
},
cleanDeadTanks: function(){
this.tanks = this.tanks.filter(function(t){
return t.hp > 0;
});
},
cleanDeadBalls: function(){
this.balls = this.balls.filter(function(ball){
return !ball.out;
});
},
increaseLastBallId: function(){
this.lastBallId ++;
if(this.lastBallId > 1000){
this.lastBallId = 0;
}
}
}
var game = new GameServer();`
Blog post has a link of http://rubentd.com/blog/creating-a-multiplayer-game-with-node-js/github.com/rubentd/tanks
which needs to be trimmed down to just
github.com/rubentd/tanks
Hey,
I noticed a lack of performance here. Okay it is not the main purpose of the tutorial but we can't do html updates in a graphical game.
What if you replace all of this by a canvas?
I'm making my own tanks game, maybe you could inspirate from what i've done, later.
Presently once the user exits the window his tank remains in the frame till someone actually destroys it, I think function for that is already implemented but it's not functioning correctly.
Hi, i'm making a game with your code and i've try to make a chest system. This chest system would be very simple : after the number of server chests defined, it appends on the arena. When a tank shoot a chest, he win +10PV.
I've tried many codes but it still don't working. Can you try to make it in your project and to publish it ? It would be great and will be very helpful for me !
Thank's you very much !
Thanks for writing a short and simple multiuser game with tanks.
But how would you do this with entity interpolation and server reconciliation?
Just wanted to report a potential bug/ improvement.
The move controls will not work if caps lock on.
In your setControls function, you could add in four more cases for all corresponding upper case keys to both keypress(), and keyup() as a potential fix, or chance from switch case to if-else.
For reference, here are the ASCII characters:
87 uppercase W
68 uppercase D
83 uppercase S
65 uppercase A
But i love this template, awesome job!!
Might want to mention this in the README.md, or in the source code, or in the blog post.
Thank you for sharing your article and source code!
Hello,
If I name my tank "hello world", or anything with a space in the middle, the tank is not rendered on the game. I can still shoot but the tank itself is hidden.
Hi,
i'm testing your game on my server. There seems to be an issue with mouse events when playing with firefox. The cannon shows allways to the top.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.