I have a problem,
my collision detection function sometimes sets entity position to NaN.
When I open console (on chrome) position of entity and collision are valid numbers but subtracting them from each other sometimes returns NaN.
updateCollision = function(entity,rect) {
var a = entity.x - rect.x; // a = NaN , entity.x = 3117.2646499953607 , rect.x = 3296.976967651385
var b = entity.y - rect.y; // b = NaN , entity.y = 3024.105915848102 , rect.y = 3144.4270586199345
if( isNaN(a) ) // isNaN(a) = true
{
console.log("not again >:("); // but console doesn't log
}
//the code continues but its not important
screenshot of console:
So I am really confused, and don't know what to do with this issue.
I have rewriten the code one more time and I dont get the NaN values anymore
Fixed function:
updateCollision = function(entity,rect) {
var a = entity.x - rect.x;
var b = entity.y - rect.y;
var unrotatedCircleY = Math.sin((-rect.angle)/180*Math.PI)*a + Math.cos((-rect.angle)/180*Math.PI)*b +rect.y;
var unrotatedCircleX = Math.cos((-rect.angle)/180*Math.PI)*a - Math.sin((-rect.angle)/180*Math.PI)*b +rect.x;
var r = entity.collRad/2;
var closestX, closestY, aX, aY;
if (unrotatedCircleX < rect.x - rect.width/2 )
{
closestX = rect.x - rect.width/2;
aX = closestX;
}
else if (unrotatedCircleX > rect.x + rect.width/2 )
{
closestX = rect.x + rect.width/2;
aX = closestX;
}
else
{
closestX = unrotatedCircleX;
aX=rect.x;
}
if (unrotatedCircleY < rect.y - rect.height/2 )
{
closestY = rect.y - rect.height/2;
aY = closestY;
}
else if (unrotatedCircleY > rect.y + rect.height/2 )
{
closestY = rect.y + rect.height/2;
aY = closestY;
}
else
{
closestY = unrotatedCircleY;
aY = rect.y;
}
var collision = false;
var distance = getDistance(unrotatedCircleX , unrotatedCircleY, closestX, closestY);
if (distance < r)
collision = true;
else
collision = false;
if( collision && entity.type == "bullet")
{
entity.hp = 0;
}
else if(collision)
{
if( entity.type == "bullet")
{
DeleteEntity(entity);
return;
}
if( rect.collType == "solid" )
{
var positionAngle = Math.atan2( -closestY + unrotatedCircleY , -closestX + unrotatedCircleX );
var y_vel = Math.sin((-rect.angle)/180*Math.PI)*entity.x_vel + Math.cos((-rect.angle)/180*Math.PI)*entity.y_vel;
var x_vel = Math.cos((-rect.angle)/180*Math.PI)*entity.x_vel - Math.sin((-rect.angle)/180*Math.PI)*entity.y_vel;
y_vel *= 0.9;
x_vel *= 0.9;
unrotatedCircleX = closestX + Math.cos(positionAngle)*(r);
unrotatedCircleY = closestY + Math.sin(positionAngle)*(r);
a = unrotatedCircleX - rect.x;
b = unrotatedCircleY - rect.y;
entity.y = Math.sin((rect.angle)/180*Math.PI)*a + Math.cos((rect.angle)/180*Math.PI)*b + rect.y;
entity.x = Math.cos((rect.angle)/180*Math.PI)*a - Math.sin((rect.angle)/180*Math.PI)*b + rect.x;
entity.y_vel = Math.sin((rect.angle)/180*Math.PI)*x_vel + Math.cos((rect.angle)/180*Math.PI)*y_vel;
entity.x_vel = Math.cos((rect.angle)/180*Math.PI)*x_vel - Math.sin((rect.angle)/180*Math.PI)*y_vel;
}
if( rect.collType == "trigger" )
{
if( level["commandList"][rect.data].command == "tp" )
{
entity.x = level["commandList"][rect.data].x;
entity.y = level["commandList"][rect.data].y;
}
if( level["commandList"][rect.data].command == "loadLevel" )
{
levelToLoad = level["commandList"][rect.data].x;
}
}
}
But thanks for the help :)
I need to see more of your code, to see what is actually wrong, but surely NaN is a result of math operations on an undefined type, so take a good look if something is undefined
Related
I've added some JavaScript to my website that adds a glitter effect following the mouse as you move it and I absolutely love it. Except the fact that about halfway down the page a random new scroll bar appears and it scrolls past the footer and on forever. I can't seem to figure out what to add, or take out to make it stop scrolling past the footer. I've tried setting a max height for the body/html... I've tried taking out the "set scroll" function, I need it to stop scrolling on forever. I've also tried adding in the finish() method but I'm not exactly sure where it goes. Here is my code.
var colour = "#ffffff";
var sparkles = 200;
var x = ox = 400;
var y = oy = 300;
var swide = 800;
var shigh = 600;
var sleft = sdown = 0;
var tiny = new Array();
var star = new Array();
var starv = new Array();
var starx = new Array();
var stary = new Array();
var tinyx = new Array();
var tinyy = new Array();
var tinyv = new Array();
colours = new Array('#ffffff', '#cbaa89')
n = 10;
y = 0;
x = 0;
n6 = (document.getElementById && !document.all);
ns = (document.layers);
ie = (document.all);
d = (ns || ie) ? 'document.' : 'document.getElementById("';
a = (ns || n6) ? '' : 'all.';
n6r = (n6) ? '")' : '';
s = (ns) ? '' : '.style';
if (ns) {
for (i = 0; i < n; i++)
document.write('<layer name="dots' + i + '" top=0 left=0 width=' + i / 2 + ' height=' + i / 2 + ' bgcolor=#ff0000></layer>');
}
if (ie)
document.write('<div id="con" style="position:absolute;top:0px;left:0px"><div style="position:relative">');
if (ie || n6) {
for (i = 0; i < n; i++)
document.write('<div id="dots' + i + '" style="position:absolute;top:0px;left:0px;width:' + i / 2 + 'px;height:' + i / 2 + 'px;background:#ff0000;font-size:' + i / 2 + '"></div>');
}
if (ie)
document.write('</div></div>');
(ns || n6) ? window.captureEvents(Event.MOUSEMOVE): 0;
function Mouse(evnt) {
y = (ns || n6) ? evnt.pageY + 4 - window.pageYOffset : event.y + 4;
x = (ns || n6) ? evnt.pageX + 1 : event.x + 1;
}
(ns) ? window.onMouseMove = Mouse: document.onmousemove = Mouse;
function animate() {
o = (ns || n6) ? window.pageYOffset : 0;
if (ie) con.style.top = document.body.scrollTop + 'px';
for (i = 0; i < n; i++) {
var temp1 = eval(d + a + "dots" + i + n6r + s);
randcolours = colours[Math.floor(Math.random() * colours.length)];
(ns) ? temp1.bgColor = randcolours: temp1.background = randcolours;
if (i < n - 1) {
var temp2 = eval(d + a + "dots" + (i + 1) + n6r + s);
temp1.top = parseInt(temp2.top) + 'px';
temp1.left = parseInt(temp2.left) + 'px';
} else {
temp1.top = y + o + 'px';
temp1.left = x + 'px';
}
}
setTimeout("animate()", 10);
}
animate();
window.onload = function() {
if (document.getElementById) {
var i, rats, rlef, rdow;
for (var i = 0; i < sparkles; i++) {
var rats = createDiv(3, 3);
rats.style.visibility = "hidden";
rats.style.zIndex = "999";
document.body.appendChild(tiny[i] = rats);
starv[i] = 0;
tinyv[i] = 0;
var rats = createDiv(5, 5);
rats.style.backgroundColor = "transparent";
rats.style.visibility = "hidden";
rats.style.zIndex = "999";
var rlef = createDiv(1, 5);
var rdow = createDiv(5, 1);
rats.appendChild(rlef);
rats.appendChild(rdow);
rlef.style.top = "2px";
rlef.style.left = "0px";
rdow.style.top = "0px";
rdow.style.left = "2px";
document.body.appendChild(star[i] = rats);
}
set_width();
sparkle();
}
}
function sparkle() {
var c;
if (Math.abs(x - ox) > 1 || Math.abs(y - oy) > 1) {
ox = x;
oy = y;
for (c = 0; c < sparkles; c++)
if (!starv[c]) {
star[c].style.left = (starx[c] = x) + "px";
star[c].style.top = (stary[c] = y + 1) + "px";
star[c].style.clip = "rect(0px, 5px, 5px, 0px)";
star[c].childNodes[0].style.backgroundColor = star[c].childNodes[1].style.backgroundColor = (colour == "random") ? newColour() : colour;
star[c].style.visibility = "visible";
starv[c] = 50;
break;
}
}
for (c = 0; c < sparkles; c++) {
if (starv[c]) update_star(c);
if (tinyv[c]) update_tiny(c);
}
setTimeout("sparkle()", 40);
}
function update_star(i) {
if (--starv[i] == 25) star[i].style.clip = "rect(1px, 4px, 4px, 1px)";
if (starv[i]) {
stary[i] += 1 + Math.random() * 3;
starx[i] += (i % 5 - 2) / 5;
if (stary[i] < shigh + sdown) {
star[i].style.top = stary[i] + "px";
star[i].style.left = starx[i] + "px";
} else {
star[i].style.visibility = "hidden";
starv[i] = 0;
return;
}
} else {
tinyv[i] = 50;
tiny[i].style.top = (tinyy[i] = stary[i]) + "px";
tiny[i].style.left = (tinyx[i] = starx[i]) + "px";
tiny[i].style.width = "2px";
tiny[i].style.height = "2px";
tiny[i].style.backgroundColor = star[i].childNodes[0].style.backgroundColor;
star[i].style.visibility = "hidden";
tiny[i].style.visibility = "visible"
}
}
function update_tiny(i) {
if (--tinyv[i] == 25) {
tiny[i].style.width = "1px";
tiny[i].style.height = "1px";
}
if (tinyv[i]) {
tinyy[i] += 1 + Math.random() * 3;
tinyx[i] += (i % 5 - 2) / 5;
if (tinyy[i] < shigh + sdown) {
tiny[i].style.top = tinyy[i] + "px";
tiny[i].style.left = tinyx[i] + "px";
} else {
tiny[i].style.visibility = "hidden";
tinyv[i] = 0;
return;
}
} else tiny[i].style.visibility = "hidden";
}
document.onmousemove = mouse;
function mouse(e) {
if (e) {
y = e.pageY;
x = e.pageX;
} else {
set_scroll();
y = event.y + sdown;
x = event.x + sleft;
}
}
window.onscroll = set_scroll;
function set_scroll() {
if (typeof(self.pageYOffset) == 'number') {
sdown = self.pageYOffset;
sleft = self.pageXOffset;
} else if (document.body && (document.body.scrollTop || document.body.scrollLeft)) {
sdown = document.body.scrollTop;
sleft = document.body.scrollLeft;
} else if (document.documentElement && (document.documentElement.scrollTop || document.documentElement.scrollLeft)) {
sleft = document.documentElement.scrollLeft;
sdown = document.documentElement.scrollTop;
} else {
sdown = 0;
sleft = 0;
}
}
window.onresize = set_width;
function set_width() {
var sw_min = 999999;
var sh_min = 999999;
if (document.documentElement && document.documentElement.clientWidth) {
if (document.documentElement.clientWidth > 0) sw_min = document.documentElement.clientWidth;
if (document.documentElement.clientHeight > 0) sh_min = document.documentElement.clientHeight;
}
if (typeof(self.innerWidth) == 'number' && self.innerWidth) {
if (self.innerWidth > 0 && self.innerWidth < sw_min) sw_min = self.innerWidth;
if (self.innerHeight > 0 && self.innerHeight < sh_min) sh_min = self.innerHeight;
}
if (document.body.clientWidth) {
if (document.body.clientWidth > 0 && document.body.clientWidth < sw_min) sw_min = document.body.clientWidth;
if (document.body.clientHeight > 0 && document.body.clientHeight < sh_min) sh_min = document.body.clientHeight;
}
if (sw_min == 999999 || sh_min == 999999) {
sw_min = 800;
sh_min = 600;
}
swide = sw_min;
shigh = sh_min;
}
function createDiv(height, width) {
var div = document.createElement("div");
div.style.position = "absolute";
div.style.height = height + "px";
div.style.width = width + "px";
div.style.overflow = "hidden";
return (div);
}
function newColour() {
var c = new Array();
c[0] = 255;
c[1] = Math.floor(Math.random() * 256);
c[2] = Math.floor(Math.random() * (256 - c[1] / 2));
c.sort(function() {
return (0.5 - Math.random());
});
return ("rgb(" + c[0] + ", " + c[1] + ", " + c[2] + ")");
}
I've also made a jsfiddle here https://jsfiddle.net/5ydty5p2/
it's the sparkles that are wrongly positioned. If you take a look at the inspector (F12 you'll see them animating). The calculated position is incorrected and since they're created directly in the body they make it grow, and grow...
Since the whole script is a hack you could further hack it with a max-height property on the body...
Having sparkless is nice but you should really look for an alternative, this piece of JS is awful. And there is no jquery involved here, it's merely divs following the mouse. You should look for a proper plugin.
In javascript, I'm making an HTML canvas game, and in that game I have an object type/constructor called gamePiece. gamePiece has a function called checkCollision:
this.checkCollision = function(piece){
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y <= this.y && piece.y <= (this.y - this.height);
if(collisionX || collisionY){
return true;
} else {
return false;
}
}
which is called by update()
function update(){
context.clearRect(0, 0, game.width, game.height);
for(var i = 0; i < gamePieces.length; i++){
gamePieces[i].update();
for(var mi = 0; mi < gamePieces.length; mi++){
gamePieces[i].checkCollision(gamePieces[mi]);
if(gamePieces[i].checkCollision(gamePieces[mi]) == true){
gamePieces[i].collisionFunction();
}
}
}
}
setInterval(function(){update();}, 1);
I have another object that is supposed to give a speed boost upon colliding with another game piece, and it logs every time it gives a speed boost.
var speedBooster = new gamePiece(25,25,"red",300,300,0);
speedBooster.collisionFunction = function(){
for(var whichpiece = 0; whichpiece < gamePieces.length; whichpiece++){
if(speedBooster.checkCollision(gamePieces[whichpiece]) == true && gamePieces[whichpiece] != this){
gamePieces[whichpiece].speed += 10;
console.log("gamePieces[" + whichpiece + "] has been given a speed boost.");
}
}
}
But it gives a speed boost whenever a piece is behind it, and I put the "piece.x >= this.x &&" there for a reason. Why is JavaScript ignoring the condition I gave it?
Try
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y >= this.y && piece.y <= (this.y + this.height);
if(collisionX && collisionY){
return true;
} else {
return false;
}
To test if two objects overlap. Where the object has x,y as the top left and w,h as width and height
//Returns true if any part of box1 touches box2
function areaTouching(box1,box2){
return ! (box1.x > box2.x + box2.w ||
box1.x + box1.w < box2.x ||
box1.y > box2.y + box2.h ||
box1.y + box1.h < box2.y)
}
I want to create a drawing in sugar thing, much the same as you would throw some sugar on a table and using your fingers to "erase" the sugar particles to form an image.
Does anyone know of a js type tool I can use to make this happen?
I suppose I can take a photo of a desk, and a photo of desk with some sugar on it, and then just erase the top layer, but I'm worried that this won't give a real effect.
I'm currently thinking of having a photo of desk, and then using JS to generate a lot of "sugary" particles, which I can then erase. This sounds incredibly hard to do though. Is it? Can someone point me in a good direction?
Sand or is it sugar?
An interesting problem that I had to give a little time.
This works by creating several buffers to hold grains of sand (sugar) and give them life when they need to move.
There is no way that Javascript could do a whole screen of a million plus grains so this demo cheats by only updating a very few and prioritising for new movement rather than allow older moving grains to hog CPU time.
The arrays active, sandStatus, holds the sand gains. active has the pixel address as a 32Bit int and sandStatus has age. The Array sand holds the amount of sand at each pixel and is used to calculate the shadow effect (shadow could be much better using a webGL shader) and to work out which direction sand should slide if disturbed or dropped to the surface.
the var activeMax holds the max number of active sand grains. Increase for a better effect, decrease if the sim runs to slow.
To drop sand use the right mouse button. Hold at one spot to make a pile. Left button pushes the sand about. When you hit a bigger pile the machine may lag (depending on CPU power and browser (best in firefox)).
The push function checks the sand array for any sand. If found it pushes the sand away from the center and piles it up around the edge. Some sand will fall back.
The function sprinkle adds grains of sand (one are a time by pixel coordinate or by index). The function push does the sand drawing FX. update moves the sand grains by checking surrounding pixels heights and moving grains down hill. renderPix handles rendering grains, creating the shadows and deactivating sand grains. The Array shadowChange holds the index of pixels that have had changes so that the shadows can be updated.
Bottom half of the demo is just boilerplate for mouse and canvas setup. All the code in regard to the answer is in the first half.
"use strict";
var activeMax = 2280; // this is the number of sand grains that are processed at
// at time. Increase for better looking effect. decrease
// if the machine is not keeping up with the load
var cw;
var ch;
var w; //
var h;
var canvasBuf = document.createElement("canvas");
var ctxB
var globalTime; // global to this
var pixels
var sand;
var sandToFall;
var sandToFallCount = 36000;
var shadow; // shadow pixels
var activeMax = 2280;
var active; // index of pixel for active grain
var sandStatus; // status of active grain
var shadowChange; // holds index of pixels that have a shadow change
var pixels;
var buf;
var grain = 0xFFFFFFFF;
var shadowGrain = 0x00000000;
var ready = false;
var sandReady = 0;
var nextActive = 0;
var nextActiveShadow = 0;
var onResize = function(){
cw = canvas.width;
ch = canvas.height;
w = cw; //
h = ch;
pixels = w*h;
canvasBuf.width = w;
canvasBuf.height = h;
ctxB = canvasBuf.getContext("2d");
sand = new Uint8ClampedArray(pixels);
shadow = new Uint8ClampedArray(pixels); // shadow pixels
sandToFall = new Uint32Array(sandToFallCount);
activeMax = 2280;
active = new Uint32Array(activeMax); // index of pixel for active grain
sandStatus = new Uint16Array(activeMax); // status of active grain
shadowChange= new Uint32Array(activeMax); // holds index of pixels that have a shadow change
sandStatus.fill(0); // clear
active.fill(0);
shadowChange.fill(0);
ctxB.clearRect(0,0,w,h);
ctxB.fillStyle = "white";
ctxB.font = "84px arial";
ctxB.textAlign = "center";
ctxB.globalAlpha = 0.01;
for(var i = 0; i < 12; i ++){
ctxB.fillText("Sand Doodler!",w/2 + (Math.random()-0.5)*5,h/2 + (Math.random()-0.5)*5);
}
ctxB.globalAlpha = 1;
pixels = ctxB.getImageData(0,0,w,h);
buf = new Uint32Array(pixels.data.buffer);
for(i = 0; i < buf.length; i += 3){
if(buf[i] !== 0){
var c = buf[i] >>> 24;
buf[i] = 0;
while(c > 0){
var ind = Math.floor(Math.random()*sandToFallCount);
if(sandToFall[ind] === 0){
sandToFall[ind] = i;
}
c = c >>> 1;
}
}
}
buf.fill(0);
offsets = [1,w-1,w,w+1,-w-1,-w,-w+1,-1];
shadowOffsets = [-w-1,-w,-1];
ready = true;
sandReady=0;
}
function sprinkle(x,y){
var ind;
if(y === undefined){
ind = x;
}else{
ind = x + y*w;
}
var alreadyExists = active.indexOf(ind);
var ac = nextActive;
if(alreadyExists > -1){
sand[ind] += 1;
shadow[ind] = 0;
sandStatus[alreadyExists] = 66;
}else{
active[nextActive] = ind;
sandStatus[nextActive] = 66;
shadowChange[nextActiveShadow];
nextActiveShadow = (nextActiveShadow+1)%activeMax;
nextActive = (nextActive +1)%activeMax;
sand[ind] += 1;
shadow[ind] = 0;
}
return ac;
}
var offsets = [1,w-1,w,w+1,-w-1,-w,-w+1,-1];
var offsetCount = 8;
function update(){
var min,max,minDir,maxDir,dir,start,jj,j,ind,level,i,l1;
for( i = 0; i <activeMax; i ++){
if(sandStatus[i] !== 0){
ind = active[i];
level = sand[ind];
if(level === 1){
sandStatus[i] = 1; // deactive is cant move (level ground)
}else{
min = level;
var d;
minDir = offsets[Math.floor(Math.random()*16)];
dir = null;
start = Math.floor(Math.random()*16); // start at a random direction
for(j=0;j < offsetCount; j++){
jj = offsets[(j + start)%offsetCount];
l1 = sand[ind+jj];
if(l1 < min){
min = l1;
minDir = jj;
d = (j + start)%offsetCount;
}
}
dir = null;
if(min >= level - 1){ // nowhere to move
sandStatus[i] = 1;
}else
if(min < level-1){ // move to lowest
dir = minDir
}
if(dir !== null){
var lv = level-min;
while(lv > 2){
active[i] = ind + dir;
if(sand[ind] > 1){
sand[ind] -= 2;
sprinkle(ind)
}else{
sand[ind] -=1;
}
ind = ind+dir;
sand[active[i]] += 1;
if(sand[active[i] + offsets[d]] >=level){
d+= Math.random()<0.5? 1 : offsetCount -1;
d %=offsetCount;
}
lv -= 1;
}
if(sand[ind]>0){
active[i] = ind + dir;
sand[ind] -= 1;
}
sand[active[i]] += 1;
}
}
}
}
}
var shadowOffsets = [-w-1,-w,-1];
var shadowCols = [0xFFf0f0f0,0xFFd0d0d0,0xFFb0b0b0,0xFF909090];
var shadowDist = [0xf0000000,0xd0000000,0xb0000000,0x90000000]; // shadow col no sand
// renders grains and adds shadows. Deactivates gains when they are done
function renderPix(){
var ac = 0;
for(var i = 0; i < activeMax; i ++){
if(sandStatus[i] !== 0){
ac += 1;
var ind = active[i];
buf[ind] = grain;
}
}
for(var i = 0; i < activeMax; i ++){
if(sandStatus[i] !== 0){
var ind = active[i];
var level = sand[ind];
var col =0;
if(sand[ind + shadowOffsets[0]] > level ){
col = 2;
}else
if(sand[ind + shadowOffsets[1]] > level ){
col =1;
}else
if(sand[ind + shadowOffsets[2]] > level ){
col = 1;
}
buf[ind] = grain; // add a sand grain to the image
shadow[ind] = col;
shadowChange[nextActiveShadow] = ind;
nextActiveShadow = (nextActiveShadow + 1)%activeMax;
var c = 4;
while(c > 0){
c-=1;
ind += w + 1;
var s = sand[ind];
var dif = level - s;
if(dif > 0){
c-= dif;
}
shadow[ind] += 1;
shadowChange[nextActiveShadow] = ind;
nextActiveShadow = (nextActiveShadow + 1)%activeMax;
}
sandStatus[i] -= 1;
if(sandStatus[i] === 1){
sandStatus[i] = 0;
active[i] = 0;
}
}
}
// add calculated shadows
for(var i = 0; i < activeMax; i ++){
if(shadowChange[i] !== 0){
var ind = shadowChange[i];
var s = shadow[ind] <4 ? shadow[ind]-1:3;
if(sand[ind] > 0){
buf[ind]=shadowCols[s];
}else{
buf[ind]=shadowDist[s];
}
shadowChange[i] = 0;
}
}
}
// push sand about
function push(x,y,radius){
var iyy,iny
var rr = radius * radius ;
x = Math.floor(x);
y = Math.floor(y);
for(var iy = -radius + 1; iy < radius; iy ++){
iyy = iy * iy;
iny = (y+iy) * w;
for(var ix = -radius + 1; ix < radius; ix ++){
if(ix*ix + iyy <= rr){ // is inside radius
var ind = (x + ix) + iny;
if(sand[ind] > 0){
var dir = Math.random() * Math.PI * 2;
dir = Math.atan2(iy,ix)
var r = radius + Math.random() * radius *0.2
var xx = Math.cos(dir) * r;
var yy = Math.sin(dir) * r;
buf[ind] = 0x000000;
sand[ind] = 0;
ind = Math.floor(xx + x) + Math.floor(yy + y) * w;
sprinkle(ind);
}else{
buf[ind] = 0;
}
}
}
}
}
function showHeight(){ // for debugging only
for(var i = 0; i < sand.length; i ++){
buf[i] = 0xff000000;
var k = sand[i];
buf[i] +=(k <<16) + (k<<8) + (k);
}
}
// main update function
function display(){
if(!ready){ // only when ready
return;
}
//ctx.setTransform(1,0,0,1,0,0); // reset transform
ctx.clearRect(0,0,cw,ch);
var mx = Math.floor((mouse.x/cw)*w); // canvas buf mouse pos
var my = Math.floor((mouse.y/ch)*h);
// drop sand
if(mouse.buttonRaw & 4){
for(var i = 0; i < 120; i ++){
var dir = Math.random()*Math.PI;
var dist = ((Math.random()+Math.random()+Math.random())/3-0.5) * 62;
var x = Math.cos(dir) * dist;
var y = Math.sin(dir) * dist;
x += mx;
y += my;
x = Math.floor(x); // floor
y = Math.floor(y); // floor
sprinkle(x,y);
}
}else{
// drop sand for intro FX
if(sandReady <sandToFallCount){
for(var i = 0; i < 120; i ++){
if(sandToFall[sandReady] !== 0){
sprinkle(sandToFall[sandReady] + offsets[Math.floor(Math.random()*8)%offsets.length]);
}
sandReady += 1;
}
}
}
// push sand about.
if(mouse.buttonRaw & 1){
push(((mouse.x/cw)*w),((mouse.y/ch)*h),32); // scale mouse to canvasBuf size
}
update();
renderPix();
//showHeight();
ctxB.putImageData(pixels,0,0);
ctx.drawImage(canvasBuf,0,0,cw,ch);
}
//==================================================================================================
// The following code is support code that provides me with a standard interface to various forums.
// It provides a mouse interface, a full screen canvas, and some global often used variable
// like canvas, ctx, mouse, w, h (width and height), globalTime
// This code is not intended to be part of the answer unless specified and has been formated to reduce
// display size. It should not be used as an example of how to write a canvas interface.
// By Blindman67
const U = undefined;const RESIZE_DEBOUNCE_TIME = 100;
var canvas,ctx,mouse,createCanvas,resizeCanvas,setGlobals,globalTime=0,resizeCount = 0;
createCanvas = function () { var c,cs; cs = (c = document.createElement("canvas")).style; cs.position = "absolute"; cs.top = cs.left = "0px"; cs.zIndex = 1000; document.body.appendChild(c); return c;}
resizeCanvas = function () {
if (canvas === U) { canvas = createCanvas(); } canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx = canvas.getContext("2d");
if (typeof setGlobals === "function") { setGlobals(); } if (typeof onResize === "function"){ resizeCount += 1; setTimeout(debounceResize,RESIZE_DEBOUNCE_TIME);}
}
function debounceResize(){ resizeCount -= 1; if(resizeCount <= 0){ onResize();}}
setGlobals = function(){ cw = w = canvas.width; ch = h = canvas.height; mouse.updateBounds(); }
mouse = (function(){
function preventDefault(e) { e.preventDefault(); }
var mouse = {
x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false, buttonRaw : 0, over : false, bm : [1, 2, 4, 6, 5, 3],
active : false,bounds : null, crashRecover : null, mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
var m = mouse;
function mouseMove(e) {
var t = e.type;
m.x = e.clientX - m.bounds.left; m.y = e.clientY - m.bounds.top;
m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1]; }
else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2]; }
else if (t === "mouseout") { m.buttonRaw = 0; m.over = false; }
else if (t === "mouseover") { m.over = true; }
else if (t === "mousewheel") { m.w = e.wheelDelta; }
else if (t === "DOMMouseScroll") { m.w = -e.detail; }
if (m.callbacks) { m.callbacks.forEach(c => c(e)); }
if((m.buttonRaw & 2) && m.crashRecover !== null){ if(typeof m.crashRecover === "function"){ setTimeout(m.crashRecover,0);}}
e.preventDefault();
}
m.updateBounds = function(){
if(m.active){
m.bounds = m.element.getBoundingClientRect();
}
}
m.addCallback = function (callback) {
if (typeof callback === "function") {
if (m.callbacks === U) { m.callbacks = [callback]; }
else { m.callbacks.push(callback); }
} else { throw new TypeError("mouse.addCallback argument must be a function"); }
}
m.start = function (element, blockContextMenu) {
if (m.element !== U) { m.removeMouse(); }
m.element = element === U ? document : element;
m.blockContextMenu = blockContextMenu === U ? false : blockContextMenu;
m.mouseEvents.forEach( n => { m.element.addEventListener(n, mouseMove); } );
if (m.blockContextMenu === true) { m.element.addEventListener("contextmenu", preventDefault, false); }
m.active = true;
m.updateBounds();
}
m.remove = function () {
if (m.element !== U) {
m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); } );
if (m.contextMenuBlocked === true) { m.element.removeEventListener("contextmenu", preventDefault);}
m.element = m.callbacks = m.contextMenuBlocked = U;
m.active = false;
}
}
return mouse;
})();
function main(timer){ // Main update loop
globalTime = timer;
display(); // call demo code
requestAnimationFrame(main);
}
resizeCanvas();
mouse.start(canvas,true);
window.addEventListener("resize",resizeCanvas);
requestAnimationFrame(main);
body {
background:#49D;
}
.help {
text-align : center;
font-family : Arial,"Helvetica Neue",Helvetica,sans-serif;
font-size : 18px;
}
<div class="help">Right mouse to drop sand, left button to push it around.</div>
Im writing a practice script where i animate a bunch of boxes and detect collision and then move them accordingly. Problem is, i found the collision but how to check in which side the collision has occurred so i can move them accordnigly.
This is the method i wrote.Is there a better way to do it?
this.ballCollide = function(){
for(var i = 0; i < ball.length; i++){
for(var j = i+1 ; j < ball.length; j++){
if( ((ballX[i] + 50) >= ballX[j]) && (ballX[i] <= (ballX[j] + 50)) && ((ballY[i] + 50) >= ballY[j]) && (ballY[i] <= (ballY[j] + 50))){
movePosX[i] = -movePosX[i];
movePosY[i] = -movePosY[i];
movePosX[j] = -movePosX[j];
movePosY[j] = -movePosY[j];
}
}
}
}
I think a little refactoring is in order. The following might help point you in the right direction:
NOTE: I didn't validate the code, so read every character. Plus, I think the left and right are set up, but didn't work through the top / bottom nor the final moving logic because I don't think I understood the original logic (or at least it started to not make sense to me -- seems like your missing an || in there somewhere).
this.ballCollide = function() {
for (var i = 0; i < ball.length; i++) {
var ax = ballX[i];
var ay = ballY[i];
for (var j = i + 1; j < ball.length; j++) {
var bx = ballX[j];
var by = ballY[j];
var left = ( ax <= bx + 50 );
var right = ( ax + 50 >= bx );
var top = ( ay + 50 >= by );
var bottom = ( ay <= by + 50 );
if( (left && right) && (top && bottom) ){
movePosX[i] = -movePosX[i];
movePosY[i] = -movePosY[i];
movePosX[j] = -movePosX[j];
movePosY[j] = -movePosY[j];
}
}
}
}
Here's a "contains" function which may prove useful:
function contains (big, small){
if( ! big || ! small ){
return false;
}
var Oresult = {};
var Obig = {x:big.x, y:big.y, w:big.width, h:big.height};
var Osmall = {x:small.x, y:small.y, w:small.width, h:small.height};
Obig.xMax = Obig.x + Obig.w;
Obig.yMax = Obig.y + Obig.h;
Osmall.xMax = Osmall.x + Osmall.w;
Osmall.yMax = Osmall.y + Osmall.h;
for (var p in Obig) {
Oresult[p] = ( Obig[p] >= Osmall[p] ) ? true : false;
}
var retval = (!Oresult.x && !Oresult.y && Oresult.xMax && Oresult.yMax) ? true : false;
return retval;
}
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
So, recently, I've been working on a JS/HTML5 Game Engine. Right now I'm calling it DimSumJs, because like DimSum isn't a full meal, my framework still runs too slowly to make a full game (it can only run about 250 "objects" despite before slowing down, it becomes very noticeable around 300 "objects"). It uses divs inside an iframe.
A sample game is available at http://pandamochi.x10.bz
just view resources with google chrome and you should be able to find the dimsum.js file
//DimSumJS - Open Source Game Engine
//DimSumJS (C) Ruochen Tang
//Can be used commerically, but please give credit
//Constants
var RIGHTKEY = 37;
var UPKEY = 38;
var LEFTKEY = 39;
var DOWNKEY = 40;
var SPACEKEY = 32;
var MASTER_WIDTH = 480;
var MASTER_HEIGHT = 600;
var Game = window.frames[0].document.body;
Game.setAttribute("width",MASTER_WIDTH + "px");
Game.setAttribute("height",MASTER_HEIGHT + "px");
var gl = setInterval("gameLoop();",15);
//Global Vars
var keyDown = new Array();
for (var i = 0; i < 256; i++){
keyDown[i] = false;
}
var gameState = 1;
//Settings
Game.style.backgroundColor = "#000";
//Key
processKeyEvent = function(event){
// MSIE hack
if (window.event)
{
event = window.event;
}
keyDown[event.keyCode] = true;
};
releaseKey = function(event){
// MSIE hack
if (window.event)
{
event = window.event;
}
keyDown[event.keyCode] = false;
}
Game.onkeydown = processKeyEvent;
Game.onkeyup = releaseKey;
var GameObjects = new Array();
function GameObject(xx, yy, w, h, i, inc, gs, name, img){
GameObjects.push(this);
this.width = w;
this.height = h;
this.index = i;
this.currIndex = 0;
this.increment = inc;
this.currInc = 0;
this.x = xx;
this.y = yy;
this.depth = 0;
this.objType = name;
this.image = img;
this.xScale = 1;
this.yScale = 1;
this.scaleString = "scale(" + this.xScale + "," + this.yScale + ")";
this.speed = 0;
this.direction = 0;
this.gravity = 0;
this.gravityDirection = 0;
this.active = true;
this.visible = true;
this.bindToRoom = false;
this.text = "";
this.color = "#FFF";
this.gameState = gs;
this.div = document.createElement("div");
this.div.className=this.objType;
this.div.style.position="absolute";
this.div.style.left= this.x + "px";
this.div.style.top= this.y + "px";
this.div.style.width= this.width + "px";
this.div.style.height= this.height + "px";
this.div.style.backgroundImage = "url(images/" + this.image + ")";
this.div.style[getTransformProperty(this.div)] = this.scaleString;
Game.appendChild(this.div);
this.isDiv = true;
this.classChanged = false;
this.move = move;
this.anim = anim;
this.setScale = setScale;
this.checkCollisionAt = checkCollisionAt;
this.objectAt = objectAt;
this.objectTypeAt = objectTypeAt;
this.toggleActive = toggleActive;
this.extend = extend;
this.unextend = unextend;
this.isType = isType;
this.update = update;
function move(xx,yy){
this.x += xx;
this.y += yy;
}
function anim(){
this.currInc += 1;
if (this.currInc >= this.increment){
this.currInc -= this.increment;
this.currIndex += 1;
if (this.currIndex >= this.index){
this.currIndex -= this.index;
}
}
}
function extend(type) {
this.objType += " " + type;
this.classChanged = true;
}
function unextend(type) {
this.objType = this.objType.replace( /(?:^|\s)type(?!\S)/ , '' );
this.classChanged = true;
}
function isType(type) {
return ((' ' + this.objType + ' ').indexOf(' ' + type + ' ') > -1);
}
function setScale(xx,yy){
this.xScale = xx;
this.yScale = yy;
this.scaleString = "scale(" + this.xScale + "," + this.yScale + ")";
}
function checkCollisionAt(xx,yy,other){
//Check For Collision
xx += this.x;
yy += this.y;
if ((xx + this.width > other.x) && (xx < other.x + other.width) && (yy + this.height > other.y) && (yy < other.y + other.height)){
return true;
}
else{
return false;
}
}
function objectAt(xx,yy,solid){
//Loop All Objects
for (var i = 0; i < GameObjects.length; i++){
if (GameObjects[i] != this && this.isDiv){
if (this.checkCollisionAt(xx,yy,GameObjects[i])){
console.log(i);
return true;
}
}
}
return false;
}
function objectTypeAt(xx,yy,type){
//Loop All Objects
for (var i = 0; i < GameObjects.length; i++){
if (GameObjects[i] != this && GameObjects[i].isType(type) && this.isDiv){
if (this.checkCollisionAt(xx,yy,GameObjects[i])){
return true;
}
}
}
return false;
}
function toggleActive(a){
this.visible = a;
this.update();
this.active = a;
}
function update(){
if ((this.active == false || this.gameState != gameState) && this.isDiv){
this.isDiv = false;
Game.removeChild(this.div);
return;
}
else if(!this.isDiv){
this.isDiv = true;
Game.appendChild(this.div);
}
this.div.style.display = "inline";
if (this.speed != 0){
this.x += this.speed*Math.cos(this.direction*Math.PI/180);
this.y += this.speed*Math.sin(this.direction*Math.PI/180);
}
if (this.bindToRoom == true){
if (this.x < 0){
this.x = 0;
}
if (this.y < 0){
this.y = 0;
}
if (this.x > MASTER_WIDTH-this.width){
this.x = MASTER_WIDTH-this.width;
}
if (this.y > MASTER_HEIGHT-this.height){
this.y = MASTER_HEIGHT-this.height;
}
}
if (!this.visible && this.isDiv){
this.isDiv = false;
Game.removeChild(this.div);
return;
}
if (this.classChanged){
this.div.className = this.objType;
}
this.div.style.zIndex = this.depth;
this.div.style.color = this.color;
this.div.innerHTML = this.text;
this.div.style.left= this.x + "px";
this.div.style.top= this.y + "px";
this.div.style[getTransformProperty(this.div)] = this.scaleString;
this.div.style.backgroundPosition = this.currIndex * this.width +"px 0";
}
}
function getTransformProperty(element) {
// Note that in some versions of IE9 it is critical that
// msTransform appear in this list before MozTransform
// By ZachAstronaut
var properties = [
'transform',
'WebkitTransform',
'msTransform',
'MozTransform',
'OTransform'
];
var p;
while (p = properties.shift()) {
if (typeof element.style[p] != 'undefined') {
return p;
}
}
return false;
}
Right now, whenever an object is not in the current gameState, becomes inactive, or is not visible, I will remove the div from the game's iframe. I have checks to make sure not to run any unnecessary scripts in the update() function. Is there anyway I can improve my speed?
Are you familiar with profilers? Google Chrome includes a fairly good one. When I run your program and start profiling it, Chrome reports that your definition of isType is expensive.
function isType(type) {
return this.objType && new RegExp("(^|\\s)" + type + "(\\s|$)").test(this.objType);
}
Sure enough, this is expensive. Dynamically constructing RegExps can be costly.
To avoid that cost, lift out the definition of the regular expression out of isType if you can. Assuming the set of types is fixed, you can pre-compute the regexps for all the types at toplevel, store them in an object, and then do a simple lookup to get the precomputed regexp. If you don't know them all up front, you can still cache regexps from prior calls to isType.
var priorTypeRegexps = {};
function isType(type) {
var aRegexp;
if (! priorTypeRegexps[type]) {
priorTypeRegexps[type] = new RegExp("(^|\\s)" + type + "(\\s|$)");
}
aRegexp = priorTypeRegexps[type];
return this.objType && aRegexp.test(this.objType);
}