detecting collision between two images in jquery - javascript

i have this game :http://jsfiddle.net/Qfe6L/5/
i am trying to detect when a shuriken hit an enemy so when it hit it the enemy should disappear and the score should be increased by 1 what i searched for is that i should calculate the position of the two images to check whether their is a collision but i don't seem i can do that any help from you guys ?
$(window).keypress(function (e) {
if (e.which == 32) {
CreateChuriken();
$("#Shuriken" + Shurikengid).animate({ left: '+=300px' }, 'slow');
if ($(".Shuriken").css('left') == $(".Enemy").css('left'))
{ alert("Met"); }
}
});

You need to check for collision in each animation step. Fortunately jQuery .animate() has a progress option, which you can pass a function to be called every frame.
$("#Shuriken" + Shurikengid).animate(
{ left: '+=300px' },
{ duration : 'slow',
progress: function(){
/* collision detection here */
}
}
);
Keep in mind that
if ($(".Shuriken").css('left') == $(".Enemy").css('left'))
will only compare position of first projectile and first enemy, while there are more of them on the screen. You need to iterate over every projectile and compare its powition with every enemy to find a colliding pair, like:
$('.Shuriken').each( function(){
var sOffset = $(this).offset();
$('.Enemy').each( function(){
var eOffset = $(this).offset();
if( sOffset.left == eOffset.left ){
/* boom! */
}
});
});
The above is close, but still won't work. Animation doesn't progress by 1px each frame, so you may go from Shuriken at 100px left and Enemy at 101px left at one frame to Shuriken at 102px left and Enemy at 99px left in the next one. They'll pass each other, but won't meet at the same point. So you'd need to round these values to, say, nearest 10s which will give you a bigger tolerance. You sholud also compare the vertical positions.
Updated fiddle: http://jsfiddle.net/Qfe6L/8/
(Fixed vertical posiotion of Enemies for easier testing).
Edit:
as suggested by #Kasyx it would be better to move all of this out of animation function and create a Game Loop and Scene Graph. Scene graph would keep track of elements' positions, and within Game Loop you'd check for collisions, then call a rendering function which would draw elements on screen based on the scene graph.

At the moment you’re running your hit check function once, directly after you’ve started the animation. What you need to be doing is running it every frame to see the intersect. Luckily jQuery provides a callback handler for this: $.animate’s step option. If you pass a second object into $.animate you can specify both your duration and step function like so:
$(window).keypress(function (e) {
if (e.which == 32) {
CreateChuriken();
$("#Shuriken" + Shurikengid).animate({
left: '+=300px'
}, {
duration: 'slow',
step: function(){
if ($(".Shuriken").css('left') == $(".Enemy").css('left')) {
alert("Met");
}
}
});
}
});
As you’re calling your step function once every frame you’ll want to cache your selectors inside ($('.Shuriken'), $('.Enemy')) first:
$(window).keypress(function (e) {
if (e.which == 32) {
var shuriken, enemy;
CreateChuriken();
shuriken = $('.Shuriken');
enemy = $('.Enemy');
$("#Shuriken" + Shurikengid).animate({
left: '+=300px'
}, {
duration: 'slow',
step: function(){
if (shuriken.css('left') == enemy.css('left')) {
alert("Met");
}
}
});
}
});

Related

Callback after element moved

