How to Remove element when reaches screen edge - javascript

I am using jquery to make a simple shooting game from the left side of screen to the right. When the bullet is shot it will travel forever to the right. How can i remove it when it reaches a certain coordinate at the end of the page?
This makes the bullet move...
var flyingBullet = function(){
$(".bullet").each(function() {
var oldLeft = $(this).offset().left;
$(this).css("left", oldLeft + 10 + "px");
});
}
setInterval(flyingBullet, 200);

jsBin demo
(Use jQuery's .remove() method once the bullet is at leftPosition === worldWidth).
(I would do that all in Canvas, for better performance results, visuals and repainting, but here you go: )
I find a really bad idea to loop constantly uncached $() class selector elements.
Create among other variables like...
var world = {$el:$("body"), width: $('body').width()};
var $player = $('#player');
var mousePosY = 0;
...an Array that will hold all the created Bullets
var allBullets = [];
to keep track of all the active bullets and to remove them.
Than create a Bullet Object with the bullet properties (with inner handlers for the position, color, shape, speed etc etc...) and append that Object to our Array of bullets and insert it into the DOM:
function Bullet() {
var obj = {
$el : $('<div/>',{'class':'bullet'}),
css : {top: 100, left:0}, // Start at left 0
speed : 10,
move : function() { // This method will be used inside the animation loop!
obj.css.left += obj.speed; // Advance Bullet
if(obj.css.left > world.width){ // Notice this!!!!
var i = allBullets.indexOf(obj); // !! Use of indexOf (xBr. support).
allBullets.splice(i, 1);
obj.$el.remove();
}else{
return obj.$el.css( obj.css );
}
}
};
allBullets.push( obj );
$('body').prepend( obj.$el );
return obj;
}
To remove the bullets (as you can see in the code above) simply:
var i = allBullets.indexOf(obj); // Find the index of that object inside Array
allBullets.splice(i, 1); // Remove it from Array
obj.$el.remove(); // Remove it from the DOM
Note that indexOf() is introduced in ES5 and not present in old browsers. You might want to use a Polyfill or replace it with an object that will collect Bullets ID... (I'll not cover that topic in this answer).
Once the player clicks to "Fire" you simply create a new instance of that Bullet like:
$("body").on('click', function(){
new Bullet(); // Create a new Bullet with all the properties, move etc.
});
and it will be immediately collected into the allBullets Array.
To move the bullets you pass the the window.requestAnimationFrame :
function moveBullets(){
if(allBullets.length>0) // Only if we have bullets in Array!
for(var i=0; i<allBullets.length; i++) allBullets[i].move(); // Move it using
// his own method.
}
I don't see how's that bullet supposed to fly nicely? 20 by 20px every 200ms?
Also for animation purposes I would go with window.requestAnimationFrame instead of setInterval, to allow the browser dictate the repainting tempo.
// ::: FRAME RATE
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
}());
// ::: ENGINE
(function engine() {
// ----- Insert here functions you want to loop in framerate:
moveBullets();
// -----
requestAnimFrame(engine); // request a new frame
})();
If you really want to use DOM element, I would also suggest to use enhanced CSS3 transitions and move the element with translate3d(x, y, z). You'll not have to move the element every tick, but the browser will move it for you! You can pre-calculate it trajectory in order to keep track of the element position in relation to the animation framerate and an internal clock. (I'll also not cover this examples in my answer.)
The above was for guidance, take a look at the result
in this DEMO (with random bullets speed)

Related

Matter.js: Method to count how many times that an object has rotated?

I am creating a project in which a body is picked up and thrown by the user (with a mouse constraint). The body is set so that it can pivot about the constrain point. I need to find out, from the moment that it is let go, how many times it fully rotates (+-360 degrees) before landing. Reading the documentation, the only thing that I could find regarding the rotation was Matter.Body.rotate() which actually just sets the rotation of a body instead of recording it. How should I go about this?
Basically: How can I count an objects rotations?
This worked for me tbh:
var rad = 6.28;
var nrad = -6.28;
Events.on(engine, "tick", function () {
if(boxA.angle > rad){
rad+=6.28;
nrad+=6.28;
hrt +=1;
//hrt is the rotation c0unter
}
if (boxA.angle < nrad){
nrad-=6.28;
rad-=6.28;
hrt +=1;
}
rnum.innerHTML = "Spins: " + hrt;
fnum.innerHTML = fcounter; });

event data in pixi.js

