adding image to different div upon change/removal of another div - javascript

I have a game which involves a dog chasing cats; upon the dog touching the cat div, the class changes so that a "dead" cat appears and is then removed. I would also like to have a smaller version of the dead cat image show up in a div in the upper right corner as a sort of score keeper.
So essentially every time a cat is killed a small image pops up in the score div.
The problem is if I have the prepend for the small image placed where it is now, it continues to add the image indefinitely as opposed to only one for each dead cat. I'm guessing it's because it's within this if statement for the collision detection but I can't figure out a way around it.
I've tried making it a function, moving it outside of the getCollision function, tried to attach a trigger...nothing I've done seems to work to solve what I assume to be a relatively simple problem.
If anyone can help or point me in the right direction I'd greatly appreciate it! Below is the code:
"use strict";
$(document).ready(function() {
console.log("linked");
var $dog = $('.dog'); //global variables
var body = $('body');
var $cat = $('.cat');
function newCat() { //creates a div w/ class cat, appends to body
var cat = $('<div class="cat"></div>');
body.append(cat);
setInterval(function() { //moves cats randomly
cat.css("top", Math.random() * window.innerHeight);
cat.css("left", Math.random() * window.innerWidth);
}, 1500)
}
for(var i=0; i<10; i++) { //create multiple cats
newCat();
}
function getCollision(cat) { //collision detection for elements
$(cat).each(function(index, cat) { //loops through each cat div
var $dogH = $dog.outerHeight(true);
var $dogW = $dog.outerWidth(true);
var $dogX = $dog.position();
var $dogY = $dog.position();
var $catH = parseInt($(cat).css('height').replace('px', ''))
var $catW = parseInt($(cat).css('width').replace('px', ''))
var $catX = parseInt($(cat).css('left').replace('px', ''))
var $catY = parseInt($(cat).css('top').replace('px', ''))
if ($dogX.left < $catX + $catW &&
$dogY.top < $catY + $catH &&
$catX < $dogX.left + $dogW &&
$catY < $dogY.top + $dogW) {
$(cat).addClass('dead');
$('.score').prepend('<img src="images/cat_dead_sm.png" />');
setTimeout(function() {
$('.dead').remove(); //removes dead cat
}, 2500);
console.log('boom');
};
});
};
$(document).mousemove(function(event) { //moves dog div to follow cursor
$('.dog').css({
'top': event.pageY,
'bottom': event.pageX,
'left': event.pageX,
'right': event.pageY
});
$cat = $('.cat')
getCollision($cat); //calls getcollision to check distance
})();
// function keepScore() {
// $('.score').prepend('<img src="images/cat_dead_sm.png" />');
// }
// };
});

I think the problem is that a dead cat can still die - another iteration of the collision detection can occur before the setTImeout that removes the dead cat is triggered. You could check if the current cat is already dead before prepending the score image.
We just need to check if it's already dead to avoid this:
if ($dogX.left < $catX + $catW &&
$dogY.top < $catY + $catH &&
$catX < $dogX.left + $dogW &&
$catY < $dogY.top + $dogW &&
!$(cat).hasClass('dead')
) {
$(cat).addClass('dead');
$('.score').prepend('<img src="images/cat_dead_sm.png" />');
setTimeout(function () {
$('.dead').remove(); //removes dead cat
}, 2500);
console.log('boom');
}
Or even better - you could avoid collision detection on dead cats entirely:
$cat = $('.cat:not(.dead)');
getCollision($cat);

Related

Issues with rotating jqueryUI modal