I have list that scrolls up using velocity. I want to play sound each time, first visible item of the list scrolled up.
<div class="viewport" data-winner="">
<ul class="participants-holder container" id="ph">
<li>...<li> //many li elements
</ul>
</div>
moveToEl(name) {
...
$(container).velocity({
translateY: -(offsetToScroll)+'px'
}, {
duration: 15000,
easing: [.74,0,.26,1],
complete: (el) => {
...
// complete animation callback
},
progress: (els, complete, remaining, start, tweenVal) => {
console.log(Math.floor(complete * 100) + '%')
// I think some check should do during progress animation
}
})
}
How to handle event or track changes when each element or entire list are scrolled up by certain pixels, for instance 62px. How can I detect this and call callback function on this happened.
You can find the current TranslateY using something like
+this.container.style.transform.replace(/[^0-9.]/g, '');
from https://stackoverflow.com/a/42267490/1544886, and compare it to the previous value plus an offset.
In the Roulette class add this.prevTranslatePos = 0.0; for storing the old value.
progress: (els, complete, remaining, start) => {
// from https://stackoverflow.com/a/42267490/1544886
var translatePos = +this.container.style.transform.replace(/[^0-9.]/g, '');
if (translatePos >= (this.prevTranslatePos + 62))
{
//console.log(translatePos, this.prevTranslatePos);
this.prevTranslatePos = translatePos;
this.sound.pause();
this.sound.currentTime = 0;
this.sound.play();
}
}
Demo applied to the 'Go To' button only: http://codepen.io/anon/pen/yMXwgd?editors=1010
Note that the sound cuts out when it runs too quickly, but that could be handled a few different ways.
Add a scroll eventListener to the parent element of the list (I believe it's participants-holder in your case), and within that do a check for whether the right amount of pixels have moved since the last check. Store the current position, and compare it to the last time you moved the desired amount.
Hope that helps!

Cut jQuery Animate Function Short and Revert to Start on Keypress

I have a simple dropping ball animation, which I'm using jQuery animate function for. The ball starts at bottom: 600 and falls until it reaches the ground, at bottom: 90.
function ballbounce() {
$('.football').animate({
'bottom': 90
}, bouncetime, 'easeOutBounce', function() {
});
}
When the spacebar is pressed, I want to cut the falling animation short and have the ball go up again. I'm trying this by detecting the keypress, getting the current bottom value of the ball, adding 300px to that value, then setting it as the new bottom value on the ball. But I want the falling animation to resume from that point.
$(document).keydown(function(e) {
switch(e.which) {
case 32: // spacebar
var ballOffset = $('.football').offset();
var currentBallPosition = $(window).height() - ballOffset.top - $('.football').height();
var newBallPosition = currentBallPosition + 300;
$('.football').css("bottom", newBallPosition);
break;
default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action
});
I can't get it working, I'm not sure where I'm going wrong. The ball's bottom is only being updated if I press the spacebar after the animation is complete.
This is for a basic keepy uppy soccer game. So the ball drops and you press spacebar to kick the ball back up in the air again. Is this even a good solution?
I would call .stop() on the element, then reset it to it's original position. You could store the original position as a data attribute on the element itself before the animation then use that to reset it later like this:
function ballbounce(selector,bouncetime) {
var $ball= $(selector);
$ball.data('original-top',$ball.position().top )
$ball.animate({ top: '+550px'}, bouncetime, "easeOutBounce", function() {
//animation complete
});
return $ball;
}
var $ballReference=ballbounce('.football',5000);
$(document).keydown(function(e) {
switch(e.which) {
case 32: // spacebar
$ballReference.stop().css({top:$ballReference.data('original-top')});
break;
default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action
});
.football{
width:100px;
height:100px;
background-color:#ccc;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.3/jquery-ui.min.js"></script>
<div class="football"></div>

Using a jquery slider for text instead of images?

This may be a little too specific, but I have a jquery slider that I am using <p> classes instead of images to cycle through customer quotes. Basically the problem I am running into right now is when it is static and non moving (JS code is commeneted out) they are aligned how I want them to be. As soon as the JS is un commented, they stretch out of view and you just see a white box?
Any ideas?
How I want each panel to look like:
jsfiddle
So I sort of made this my Friday project. I've changed a whole lot of your code, and added a vertical-align to the quotes and authors.
Here's the fiddle http://jsfiddle.net/qLca2fz4/49/
I added a whole lot of variables to the top of the script so you could less typing throughout.
$(document).ready(function () {
//rotation speed and timer
var speed = 5000;
var run = setInterval(rotate, speed);
var slides = $('.slide');
var container = $('#slides ul');
var elm = container.find(':first-child').prop("tagName");
var item_width = container.width();
var previous = 'prev'; //id of previous button
var next = 'next'; //id of next button
Since you used a % based width I'm setting the pixel widths of the elements in case the screen is reszed
slides.width(item_width); //set the slides to the correct pixel width
container.parent().width(item_width);
container.width(slides.length * item_width); //set the slides container to the correct total width
As you had, I'm rearranging the slides in the event the back button is pressed
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
I combined the prev and next click events into a single function. It checks for the ID of the element targeted in the click event, then runs the proper previous or next functions. If you reset the setInterval after the click event your browser has trouble stopping it on hover.
//if user clicked on prev button
$('#buttons a').click(function (e) {
//slide the item
if (container.is(':animated')) {
return false;
}
if (e.target.id == previous) {
container.stop().animate({
'left': 0
}, 1500, function () {
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
});
}
if (e.target.id == next) {
container.stop().animate({
'left': item_width * -2
}, 1500, function () {
container.find(elm + ':last').after(container.find(elm + ':first'));
resetSlides();
});
}
//cancel the link behavior
return false;
});
I've found mouseenter and mouseleave to be a little more reliable than hover.
//if mouse hover, pause the auto rotation, otherwise rotate it
container.parent().mouseenter(function () {
clearInterval(run);
}).mouseleave(function () {
run = setInterval(rotate, speed);
});
I broke this in to its own function because it gets called in a number of different places.
function resetSlides() {
//and adjust the container so current is in the frame
container.css({
'left': -1 * item_width
});
}
});
//a simple function to click next link
//a timer will call this function, and the rotation will begin :)
And here's your rotation timer.
function rotate() {
$('#next').click();
}
It took me a little bit, but I think I figured out a few things.
http://jsfiddle.net/qLca2fz4/28/
First off, your console was throwing a few errors: first, that rotate wasn't defined and that an arrow gif didn't exist. Arrow gif was probably something you have stored locally, but I changed the 'rotate' error by changing the strings in the code here to your actual variables.
So, from:
run = setInterval('rotate()', speed);
We get:
run = setInterval(rotate, speed);
(No () based on the examples here: http://www.w3schools.com/jsref/met_win_setinterval.asp)
But I think a more important question is why your text wasn't showing up at all. It's because of the logic found here:
$('#slides ul').css({'left' : left_value});
You even say that this is setting the default placement for the code. But it isn't..."left_vaule" is the amount that you've calculated to push left during a slide. So if you inspect the element, you can see how the whole UL is basically shifted one slide's worth too far left, unable to be seen. So we get rid of 'left_value', and replace it with 0.
$('#slides ul').css({'left' : 0});
Now, there's nothing really handling how the pictures slide in, so that part's still rough, but this should be enough to start on.
Let me know if I misunderstood anything, or if you have any questions.
So, a few things:
1) I believe you are trying to get all of the lis to be side-by-side, not arranged up and down. There are a few ways to do this. I'd just make the ul have a width of 300%, and then make the lis each take up a third of that:
#slides ul {
....
width: 300%;
}
#slides li {
width: calc(100% / 3);
height:250px;
float:left;
}
2) You got this right, but JSFiddle automatically wraps all your JS inside a $(document).ready() handler, and your function, rotate needs to be outside, in the normal DOM. Just change that JSFiddle setting from 'onload' to 'no wrap - in head'
3) Grabbing the CSS value of an element doesn't always work, especially when you're dealing with animating elements. You already know the width of the li elements with your item_width variable. I'd just use that and change your code:
var left_indent = parseInt($('#slides ul').css('left')) - item_width;
$('#slides ul').animate({'left' : left_indent}, 1500, function () {
to:
$('#slides ul').stop().animate({'left' : -item_width * 2}, 1500, function () {
4) Throw in the .stop() as seen in the above line. This prevents your animations from overlapping. An alternative, and perhaps cleaner way to do this, would be to simply return false at the beginning of your 'next' and 'prev' functions if #slides ul is being animated, like so:
if ($('#slides ul').is(':animated')) return false;
And I think that's everything. Here's the JSFiddle. Cheers!
EDIT:
Oh, and you may also want to clearInterval at the beginning of the next and prev functions and then reset it in the animation callback functions:
$('#prev').click(function() {
if ($('#slides ul').is(':animated')) return false;
clearInterval(run);
$('#slides ul').stop().animate({'left' : 0}, 1500,function(){
....
run = setInterval('rotate()', speed);
});
});

Move image to specified minimum value

I have the code
$(document).keydown(function (key) {
switch (parseInt(key.which, 10)) {
case 38://up
mObj.animate({
top: "-=100px"
});
mObj.animate({
top: "+=" + change + "px"
});
break;
default:
break;
}
});
Which moves my image up and down correctly upon the up button, given the up button is not pressed again while Mario is in the air. I would like to remedy this condition (not being able to click up while Mario is in the air) through a method such as the attempted in lines 43-46 of my code found here.
In essence I want to allow Mario to simply fall all the way back down to a set minimum level when not being moved up. Any help on getting it to do this or pointing out why my alternate method (the one commented out in lines 43-46) doesn't work?
As an immediate solution, you could try using this:
$(document).ready(function () {
var jumping = false;
$(document).keydown(function (key) {
switch (parseInt(key.which, 10)) {
case 38://up
if (!jumping) {
jumping = true;
var jumpUp = new $.Deferred();
var jumpDown = new $.Deferred();
mObj.animate({
top: "-=100px"
}, {
done: function () {
jumpUp.resolve();
}
});
mObj.animate({
top: "+=" + change + "px"
}, {
done: function () {
jumpDown.resolve();
}
});
$.when(jumpUp, jumpDown).done(function () {
jumping = false;
});
}
break;
default:
break;
}
});
});
http://jsfiddle.net/wuY9V/1/
It basically just has a "state" of whether or not Mario is jumping. When the "up" arrow is pressed, Mario is jumping. As soon as the animations that move him up and then back down, are done, Mario is no longer jumping. So the function ignores the "up" key when Mario is jumping. I'm sure there's a more elegant way (like built into .animate) but this is what I came up with.
So obviously to test it, try pressing the "up" key at any point during Mario's jumping...it shouldn't do anything.
I didn't look into it too much, but I'm wondering why you have a setInterval for moving Mario? The way I would've done it is only listened for the keydown event. If it's the "up" arrow, animate him to move up and then back down (like you have, and like I've assisted with here). If it's the left arrow, animate him to move left a set distance. If it's the right arrow, animate him to move right a set distance. Is there a reason you have the setInterval to constantly check for a key pressed? Maybe I'm missing something.

Fixing the animation properties

I am doing some research at the moment into creating a new maths game for primary school children where divs from 0-9 appear at random inside a container.
A question is given at the beginning. Something like, multiples of 20. The user will then have to click on the correct ones, and they will then be counted at the end and a score will be given.
I have just changed the speed in which the divs appear so that they appear for longer and more than one at a time to make the game easier for younger children.
I used "fadeIn" like so..
$('#' + id).animate({
top: newY,
left: newX
}, 'slow', function() {}).fadeIn(2000);
}
My problem is that now when I shoot the correct or incorrect number the animation is very glitchy and I cannot figure out why.
Fiddle: http://jsfiddle.net/cFKHq/6/ (See version 5 to see what it was like before)
Inside startplay(), control the concurrency when calling scramble() , I do it with a global var named window.cont, so I replaced your following call:
play = setInterval(scramble, 1800);
for this one:
play = setInterval(function() {
if (window.cont){
window.cont = false;
scramble();
}
}, 1000);
The var window.cont needs to be set globally at the start of your code, like so:
var miss = 0;
var hit = 0;
var target = $("#target");
window.cont = true;
So with window.cont you now can control that animations are executed one after another, without overlapping, like so:
$('#'+id).css({
top: newY,
left: newX
}).fadeIn(2000, function() {
setTimeout(function() {
$('#' + id).slideUp('fast');
window.cont = true;
}, 1500);
});
See working demo

Categories

Resources