Is this a bug? (JavaScript conditional) - javascript

I've got some code for part of a game where an absolutely positioned div (id = 'cursor') follows your mouse's cursor around. When the cursor div runs into another div (class = 'thing') (these are the white boxes in the jsfiddles), the cursor speed changes.
In this JSfiddle you'll see that it works perfectly fine. When cursor hits thing, cursor speeds up. This is the conditional used to change the speed (newSpeed is what determines the speed for cursor):
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 200;
changeCursorSpeed();
} else {
newSpeed = 12;
changeCursorSpeed();
console.log('hit');
}
The problem I'm having is when I switch around the values for newSpeed in the conditional:
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 12;
changeCursorSpeed();
} else {
newSpeed = 200;
changeCursorSpeed();
console.log('hit');
}
Here's the JSFiddle for this. This causes the collision to not change newSpeed in the else part of the condition. However, using console.log('hit'), you can clearly see that the collision is detected.
Logically, this doesn't seem to make sense. I'd like to hear input from others about this as well as possible solutions. Thanks for any help.
Here's the entire code for the collision detection. The JSfiddles have a more complete code for the program.
var newSpeed;
var newInt = setInterval(function() {
function collision($cursor, $thing) {
var x1 = $cursor.offset().left;
var y1 = $cursor.offset().top;
var h1 = $cursor.outerHeight(true);
var w1 = $cursor.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
$thing.each(function(i){
var x2 = $(this).offset().left;
var y2 = $(this).offset().top;
var h2 = $(this).outerHeight(true);
var w2 = $(this).outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2){
newSpeed = 12;
changeCursorSpeed();
} else {
newSpeed = 200;
changeCursorSpeed();
console.log('hit');
}
});
function changeCursorSpeed(){
$xp += (($mouseX - $xp)/newSpeed);
$yp += (($mouseY - $yp)/newSpeed);
$("#cursor").css({left:$xp +'px', top:$yp +'px'});
}
}
$(collision($('#cursor'), $('.thing')));
}, 20);

Related

When the bullet hits, the cowboys should fall down and a message should be shown [duplicate]