I am trying to build a modal that rotates to a particular element, $(.linkmoddet), based on a clicked element in the navbar $('.selectcircle') using the .switchClass function in jQueryUI.
However, I am having issues with the actual math involved, often causing:
only one or two elements to rotate at a time.
multiple elements gaining classes but not losing them.
occasionally losing all the classes involved, defaulting the element in question to a standard size and position in CSS.
Code
Edit: This has now been fixed.
http://codepen.io/yeasayer/pen/ZWxYZG
var selectcircle = $('.selectcircle');
var linkmoddet = $('.linkmoddet');
selectcircle.click(function(){
var circleindex = $(this).index()-1;
var centerindex;
console.log(circleindex);
selectcircle.each(function (index){
if (circleindex == index)
{
console.log($(this));
}
});
linkmoddet.each(function (index){
if ($(this).hasClass('moddetcenter'))
{
centerindex = $(this).index();
console.log("the center is index #"+centerindex);
}
var rotation = centerindex - circleindex;
//This is where I start having issues.
var i = $(this).index() + rotation;
var j;
if (i <= -1)
{
j = i + moddetids.length-1;
$(this).switchClass(classes[i+$(this).index()],classes[j]);
}
if (i >= moddetids.length)
{
j = i - moddetids.length;
$(this).switchClass(classes[i-$(this).index()],classes[j]);
}
else
{
if (rotation < 0)
{
j = i-1;
}
else
{
j = i+1;
}
$(this).switchClass(classes[i], classes[j]);
}
});
});
Does anyone have an idea on how to achieve the desired results, possibly in a simpler manner than described above?
Alright, it turns out that I figured it out by doing the following:
linkmoddet.each(function (index){
var classnum;
var newrot;
if ($(this).hasClass('moddetcenter'))
{
classnum = 2;
if (rotation < 0)
{
rotation += classes.length;
}
if (classnum + rotation >= classes.length)
{
newrot = classnum + rotation - classes.length;
$(this).switchClass(classes[classnum],classes[newrot]);
}
else if (rotation != 0)
{
$(this).switchClass(classes[classnum],classes[classnum+rotation]);
}
}
/* This is repeated for all the classes available in the classes array.
* ie: 0 being the first class, 1 being the second, etc. It's not an
* elegant solution, but it works for my current needs at the moment
* while I put it in a function in the future. */
Thanks!

Touch Events not registering for HTML5 Canvas Authoring using Flash CC

I have been having some issues when it comes to authoring HTML 5 Canvas in Flash CC, mostly as a result of the lack of information on writing JavaScript inside Flash.
I have been converting an existing drag and drop .fla into HTML 5 with the hope of making it iOS and Android compatible. It is already functioning with mouse, but I have hit a brick wall on trying to add touch support.
The only way I have been able to even register the touch events is by listening to the entire window, which isn't very useful when I have multiple pieces that I want to move around.
This is what I have so far, all this code is located on the first frame of the main Scene Timeline, and the scene is composed of 5 pieces and 5 targets for those pieces, as well as a pop up task completed box and a reset button.
this.stop();
MainStage = this;//Declare
//*********************
//Actual Drag and Dropping
// Initialize:
var numPieces = 5;//<---------------Place number of pieces HERE---------------
var homePosX = [];
var homePosY = [];
var correctAns = 0;
var isClickableAry = [];
var whoAmI = [];//Declared "Globally" so that I can identify which piece is being grabbed later
for (var i = 0; i < numPieces; i++)
{
var pieceName = "p" + (i + 1);
var piece = this[pieceName];
//This sets the starting position for each piece
homePosX[i+1] = piece.x;//(i+1) is so that Piece names line up with Target names and MC names
homePosY[i+1] = piece.y;
whoAmI[i] = piece;
isClickableAry[i] = 1;//Makes it so each pieces is set as clickable
if( piece ){
piece.name = pieceName;
piece.on("mousedown" || "touchstart", function(evt)
{
evt.preventDefault();
//Debug
console.log(checkPiece(this));
//Rather than adding and removing event listeners, just check to see if piece is clickable
if(isClickableAry[checkPiece(this)] == 1){
this.parent.addChild(this);// Bump to top
this.offset = {x:this.x - evt.stageX, y:this.y - evt.stageY};
//Debug
console.log(piece + "PICKED UP, X " + piece.x + ", Y " + piece.y + " is Clickable? ");
//Set Home Coordinates (Where it was picked up)
homeX = this.x;
homeY = this.y;
}
});
piece.on("touchmove",function(evt)
{
console.log("touch moved! " + touchobj);
evt.preventDefault();
});
piece.on("pressmove", function(evt)
{
if(isClickableAry[checkPiece(this)] == 1){
this.x = evt.stageX + this.offset.x;
this.y = evt.stageY + this.offset.y;
//Mouse Cursor change
document.body.style.cursor='move';
}
});
piece.on("pressup" || "touchend" || "touchcancel", function(evt)
{
var target = this.parent["t"+this.name.substr(1)];
//Reset Cursor
document.body.style.cursor='auto';
if( target && hitTestInRange( target, 60) && isClickableAry[checkPiece(this)] == 1 ){
this.x = target.x;
this.y = target.y;
//If it is correct add one
correctAns++;
//Make that button Unclickable
isClickableAry[checkPiece(this)] = 0;
if(correctAns >= numPieces){
//If they have answered correctly equal to the the number of pieces
MainStage.complete_mc.parent.addChild(MainStage.complete_mc);//Bump to top
MainStage.complete_mc.gotoAndStop(1);
//reset answer counter and make drag pieces and buttons unclickable
correctAns = 0;
//Debug
console.log(correctAns + "CORRECT!";)
}
}else{
//Return to home Coordinates (Where it was on intialization)
if(isClickableAry[checkPiece(this)] == 1){
this.x = homePosX[checkPiece(this)+1];
this.y = homePosY[checkPiece(this)+1];
}
}
});
piece.on("mouseover", function(evt)
{
if(isClickableAry[checkPiece(this)] == 1){
//Makes cursor a pointer finger
document.body.style.cursor='pointer';
}
});
piece.on('mouseout',function(evt)
{
//sets cursor back to normal
document.body.style.cursor='auto';
});
}
}
function hitTestInRange( target, range )
{
if( target.x > stage.mouseX - range &&
target.x < stage.mouseX + range &&
target.y > stage.mouseY - range &&
target.y < stage.mouseY + range )
{
return true;
}
return false;
}
//Check which piece it is
function checkPiece(checkName)
{
for (var i = 0; i < numPieces; i++)
{
if (checkName == whoAmI[i]){
return i;
}
}
}
//Reset Functionality
this.complete_mc.reset_btn.addEventListener("click", resetPos.bind(this));
function resetPos(){
for (var i = 0; i < numPieces; i++)
{
var pieceName = "p" + (i + 1);
var piece = this[pieceName];
correctAns = 0;
//Makes Pieces Grabable again
isClickableAry[i] = 1;
//This returns each piece to their Original Starting Positions
piece.x = homePosX[i+1];
piece.y = homePosY[i+1];
}
}
//Controlling the Pop Up Window, window pops up when user answers everything correctly
this.complete_mc.exitComplete_btn.addEventListener("click", closePopUp.bind(this));
this.complete_mc.exitComplete_btn_alt. addEventListener("click", closePopUp.bind(this));
function closePopUp(){
MainStage.complete_mc.gotoAndStop(0);
}
In my own troubleshooting with other problems that have come up generally the issue has to do with scope of either functions or variables, since when flash exports the files it generates its own .js file and turns all of your movie clips into code and separates the code that you have written by whichever frame you wrote it on.
Any help at all would be appreciated.
EDIT: After a bit more research I think the problem might have something to do with touch events only being able to target separate elements? So it isn't able to grab objects inside the canvas element just the canvas element itself?
Turns out that adding touch support is incredibly easy. All I was missing was one line of code
createjs.Touch.enable(stage);
this makes all the touch events respond as mouse events. and fixed all my issues.

Menu items changing color according to position of element

My page is divided into three sections and each section can be accessed by respective menu item. I am trying to achieve this in Javascript: when the user has reached any of the sections by scrolling, the font color of respective menu item should change.
Here I call the function:
<body onscroll="detectScroll(); showPosition();">
This is the function that detects scrolling and changes some items accordingly. It's working fine:
function detectScroll() {
var header = document.querySelector(".headerOrig"),
header_height = getComputedStyle(header).height.split('px')[0],
header_class = "changeHeader",
logo = document.getElementById("logo")
;
if( window.pageYOffset > (parseInt(header_height) + 500)) {
header.classList.add(header_class);
logo.src = "images/logo2.png";
}
if( window.pageYOffset < (parseInt(header_height) + 500)) {
header.classList.remove(header_class);
logo.src = "images/logo1.png";
}
}
This JS function returns the position of an element. Works fine as well:
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
while(element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
And, finally, this is the JS function that is being called when scrolling:
function showPosition() {
var myElement = document.getElementById("posBIKES");
var position = getPosition(myElement);
var bike = document.getElementById("bikesMenu");
//alert("The element is located at: " + position.x + ", " + position.y);
if(window.pageYOffset < position.y) {
window.getElementById("bikesMenu").classList.remove("changeMenu");
}
if(window.pageYOffset > position.y) {
window.getElementById("bikesMenu").classList.add("changeMenu");
}
}
The problem is everything works fine until I try to add or remove the class to the item selected (the last function). Any other statement works fine, for example, I tried putting alert("something"); in both conditions and both worked as desired. Whats wrong with adding and removing classes then?
And yes, I have checked the corresponding names and IDs of everything like million times, so theres no issue with that.
Any help is more than appreciated.
Thanks

Resetting jquery varible to lowest possible value that doesn't exist

This script generate divs with cloud images that fly from left to right with random height and intervals. It generally works but it keeps incrementing divs "id" infinitely. I can't figure out how to reset the counter being safe that never two identical "id"s will exist in the same time.
function cloudgenerator(){
var nr=1;
var t1 = 20000;
var t2 = 50000;
function cloud(type,time,nr){
$("#sky").append("<div id=\"cloudFL"+nr+"\" class=\"cloud"+type+"\" ></div>");
setTimeout(function() {
$("#cloudFL"+nr).css({top:Math.floor(Math.random() * 400)+'px'}).animate({
left:'100%',
},time,'linear',function(){$(this).remove();
});
}, Math.floor(Math.random() * t1));
};
function wave(){
var tx = 0;
setInterval(function(){
cloud(1,t1,nr);
nr++;
var n = $( "div.cloud1" ).length;
$( "span" ).text( "There are " + n +" n and "+ tx +" tx")
if(tx < n){tx = n}
else(tx = 1)
},500);
};
wave()};
cloudgenerator()
In the bottom, there is an instruction that checks if number of divs is starting to drop and presents those values in span for debugging.
Quick and easy solutionYou could loop through the id's in JQuery, starting from the lowest number, until you find a JQuery selector that yields 0 results...
var newid = 0;
var i = 1;
while(newid == 0) {
if( $('#cloudFL' + i).length == 0 ) { newid = i; }
else { i++; }
}
JSFIDDLE DEMO
Alternative solution (scalable)
Given that you may have many clouds onscreen at one time, you could try this alternative approach.
This approach creates an array of 'used ids' and the wave function then checks if any 'used ids' are available before creating a new id for the cloud function. This will run quite a bit more efficiently that then above 'quick fix solution' in situations where many clouds appear on screen.
function cloudgenerator(){
var nr=1;
var t1 = 20000;
var t2 = 50000;
var spentids = [];
function cloud(type,time,id){
$("body").append('<div id="' + id + '" class="cloud' + type + '" >' + id + '</div>');
setTimeout(function() {
$('#'+id).css({top:Math.floor(Math.random() * 400)+'px'}).animate({
left:'100%',
},time,'linear',function(){
spentids.push( $(this).attr('id') );
$(this).remove();
});
}, Math.floor(Math.random() * t1));
};
function wave(){
setInterval(function(){
if(spentids.length == 0) {
cloud(1,t1,"cloudFL" + nr);
nr++;
} else {
spentids = spentids.sort();
cloud(1,t1,spentids.shift());
}
},500);
};
wave()};
cloudgenerator()
JSFIDDLE DEMO - ALTERNATIVE
Why not get the timestamp and add this to your id?
If you donĀ“t need the ids i would stick to #hon2a and just add the styling to the class and remove the ids.
And another solution:
You could make a check if ID xyz is used. Like this e.g.
var cloudCount = jQuery('.cloud20000').length + jQuery('.cloud50000').length + 10;
for(var i = 0; i <= cloudCount; i++) {
if(jQuery('#cloudFL' + i).length <= 0) {
nr = i;
return false;
}
}
cloud(1,t1,nr);

passing array of hyperlinks in jquery

I am creating a flowchart using jquery and html which has nodes(circles) and arrows which connect these circles.. two actions need to be done, one is a tooltip action, which will show a particular text when u hover your cursor on particular circle. And the other function is that whenever we click those circles another html page pops up AKA hyperlinks. I have 18 circles and i hav created desired 18 HTML pages. BUt m stuck at hyperlinking. I dont know how to pass these hyperlinks to my Jquery plugin. Below is an attached code for tooltip function
function oncanvasmousemove(evt) {
clearTimeout(timer);
lastTimeMouseMoved = new Date().getTime();
timer = setTimeout(function () {
var currentTime = new Date().getTime();
if (currentTime - lastTimeMouseMoved > 300) {
var mousePos = getMousePos(canvas, evt);
var tC, isMatched = false;
for (c = 0; c < circles.length; c++) {
tC = circles[c];
if (mousePos.DistanceTo(tC.centerX, tC.centerY) < tC.Radius + 5) {
isMatched = true;
break;
}
}
if (isMatched === true) {
$("#tooltip").html(tC.Text).css({
'top': mousePos.Y + canvasoffset.top - 40,
'left': mousePos.X + canvasoffset.left - $("#tooltip").width() / 2
}).show();
} else {
$("#tooltip").hide();
}
}
}, 300);
}
i am attaching a image of the page
You need to give each circle a CSS ID.
For my example, I will just use "#circle-1", "#circle-2" ... "#circle-18".
Also add a CSS class to every circle. For my example I will use ".circle-link".
//On clicking anything with the circle-link class...
$('.circle-link').click(function() {
var link_id = $(this).attr("id"); //Get ID of circle that was clicked
//Get ID number
link_id = link_id.split("-"); //Split the string on the dash/hyphen (returns array)
link_id = link_id[2]; //Get second array element (should be the number)
//Use the above number to determine which link to call
});

Categories

Resources