I just started playing around with pixi and have drawn multiple rectangles from an array with pixel coordinates like this:
var rectangle = [....];
....
var stage = new PIXI.Stage();
var renderer = PIXI.autoDetectRenderer(wrapper.getWidth(), wrapper.getHeight(), { transparent: true });
....
var graphics = new PIXI.Graphics();
graphics.interactive = true;
graphics.on("mouseover", function(e) {
this.alpha = 0.5;
}).on("mouseout", function() {
this.alpha = 1;
});
graphics.beginFill(0xFFFFFF);
graphics.lineStyle(2, 0x000000);
for (var i = 0; i < rectangle.length; i++) {
graphics.drawRect(rectangle[i][0], rectangle[i][1], 10, 10);
}
graphics.endFill();
stage.addChild(graphics);
renderer.render(stage);
The events are triggered but the object I get by "e" or "this" inside the callback is the object for all graphics. I want to get that single "mouseovered" rectangles object I can see in the graphicsData, but there is no id or anything to identify it by. How can I do this?
Performance is of essence as I'm going to render 20k+ rectangles or circles.
Without drawing each rectangle onto it's own PIXI.Graphics object you won't be able to get individual mouseover events. This is because as far as PIXI is concerned the Graphics object is a single bitmap image.
I would suggest performing your own hit tests inside the mouseover function to detect which rectangle the cursor is over.
If you are using PIXI.Rectangles you can take advantage of the built in Rectangle.Contains function to check if a point (in this case the mouse position) is inside the bounds.

Loop animation with svg.js

I have a very simple animation with svg.js that I would like to run on a loop as long as the page is open. I haven't been able to find any thing while looking through either the github, documentation, or stack overflow pages. A working version of the animation without looping can be found here. The important js is:
//create the svg element and the array of circles
var draw = SVG('canvas').size(300, 50);
var circ = [];
for (var i = 0; i < 5; i++) {
//draw the circles
circ[i] = draw.circle(12.5).attr({
fill: '#fff'
}).cx(i * 37.5 + 12.5).cy(20);
//first fade the circles out, then fade them back in with a callback
circ[i].animate(1000, '<>', 1000 + 100 * i).attr({
opacity: 0
}).after(function () {
this.animate(1000, '<>', 250).attr({
opacity: 1
});
});
}
I know this would be pretty easy to do without a js library, but I'm looking at this as just a first step into using svg.js. Later I plan on using it for much more robust animations. Thanks for any advice or pointers.
From version 0.38 of svg.js on the loop() method is built in:
https://github.com/wout/svg.js#loop
I'm also planning on creating a reverse() method in one of the upcoming releases. Right now the loop() method restarts the animation from the beginning.
I'm not sure if its possible just with svg.js attributes, as its not clear from svg.js if its creating typical svg animation elements or not. Whatever, it could be done with a loop though. So...
function anim( obj,i ) {
obj.animate(1000, '<>', 1000 + 100 * i).attr({
opacity: 0
}).after(function () {
obj.animate(1000, '<>', 250).attr({
opacity: 1
});
});
};
function startAnims() {
for( var i = 0; i< 5; i++ ) {
anim( circ[i],i );
}
setTimeout( startAnims, 5000 ); // Or possibly setInterval may be better
};
jsfiddle here http://jsfiddle.net/8bMBZ/7/ As its not clear if its adding elements each time behind the scenes (you may want to store the animation and just start that if so). There are other libs that tie in differently to SVG if you need like Raphael, snap, d3, Pablo.js that you could try as alternatives if you need to look at animation from a slightly different way.
I used after to call a function that start the animation recursively. This way I was able to achieve both infinite looping and reversing. Of course you can count to avoid infinite looping but the general idea is as follows:
//custom animation function whose context is the element animated
function myCustomAnimation(pos, morph, from, to) {
var currentVal = morph(from, to); //do morphing and your custom math
this.attr({ 'some prop': currentVal });
}
var animationStart = 0; //just extra values for my custom animation function
var animationEnd = 1; //animation values start at 0 and ends at 1
line.attr({ 'stroke-width': 2, stroke: 'red' });
animateMeRepeatedly.apply(line);
function animateMeRepeatedly()
{
this.animate(1500)
.during(function (pos, morph) {
myCustomAnimation.apply(this, [pos, morph, animationStart, animationEnd]);
})
.after(function () {
this.animate(1500).during(function (pos, morph) {
myCustomAnimation.apply(this, [pos, morph, animationEnd, animationStart]);
}).after(animateMeRepeatedly);
});
}

in gamequery; how would I move an object "slowly" from its "dropped" location to where it needs to go?

