Senin, 18 Februari 2013
Ball Game - with mouse enabled.

I use no image but draws radial gradient into the canvas.
Try to click and drag the white ball after re-creates it.
Script in the html
This is the script I put in the html's footer (don't forget to add a canvas in the body and give id as "myCancas"):var game = new ICHOLE.Game(document.getElementById("myCanvas"));
game.canvas.onmousedown = function(e){ game.mouseDown(e); };
game.canvas.onmouseup = function(e){ game.mouseUp(e); };
window.setInterval( function(e){ game.updateAll(); }, 1000/game.FPS) ;
Script at js folder
... and this is the js/gchole.js:var ICHOLE = {author:"mi_kuncoro@yahoo.co.id", ver:"20130207"};
ICHOLE.Game = function(cvs)
{
this.canvas = cvs;
this.context = this.canvas.getContext("2d");
this.init();
};
ICHOLE.Game.prototype = {
costructor:ICHOLE.Game,
FRICTION:0.99,
PR:Math.PI * 2,
P180:Math.PI / 180,
I180:180 / Math.PI,
FPS:50,
mouseIsDown:false,
wall:{left:50, top:50, right:450, down:450},
players:[{id:0, playerName:"Player 1", score:0}, {id:1, playerName:"Player 2", score:0}],
hole:null,
gaco:null,
rBalls:[],
gBalls:[],
aBalls:[],
collides:[],
busy:false,
curLevel:0,
curPlayer:null,
canvas:null,
context:null,
createBall:function(xx, yy, rr, knd, clr){
return {x:xx, y:yy, vx:0, vy:0, radius:rr, kind:knd, color:clr, alive:true, collided:false};
},
collideA:function(a, firstTime){
if (a.length == 0) return;
for (var i = 0; i < a.length; i++){
this.collideBA(a[i], a, firstTime);
}
},
collideBA:function(b, a, firstTime){
var aCol = [];
var dMin = 100000;
var cObj;
for (var i = 0; i < a.length; i++){
cObj = this.collideBB(b, a[i]);
if (cObj.collide == true) {
if (firstTime) {
this.collides.push([b, a[i]]);
}
if (cObj.dist < dMin){
aCol.length = 0;
dMin = cObj.dist;
aCol.push(cObj);
}
else if (cObj.dist == dMin){
aCol.push(cObj);
}
}
}
this.resolveA(aCol);
},
collideBB:function(b1, b2){
if (b1 == b2) return {collide:false};
var o = {collide:false, ball1:b1, ball2:b2, dist:this.distance(b2.x, b2.y, b1.x, b1.y), dist2:0};
o.dist2 = b1.radius + b2.radius - o.dist;
if (o.dist2 > 0) o.collide = true;
return o;
},
collideBW:function(b, w){
if ((b.x - w.left) < b.radius){
b.x = b.x + b.x - w.left - b.radius + 1;
if (b.vx < 0) b.vx *= -1;
}
else if ((w.right - b.x) < b.radius){
b.x = b.x + b.x + b.radius - w.right - 1;
if (b.vx > 0) b.vx *= -1;
}
if ((b.y - w.top) < b.radius){
b.y = b.y + b.y - b.radius - w.top + 1;
if (b.vy < 0) b.vy *= -1;
}
else if ((w.down - b.y) < b.radius){
b.y = b.y + b.y + b.radius - w.down - 1;
if (b.vy > 0) b.vy *= -1;
}
},
resolveA:function(a){
if (a.length == 0) return;
var ab = [];
var ao;
while (a.length > 0){
ao = a.shift();
this.resolveO(ao);
this.collideBW(ao.ball1, this.wall);
this.collideBW(ao.ball2, this.wall);
ab.push(ao.ball1);
ab.push(ao.ball2);
}
this.collideA(ab);
},
resolveO:function(o){
var b1 = o.ball1;
var b2 = o.ball2;
var x1h = b1.vx / 2; var y1h = b1.vy / 2;
var x2h = b2.vx / 2; var y2h = b2.vy / 2;
var px = (b2.x - b1.x) / 2 + b1.x;
var py = (b2.y - b1.y) / 2 + b1.y;
var dx = b1.x - px;
var dy = b1.y - py;
var dd = Math.sqrt(dx * dx + dy * dy);
var dx2 = b2.x - px;
var dy2 = b2.y - py;
var dd2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
var pwr1 = Math.sqrt(b1.vx * b1.vx + b1.vy * b1.vy) / 2;
var pwr2 = Math.sqrt(b2.vx * b2.vx + b2.vy * b2.vy) / 2;
var pwr = (pwr1 + pwr2) / 2;
b1.vx = dx / dd * pwr + x1h;
b1.vy = dy / dd * pwr + y1h;
b2.vx = dx2 / dd2 * pwr + x2h;
b2.vy = dy2 / dd2 * pwr + y2h;
var ddd = o.dist2 + 1;
b1.x += b1.vx * ddd;
b1.y += b1.vy * ddd;
b2.x += b2.vx * ddd;
b2.y += b2.vy * ddd;
},
draw:function(ctx)
{
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
ctx.fillStyle = "#333333";
ctx.fillRect(this.wall.left, this.wall.top, this.wall.right - this.wall.left, this.wall.down - this.wall.top);
this.drawBall(ctx, this.hole);
for (var i = 0; i < this.aBalls.length; i++){
this.drawBall(ctx, this.aBalls[i]);
}
},
drawBall:function(ctx, b){
if (b.alive == false) return;
var curFill;
try {
curFill = ctx.createRadialGradient(b.x-b.radius, b.y - b.radius, 0, b.x + b.radius, b.y + b.radius, 50);
curFill.addColorStop(0, '#FFFFFF');
curFill.addColorStop(0.5, b.color);
curFill.addColorStop(1, '#000000');
ctx.fillStyle = curFill;
ctx.strokeStyle = "#553300";
ctx.beginPath();
ctx.arc(b.x, b.y, b.radius, 0, this.PR, true);
ctx.closePath();
ctx.fill();
ctx.stroke();
}catch(e){}
},
distance:function(x1, y1, x2, y2){
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt((dx * dx) + (dy * dy));
},
normalize:function(x1, y1){
var dd = Math.sqrt((x1 * x1) + (y1 * y1));
if (dd != 0 && dd != 1)
{
x1 /= dd;
y1 /= dd;
}
},
updateAll:function(e){
this.collides.length = 0;
var n = this.aBalls.length;
var b;
for (var i = 0; i < n; i++) {
b = this.aBalls[i];
if (b.vx != 0 || b.vy != 0){
b.x += b.vx;
b.y += b.vy;
b.vx *= this.FRICTION;
b.vy *= this.FRICTION;
if (Math.abs(b.vx * b.vy) < 0.01) b.vx = b.vy = 0;
this.collideBW(b, this.wall);
}
} this.collideA(this.aBalls, true);
this.draw(this.context);
},
mouseDown:function(e){
if (this.gaco == null) return;
var b = this.gaco; //console.log(b);
if (Math.abs(e.offsetX - b.x) < b.radius || Math.abs(e.offsetY - b.y) < b.radius) this.mouseIsDown = true;
},
mouseUp:function(e){
if (this.mouseIsDown) {
var b = this.gaco;
var dx = b.x - e.offsetX;
var dy = b.y - e.offsetY;
var dd = Math.sqrt(dx * dx + dy * dy);
var dn = (Math.abs(dd) < 10) ? dd : (9 * dd / Math.abs(dd));
if (dd != 0 && dd != 1)
{
b.vx = dx/dd * dn;
b.vy = dy/dd * dn;
}
}
this.mouseIsDown = false;
},
startLevel:function(v){
var a = - Math.PI / 2;
var aa = Math.PI * 2 / 7;
var b;
this.gaco.x = 250;
this.gaco.y = 400;
this.gaco.vx = 2;
this.gaco.vy = -3;
this.aBalls.push(this.gaco);
for (var i = 0; i < 7; i++){
b = this.rBalls[i];
b.x = Math.cos(a) * 100 + 250;
b.y = Math.sin(a) * 100 + 250;
b.alive = true;
this.aBalls.push(b);
b = this.gBalls[i];
b.x = Math.cos(a) * 150 + 250;
b.y = Math.sin(a) * 150 + 250;
b.alive = true;
this.aBalls.push(b);
a += aa;
}
this.draw(this.context, 500, 500);
this.curPlayer = this.players[0];
},
init:function(){
this.hole = this.createBall(250, 250, 16, -1, "#000000");
this.gaco = this.createBall(250, 400, 16, 0, "#cccccc");
for (var i = 0; i < 7; i++){
this.rBalls.push(this.createBall(0, 0, 16, 1, "#ff0000"));
this.gBalls.push(this.createBall(0, 0, 16, 2, "#00ff00"));
}
this.context.fillStyle = "#550033";
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.startLevel(1);
}
};
You also can copy and paste the script right into the html.
if (a.length == 0) return;
var ab = [];
var ao;
while (a.length > 0){
ao = a.shift();
this.resolveO(ao);
this.collideBW(ao.ball1, this.wall);
this.collideBW(ao.ball2, this.wall);
ab.push(ao.ball1);
ab.push(ao.ball2);
}
this.collideA(ab);
},
resolveO:function(o){
var b1 = o.ball1;
var b2 = o.ball2;
var x1h = b1.vx / 2; var y1h = b1.vy / 2;
var x2h = b2.vx / 2; var y2h = b2.vy / 2;
var px = (b2.x - b1.x) / 2 + b1.x;
var py = (b2.y - b1.y) / 2 + b1.y;
var dx = b1.x - px;
var dy = b1.y - py;
var dd = Math.sqrt(dx * dx + dy * dy);
var dx2 = b2.x - px;
var dy2 = b2.y - py;
var dd2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
var pwr1 = Math.sqrt(b1.vx * b1.vx + b1.vy * b1.vy) / 2;
var pwr2 = Math.sqrt(b2.vx * b2.vx + b2.vy * b2.vy) / 2;
var pwr = (pwr1 + pwr2) / 2;
b1.vx = dx / dd * pwr + x1h;
b1.vy = dy / dd * pwr + y1h;
b2.vx = dx2 / dd2 * pwr + x2h;
b2.vy = dy2 / dd2 * pwr + y2h;
var ddd = o.dist2 + 1;
b1.x += b1.vx * ddd;
b1.y += b1.vy * ddd;
b2.x += b2.vx * ddd;
b2.y += b2.vy * ddd;
},
draw:function(ctx)
{
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
ctx.fillStyle = "#333333";
ctx.fillRect(this.wall.left, this.wall.top, this.wall.right - this.wall.left, this.wall.down - this.wall.top);
this.drawBall(ctx, this.hole);
for (var i = 0; i < this.aBalls.length; i++){
this.drawBall(ctx, this.aBalls[i]);
}
},
drawBall:function(ctx, b){
if (b.alive == false) return;
var curFill;
try {
curFill = ctx.createRadialGradient(b.x-b.radius, b.y - b.radius, 0, b.x + b.radius, b.y + b.radius, 50);
curFill.addColorStop(0, '#FFFFFF');
curFill.addColorStop(0.5, b.color);
curFill.addColorStop(1, '#000000');
ctx.fillStyle = curFill;
ctx.strokeStyle = "#553300";
ctx.beginPath();
ctx.arc(b.x, b.y, b.radius, 0, this.PR, true);
ctx.closePath();
ctx.fill();
ctx.stroke();
}catch(e){}
},
distance:function(x1, y1, x2, y2){
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt((dx * dx) + (dy * dy));
},
normalize:function(x1, y1){
var dd = Math.sqrt((x1 * x1) + (y1 * y1));
if (dd != 0 && dd != 1)
{
x1 /= dd;
y1 /= dd;
}
},
updateAll:function(e){
this.collides.length = 0;
var n = this.aBalls.length;
var b;
for (var i = 0; i < n; i++) {
b = this.aBalls[i];
if (b.vx != 0 || b.vy != 0){
b.x += b.vx;
b.y += b.vy;
b.vx *= this.FRICTION;
b.vy *= this.FRICTION;
if (Math.abs(b.vx * b.vy) < 0.01) b.vx = b.vy = 0;
this.collideBW(b, this.wall);
}
} this.collideA(this.aBalls, true);
this.draw(this.context);
},
mouseDown:function(e){
if (this.gaco == null) return;
var b = this.gaco; //console.log(b);
if (Math.abs(e.offsetX - b.x) < b.radius || Math.abs(e.offsetY - b.y) < b.radius) this.mouseIsDown = true;
},
mouseUp:function(e){
if (this.mouseIsDown) {
var b = this.gaco;
var dx = b.x - e.offsetX;
var dy = b.y - e.offsetY;
var dd = Math.sqrt(dx * dx + dy * dy);
var dn = (Math.abs(dd) < 10) ? dd : (9 * dd / Math.abs(dd));
if (dd != 0 && dd != 1)
{
b.vx = dx/dd * dn;
b.vy = dy/dd * dn;
}
}
this.mouseIsDown = false;
},
startLevel:function(v){
var a = - Math.PI / 2;
var aa = Math.PI * 2 / 7;
var b;
this.gaco.x = 250;
this.gaco.y = 400;
this.gaco.vx = 2;
this.gaco.vy = -3;
this.aBalls.push(this.gaco);
for (var i = 0; i < 7; i++){
b = this.rBalls[i];
b.x = Math.cos(a) * 100 + 250;
b.y = Math.sin(a) * 100 + 250;
b.alive = true;
this.aBalls.push(b);
b = this.gBalls[i];
b.x = Math.cos(a) * 150 + 250;
b.y = Math.sin(a) * 150 + 250;
b.alive = true;
this.aBalls.push(b);
a += aa;
}
this.draw(this.context, 500, 500);
this.curPlayer = this.players[0];
},
init:function(){
this.hole = this.createBall(250, 250, 16, -1, "#000000");
this.gaco = this.createBall(250, 400, 16, 0, "#cccccc");
for (var i = 0; i < 7; i++){
this.rBalls.push(this.createBall(0, 0, 16, 1, "#ff0000"));
this.gBalls.push(this.createBall(0, 0, 16, 2, "#00ff00"));
}
this.context.fillStyle = "#550033";
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.startLevel(1);
}
};
You also can copy and paste the script right into the html.
Sabtu, 16 Februari 2013
Simple way to start html5 canvas game
example.js:
var renderer = null;
var sprites = null;
var FPS = 60;
function init(canvas, tex)
{
this.renderer = new KOEN2D.Renderer(canvas);
var a = [];
var p2 = Math.PI * 2;
var s;
for (var i = 0; i < 2000; i++){
a.push(new KOEN2D.Sprite());
a[i].name = "sprite" + i.toString();
a[i].image = tex;
a[i].position.x = Math.random() * 500 + 50;
a[i].position.y = Math.random() * 300 + 50;
a[i].rotation = Math.random() * p2;
a[i].vector.x = Math.cos(a[i].rotation);
a[i].vector.y = Math.sin(a[i].rotation);
a[i].scaleX = 0.25;
a[i].scaleY = 0.25;
a[i].speed = Math.random() * 5 + 1;
console.log(a[i].name + " x " + a[i].position.x);
}
this.sprites = a;
window.setInterval(this.step, FPS);
};
function step(e)
{
if (this.sprites.length == 0) return;
for (var i = 0; i < this.sprites.length; i++){ this.stepSprite(this.sprites[i]); }
renderer.render(this.sprites);
};
function stepSprite(o)
{
var rotChange = false;
o.position.x += (o.vector.x * o.speed);
o.position.y += (o.vector.y * o.speed);
if (o.position.x > 695 || o.position.x < 25){
o.vector.x *= -1;
o.position.x += (o.vector.x * o.speed * 2);
rotChange = true;
}
if (o.position.y > 375 || o.position.y < 25){
o.vector.y *= -1;
o.position.y += (o.vector.y * o.speed * 2);
rotChange = true;
}
if (rotChange){
o.rotation = Math.atan2(o.vector.y, o.vector.x);
}
};
var tex = new Image();
tex.src = "res/redship.png";
tex.onload = function(){init(document.getElementById("myCanvas"), tex);};
koen2d.js:
( function () {
var lastTime = 0;
var vendors = [ 'ms', 'moz', 'webkit', 'o' ];
for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++ x ) {
window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ];
window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ];
}
if ( !window.requestAnimationFrame ) {
window.requestAnimationFrame = function ( callback, element ) {
var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
var id = window.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall );
lastTime = currTime + timeToCall;
return id;
};
}
if ( !window.cancelAnimationFrame ) {
window.cancelAnimationFrame = function ( id ) { clearTimeout( id ); };
}
}() );
var KOEN2D = KOEN2D || {
VERSION: '2013_1.0',
P180:Math.PI / 180,
PROUND:Math.PI * 2,
lastID:0
};
// Point
KOEN2D.Point = function(xx, yy)
{
this.name = "point" + (KOEN2D.lastID++);
this.x = xx;
this.y = yy;
};
KOEN2D.Point.prototype = {
constructor:KOEN2D.Point,
name:'',
x:0,
y:0
};
KOEN2D.Point.add = function(p1, p2) {
return new KOEN2D.Point(p1.x + p2.x, p1.y + p2.y);
};
KOEN2D.Point.angle = function(p1, p2) {
var dx = p1.x - p1.x;
var dy = p2.y - p1.y;
return Math.atan2(dy, dx);
};
KOEN2D.Point.clone = function(p) {
return new KOEN2D.Point(p.x, p.y);
};
KOEN2D.Point.distance = function(p1, p2) {
var dx = p1.x - p1.x;
var dy = p2.y - p1.y;
return Math.sqrt(dx * dx + dy * dy);
};
KOEN2D.Point.multiply = function(p, n) {
return new KOEN2D.Point(p.x * n, p.y * n);
};
KOEN2D.Point.normalize = function(p) {
var d = Math.sqrt(p.x * p.x + p.y * p.y);
if (d > 1)
{
p.x /= d;
p.y /= d;
}
};
KOEN2D.Point.subtract = function(p1, p2) {
return new KOEN2D.Point(p1.x - p2.x, p1.y - p2.y);
};
KOEN2D.Renderer = function(canvas){
this.canvas = canvas;
this.context = canvas.getContext("2d");
};
KOEN2D.Renderer.prototype = {
constructor:KOEN2D.Renderer,
canvas:null,
context:null,
render:function(a)
{
this.context.fillStyle = "#333333";
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
//sprites.sortOn("y", Array:NUMERIC);
//a.sort(function(a,b) {return (a.y > b.y) ? 1 : 0; });
for (var i = 0; i < a.length; i++) { this.renderItem(this.context, a[i]); }
},
renderItem:function(c, o)
{
c.save();
c.translate(o.position.x, o.position.y);
c.scale(o.scaleX, o.scaleY);
c.rotate(o.rotation);
c.drawImage(o.image, -o.image.width * 0.5, -o.image.height * 0.5);
c.restore();
}
}
// rotation in rad;
KOEN2D.Sprite = function(){
this.name = "sprite_" + (KOEN2D.lastID++);
this.position = new KOEN2D.Point(0, 0);
this.vector = new KOEN2D.Point(0, 0);
// why defining object in prototype will cause single object for every new object?
};
KOEN2D.Sprite.prototype = {
constructor:KOEN2D.Sprite,
name:'',
position:null,
rotation:0,
vector:null,
scaleX:1.0,
scaleY:1.0,
speed:0.0,
image:null,
data:null,
dispose:function(){
this.image = null;
this.data = null;
}
};
The html body contain canvas with id mycanvas.
The footer inlcudes js/example.js and js/koen2d.js.
That's all. Look at the speed. I can put more than 3000 sprites in chrome!.
Langganan:
Komentar (Atom)