I'm building a game in Javascript using canvas which requires collision detection, in this case if the player sprite hits a box, the player must not be allowed through the box.
I have a global array called blockList that holds all the boxes being drawn to the canvas. It looks like this:
var blockList = [[50, 400, 100, 100]];
And they're being drawn to the canvas like this:
c.fillRect(blockList[0][0], blockList[0][1], blockList[0][2], blockList[0][3]);
I also have a player object, which has an update method and a draw method. Update sets the position of the player based on keyboard input etc, and draw is used by the main game loop to draw the player to the canvas. The player is being drawn like this:
this.draw = function(timestamp) {
if(this.state == "idle") {
c.drawImage(this.idleSprite, this.idleSprite.frameWidth * this.idleSprite.frameCount, 0, this.idleSprite.frameWidth, this.idleSprite.frameHeight, this.xpos, this.ypos, this.idleSprite.frameWidth, this.idleSprite.frameHeight);
if(timestamp - this.lastDraw > this.idleSprite.updateInterval) {
this.lastDraw = timestamp;
if(this.idleSprite.frameCount < this.idleSprite.frames - 1) { this.idleSprite.frameCount++; } else { this.idleSprite.frameCount = 0; }
}
} else if(this.state == "running") {
var height = 0;
if(this.facing == "left") { height = 37; }
c.drawImage(this.runningSprite, this.runningSprite.frameWidth * this.runningSprite.frameCount, height, this.runningSprite.frameWidth, this.runningSprite.frameHeight, this.xpos, this.ypos, this.runningSprite.frameWidth, this.runningSprite.frameHeight);
if(timestamp - this.lastDraw > this.runningSprite.updateInterval) {
this.lastDraw = timestamp;
if(this.runningSprite.frameCount < this.runningSprite.frames - 1) { this.runningSprite.frameCount++; } else { this.runningSprite.frameCount = 0; }
}
}
}
Now, the player has certain properties being player.xpos, player.ypos, player.width, player.height. The same properties exist for the blocks. So I have everything I need to impliment collision detection, I just have no idea how to do it. I've tried doing things like:
if(player.x > blockList[0][0] && player.y > blockList[0][1])
but it's far from perfect or playable.
Does anyone know of a simple method or function to be able to return true or false based on if two objects are colliding?
I use the following function for collision detection between two rectangles:
rect_collision = function(x1, y1, size1, x2, y2, size2) {
var bottom1, bottom2, left1, left2, right1, right2, top1, top2;
left1 = x1 - size1;
right1 = x1 + size1;
top1 = y1 - size1;
bottom1 = y1 + size1;
left2 = x2 - size2;
right2 = x2 + size2;
top2 = y2 - size2;
bottom2 = y2 + size2;
return !(left1 > right2 || left2 > right1 || top1 > bottom2 || top2 > bottom1);
};
This determines whether two squares, centered at (x1, y1) and (x2, y2), with side lengths 2*size1 and 2*size2, respectively, are overlapping. It should be easy enough to alter the definitions of left1, right1, etc. to deal with general rectangles rather than just squares and to use a different data format.
Specifically, left1 is the left side of the the first square, right1 the right side, etc. Note that, in my coordinate system, the y-axis is inverted (top1 < bottom1).
You just want to know if two rectangles overlap?
Here is a bulletproof function for you:
// returns true if there is any overlap
// params: x,y,w,h of two rectangles
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) {
if (w2 !== Infinity && w1 !== Infinity) {
w2 += x2;
w1 += x1;
if (isNaN(w1) || isNaN(w2) || x2 > w1 || x1 > w2) return false;
}
if (y2 !== Infinity && h1 !== Infinity) {
h2 += y2;
h1 += y1;
if (isNaN(h1) || isNaN(y2) || y2 > h1 || y1 > h2) return false;
}
return true;
}
If your program can be certain that the numbers will always be finite you can use a simpler version:
// returns true if there is any overlap
// params: x,y,w,h of two rectangles
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) {
w2 += x2;
w1 += x1;
if (x2 > w1 || x1 > w2) return false;
h2 += y2;
h1 += y1;
if (y2 > h1 || y1 > h2) return false;
return true;
}
What its doing is finding the where the right side and bottom side of the two rectangles are, then it sees if the second one starts outside of the first one or if the first one starts outside of the second one.
If either rectangle begins after the other one has ended, then there is no collision. Otherwise there must be a collision.
In my opinion, I'm not a fan of functions that require many parameters.
Here's how I would do it :
function collisionCheckRectRect(rectOne, rectTwo){
var x1=rectOne.x, y1 = rectOne.y, height1 = rectOne.height, width1 = rectOne.width;
var x2=rectTwo.x, y2 = rectTwo.y, height2 = rectTwo.height, width2 = rectTwo.width;
return x1 < x2+width2 && x2 < x1+width1 && y1 < y2+height2 && y2 < y1+height1;
}

Hide an element when it touches other elements on the page with jQuery

I wanted to hide a sidebar element when it overlaps with the images on the page. I found a great answer on StackOverflow, but it doesn't entirely solve my problem. Right now, it only works with the first image on the page. It will hide the sidebar when it touches the first image. But it won't hide for the rest of the images. What should I do if I want it to work with all the images on the page?
Here is my code.
function collision ($div1, $div2) {
var x1 = $div1.offset().left
var y1 = $div1.offset().top
var h1 = $div1.outerHeight(true)
var w1 = $div1.outerWidth(true)
var b1 = y1 + h1
var r1 = x1 + w1
var x2 = $div2.offset().left
var y2 = $div2.offset().top
var h2 = $div2.outerHeight(true)
var w2 = $div2.outerWidth(true)
var b2 = y2 + h2
var r2 = x2 + w2
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) {
$div1.addClass('show')
} else {
$div1.removeClass('show')
}
}
window.setInterval(function () {
collision($('#content-nav'), $('.image-container'))
}, 100)
Here is how it's working right now. https://imgur.com/a/BvTyiDQ
What's happening is that you're calling only the first element with the image-container class, so it'll only check the topmost image-container. You have to retrieve all instances of image-container and check against them for overlap.
Here's what your collision function would look like & a working JSFiddle
function collision ($nav) {
var x1 = $nav.offset().left
var y1 = $nav.offset().top
var h1 = $nav.outerHeight(true)
var w1 = $nav.outerWidth(true)
var b1 = y1 + h1
var r1 = x1 + w1
var hide = false
$(".image-container").each(function() {
var x2 = $(this).offset().left
var y2 = $(this).offset().top
var h2 = $(this).outerHeight(true)
var w2 = $(this).outerWidth(true)
var b2 = y2 + h2
var r2 = x2 + w2
if (!(b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)) {
hide = true;
}
});
if (!hide) {
$nav.removeClass('hide')
} else {
$nav.addClass('hide')
}
}