I am not trying to get it to follow a set path since the path is variable. but I am trying to set the object to fall in a noticable pattern from where Idrop it.
$(".gQ_sprite").mouseup(function() {
//test condition to see if collides with a box etc...
collision1 = $("#" + currentClickedDivId).collision(".gQ_group, .box");
if(collision1.length > 0)
{
//irrelevent
}
else
{
//figure out yarnball Id...
i = wordLength - 1
yarnBallIdNumber = currentClickedDivId.charAt(10);
yarnBallPositionFromStart = i - yarnBallIdNumber
initialMovedYarnBallXPosition = yarnBallPositionFromStart * yarnSpacing
initialMovedYarnBallXPosition = initialXYarnPosition - initialMovedYarnBallXPosition
$("#" + currentClickedDivId).xy(initialMovedYarnBallXPosition ,yarnYPosition);
}
right now my code simply flashes the object back to its location after the user releases it, and I am trying to move it back "slowly" if you will and can't think of the best way to do it.
so far my thoughts are to use a loop and subtract (or add) the location of the object with delay, but there may be a better way to move the object that I don't know about.
any ideas?
What you could do is to use jQuery to animate something else than a CSS property, like explained there: https://coderwall.com/p/fn2ysa
In your case to make your sprite move from currentX to destinationX in one second you code would look like:
var from = {x: currentX};
var to = {x: destinationX};
$(from).animate(to,{duration: 1000, step: function(step){
$(mySprite).x(step);
}});

How to optimize this js (now CPU is over 40% when the page is opened)

I have this piece of JavaScript on my page and it loads the CPU considerably. Is there any way to optimize the code? ( I'm using jQuery, so jQuery solutions will be fine )
function Particle() {
this.particleContainerWidth = $('#particle-container').width() - 100;
this.particleContainerHeight = $('#particle-container').height() - 100;
this.path = 'img/';
this.images = ['particle1.png', 'particle2.png', 'particle3.png', 'particle4.png'];
// Randomly Pick a Particle Model
this.image = this.images[randomInt(this.images.length)];
this.file = this.path + this.image;
// Create a Particle DOM
this.element = document.createElement('img');
this.speed().newPoint().display().newPoint().fly();
};
// Generate Random Speed
Particle.prototype.speed = function() {
this.duration = (randomInt(10) + 5) * 1100;
return this;
};
// Generate a Random Position
Particle.prototype.newPoint = function() {
this.pointX = randomInt(this.particleContainerWidth);
this.pointY = randomInt(this.particleContainerHeight);
return this;
};
// Display the Particle
Particle.prototype.display = function() {
$(this.element)
.attr('src', this.file)
.css('position', 'absolute')
.css('top', this.pointY)
.css('left', this.pointX);
$('#particle-container').append(this.element);
return this;
};
// Animate Particle Movements
Particle.prototype.fly = function() {
var self = this;
$(this.element).animate({
"top": this.pointY,
"left": this.pointX
}, this.duration, 'linear', function(){
self.speed().newPoint().fly();
});
};
function randomInt(max) {
// Generate a random integer (0 <= randomInt < max)
return Math.floor(Math.random() * max);
}
$(function(){
$('body').append('<div id="particle-container"></div>');
var total = 8;
var particles = [];
for (i = 0; i < total; i++){
particles[i] = new Particle();
}
});
You cannot make JavaScript consume less of your CPU. That is governed by the priority of the executing application in the OS kernel. The best you can hope for is to reduce execution time.
To improve your execution efficiency limit your usage of prototype and stop assigning values to properties. This method of coding has become popular because it is extremely clean and easy to read, but it horribly backwards to execute.
If you are capable of coding using only variables for assignment, if statements for decisions, and for loops for looping your code execution will be far faster. That will require you to write more code, however, and it will not be so pretty.
To improve output performance write all output segments each into an index of an array and use only a single join method when all output is created and a single innerHTML method to output this text to the page. This will reduce output execution by up to 4 times.
Have you thought about implementing this with a <canvas> version? It won't work in IE directly, of course, and off-hand I'm not sure whether it'd be faster or slower. You could also try it with Processing.
This would need a lot of changing and rewriting, but You can create a new easing function for jquery and post it to animate. Then every particle You have would just be once issued with animate() with Your easing function and the function has to be based on those:
random
current time (new Date()) modulo some number
a singleton holding individual directions
ideas:
Assuming You don't want to change Your code You can try setting the particle to fly with some random timeout when first running fly(). It could change the way it's all executed. No idea if it helps or makes it slower though ;)
Second thing is quality. jquery animate does it too smoothly. You can move Your particles instead of animating and just chande the distance to lower and increase speed and use setTimeout to make it move the same pace as now.

Categories