topical media & game development
mobile-game-ch21-pong-public-pong.js / js
$(function() {
var Q = window.Q = Quintus()
.include('Input,Sprites,Scenes')
.setup('quintus');
var socket = io.connect();
Q.input.keyboardControls()
Q.input.touchControls({
controls: [ ['left','<' ],[],[],[],['right','>' ]]
});
var gameType = null, delay = 0;
Q.Paddle = Q.Sprite.extend({
init: function(props) {
this._super(_(props).defaults({
w: 60, h: 20,
speed: 200,
direction: null
}));
},
step: function(dt) {
dt += this.p.paddleDelay / 1000;
this.p.paddleDelay = 0;
if(this.p.direction == 'left') {
this.p.x -= this.p.speed * dt;
} else if(this.p.direction == 'right') {
this.p.x += this.p.speed * dt;
}
if(this.p.x < 0) { this.p.x = 0; }
if(this.p.x > Q.width - this.p.w) { this.p.x = Q.width - this.p.w; }
},
draw: function(ctx) {
ctx.fillStyle = "black";
ctx.fillRect(Math.floor(this.p.x),
Math.floor(this.p.y),
this.p.w,this.p.h);
}
});
Q.PlayerPaddle = Q.Paddle.extend({
step: function(dt) {
var lastDirection = this.p.direction;
this.p.direction = null;
if(Q.inputs['left']) {
this.p.direction = 'left';
} else if(Q.inputs['right']) {
this.p.direction = 'right';
}
this._super(dt);
if(lastDirection != this.p.direction) {
socket.emit("move",[this.p.direction,this.p.x]);
}
}
});
Q.EnemyPaddle = Q.Paddle.extend({
init: function(props) {
this._super(props);
var self = this, p = this.p;
socket.on("move",function(data) {
p.direction = data[0];
p.x = data[1];
self.step(delay/1000);
});
}
});
Q.Ball = Q.Sprite.extend({
init: function(props) {
this._super(_(props||{}).defaults({
x: 200, y: 100,
w: 10, h: 10,
dx: -1, dy: -1,
speed: 100,
ballRate: 0.5,
ballSend: 0.5
}));
var self = this, p = this.p;
if(gameType == 'slave') {
socket.on("ball",function(pos) {
p.x = pos.x;
p.y = pos.y;
p.dx = pos.dx;
p.dy = pos.dy;
self.step(delay/1000);
});
}
},
step: function(dt) {
var p = this.p;
var hit = Q.stage().collide(this);
if(hit) {
p.dy = hit.p.y < 100 ? 1 : -1;
}
p.x += p.dx * p.speed * dt;
p.y += p.dy * p.speed * dt;
var maxX = Q.width - p.w;
if(p.x < 0) { p.x = 0; p.dx = 1; }
else if(p.x > maxX) { p.dx = -1; p.x = maxX; }
if(p.y < 0 || p.y > Q.height) {
p.x = 200; p.y = 100;
p.dy *= -1;
}
if(gameType == 'master') {
p.ballSend -= dt;
if(p.ballSend < 0) {
socket.emit("ball", { x: p.x, y: p.y, dx: p.dx, dy: p.dy });
p.ballSend += p.ballRate;
}
}
},
draw: function(ctx) {
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(this.p.x + this.p.w/2,
this.p.y + this.p.h/2,
this.p.w/2,0,Math.PI*2);
ctx.fill();
}
});
Q.scene('game',new Q.Scene(function(stage) {
if(gameType == 'master') {
stage.insert(new Q.PlayerPaddle({ x:0, y: 40}));
stage.insert(new Q.EnemyPaddle({ x:0, y: Q.height - 100}));
} else if(gameType == 'slave') {
stage.insert(new Q.EnemyPaddle({ x:0, y: 40}));
stage.insert(new Q.PlayerPaddle({ x:0, y: Q.height - 100}));
}
stage.insert(new Q.Ball());
}));
socket.on("master",function() {
gameType = 'master';
Q.stageScene("game");
});
socket.on("slave",function() {
gameType = 'slave';
Q.stageScene("game");
});
socket.on("end",function() {
Q.clearStage(0);
});
socket.on('delay',function(data) {
if(data.steps == 3) {
// delay 1/2 of the round trip time
delay = (new Date().getTime() - data.timer)/2;
if(delay > 50) {
delay = 50;
}
} else {
data.steps += 1;
socket.emit('delay',data);
}
});
setInterval(function() {
socket.emit('delay',{ steps: 0, timer: new Date().getTime() });
},2000);
});
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.