I have a bug with my javascript for a simple game

The Bug I encountered is when I was making the collision detection system for detecting collision between the player and squares drawn using a for statement, It picks up the collisions perfectly fine I know this because I have it logging to the console whenever it detects a collision along with the side that the collision was one. But after that console log, it should stop the player movement by setting a variable I am using for movement from 10 to 0 but it isn't, Sorry for adding all the code I just have no clue as to why the problem exists in the first place
var frame = setInterval(draw,10);
var canvas = document.getElementById('Canvas');
var ctx = canvas.getContext('2d');
var pos = [[300,250],[500,250],[700,250]]
var height = 150;
var width = 150;
var plyr = {pos:[0,0],width: 50,height: 50};
var a = {up: 10, down:10, left:10, right:10};
function draw(){
canvas.width = canvas.width
for(var i=0;i < pos.length;i++){
ctx.rect(pos[i][0],pos[i][1],height,width);
ctx.stroke();
}
ctx.rect(plyr.pos[0],plyr.pos[1],plyr.width,plyr.height);
ctx.stroke();
}
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {/*up*/plyr.pos[1] -= a.up;}
else if (e.keyCode == '40') {/*down*/plyr.pos[1] += a.down;}
else if (e.keyCode == '37') {/*left*/plyr.pos[0] -= a.left;d=1;}
else if (e.keyCode == '39') {/*right*/plyr.pos[0] +=
a.right;d=0;}
for(var c=0;c < pos.length;c++){
touch(plyr.pos[0],plyr.pos[1],plyr.width,plyr.height,pos[c]
[0],pos[c][1],height,width);
}
}
function touch(x1,y1,width1,height1,x2,y2,width2,height2){
if( x1 + width1 > x2 && x2 + width2 > x1 && y1 + height1 > y2 &&
y2 + height2 > y1){
if( y1 + height1 > y2 && y2 + 20 > y1 + height1 )
{console.log('touch down');a.down = 0;}
else if( y2 + height2 > y1 && y1 + 20 > y2 + height2)
{console.log('touch up');a.up = 0;}
else if( x1 + width1 > x2 && x2 + 20 > x1 + width1)
{console.log('touch right');a.right = 0;}
else if( x2 + width2 > x1 && x1 + 20 > x2 + width2)
{console.log('touch left');a.left = 0;}
}
else{
a.up = 10;
a.down = 10;
a.left = 10;
a.right = 10;
}
}
<!doctype html>
<html>
<head>
<title>Testing</title>
</head>
<body>
<canvas id="Canvas" width="1000" height="500"></canvas>
</body>
</html>
Perhaps a better way to solve this, is to set the players position to the edge of the object on collision.
function touch(x1,y1,width1,height1,x2,y2,width2,height2){
if( x1 + width1 > x2 && x2 + width2 > x1 && y1 + height1 > y2 &&
y2 + height2 > y1){
if( y1 + height1 > y2 && y2 + 20 > y1 + height1 )
{console.log('touch down');plyr.pos[1] = y2-plyr.height;}
else if( y2 + height2 > y1 && y1 + 20 > y2 + height2)
{console.log('touch up');plyr.pos[1] = y2+height2;}
else if( x1 + width1 > x2 && x2 + 20 > x1 + width1)
{console.log('touch right');plyr.pos[0] = x2-plyr.width;}
else if( x2 + width2 > x1 && x1 + 20 > x2 + width2)
{console.log('touch left');plyr.pos[0] = x2+plyr.width;}
}
}

Check overlay for many divs issue

