sorry for the code dump but if any of you could help me figure out why the ball on this pong game moves vertically up and down instead of waiting for a serve command and then moving left to right, please let me know!
I’ve tried to cut most of the unnecessary stuff regarding the rest of the game but as movement is tied in to a lot of things and could come from a lot of places I’ve had to send it out as is.
main.js
'use strict'
//let divs=[];
/*
socket.on('css', function(data) {
console.log(data);
for(var i=0;i<data.length;i++) {
let css = data[i];
let div = divs[i];
if(!div) {
$('body').append('<div id="id'+i+'">');
div= divs[i] = $('#id'+i);
}
div.css(css.css);
}
});
*/
//framerate class
class Framerate {
timestamps = [];
framerate =60;
constructor(defaultFramerate) {
this.framerate = defaultFramerate;
}
update() {
const now = performance.now();
while (this.timestamps.length > 0 && this.timestamps[0] <= now - 1000) {
this.timestamps.shift();
}
this.timestamps.push(now);
if(this.timestamps.length<45) {
this.framerate = 30;
} else if (this.timestamps.length<75) {
this.framerate = 60;
} else if (this.timestamps.length<105) {
this.framerate = 90;
} else if (this.timestamps.length<135) {
this.framerate = 120;
} else if (this.timestamps.length<160) {
this.framerate = 144;
} else {
this.framerate = 240;
}
createjs.Ticker.framerate = this.framerate;
}
}
/***
* EaselJS Global Variables
*
*/
let easelCan, easelCtx, loader, stage, stageheight, stagewidth;
let easelbg, easelp1, easelp2, easelball;
let framerate=new Framerate(60);
let datarate=new Framerate(60);
let socket = io();
let objs =[];
let gamepanel = document.getElementById('gamepanel');
let pinst = document.getElementById('gamestatus');
let gamestate = 'prestart';
let pready = false;
let isserver = false;
let updown = false;
let downdown = false;
let nudgeallowed = true;
let R2D=180/Math.PI;
function init() {
easelCan = document.getElementById('easelcan');
if (easelCan) {
easelCtx = easelCan.getContext('2d');
stage = new createjs.Stage(easelCan);
stage.snapPixelsEnabled = true;
stagewidth = stage.canvas.width;
stageheight = stage.canvas.height;
let manifest = [
{src: 'assets/ball.png', id: 'ball'},
{src: 'assets/bar.png', id: 'bar'},
{src: 'assets/background1.png', id: 'bg'},
];
loader = new createjs.LoadQueue(false);
loader.addEventListener('complete', handleComplete);
loader.loadManifest(manifest);
} else {
console.error("Canvas element with ID 'easelcan' not found.");
}
}
function tick(e) {
document.getElementById('fps').innerHTML = 'fps '+framerate;
stage.update(e);
}
function handleComplete() {
easelbg = makeBitmap(loader.getResult('bg'), stagewidth, stageheight);
easelbg.x = 0;
easelbg.y = 0;
stage.addChild(easelbg);
socket.on('init', function(data) {
console.log('init');
console.log(data);
createjs.Ticker.framerate = framerate;
createjs.Ticker.atimingMode = createjs.Ticker.RAF;
createjs.Ticker.addEventListener('tick', tick);
for (let i = 0; i < data.length; i++) {
switch (data[i].id) {
case 'p1':
easelp1 = makeBitmap(loader.getResult('bar'), data[i].objwidth, data[i].objheight);
easelp1.x = data[i].x;
console.log(easelp1.x);
easelp1.y = data[i].y;
console.log(easelp1);
break;
case 'p2':
easelp2 = makeBitmap(loader.getResult('bar'), data[i].objwidth, data[i].objheight);
easelp2.x = data[i].x;
easelp2.y = data[i].y;
console.log(easelp2);
break;
case 'ball':
easelball = makeBitmap(loader.getResult('ball'), data[i].objwidth, data[i].objheight);
easelball.x = data[i].x;
easelball.y = data[i].y;
console.log(easelball);
break;
}
}
stage.addChild(easelp1, easelp2, easelball);
});
//handle gamestate
socket.on('connectionlist', function(data) {
console.log(data);
if (data.length==2) {
if (data[0].nickname != 'Anon' && data[1].nickname != 'Anon') {
let p1data = data.findIndex(element => element.sock == socket.id);
let p2data = data.findIndex(element => element.sock != socket.id);
console.log("p1data: " + p1data);
console.log("p2data: " + p2data);
document.getElementById('p1tag').innerHTML = data[p1data].nickname;
document.getElementById('p1score').innerHTML = data[p1data].pscore;
document.getElementById('p2tag').innerHTML = data[p2data].nickname;
document.getElementById('p2score').innerHTML = data[p2data].pscore;
console.log('game ready');
if (gamestate == 'prestart') {
pinst.innerHTML = 'waiting for server to start game';
gamestate = 'waiting';
console.log('waiting');
}
}
}
});
function isServerPlayer(socketId) {
// Find the player with the given socket ID in the connections array
const player = connections.find((element) => element.sock === socketId);
// If the player is found and they have pnum = 1, then they are the server
if (player && player.pnum === 1) {
return true;
}
// Otherwise, the player is not the server
return false;
}
socket.on('prestart', function (data) {
if (isServerPlayer(socket.id)) {
pinst.innerHTML = 'to start game press space';
gamestate = 'start';
socket.emit('server','server');
} else {
pinst.innerHTML = 'Waiting for server to start game';
gamestate = 'waiting';
}
});
socket.on('gamedata', function(data) {
datarate.update();
document.getElementById('datarate').innerHTML = 'datarate '+datarate.rate;
for (let i = 0; i < data.length; i++) {
switch (data[i].id) {
case 'p1':
easelp1.x = data[i].x;
easelp1.y = data[i].y;
break;
case 'p2':
easelp2.x = data[i].x;
easelp2.y = data[i].y;
break;
case 'ball':
easelball.x = data[i].x;
easelball.y = data[i].y;
easelball.rotation = data[i].rotation*R2D;
break;
}
}
});
//starting game
socket.on('startgame', function(data) {
pinst.innerHTML = 'Game Started';
gamestate = 'start';
});
socket.on('restround', function(data) {
pinst.innerHTML = isserver ? 'to start round press space' : 'waiting for server to start round';
gamestate = 'ready';
});
socket.on('server', function(data) {
isserver = data;
pinst.innerHTML = isserver ? 'to start round press space' : 'waiting for server to start round';
});
socket.on('roundactive', function(data) {
pinst.innerHTML = 'Round Active';
gamestate = 'roundactive';
});
//handle keypresses
document.addEventListener('keydown', function(e) {
if (e.code == "KeyW") {
if (!updown) {
updown = true;
socket.emit('playerctrl','updown');
}
}
if (e.code == "KeyS") {
if (!downdown) {
downdown = true;
socket.emit('playerctrl','downdown');
}
}
});
// Keyup event listener
document.addEventListener('keyup', function(e) {
console.log(e.code);
if (gamestate == 'waiting') {
socket.emit('playerready','ready');
gamestate = 'ready';
pinst.innerHTML = 'waiting for server to start round';
}
if (e.code == 'space' && gamestate == 'ready') {
pinst.innerHTML = 'Game Started';
gamestate = 'roundactive';
socket.emit('serve','serve');
}
if (e.code == 'space' && gamestate == 'roundactive' && nudgeallowed) {
nudgeallowed = false;
setTimeout(function() {
nudgeallowed = true;
}, 7000);
gamestate = 'roundactive';
socket.emit('nudge','nudge');
}
if (e.code == "KeyW" || e.code == "KeyA") {
updown = false;
socket.emit('playerctrl','upup');
}
if (e.code == "KeyS" || e.code == "KeyD") {
downdown = false;
socket.emit('playerctrl','downup');
}
if (e.code == "KeyR") {
if (easelCan.style.contains('p1focus')){
easelCan.classlist.remove('p1focus');
easelCan.classlist.add('p2focus');
} else if (easelCan.classlist.value('p2focus')){
easelCan.classlist.remove('p2focus');
easelCan.classlist.add('overview');
} else {
easelCan.classlist.remove('overview');
easelCan.classlist.add('p1focus');
}
}
});
}
init();
/**
* EJS Helper Functions
*/
function makeBitmap(ldrimg, b2x, b2y, yadjust = 0) {
var theimage = new createjs.Bitmap(ldrimg);
var scalex = (b2x * 2) / theimage.image.naturalWidth;
var scaley = (b2y * 2) / theimage.image.naturalHeight;
theimage.scaleX = scalex;
theimage.scaleY = scaley;
theimage.regX = theimage.image.width / 2;
theimage.regY = theimage.image.height / 2 - yadjust;
return theimage;
}
/**
* button functions
*/
/*
Index.js
'use strict'
const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http); // Socket.io
const Box2D = require('box2dweb-commonjs').Box2D;
let b2Vec2 = Box2D.Common.Math.b2Vec2;
let b2AABB = Box2D.Collision.b2AABB;
let b2BodyDef = Box2D.Dynamics.b2BodyDef;
let b2Body = Box2D.Dynamics.b2Body;
let b2FixtureDef = Box2D.Dynamics.b2FixtureDef;
let b2Fixture = Box2D.Dynamics.b2Fixture;
let b2World = Box2D.Dynamics.b2World;
let b2MassData = Box2D.Collision.Shapes.b2MassData;
let b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
let b2CircleShape = Box2D.Collision.Shapes.b2CircleShape;
let b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
let b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef;
let b2EdgeShape = Box2D.Collision.Shapes.b2EdgeShape;
let connections = [];
let world, interval, ball, p1, p2;
const SCALE = 30;
const WIDTH = 900;
const HEIGHT = 500;
const SIZE = 50;
let size = 50;
let fps = 30;
let gamestate = 'init';
let activeplayers = 0;
let serve =false;
let p1move = 'stop';
let p2move = 'stop';
let whoserves = 0;
let servecount = 0;
function createAnObject(objid,x,y,dims,objtype,isstatic) {
let bodyDef = new b2BodyDef();
bodyDef.type = isstatic ? b2Body.b2_staticBody : b2Body.b2_dynamicBody;
bodyDef.position.x = x / SCALE;
bodyDef.position.y = y / SCALE;
let fixDef = new b2FixtureDef();
fixDef.density = 1.5;
fixDef.friction = 0.5;
fixDef.restitution = 1.2;
let width, height;
if(objtype == 'circle') {
fixDef.shape = new b2CircleShape(dims.radius / SCALE);
width = dims.radius*2;
height = dims.radius*2;
} else if (objtype == 'rect'){
fixDef.shape = new b2PolygonShape();
fixDef.shape.SetAsBox(dims.width / SCALE, dims.height / SCALE);
width = dims.width;
height = dims.height;
} else {
console.log('invalid object type');
}
let thisobj = world.CreateBody(bodyDef).CreateFixture(fixDef);
thisobj.GetBody().SetUserData({
id:objid,
width:width,
height:height,
objtype:objtype,
isstatic:isstatic,
});
console.log(thisobj);
return thisobj;
}
/**
* Gamestates
*
* init - waiting for players
* lobby - players connected, waiting for ready
* startgame - players ready, waiting for serve
* roundactive - game in progress
* roundend - round over, waiting for serve
* gameover - game over, waiting for players
*
* Player states
* not connected
* anon
* registered
* ready
*
* isserver: true/false
* score
* nickname
* socketid
* pnum
*
*/
function creab2dObj(x, y, width, height, isstatic, circle) {
let bodyDef = new b2BodyDef;
bodyDef.type = isstatic ? b2Body.b2_staticBody : b2Body.b2_dynamicBody;
bodyDef.position.x = x / SCALE;
bodyDef.position.y = y / SCALE;
let fixDef = new b2FixtureDef;
fixDef.density = 1.0;
fixDef.friction = 0.5;
fixDef.restitution = 1.03;
if (circle) {
fixDef.shape = new b2CircleShape(width / SCALE);
} else {
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(width / SCALE, height / SCALE);
}
return world.CreateBody(bodyDef).CreateFixture(fixDef);
}
function createDOMObj(x, y, size, circle, objid) {
let width = size / 2;
let height = size / 2;
let gx = x + width;
let gy = y + height;
let body = creab2dObj(gx, gy, width, height, false, circle);
body.SetUserData({
domObj: objid,
width: width,
height: height,
circle: circle,
setup: true
});
}
function drawDOMObjects() {
let ret = [];
for (let b = world.GetBodyList(); b; b = b.GetNext()) {
for (let f = b.GetFixtureList(); f; f = f.GetNext()) {
let id = f.GetBody().GetUserData().id;
let x = Math.round(f.GetBody().GetPosition().x * SCALE);
console.log(x);
let y = Math.round(f.GetBody().GetPosition().y * SCALE);
console.log(y);
let r = Math.round(f.GetBody().GetAngle()*100)/100;
console.log(r);
let objtype = f.GetBody().GetUserData().objtype;
let objwidth = Math.round(f.GetBody().GetUserData().width);
let objheight = Math.round(f.GetBody().GetUserData().height);
ret.push({id:id,x:x,y:y,r:r,objtype:objtype,objwidth:objwidth,objheight:objheight});
}
}
return ret;
}
/**
* Listeners
*/
var listener = new Box2D.Dynamics.b2ContactListener();
listener.BeginContact = function (contact) {
let fixA = contact.GetFixtureA().GetUserData();
let fixB = contact.GetFixtureB().GetUserData();
if (fixA.id == 'ball' && fixB.id == 'ball') {
if (fixA.id == 'p1goal' || fixB.id == 'p1goal'){}
gamestate = 'p2score';
}
if (fixA.id == 'p2goal' || fixB.id == 'p2goal') {
gamestate = 'p1score';
}
//space for effects
};
listener.EndContact = function (contact) {
//space for effects
};
listener.PostSolve = function (contact, impulse) {
//space for effects
};
listener.PreSolve = function (contact, oldManifold) {
//space for effects
};
function update() {
world.Step(
1 / fps, //frame-rate
10, //velocity iterations
10 //position iterations
);
/**
* ball motion
*/
let varirate=(ball.GetBody().GetAngularVelocity())/240;
let xvar = (1-Math.cos(varirate))+ball.GetBody().GetLinearVelocity().x;
let yvar = (1-Math.sin(varirate))+ball.GetBody().GetLinearVelocity().y;
ball.GetBody().SetLinearVelocity(new b2Vec2(xvar,yvar));
/**
* game states
*/
if (gamestate == 'p1score' || gamestate == 'p2score') {
ball.GetBody().SetAngularVelocity(0);
ball.GetBody().SetPosition(new b2Vec2(WIDTH / 2 / SCALE, HEIGHT / 2 / SCALE));
ball.GetBody().SetLinearVelocity(new b2Vec2(0, 0));
let scorer = gamestate == 'p1score' ? 1 : 2;
let scorerindex = connections.findIndex(element => element.pnum == scorer);
connections[scorerindex].playerscore++;
if (servecount == 3) {
servecount = 0;
io.to(connections[currentserver].sock).emit('server',false);
currentserver = currentserver == 0 ? 1 : 0;
io.to(connections[currentserver].sock).emit('server',true);
}
gamestate = 'active';
serveball = true;
io.sockets.emit('connectionlist', connections);
io.sockets.emit('resetround','resetround');
}
/**
* p1 movement
*/
if (p1move != 'stop') {
let dir = p1move == 'up' ? -10 : 10;
p1.GetBody().SetPosition(new b2Vec(20/SCALE,p1.GetBody().GetPosition().y));
p1.GetBody().SetLinearVelocity(new b2Vec2(0,dir));
} else {
p1.GetBody().SetLinearVelocity(new b2Vec2(0,0));
}
/**
* p2 movement
*/
if (p2move != 'stop') {
let dir = p2move == 'up' ? -10 : 10;
p2.GetBody().SetPosition(new b2Vec((WIDTH-20)/SCALE,p2.GetBody().GetPosition().y));
p2.GetBody().SetLinearVelocity(new b2Vec2(0,dir));
} else {
p2.GetBody().SetLinearVelocity(new b2Vec2(0,0));
}
/**
* is active game
*/
if (activeplayers == 2) {
if (gamestate == 'roundactive') {
//check player states
if (serveball) {
serveball = false;
let servedir = connections[currentserver].pnum == 1 ? 1 : -1;
applyHit(servedir);
}
}
//send player states
io.sockets.emit('gamedata', drawGameData(true));
}
world.ClearForces();
}
/**
* nudge/serve ball
*/
function applyHit(dir) {
ball.GetBody().ApplyImpulse(new b2Vec(Math.random() * 6 * dir, (Math.random()- .4), ball.GetBody().GetWorldCenter()));
}
function init() {
world = new b2World(
new b2Vec2(0, 0), //gravity
false //allow sleep
);
//static objects
createAnObject('topwall',0,0,{width: WIDTH,height: 5, density: 5,friction: 0, restitution: 0},'rect',true,false);
createAnObject('bottomwall',0,HEIGHT,{width: WIDTH,height: 5, density: 5,friction: 0, restitution: 0},'rect',true,false);
createAnObject('p1goal',-5,0,{width: 5,height: HEIGHT, density: 5,friction: 0, restitution: 0},'rect',true,true);
createAnObject('p2goal',WIDTH +5 ,0,{width: 5,height: HEIGHT, density: 5,friction: 0, restitution: 0},'rect',true,true);
//dynamic objects
p1 = createAnObject('p1',20,HEIGHT/2,{width: 10,height: 100, density: 9,friction: 0, restitution: 0},'rect',false,false);
p1.GetBody().SetFixedRotation(true);
p2 = createAnObject('p2',WIDTH-20,HEIGHT/2,{width: 10,height: 100, density: 9,friction: 0, restitution: 0},'rect',false,false);
p2.GetBody().SetFixedRotation(true);
ball = createAnObject('ball',WIDTH/2,HEIGHT/2,{radius: 10, density: 1,friction: 1, restitution: 1},'circle',false,false);
ball.GetBody().IsBullet(true);
console.log(p1);
console.log(p2);
console.log(ball);
//createAnObject('rand',Math.random() * (WIDTH - SIZE), Math.random() * (HEIGHT - SIZE),{radius:Math.random()*SIZE},true,false);
//createAnObject('rand',Math.random() * (WIDTH - SIZE), Math.random() * (HEIGHT - SIZE),{width:Math.random()*SIZE,height:Math.random()*SIZE},true,false);
//createDOMObj(Math.random() * (WIDTH - size), Math.random() * (HEIGHT - size), Math.random() * 2 * size, Math.random() > 0.5, 'obj1');
interval = setInterval(function () {
if(gamestate!=='init') update();
}, 1000 / fps);
update();
}
function drawGameData(dynamiconly) {
let gamedata =[]
for (let b = world.GetBodyList(); b; b = b.GetNext()) {
for (let f = b.GetFixtureList(); f; f = f.GetNext()) {
if (!(dynamiconly && f.GetBody().GetUserData().isstatic)){
let id = f.GetBody().GetUserData().id;
let x = Math.round(f.GetBody().GetPosition().x * SCALE);
let y = Math.round(f.GetBody().GetPosition().y * SCALE);
let r = Math.round(f.GetBody().GetAngle()*100)/100;
let objtype = f.GetBody().GetUserData().objtype;
let objwidth = Math.round(f.GetBody().GetUserData().width);
let objheight = Math.round(f.GetBody().GetUserData().height);
gamedata.push({id:id,x:x,y:y,r:r,objtype:objtype,objwidth:objwidth,objheight:objheight});
}
}
}
return gamedata;
}
app.use(express.static('public'));
app.use('/js', express.static(__dirname + 'public/js'));
app.use('/css', express.static(__dirname + 'public/css'));
app.use('/assets', express.static(__dirname + 'public/assets'));
http.listen(8000, function () {
console.log('listening on *:8000');
let socket = io;
io.on('connection', (socket) => {
//connections.push(socket);
console.log('a user connected');
let pnum = connections.findIndex(element => element.pnum == 1) < 0 ? 1 : 2;
connections.push({sock:socket.id, nickname: 'Anon',pready: false,pscore:0,pnum:pnum});
ball.GetBody().SetPosition(new b2Vec2(WIDTH / 2 / SCALE, HEIGHT / 2 / SCALE));
ball.GetBody().SetLinearVelocity(new b2Vec2(0, 0));
io.sockets.emit('connectionlist', connections);
//on disconnect
socket.on('disconnect', () => {
gamestate = 'init';
let discoverplayer = connections.findIndex(element => element.sock == socket.id);
if (connections[discoverplayer].nickname != 'Anon') activeplayers--;
console.log(socket.id + ' disconnected');
connections = connections.filter(element => element.sock != socket.id);
console.log("connections");
io.sockets.emit('connectionlist', connections);
});
//player ready
socket.on('ready', () => {
let i = connections.findIndex(element => element.sock == socket.id);
connections[i].pready = true;
/*let readyplayers = connections.filter(element => element.pready == true);
if (readyplayers.length == 2) {
gamestate = 'roundactive';
io.sockets.emit('startgame', 'startgame');
}*/
if (connections.length ==2) {
if (connections[0].pready && connections[1].pready) {
console.log('game starting');
gamestate = 'startgame';
currentserver = connections.findIndex(element => element.pnum == 1);
io.to(connections[currentserver]).emit('server', 'server');
}
}
});
//control signals
socket.on('pcontrol', (data) => {
console.log("pcontrol")
let i = connections.findIndex(element => element.sock == socket.id);
if (data == 'updown') {
connections[i].pnum == 1 ? p1move = 'up' : p2move = 'up';
} else if (data == 'downdown') {
connections[i].pnum == 1 ? p1move = 'down' : p2move = 'down';
} else if (data == 'upup' || data == 'downup') {
connections[i].pnum == 1 ? p1move = 'stop' : p2move = 'stop';
}
});
// serve handling
socket.on('serve', (data) => {
console.log('serve');
servecount++;
gamestate = 'roundactive'
serveball = true;
let i = connections.findIndex(element => element.sock == socket.id);
connections[i].pnum == 1 ? p1serve = data : p2serve = data;
});
//update game
socket.on('nudge', (data) => {
console.log('nudge');
let i = connections.findIndex(element => element.sock == socket.id);
let nudgedirection = connections[i].pnum == 1 ? 1 : -1;
applyHit(nudgedirection);
});
});
});
init();