I have a function that adds random images to my divs that disappear over time and create a mouse trail. My issue is: there are double images.
I'd like to add something that checks if the background url is already located on the page and if that's the case, skips to the next in the array and check it again until until it comes across one that is not there. So like a loop that refreshes every time a 'trail' is being created.
Maybe I am asking for something that won't work? What if all the images are already on the page? I don't really have an answer for it and I also don't have an idea how to solve that problem yet.
For now I tried adding a counter that checks the usedImages and counts them, but it seems to have flaws and I am unsure where to look or how to fix it. Does anyone have any tips on how to do this? Is it even possible?
My fiddle
var bgImages = new Array(
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/schraegluftbild-1024x725.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/pikto-608x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/Jettenhausen-EG-Grundriss-913x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/lageplan-945x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/Jettenhausen-EG-Grundriss-913x1024.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/05/Jettenhauser-Esch-Modell-2-1024x768.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/07/DSCN3481-1024x768.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2019/07/zoom-in-3_ASTOC-1024x683.jpg",
"https://www.studiourbanestrategien.com/wordpress/wp-content/uploads/2016/07/IMG_1345-1024x768.jpg"
);
const numberOfImages = 10;
const timesPerSecond = .1;
var usedImages = {};
var usedImagesCount = 0;
function preloadImages(images) {
for (i = 0; i < images.length; i++) {
let l = document.createElement('link')
l.rel = 'preload'
l.as = 'image'
l.href = images[i]
document.head.appendChild(l);
}
}
function animate(e) {
var image = document.createElement('div');
image.classList.add('trail');
var sizew = 200;
var sizeh = 200;
image.style.transition = '3s ease';
image.style.position = 'fixed';
image.style.top = e.pageY - sizeh / 2 + 'px';
image.style.left = e.pageX - sizew / 2 + 'px';
image.style.width = sizew + 'px';
image.style.height = sizeh + 'px';
var random = Math.floor(Math.random() * (bgImages.length));
if (!usedImages[random]) {
image.style.backgroundImage = "url(" + bgImages[random] + ")";
usedImages[random] = true;
usedImagesCount++;
if (usedImagesCount === bgImages.length) {
usedImagesCount = 0;
usedImages = {};
}
} else {
animate(e);
}
console.log(usedImages);
console.log(usedImagesCount);
image.style.backgroundSize = 'cover';
image.style.pointerEvents = 'none';
image.style.zIndex = 1;
document.body.appendChild(image);
//opacity and blur animations
window.setTimeout(function() {
image.style.opacity = 0;
image.style.filter = 'blur(20px)';
}, 40);
window.setTimeout(function() {
document.body.removeChild(image);
}, 2100);
};
window.onload = function() {
preloadImages(bgImages);
var wait = false;
window.addEventListener('mousemove', function(e) {
if (!wait) {
wait = true;
setTimeout(() => {
wait = false
}, timesPerSecond * 800);
animate(e);
}
});
};
I'm trying to get a spaceship animation scene with a group of comets going down.
//Create a comet div with img attached to it
var cometScene = function(spaceNo){
var b = document.createElement('div');
b.id = 'cometio';
var cometImage = document.createElement('img');
cometImage.setAttribute('src', 'images/comet1.png');
b.appendChild(cometImage);
document.getElementById('wrap').appendChild(b);
}
//Comet move
function cometMove(){
var comet = document.getElementById('cometio');
var pos = 0;
var interval = setInterval(scene, 3);
function scene(){
if (pos === 1000){
clearInterval(interval);
} else {
pos++;
comet.style.top = pos + 'px';
comet.style.left = pos + 'px';
}
}
setInterval(scene, 3)
}
But when I call a function cometScene(3) I'm not getting 3 similar objects. Also how these objects can be allocated across the whole screen as this is just a single div.
function main(){
var w = document.createElement('div');
w.id = 'wrap';
document.querySelector('body').appendChild(w);
astronautScene();
cometScene();
shaceshipScene();
cometMove();
astronautMove();
}
This it what I would do:
Give the comets a class instead of an id, because there can be more of them.
Because there can be multiple use a loop to iterate through them
To give them the ability to move freely, they need to have position:absolute or something similiar
Don't use the same variable for the position of all comets, because they could be in different positions
To get the current position just parse the currect top and left value to a Number
//Create a comet div with img attached to it
var cometScene = function(spaceNo) {
var b = document.createElement('div');
b.className = 'cometio';
var cometImage = document.createElement('img');
cometImage.setAttribute('src', 'images/comet1.png');
b.appendChild(cometImage);
document.getElementById('wrap').appendChild(b);
}
//Comet move
function cometMove() {
var comets = document.getElementsByClassName('cometio');
for (let i = 0; i < comets.length; i++) {
const comet = comets[i];
comet.style.top = "0px";
comet.style.left = "0px";
comet.style.position = "absolute";
var interval = setInterval(scene, 3);
function scene() {
let x = parseInt(comet.style.left);
let y = parseInt(comet.style.top);
if (x === 1000) {
clearInterval(interval);
} else {
comet.style.top = (1 + x) + 'px';
comet.style.left = (1 + y) + 'px';
}
}
}
//setInterval(scene, 3)don't start the interval twice
}
function main() {
var w = document.createElement('div');
w.id = 'wrap';
document.querySelector('body').appendChild(w);
//astronautScene();
cometScene();
//shaceshipScene();
cometMove();
//astronautMove();
}
main();
I am trying to create a simple javascript animation that will expand the width of an element from 0px to a specified width. Although this is probably a pretty elementary problem for some, I just can't seem to figure out what I am doing wrong. Instead of the loop running and expanding the div as desired I am only able to expand the div by repeatedly firing the function manually.
Fiddle
Current js code:
var el = document.getElementById('h');
var btn = document.getElementById('button1');
var oswidth = el.offsetWidth;
var target_width = 100;
btn.onclick = function grow() {
var loop = setTimeout('grow(\'' + el + '\')', 20);
if (oswidth < target_width) {
oswidth += 5;
} else {
clearTimeout(loop);
}
el.style.width = oswidth + 'px';
}
And as always, thank you in advance!
Try this code.fiddle-https://jsfiddle.net/L8kLx7d2/
var el = document.getElementById('h');
var btn = document.getElementById('button1');
var oswidth = el.offsetWidth;
var target_width = 100;
var loop;
function grow() {
if (oswidth < target_width) {
oswidth += 5;
} else {
clearInterval(loop);
}
el.style.width = oswidth + 'px';
}
btn.onclick=function(){
loop=setInterval(grow, 1000)};
Try this:
var el = document.getElementById('h');
var btn = document.getElementById('button1');
var oswidth = el.offsetWidth;
var target_width = 100;
btn.onclick = function grow() {
if (oswidth < target_width) {
oswidth += 5;
el.style.width = oswidth + 'px';
setTimeout(grow, 20);
}
}
I'll leave it to you to puzzle over the differences.
You can call the grow function in setInterval
JS:
var el = document.getElementById('h');
var btn = document.getElementById('button1');
var oswidth = el.offsetWidth;
var target_width = 100;
function grow() {
var loop = setTimeout('grow(\'' + el + '\')', 20);
if (oswidth < target_width) {
oswidth += 5;
} else {
clearTimeout(loop);
}
el.style.width = oswidth + 'px';
}
setInterval(grow, 1000);
Demo: http://jsfiddle.net/lotusgodkk/jeq834de/1/
There are three solutions. The first is using recursive setTimeout:
function grow(time) {
if (oswidth < target_width) {
oswidth += 5;
el.style.width = oswidth + 'px';
setTimeout(function() {grow(time);}, time);
}
}
The second is to use setInterval as described in the answer of K K.
The third is my personal favorite, using the transition css attribute.
I want to make a rectangular move by click on a button and stop it clicking on the same button. Here is a part of my code:
document.getElementById("startStop").addEventListener("click", changePlace);
function changePlace() {
nIntervMove = setInterval(movement, 100);
};
var tmp1 = 0;
function movement() {
var oElem = document.getElementById("colorRectangular");
oElem.getPropertyValue = tmp1;
tmp1 += "10px";
};
function stopMove(){
clearInterval(nIntervMove);
};
Pretty straight forward:
var makeMove = function(x, hx, t, complete) {
var target = document.getElementById('rect'),
dx = 0,
d = setInterval(function() {
target.style.left = dx + "px";
dx += hx;
if(dx >= x) {
clearInterval(d);
complete();
}
}, t);
};
makeMove(100, 5, 500, function() {
alert('done');
});
JSFiddle: http://jsfiddle.net/8ay9cqmd/
I am trying to get the distance between my character and the ground, I have found something that looks like it should do what I want but it has been written for another version of box2d.
Original:
float targetHeight = 3;
float springConstant = 100;
//make the ray at least as long as the target distance
b2Vec2 startOfRay = m_hovercarBody->GetPosition();
b2Vec2 endOfRay = m_hovercarBody->GetWorldPoint( b2Vec2(0,-5) );
overcarRayCastClosestCallback callback;
m_world->RayCast(&callback, startOfRay, endOfRay);
if ( callback.m_hit ) {
float distanceAboveGround = (startOfRay - callback.m_point).Length();
//dont do anything if too far above ground
if ( distanceAboveGround < targetHeight ) {
float distanceAwayFromTargetHeight = targetHeight - distanceAboveGround;
m_hovercarBody->ApplyForce( b2Vec2(0,springConstant*distanceAwayFromTargetHeight),
m_hovercarBody->GetWorldCenter() );
}
}
I have tried to change it to what I think it should be but it doesn't even call the callback.
var targetHeight = 3;
var springConstant = 100;
//make the ray at least as long as the target distance
startOfRay = new b2Vec2(m_hovercarBody.GetPosition());
endOfRay = new b2Vec(m_hovercarBody.GetWorldPoint( b2Vec2(0,-5)));
function callback(raycast){
if ( raycast.m_hit ) {
var distanceAboveGround = (startOfRay - raycast.m_point).Length();
//dont do anything if too far above ground
if ( distanceAboveGround < targetHeight ) {
var distanceAwayFromTargetHeight = targetHeight - distanceAboveGround;
m_hovercarBody.ApplyForce( b2Vec2(0,springConstant*distanceAwayFromTargetHeight),
m_hovercarBody.GetWorldCenter() );
}
}
}
m_world.RayCast(callback, startOfRay, endOfRay);
Any idea how to convert it to work with box2dweb?
Thanks
It might be that the original bit of code was written for a platform where the coordinate system works differently.
In a Canvas element, the coordinate system starts from the top left corner, meaning that m_hovercarBody.GetWorldPoint( b2Vec2(0,-5)) is checking for a point above the character, rather than below.
I'm not sure about the rest of the code but try changing that to m_hovercarBody.GetWorldPoint( b2Vec2(0,5)) and see what happens.
EDIT:
I think actually the problem is with the way you've structured your callback. Looking up the reference for the Raycast function would reveal more.
(The Javascript version of Box2D you're using is an automatic port of the Actionscript one. Given the two have fairly similar syntax, you can use the reference for Flash.)
The original code you posted seems to be C++, but I don't know much about its syntax. It seems there's some sort of class that does the raycasting (overcarRayCastClosestCallback). You can either look for that, or try and build your own callback function according to the first link I posted. It would be something along the lines of:
function customRaycastCallback(fixture, normal, fraction) {
// you can, for instance, check if fixture belongs to the ground
// or something else, then handle things accordingly
if( /* fixture belongs to ground */ ) {
// you've got the fraction of the original length of the raycast!
// you can use this to determine the distance
// between the character and the ground
return fraction;
}
else {
// continue looking
return 1;
}
}
Try running this on your browser. I coded this when I was learning sensor and RAYCAST in Box2Dweb. Hope it helps.
<html>
<head>
<title>Box2dWeb Demo</title>
</head>
<body>
<canvas id="canvas" width="600" height="420" style="background-color:#333333;" ></canvas>
<div id="cc" style="position:absolute; right:0; top:100px; width:500px; height:50px; margin:0;"></div>
</body>
<script type="text/javascript" src="Box2dWeb-2.1.a.3.js"></script>
<script type="text/javascript" src="jquery-1.7.2.js"></script>
<script type="text/javascript">
var b2Vec2 = Box2D.Common.Math.b2Vec2
, b2BodyDef = Box2D.Dynamics.b2BodyDef
, b2Body = Box2D.Dynamics.b2Body
, b2FixtureDef = Box2D.Dynamics.b2FixtureDef
, b2World = Box2D.Dynamics.b2World
, b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
, b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
, b2ContactFilter = Box2D.Dynamics.b2ContactFilter
, b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef
, b2DebugDraw = Box2D.Dynamics.b2DebugDraw
, b2Fixture = Box2D.Dynamics.b2Fixture
, b2AABB = Box2D.Collision.b2AABB
, b2WorldManifold = Box2D.Collision.b2WorldManifold
, b2ManifoldPoint = Box2D.Collision.b2ManifoldPoint
, b2RayCastInput = Box2D.Collision.b2RayCastInput
, b2RayCastOutput = Box2D.Collision.b2RayCastOutput
, b2Color = Box2D.Common.b2Color;
var world = new b2World(new b2Vec2(0,10), true);
var canvas = $('#canvas');
var context = canvas.get(0).getContext('2d');
//box
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(9,7);
bodyDef.userData = 'box';
var fixDef = new b2FixtureDef;
fixDef.filter.categoryBits = 1;
fixDef.density = 10.0;
fixDef.friction = 0.5;
fixDef.restitution = .5;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(1,5);
var box1 = world.CreateBody(bodyDef);
box1.CreateFixture(fixDef);
//circle
var bodyDef2 = new b2BodyDef;
bodyDef2.type = b2Body.b2_dynamicBody;
bodyDef2.position.Set(4,8);
bodyDef2.userData = 'obj';
var fixDef2 = new b2FixtureDef;
fixDef2.filter.categoryBits = 2;
fixDef2.filter.maskBits = 13;
fixDef2.density = 10.0;
fixDef2.friction = 0.5;
fixDef2.restitution = .2;
fixDef2.shape = new b2CircleShape(1);
//circlesensor
var cc = new b2FixtureDef;
cc.shape = new b2CircleShape(2);
cc.shape.SetLocalPosition(new b2Vec2(0 ,0));
cc.density = 0;
cc.isSensor = true;
cc.filter.categoryBits = 8;
var wheel = world.CreateBody(bodyDef2);
wheel.CreateFixture(fixDef2);
wheel.CreateFixture(cc);
//create a ground
var holderDef = new b2BodyDef;
holderDef.type = b2Body.b2_staticBody;
holderDef.userData = "ground";
holderDef.position.Set(10, 14);
var fd = new b2FixtureDef;
fd.filter.categoryBits = 4;
fd.shape = new b2PolygonShape;
fd.shape.SetAsBox(10,1);
var ground = world.CreateBody(holderDef);
ground.CreateFixture(fd);
//create another static body
var holderDef = new b2BodyDef;
holderDef.type = b2Body.b2_staticBody;
holderDef.position.Set(10, 20);
var temp = world.CreateBody(holderDef);
temp.CreateFixture(fd);
var c=0;
$(window).keydown(function(e) {
$('#aa').html(++c);
code = e.keyCode;
if(c==1) {
if(code == 38 && onground)
wheel.SetLinearVelocity(new b2Vec2(0,-10));
if(code == 39)
wheel.ApplyForce(new b2Vec2(1000,0), box1.GetWorldPoint(new b2Vec2(0,0)));
if(code == 37)
wheel.ApplyForce(new b2Vec2(-1000,0), box1.GetWorldPoint(new b2Vec2(0,0)));
}
});
$(window).keyup(function(e) {
c=0;
});
var listener = new Box2D.Dynamics.b2ContactListener;
listener.BeginContact = function(contact) {
if(contact.GetFixtureA().GetBody().GetUserData()== 'obj' || contact.GetFixtureB().GetBody().GetUserData()== 'obj' ) // think about why we don't use fixture's userData directly.
onground = true;// don't put 'var' here!
fxA=contact.GetFixtureA();
fxB=contact.GetFixtureB();
sA=fxA.IsSensor();
sB=fxB.IsSensor();
if((sA && !sB) || (sB && !sA)) {
if(sA) {
$('#cc').prepend(contact.GetFixtureB().GetBody().GetUserData() + ' is in the viscinity of body '+contact.GetFixtureA().GetBody().GetUserData()+'<br>');
}
else {
$('#cc').prepend(contact.GetFixtureA().GetBody().GetUserData() + ' is in the viscinity of body '+contact.GetFixtureB().GetBody().GetUserData()+'<br>');
}
}
}
listener.EndContact = function(contact) {
if (contact.GetFixtureA().GetBody().GetUserData()== 'obj' || contact.GetFixtureB().GetBody().GetUserData()== 'obj' )
onground = false;
}
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite ( document.getElementById ("canvas").getContext ("2d"));
debugDraw.SetDrawScale(30); //define scale
debugDraw.SetAlpha(1);
debugDraw.SetFillAlpha(.3); //define transparency
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
window.setInterval(update,1000/60);
//mouse
var mouseX, mouseY, mousePVec, isMouseDown, selectedBody, mouseJoint;
var canvasPosition = getElementPosition(document.getElementById("canvas"));
document.addEventListener("mousedown", function(e) {
isMouseDown = true;
handleMouseMove(e);
document.addEventListener("mousemove", handleMouseMove, true);
}, true);
document.addEventListener("mouseup", function() {
document.removeEventListener("mousemove", handleMouseMove, true);
isMouseDown = false;
mouseX = undefined;
mouseY = undefined;
}, true);
function handleMouseMove(e) {
mouseX = (e.clientX - canvasPosition.x) / 30;
mouseY = (e.clientY - canvasPosition.y) / 30;
};
function getBodyAtMouse() {
mousePVec = new b2Vec2(mouseX, mouseY);
var aabb = new b2AABB();
aabb.lowerBound.Set(mouseX - 0.001, mouseY - 0.001);
aabb.upperBound.Set(mouseX + 0.001, mouseY + 0.001);
// Query the world for overlapping shapes.
selectedBody = null;
world.QueryAABB(getBodyCB, aabb);
return selectedBody;
}
function getBodyCB(fixture) {
if(fixture.GetBody().GetType() != b2Body.b2_staticBody) {
if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(), mousePVec)) {
selectedBody = fixture.GetBody();
return false;
}
}
return true;
}
//at global scope
var currentRayAngle = 0;
var input = new b2RayCastInput();
var output = new b2RayCastOutput();
var b = new b2BodyDef();
var f = new b2FixtureDef();
var closestFraction = 1;
var intersectionNormal = new b2Vec2(0,0);
var intersectionPoint = new b2Vec2();
rayLength = 25; //long enough to hit the walls
var p1 = new b2Vec2( 11, 7 ); //center of scene
var p2 = new b2Vec2();
var normalEnd = new b2Vec2();
function update() {
if(isMouseDown && (!mouseJoint)) {
var body = getBodyAtMouse();
if(body) {
var md = new b2MouseJointDef();
md.bodyA = world.GetGroundBody();
md.bodyB = body;
md.target.Set(mouseX, mouseY);
md.collideConnected = true;
md.maxForce = 300.0 * body.GetMass();
mouseJoint = world.CreateJoint(md);
body.SetAwake(true);
}
}
if(mouseJoint) {
if(isMouseDown) {
mouseJoint.SetTarget(new b2Vec2(mouseX, mouseY));
} else {
world.DestroyJoint(mouseJoint);
mouseJoint = null;
}
}
world.Step(1 / 60, 10, 10);
world.DrawDebugData();
world.ClearForces();
world.SetContactListener(listener);
ray();
};
function ray() {
//in Step() function
var k = 360/20;
var t = k/60;
var DEGTORAD = Math.PI/180;
currentRayAngle += t * DEGTORAD; //one revolution every 20 seconds
//console.log(currentRayAngle*(180/Math.PI));
//calculate points of ray
p2.x = p1.x + rayLength * Math.sin(currentRayAngle);
p2.y = p1.y + rayLength * Math.cos(currentRayAngle);
input.p1 = p1;
input.p2 = p2;
input.maxFraction = 1;
closestFraction = 1;
var b = new b2BodyDef();
var f = new b2FixtureDef();
for(b = world.GetBodyList(); b; b = b.GetNext()) {
for(f = b.GetFixtureList(); f; f = f.GetNext()) {
if(!f.RayCast(output, input))
continue;
else if(output.fraction < closestFraction) {
closestFraction = output.fraction;
intersectionNormal = output.normal;
}
}
}
intersectionPoint.x = p1.x + closestFraction * (p2.x - p1.x);
intersectionPoint.y = p1.y + closestFraction * (p2.y - p1.y);
normalEnd.x = intersectionPoint.x + intersectionNormal.x;
normalEnd.y = intersectionPoint.y + intersectionNormal.y;
context.strokeStyle = "rgb(255, 255, 255)";
context.beginPath(); // Start the path
context.moveTo(p1.x*30,p1.y*30); // Set the path origin
context.lineTo(intersectionPoint.x*30, intersectionPoint.y*30); // Set the path destination
context.closePath(); // Close the path
context.stroke();
context.beginPath(); // Start the path
context.moveTo(intersectionPoint.x*30, intersectionPoint.y*30); // Set the path origin
context.lineTo(normalEnd.x*30, normalEnd.y*30); // Set the path destination
context.closePath(); // Close the path
context.stroke(); // Outline the path
}
//helpers
//http://js-tut.aardon.de/js-tut/tutorial/position.html
function getElementPosition(element) {
var elem=element, tagname="", x=0, y=0;
while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) {
y += elem.offsetTop;
x += elem.offsetLeft;
tagname = elem.tagName.toUpperCase();
if(tagname == "BODY")
elem=0;
if(typeof(elem) == "object") {
if(typeof(elem.offsetParent) == "object")
elem = elem.offsetParent;
}
}
return {x: x, y: y};
}
</script>
</html>
Here's a Raycast in Box2dWeb that I got working:
var p1 = new b2Vec2(body.GetPosition().x, body.GetPosition().y); //center of scene
var p2 = new b2Vec2(body.GetPosition().x, body.GetPosition().y + 5); //center of scene
world.RayCast(function(x){
console.log("You've got something under you");
}, p1,p2);