I want to check if some divs are overlaying. Here are the functions i'm using
function collision($div1, $div2) {
var x1 = $div1.offset().left;
var y1 = $div1.offset().top;
var h1 = $div1.outerHeight(true);
var w1 = $div1.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = $div2.offset().left;
var y2 = $div2.offset().top;
var h2 = $div2.outerHeight(true);
var w2 = $div2.outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)
return false;
return true;
}
$("#flex[data-item-id]").each(function() {
var id_item = $(this).data('item-id');
var status = collision($('#c + id_item), $("#r" + id_item));
if (status) {
$('.here').css('background-color', 'red');
}
});
I don't know why but in console put ok true and false...exact where it needs but the if(status) won't work so well..
Like #Rory McCrossan just told, you are missing a ' in your selector.
Try this code:
function collision($div1, $div2) {
var x1 = $div1.offset().left;
var y1 = $div1.offset().top;
var h1 = $div1.outerHeight(true);
var w1 = $div1.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = $div2.offset().left;
var y2 = $div2.offset().top;
var h2 = $div2.outerHeight(true);
var w2 = $div2.outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)
return false;
return true;
}
$.each( "#flex[data-item-id]" , function() {
var id_item = $(this).data('item-id');
var status = collision($('#c' + id_item), $("#r" + id_item));
if (status) {
$('.here').css('background-color', 'red');
}
});
EDIT: I adjusted the jQuery each function to the jQuery each documentation. I can't test if it's working untill you add your html code.
A working revision of your collision function, it checks for vertical overlap of both tops and bottoms in addition to horizontal overlaps to confirm an actual overlap.
function collision($div1, $div2) {
var x1 = $div1.offset().left,
y1 = $div1.offset().top,
b1 = $div1.outerHeight(true) + y1,
r1 = $div1.outerWidth(true) + x1;
var x2 = $div2.offset().left,
y2 = $div2.offset().top,
b2 = $div2.outerHeight(true) + y2,
r2 = $div2.outerWidth(true) + x2;
var v = false,
h = false,
collide = false;
if (b1 > y2 && b1 < b2) {
v = true;
}
if (b2 > y1 && b2 < b1) {
v = true;
}
// vertical overlap check
if (r1 > x2 && r1 < r2) {
h = true;
}
if (r2 > x1 && r2 < r1) {
h = true;
}
// horizontal overlap check
if (h && v) {
collide = true;
}
return collide
}
/*
$.each( "#flex[data-item-id]" , function() {
var id_item = $(this).data('item-id');
var status = collision($('#c' + id_item), $("#r" + id_item));
if (status) {
$('.here').css('background-color', 'red');
}
}); */
$("#monitor").text(collision($('#alpha'), $('#beta')));
// display the result
#alpha {
position: absolute;
left: 3em;
top: 2em;
width: 4em;
height: 4em;
background: #489;
}
#beta {
position: absolute;
left: 4em;
top: 4em;
width: 4em;
height: 4em;
background: #498;
}
#monitor {
position: fixed;
bottom: 1em;
left: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="alpha"></div>
<div id="beta"></div>
<div id="monitor"></div>

Smooth random line, with loops, using Raphael/JS

$(document).ready(function(){
var x1 = Math.random()*$(window).width(); var y1 = Math.random()*$(window).height();
var x2 = 1; var y2 = 1;
var paper = Raphael(document.body);
setInterval(function() {
randx = Math.random(); randy = Math.random();
if (randx > 0.9) {
if (x2 = 1) {
if (randx > 0.99) x2 = -1;
}
else if (x2 = -1) {
if (randx > 0.99) x2 = 1;
}
} else x2 = 0;
if (randy > 0.9) {
if (y2 = 1) {
if (randy > 0.99) y2 = -1;
}
else if (y2 = -1) {
if (randy > 0.99) y2 = 1;
}
} else y2 = 0;
paper.path("M"+x1+" "+y1+"L"+(x1+x2)+" "+(y1+y2));
x1 = x1+x2;
y1 = y1+y2;
}, 0);
});
This is my "random line" generating script. I know it must look terrible, I am just learning. But I am trying to get something resembling this: http://i.stack.imgur.com/R7Kkv.png
I'd really appreciate some tips/suggestions for the algorithm that will make the line smoother and more likely to turn do a u-turn etc.
Thanks
The answer is to generate points within a 40x40 or so box around the previous point, and interpolate between them with a cubic spline.

Categories