Little premise: I didn't want to make this question, because I thought it was a too personal and generic problem; but after 2 days without any improvement, I couldn't resist anymore.
So basically, my project is an aquarium with multiple fishes inside.
It all works fine, the only problem is that, in short words: the first fish image remains inside the div(it even stops too soon), the second one arrives a bit farther, the third even farther, and so on.
The opposite thing happens with the top margin: going forward, the last fish is always farther from the margin, and I can't find out the reason.
My scope is to keep all the fishes inside the "acquario" div (which has the black borders).
P.S. With sx and dx margins, they have no problem.
var BORDER_LEFT_RIGHT = 7;
var BORDER_TOP_DOWN = 28;
var fishes = new Array();
var nextId = 0;
var heightMax;
var widthMax;
var n; //initial direction, see createFish()
init();
/* light blue fish (dory, to clarify)*/
createFish("https://s18.postimg.org/n8sqmtjkp/pesce1_sx.png", "https://s30.postimg.org/6w8xyqwep/pesce1_dx.png");
/* white and yellow fish */
createFish("https://s28.postimg.org/6aalv0pst/pesce2_sx.png", "https://s29.postimg.org/dxbi0vypz/pesce2_dx.png");
/* dark blue fish */
createFish("https://s24.postimg.org/sbgt8zn6t/pesce3_sx.png", "https://s29.postimg.org/v65opob7r/pesce3_dx.png");
/* white-blue-yellow fish */
createFish("https://s30.postimg.org/62lb9bfwx/pesce4_sx.png", "https://s28.postimg.org/kt5m4ea65/pesce4_dx.png");
/* orange fish */
createFish("https://s18.postimg.org/q5sq0saex/pesce5_sx.png", "https://s18.postimg.org/uqnwe2vex/pesce5_dx.png");
showFishes();
function init() {
heightMax = document.getElementById("acquario").clientHeight - BORDER_TOP_DOWN;
widthMax = document.getElementById("acquario").clientWidth - BORDER_LEFT_RIGHT;
n = 1;
}
function createFish(src1, src2) {
imgFishSX = new Image();
imgFishDX = new Image();
imgFishSX.src = src1;
imgFishDX.src = src2;
n *= -1;
var fish = {
id: nextId,
/* default x position: random number between 1 and widthMax */
x: Math.floor((Math.random() * widthMax - imgFishSX.width) + 1),
/* default y position: random number between 1 and heightMax */
y: Math.floor((Math.random() * heightMax - imgFishSX.height) + 1),
xIncrease: n * getIncrease(),
yIncrease: n * getIncrease(),
imageSX: imgFishSX,
imageDX: imgFishDX
};
addFishToArray((fish));
nextId++;
}
function addFishToArray(fish) {
fishes.push(fish);
}
function showFishes() {
var node = document.getElementById("acquario");
var stringToInner = "";
var src;
/* first, we make the string with all the img filled in */
for (var i = 0; i < fishes.length; i++) {
/* we have to check if the default increase direction was <-- or --> */
fishes[i].xIncrease > 0 ? src = fishes[i].imageSX.src : src = fishes[i].imageDX.src;
/* z-index --> overlap priority */
stringToInner += "<img src =\"" + src +
"\" id=\"" + fishes[i].id + "\" style= \"margin-left: " +
fishes[i].x + "px;margin-top: " + fishes[i].y + "px;z-index: " +
fishes[i].id + ";position: absolute;\">";
stringToInner += "<br>";
}
/* then, we insert it */
node.innerHTML = stringToInner;
/* let's raise hell! */
moveFishes();
}
function getIncrease() {
return Math.floor((Math.random() * 5) + 1);
}
function moveFishes() {
/* scroll the array: we need to check each fish one by one */
for (var i = 0; i < fishes.length; i++) {
moveFish(fishes[i]);
}
/* infinite loop */
setTimeout(function() {
moveFishes()
}, 50);
}
function moveFish(fish) {
/* with this node, I'll apply changes to my html document */
node = document.getElementById(fish.id);
/* we are inside, just move */
if (fish.x > 0 && fish.x < widthMax - node.width && fish.y > 0 && fish.y < heightMax - node.height) {
node.style.marginLeft = fish.x + "px";
node.style.marginTop = fish.y + "px";
fish.x += fish.xIncrease;
fish.y += fish.yIncrease;
/* too --> , we need to get <-- */
} else if (fish.x >= widthMax - node.width) {
node.src = fish.imageDX.src;
fish.xIncrease = -getIncrease();
fish.x += fish.xIncrease;
/* too <-- , we need to get --> */
} else if (fish.x <= 0) {
node.src = fish.imageSX.src;
fish.xIncrease = 5;
fish.x += getIncrease();
/* too up, we need to get down */
} else if (fish.y >= heightMax - node.height) {
fish.yIncrease = -getIncrease();
fish.y += fish.yIncrease;
/* too down, we need to get up */
} else if (fish.y <= 0) {
fish.yIncrease = getIncrease();
fish.y += fish.yIncrease;
}
}
* {
box-sizing: border-box;
}
.row::after {
content: "";
clear: both;
display: block;
}
html {
background: url("https://s24.postimg.org/rakxoa7sl/sfondo.jpg") no-repeat center center fixed;
-webkibact-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
html,
body {
height: 100%;
margin: 0;
}
#main {
margin: 0;
height: 100%;
}
#acquario {
border-bottom: 28px solid black;
border-top: 28px solid black;
border-right: 7px solid black;
border-left: 7px solid black;
height: 100%;
}
<body>
<div id="main">
<div id="acquario">
</div>
</div>
</body>
do you want the fishes to bound off the walls or to hide under the wall? and why do you use margin-left and margin-top instead of top and left properties? it makes the aquarium scrolling. Is it ok now?
var BORDER_LEFT_RIGHT = 7;
var BORDER_TOP_DOWN = 28;
var fishes = new Array();
var nextId = 0;
var heightMax;
var widthMax;
var n; //initial direction, see createFish()
init();
/* light blue fish (dory, to clarify)*/
createFish("https://s18.postimg.org/n8sqmtjkp/pesce1_sx.png", "https://s30.postimg.org/6w8xyqwep/pesce1_dx.png");
/* white and yellow fish */
createFish("https://s28.postimg.org/6aalv0pst/pesce2_sx.png", "https://s29.postimg.org/dxbi0vypz/pesce2_dx.png");
/* dark blue fish */
createFish("https://s24.postimg.org/sbgt8zn6t/pesce3_sx.png", "https://s29.postimg.org/v65opob7r/pesce3_dx.png");
/* white-blue-yellow fish */
createFish("https://s30.postimg.org/62lb9bfwx/pesce4_sx.png", "https://s28.postimg.org/kt5m4ea65/pesce4_dx.png");
/* orange fish */
createFish("https://s18.postimg.org/q5sq0saex/pesce5_sx.png", "https://s18.postimg.org/uqnwe2vex/pesce5_dx.png");
showFishes();
function init() {
heightMax = document.getElementById("acquario").clientHeight + BORDER_TOP_DOWN;
widthMax = document.getElementById("acquario").clientWidth + BORDER_LEFT_RIGHT;
n = 1;
}
function createFish(src1, src2) {
imgFishSX = new Image();
imgFishDX = new Image();
imgFishSX.src = src1;
imgFishDX.src = src2;
n *= -1;
var fish = {
id: nextId,
/* default x position: random number between 1 and widthMax */
x: Math.floor((Math.random() * (widthMax - BORDER_LEFT_RIGHT - imgFishSX.width)) + BORDER_LEFT_RIGHT),
/* default y position: random number between 1 and heightMax */
y: Math.floor((Math.random() * (heightMax - BORDER_TOP_DOWN - imgFishSX.height)) + BORDER_TOP_DOWN),
xIncrease: n * getIncrease(),
yIncrease: n * getIncrease(),
imageSX: imgFishSX,
imageDX: imgFishDX
};
addFishToArray((fish));
nextId++;
}
function addFishToArray(fish) {
fishes.push(fish);
}
function showFishes() {
var node = document.getElementById("acquario");
var stringToInner = "";
var src;
/* first, we make the string with all the img filled in */
for (var i = 0; i < fishes.length; i++) {
/* we have to check if the default increase direction was <-- or --> */
fishes[i].xIncrease > 0 ? src = fishes[i].imageSX.src : src = fishes[i].imageDX.src;
/* z-index --> overlap priority */
stringToInner += "<img src =\"" + src +
"\" id=\"" + fishes[i].id + "\" style= \"left: " +
fishes[i].x + "px;top: " + fishes[i].y + "px;z-index: " +
fishes[i].id + ";position: absolute;\">";
stringToInner += "<br>";
}
/* then, we insert it */
node.innerHTML = stringToInner;
/* let's raise hell! */
moveFishes();
}
function getIncrease() {
return Math.floor((Math.random() * 5) + 1);
}
function moveFishes() {
/* scroll the array: we need to check each fish one by one */
for (var i = 0; i < fishes.length; i++) {
moveFish(fishes[i]);
}
/* infinite loop */
setTimeout(function() {
moveFishes()
}, 50);
}
function moveFish(fish) {
/* with this node, I'll apply changes to my html document */
node = document.getElementById(fish.id);
/* we are inside, just move */
if (fish.x > BORDER_LEFT_RIGHT && fish.x < widthMax - node.width && fish.y > BORDER_TOP_DOWN && fish.y < heightMax - node.height) {
node.style.left = fish.x + "px";
node.style.top = fish.y + "px";
fish.x += fish.xIncrease;
fish.y += fish.yIncrease;
/* too --> , we need to get <-- */
} else if (fish.x >= widthMax - node.width) {
node.src = fish.imageDX.src;
fish.xIncrease = -getIncrease();
fish.x += fish.xIncrease;
/* too <-- , we need to get --> */
} else if (fish.x <= BORDER_LEFT_RIGHT) {
node.src = fish.imageSX.src;
fish.xIncrease = 5;
fish.x += getIncrease();
/* too up, we need to get down */
} else if (fish.y >= heightMax - node.height) {
fish.yIncrease = -getIncrease();
fish.y += fish.yIncrease;
/* too down, we need to get up */
} else if (fish.y <= BORDER_TOP_DOWN) {
fish.yIncrease = getIncrease();
fish.y += fish.yIncrease;
}
}
* {
box-sizing: border-box;
}
.row::after {
content: "";
clear: both;
display: block;
}
html {
background: url("https://s24.postimg.org/rakxoa7sl/sfondo.jpg") no-repeat center center fixed;
-webkibact-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
html,
body {
height: 100%;
margin: 0;
}
#main {
margin: 0;
height: 100%;
}
#acquario {
border-bottom: 28px solid black;
border-top: 28px solid black;
border-right: 7px solid black;
border-left: 7px solid black;
height: 100%;
}
<body>
<div id="main">
<div id="acquario">
</div>
</div>
</body>
I know Pawel has fixed your issue, but I did state I would provide a canvas version so here it is
jsFiddle : https://jsfiddle.net/CanvasCode/zh0b7zrj/1/
HTML :
<canvas id="myCanvas"></canvas>
CSS :
html,
body {
width: 100%;
height: 100%;
margin: 0px;
overflow: hidden;
}
Javascript :
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var backgroundImage = new Image();
canvas.width = document.body.clientWidth; //document.width is obsolete
canvas.height = document.body.clientHeight; //document.height is obsolete
// Fish
function FishObject(xSet, ySet, xSpeed, ySpeed, spriteUrlRight, spriteUrlLeft) {
this.XPos = xSet;
this.YPos = ySet;
this.XDefaultSpeed = xSpeed;
this.YDefaultSpeed = ySpeed;
this.xSpeed = this.XDefaultSpeed;
this.ySpeed = this.YDefaultSpeed;
this.RightSprite = new Image();
this.RightSprite.src = spriteUrlRight;
this.LeftSprite = new Image();
this.LeftSprite.src = spriteUrlLeft;
}
FishObject.prototype.Draw = function(ctx) {
if (this.xSpeed > 0) {
ctx.drawImage(this.RightSprite, this.XPos, this.YPos);
} else {
ctx.drawImage(this.LeftSprite, this.XPos, this.YPos);
}
}
FishObject.prototype.Update = function(ctx) {
this.XPos += this.xSpeed;
this.YPos += this.ySpeed;
if (this.XPos <= 0) {
this.xSpeed = this.XDefaultSpeed;
} else if ((this.XPos + this.RightSprite.width) >= canvas.width) {
this.xSpeed = -this.XDefaultSpeed;
}
if (this.YPos <= 0) {
this.ySpeed = this.YDefaultSpeed;
} else if ((this.YPos + this.RightSprite.height) >= canvas.height) {
this.ySpeed = -this.YDefaultSpeed;
}
}
backgroundImage.src = 'https://s24.postimg.org/rakxoa7sl/sfondo.jpg';
var Fishs = [];
Fishs.push(new FishObject(0, 0, 1, 1, "https://s18.postimg.org/n8sqmtjkp/pesce1_sx.png",
"https://s30.postimg.org/6w8xyqwep/pesce1_dx.png"));
Fishs.push(new FishObject(0, 0, 2, 1.2, "https://s28.postimg.org/6aalv0pst/pesce2_sx.png",
"https://s29.postimg.org/dxbi0vypz/pesce2_dx.png"));
Fishs.push(new FishObject(0, 0, 1.7, 2.8, "https://s24.postimg.org/sbgt8zn6t/pesce3_sx.png",
"https://s29.postimg.org/v65opob7r/pesce3_dx.png"));
Fishs.push(new FishObject(0, 0, 0.2, 0.5, "https://s30.postimg.org/62lb9bfwx/pesce4_sx.png",
"https://s28.postimg.org/kt5m4ea65/pesce4_dx.png"));
Fishs.push(new FishObject(0, 0, 0.7, 0.1, "https://s18.postimg.org/q5sq0saex/pesce5_sx.png",
"https://s18.postimg.org/uqnwe2vex/pesce5_dx.png"));
setInterval(function() {
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(backgroundImage, 0, 0);
for (var i = 0; i < Fishs.length; i++) {
var fishObject = Fishs[i];
fishObject.Draw(ctx);
fishObject.Update(ctx);
}
}, (1000 / 60)); // 60 FPS (frames per second)
Related
There is an animation of the flight of leaves in pure js. The problem is that it needs to be optimized for maximum performance, because there will be more animations of this kind on the page. Besides optimizing the original SVG image and reducing the number of leaflets, what tips can you give to improve the performance of your code?
var LeafScene = function(el) {
this.viewport = el;
this.world = document.createElement('div');
this.leaves = [];
this.options = {
numLeaves: 6,
wind: {
magnitude: 0,
maxSpeed: 12,
duration: 300,
start: 0,
speed: 10
},
};
this.width = this.viewport.offsetWidth;
this.height = this.viewport.offsetHeight;
this.timer = 0;
this._resetLeaf = function(leaf) {
leaf.x = this.width * 2 - Math.random()*this.width*1.75;
leaf.y = -10;
leaf.z = Math.random()*200;
if (leaf.x > this.width) {
leaf.x = this.width + 10;
leaf.y = Math.random()*this.height/2;
}
if (this.timer == 0) {
leaf.y = Math.random()*this.height;
}
leaf.rotation.speed = Math.random()*10;
var randomAxis = Math.random();
if (randomAxis > 0.5) {
leaf.rotation.axis = 'X';
} else if (randomAxis > 0.25) {
leaf.rotation.axis = 'Y';
leaf.rotation.x = Math.random()*180 + 90;
} else {
leaf.rotation.axis = 'Z';
leaf.rotation.x = Math.random()*360 - 180;
leaf.rotation.speed = Math.random()*3;
}
leaf.xSpeedVariation = Math.random() * 0.8 - 0.4;
leaf.ySpeed = Math.random() + 1.5;
return leaf;
}
this._updateLeaf = function(leaf) {
var leafWindSpeed = this.options.wind.speed(this.timer - this.options.wind.start, leaf.y);
var xSpeed = leafWindSpeed + leaf.xSpeedVariation;
leaf.x -= xSpeed;
leaf.y += leaf.ySpeed;
leaf.rotation.value += leaf.rotation.speed;
var t = 'translateX( ' + leaf.x + 'px ) translateY( ' + leaf.y + 'px ) translateZ( ' + leaf.z + 'px ) rotate' + leaf.rotation.axis + '( ' + leaf.rotation.value + 'deg )';
if (leaf.rotation.axis !== 'X') {
t += ' rotateX(' + leaf.rotation.x + 'deg)';
}
leaf.el.style.webkitTransform = t;
leaf.el.style.MozTransform = t;
leaf.el.style.oTransform = t;
leaf.el.style.transform = t;
if (leaf.x < -10 || leaf.y > this.height + 10) {
this._resetLeaf(leaf);
}
}
this._updateWind = function() {
if (this.timer === 0 || this.timer > (this.options.wind.start + this.options.wind.duration)) {
this.options.wind.magnitude = Math.random() * this.options.wind.maxSpeed;
this.options.wind.duration = this.options.wind.magnitude * 50 + (Math.random() * 20 - 10);
this.options.wind.start = this.timer;
var screenHeight = this.height;
this.options.wind.speed = function(t, y) {
var a = this.magnitude/2 * (screenHeight - 2*y/3)/screenHeight;
return a * Math.sin(2*Math.PI/this.duration * t + (3 * Math.PI/2)) + a;
}
}
}
}
LeafScene.prototype.init = function() {
for (var i = 0; i < this.options.numLeaves; i++) {
var leaf = {
el: document.createElement('div'),
x: 0,
y: 0,
z: 0,
rotation: {
axis: 'X',
value: 0,
speed: 0,
x: 0
},
xSpeedVariation: 0,
ySpeed: 0,
path: {
type: 1,
start: 0,
},
image: 1
};
this._resetLeaf(leaf);
this.leaves.push(leaf);
this.world.appendChild(leaf.el);
}
this.world.className = 'leaf-scene';
this.viewport.appendChild(this.world);
this.world.style.webkitPerspective = "400px";
this.world.style.MozPerspective = "400px";
this.world.style.oPerspective = "400px";
this.world.style.perspective = "400px";
var self = this;
window.onresize = function(event) {
self.width = self.viewport.offsetWidth;
self.height = self.viewport.offsetHeight;
};
}
LeafScene.prototype.render = function() {
this._updateWind();
for (var i = 0; i < this.leaves.length; i++) {
this._updateLeaf(this.leaves[i]);
}
this.timer++;
requestAnimationFrame(this.render.bind(this));
}
var leafContainer = document.querySelector('.falling-leaves'),
leaves = new LeafScene(leafContainer);
leaves.init();
leaves.render();
body, html {
height: 100%;
}
.falling-leaves {
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 100%;
max-width: 880px;
max-height: 880px;
transform: translate(-50%, 0);
border: 20px solid #fff;
border-radius: 50px;
background-size: cover;
overflow: hidden;
}
.leaf-scene {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
transform-style: preserve-3d;
}
.leaf-scene div {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background: url(https://www.flaticon.com/svg/static/icons/svg/892/892881.svg) no-repeat;
background-size: 100%;
transform-style: preserve-3d;
-webkit-backface-visibility: visible;
backface-visibility: visible;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<div class="falling-leaves"></div>
Unless you're using HTML Canvas, vanilla JS solutions are pretty heavy compared to CSS/JS hybrid because of the browser call stack.
It looks like this:
JS > Style > Layout > Paint > Composite
By minimizing the amount of calculations the browser has to do in JS and grouping reads/writes to the DOM you'll see a significant performance increase. The workload can be recorded with Chrome Dev tools under 'Performance' tab. And you'll be able to see every step the browser is taking to display the content. The less steps, the better performance .. simple as that.
You're writing to the DOM every single transform which is heavy even with 3d acceleration.
I usually make use of CSS variables and transitions for dynamic animation that I update in steps.
What you did is great otherwise. Try rendering on a HTML Canvas and your performance problems will vanish. Here's a start:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
But if you want or cant do canvas adapt to utilize CSS to not drop further than the Paint browser call for majority of frames.
why my checkCollision function is not working in foreach loop ? I want to check whether obs (obstacle) is hits/overlaps on collector (gray object). I am checking every 1 millisecond using setInterval checkCollision function. Basically I am trying to build a simple car game. please help me and thank you in advance
let body = document.body[0];
let container = document.querySelector(".container");
let allObstacles = [];
let colors = ["green", "green", "red"];
let collector = document.getElementById("collector");
class Obstacle {
constructor(yPos) {
this.yPos = -50;
}
randomnum() {
let randX = Math.floor(Math.random() * (container.clientWidth - 50));
return randX;
}
createObstacle() {
let obstacle = document.createElement("div");
obstacle.classList.add("obstacle");
let bgColor = colors[Math.floor(Math.random() * colors.length)];
obstacle.style.width = "50px";
obstacle.style.height = "50px";
obstacle.style.position = "absolute";
obstacle.style.left = this.randomnum() + "px";
obstacle.style.top = this.yPos + "px";
obstacle.style.backgroundColor = bgColor;
obstacle.dataset.behave = bgColor;
container.appendChild(obstacle);
return obstacle;
}
element = this.createObstacle();
updatePosition() {
this.yPos += 2;
this.element.style.top = this.yPos + "px";
}
kill() {
this.element.remove();
}
}
let dropObs = setInterval(function() {
allObstacles.forEach(function(obs) {
obs.updatePosition();
});
allObstacles.forEach(function(obs) {
// why checkCollision function is not working?
if (checkCollision(obs, collector)) {
console.log("hit");
}
if (obs.yPos > container.clientHeight) {
obs.kill();
}
});
}, 10);
let generateObs = setInterval(function() {
let obs = new Obstacle();
allObstacles.push(obs);
}, 2000);
function checkCollision(obj1, obj2) {
var obj1Y = obj1.offsetTop;
var obj2Y = obj2.offsetTop;
var obj1X = obj1.offsetLeft;
var obj2X = obj2.offsetLeft;
if (
obj2Y + 100 >= obj1Y &&
obj2Y <= obj1Y + 100 &&
obj2X + 100 >= obj1X &&
obj2X <= obj1X + 100
) {
return 1;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.container {
position: relative;
width: 100%;
height: 100%;
}
#collector {
width: 50px;
height: 100px;
background: gray;
position: absolute;
top: calc(100vh - 100px);
left: 50%;
margin-left: -25px;
}
<div class="container">
<div id="collector"></div>
</div>
The first thing you should not use setInterval for this type of animation. Use requestAnimationFrame
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
obj1X,obj1Y comming undefined.
I wanna do some effect to my background so i tought i can add some shapes flying around but i do only 1 shape i cant loop or anything
i tried call function more than a one time but it doesnt help
function animasyon(a) {
window.onload=function(){
var id = setInterval(anim,5);
$('body').append('<div class=shape></div>');
$('body').append('<div class=shape></div>');
var kutu = document.getElementsByClassName("shape");
var pos = 0;
var x = window.innerWidth;
var y = window.innerHeight;
var borderSize = Math.floor(Math.random() * 3 ) + 1;
var ySize = Math.floor(Math.random() * y ) + 1;
var Size = Math.floor(Math.random() * 30 ) + 5;
var yon = Math.floor(Math.random() *2)+1;
var dolu = Math.floor(Math.random() *2)+1;
if (ySize > 50) { ySize-=20; }
function anim(){
if (pos == x) {
clearInterval(id);
document.getElementById("shape").remove();
}else{
pos++;
kutu[a].style.position = "absolute";
kutu[a].style.border = "solid rgb(119,38,53) "+borderSize+"px";
kutu[a].style.left = pos+"px";
kutu[a].style.width = Size+"px";
kutu[a].style.height = Size+"px";
if (yon == 1) { ySize-=0.2; } else { ySize+=0.2; }
if (dolu==1) {kutu[a].style.background = "rgb(119,38,53)";}
if (kutu[a].offsetTop < 0 || kutu[a].offsetTop > y-30) {document.getElementById("shape").remove();}
kutu[a].style.top = ySize+"px";
}
}
}
}
animasyon(0);
Try Calling 'anim' function in this way
setInterval(function(){anim()},5);
Your problem is that you are assigning window.onload function a value inside the function animasyon
window.onload holds only 1 function. If you call animation function more than once, then the last one will overwrite the first one.
Edit: You need to separate your animation logic from the page load logic. They are completely separate things.
Here is an example of adding multiple objects and animating each separately.
// HTML
<div id="container">
<div id="ball"></div>
<div id="ball2"></div>
<div id="ball3"></div>
<div id="ball4"></div>
</div>
// CSS
#ball, #ball2, #ball3, #ball4 {
background: red;
border: 1px solid #FAFDFA;
display: inline-block;
width: 1em;
height: 1em;
border-radius: 2em;
position: absolute;
}
#ball2 {
background: blue;
}
#ball3 {
background: green;
}
#ball4 {
background: purple;
}
#container {
width: 512px;
height: 512px;
background: black;
position: relative;
}
// JS
const container = document.getElementById('container');
const stageWidth = 512;
const stageHeight = 512;
const makeFall = (elementId) => {
// this function makes an enlement fall in random direction
const animationSpeed = 4;
// your onload function
const ball = document.getElementById(elementId);
let directionX = (Math.random() * animationSpeed * 2) - animationSpeed;
let directionY = Math.random() * animationSpeed;
const setRandomStart = () => {
ball.style.top = '10px';
ball.style.left = (Math.random() * (stageWidth / 2)) + 'px';
directionX = (Math.random() * animationSpeed * 2) - animationSpeed;
directionY = Math.random() * animationSpeed;
}
setRandomStart();
let animationInterval = setInterval(() => {
let px = parseFloat(ball.style.left);
let py = parseFloat(ball.style.top);
px += directionX;
py += directionY;
if (px > stageWidth - 20 || py > stageHeight - 20 || px < -20) {
setRandomStart();
} else {
ball.style.left = px + 'px';
ball.style.top = py + 'px';
}
}, 48);
}
// In Your onload function you can add the elements and then animate
makeFall('ball');
makeFall('ball2');
makeFall('ball3');
makeFall('ball4');
https://jsfiddle.net/753oL8re/4/
I got some simple bomberman game from code pen.For my study,i need to limit how many tiles and target.For tiles max 32 and target 7 (tiles grey & target red).
Here the source : codepen.io/Digiben/pen/oGYGrx
I dont understand how the script create the target and tiles with random algoritm.
Thanks for anyone who look this thread.
window.onload = function(){
//Map Kelas
class Map {
constructor (nbX, nbY, tileSize){
this.nbX = nbX;
this.nbY = nbY;
this.mapArray = new Array(this.nbX);
this.tileSize = tileSize;
this.map = document.getElementById('map');
}
init() {
console.log('Map size: ' + this.nbX * this.nbY);
let i = 0;
let j = 0;
let bool = null;
this.map.style.width = (this.tileSize * this.nbX) + 'px';
this.map.style.height = this.tileSize * this.nbY + 'px';
for (i = 0; i < this.nbX; i++) {
this.mapArray[i] = new Array(this.nbY);
for (j = 0; j < this.nbY; j++) {
bool = Math.random() >= 0.7 ? true : false;
if (bool) {
for (var z = Things.length - 1; i >= 0; i-) {
Things[i]
}
} else if (!bool) {
this.mapArray[i][j] = 1;
}
}
}
}
appendTile(i, j) {
let tile = document.createElement('div');
this.map.appendChild(tile);
tile.style.width = this.tileSize + 'px';
tile.style.height = this.tileSize + 'px';
tile.classList.add('tile');
tile.style.left = (i * this.tileSize) + 'px';
tile.style.top = (j * this.tileSize) + 'px';
}
getMapArray () {
return this.mapArray;
}
getMapSize () {
return {sizeX: this.nbX, sizeY:this.nbY}
}
}
//Create Target
class Target {
constructor (map, tileSize) {
this.mapArray = map.getMapArray();
this.playerSpace = map.getMapSize();
this.targetsArray = new Array();
this.possiblePositionToStartX = new Array();
this.possiblePositionToStartY = new Array();
this.tileSize = tileSize;
this.map = document.getElementById('map');
this.totalTargets = 0;
}
getTotalTargets(){
return this.totalTargets;
}
//Show Total Target
showTotalTargets () {
let totalDiv = document.querySelector('#score strong');
totalDiv.innerHTML = ' / ' + this.totalTargets;
}
showTargets(i, j) {
let tile = document.createElement('div');
this.map.appendChild(tile);
tile.classList.add('target');
tile.style.width = this.tileSize + 'px';
tile.style.height = this.tileSize + 'px';
// set attribute to identify the target when we need to remove it
tile.setAttribute('data-pos', i + ':' + j );
// positionning and styling
tile.style.left = (i * this.tileSize) + 'px';
tile.style.top = (j * this.tileSize) + 'px';
tile.style.backgroundColor = 'red';
tile.style.opacity = 0.5;
}
createTargets() {
//Target looping
for (var i = 1; i < this.playerSpace.sizeX-1; i++) {
//Maks Target 2D 10x10
this.targetsArray[i] = new Array();
if (i == 1) this.targetsArray[i-1] = new Array();
if (i == 8) this.targetsArray[i+1] = new Array();
for (var j = 1; j < this.playerSpace.sizeY-1; j++) {
this.targetsArray[i][j] = 1;
//Target aLgorithm
//Player dont Looping On red Zone
this.possiblePositionToStartX.push(i+1);
this.possiblePositionToStartY.push(j+1);
//Target Array if 0 to display Win on the End
this.targetsArray[i][j] = 0;
//Total Targets
this.totalTargets++;
//Show Target On map
this.showTargets(i, j);
}
}
}
//Show Total Targets
this.showTotalTargets();
}
// Start Player
getPossiblePosToStart() {
//Random Start PLayer
let xPos = this.possiblePositionToStartX[Math.floor(Math.random() * (this.possiblePositionToStartX.length))];
let yPos = this.possiblePositionToStartY[Math.floor(Math.random() * (this.possiblePositionToStartY.length))];
return {x: xPos, y: yPos}
}
//Player Array
getTargetsArray(){
return this.targetsArray;
}
}
//PLayer CLass
class Player {
constructor (mapArray, map, targets, tileSize) {
this.positionArray = mapArray;
this.position = {x: 0, y: 0}
this.playerDiv = document.getElementById('player');
this.playerDiv.style.left = 0;
this.playerDiv.style.top = 0;
this.playerDiv.style.right = 0;
this.playerDiv.style.bottom = 0;
this.playerDiv.style.width = tileSize + 'px';
this.playerDiv.style.height = tileSize + 'px';
this.playerSpace = map.getMapSize();
this.playerMap = map.getMapArray();
this.score = 0;
this.targetsArray = targets.getTargetsArray();
this.totalTargets = targets.getTotalTargets();
this.tileSize = tileSize;
}
//Record Posisition Player
recordPosition(mapArray){
this.positionArray = mapArray;
}
//Reset Score when Restart The game
static resetScore() {
let scoreSpan = document.querySelector('#score span'); scoreSpan.innerHTML = '0';
}
//Set Palyer
setPosition (position){
this.playerDiv.style.left = (position.x * this.tileSize) + 'px';
this.playerDiv.style.top = (position.y * this.tileSize) + 'px';
this.position.x = position.x;
this.position.y = position.y;
}
getPosition() {
return this.position;
}
//Limt Map
moveRight() {
if(this.position.x > this.playerSpace.sizeX-2) return false;
if(this.positionArray[this.position.x+1][this.position.y] != 0){
this.position.x++;
let nb = this.playerDiv.style.left.split('px');
this.playerDiv.style.left = (parseInt(nb[0]) + this.tileSize) + 'px';
console.log('Droite | X : ' + this.playerDiv.style.left);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
moveDown() {
if(this.position.y > this.playerSpace.sizeY-2) return false;
if(this.positionArray[this.position.x][this.position.y+1] != 0){
this.position.y++;
let nb = this.playerDiv.style.top.split('px');
this.playerDiv.style.top = (parseInt(nb[0]) + this.tileSize) + 'px';
console.log('Bas | Y : ' + this.playerDiv.style.top);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
moveLeft() {
if(this.position.x == 0) return false;
if(this.positionArray[this.position.x-1][this.position.y] != 0){
this.position.x--;
let nb = this.playerDiv.style.left.split('px');
this.playerDiv.style.left = (parseInt(nb[0]) - this.tileSize) + 'px';
console.log('Gauche | X : ' + this.playerDiv.style.left);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
moveUp() {
if(this.position.y <= 0) return false;
if(this.positionArray[this.position.x][this.position.y-1] != 0){
this.position.y--;
let nb = this.playerDiv.style.top.split('px');
this.playerDiv.style.top = (parseInt(nb[0]) - this.tileSize) + 'px';
console.log('Haut | Y : ' + this.playerDiv.style.top);
console.log(this.position.x + ' : ' + this.position.y);
} else {
console.log('Not OK');
}
}
//Update Score
updateScore () {
let scoreDiv = document.querySelector('#score span');
scoreDiv.innerHTML = this.score;
//Winner Message
if(this.score == this.totalTargets) document.querySelector ('#win').classList.add('show');
console.log('Score : ' + this.score);
}
//Update Target Array
updateTargetsArray (posx, posy){
this.targetsArray[posx][posy] = 1;
console.log('Array state : ');
console.log(this.targetsArray);
}
//Remove Target
removeTarget(posx, posy) {
let targetToRemove = document.querySelectorAll('.target');
let coords = posx + ':' + posy;
let attr = '';
//Loop To find Right Target accroding Coordinates Player
for (var i = 0; i< targetToRemove.length; i++) {
attr = targetToRemove[i].getAttribute('data-pos');
if(attr == coords) {
targetToRemove[i].remove();
//Update Score
this.score++;
this.updateScore();
}
}
//Remove Html node (Remove Array Target)
if(this.targetsArray[posx][posy] == 0){
this.targetsArray[posx][posy] == 1;
}
}
//Plant Bomb
plantBomb(){
//Make Child Bomb
let map = document.getElementById('map');
let bomb = document.createElement('div');
map.appendChild(bomb);
bomb.style.width = this.tileSize + 'px';
bomb.style.height = this.tileSize + 'px';
//Posision Bomb
bomb.classList.add('bomb');
bomb.style.left = (this.position.x * this.tileSize) + 'px';
bomb.style.top = (this.position.y * this.tileSize) + 'px';
//Variables
var posx = this.position.x;
var posy = this.position.y;
var that = this;
var timer = setInterval(bombTimer, 500, posx, posy, that);
var iter = 0;
//BombTimer
function bombTimer() {
switch (iter) {
case 1:
bomb.classList.add('waiting');
break;
case 2:
bomb.classList.add('before');
bomb.classList.remove('waiting');
break;
case 3:
bomb.classList.add('explode');
bomb.classList.remove('before');
break;
case 4:
clearInterval(timer);
bomb.remove();
that.updateTargetsArray(posx, posy);
that.removeTarget(posx, posy);
default:
break;
}
iter++;
}
}
}
//Game Class
class Game {
constructor (tileSize, mapX, mapY) {
//Create Map
var map = new Map(mapX,mapY, tileSize);
map.init();
//Create Target
var targets = new Target(map, tileSize);
targets.createTargets();
//Create PLayer
var player = new Player(map.getMapArray(), map, targets, tileSize);
//Place The player
player.setPosition(targets.getPossiblePosToStart());
//Keyboard Events
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {
player.moveUp();
}
else if (e.keyCode == '40') {
player.moveDown();
}
else if (e.keyCode == '37') {
player.moveLeft();
}
else if (e.keyCode == '39') {
player.moveRight();
}
else if (e.keyCode == '32') {
player.plantBomb();
}
}
}
//Destroy Game
static destroy () {
let targets = document.querySelectorAll('.target');
let tiles = document.querySelectorAll('.tile');
Player.resetScore();
if(tiles){
targets.forEach(function(element) {
element.remove();
});
tiles.forEach(function(element) {
element.remove();
});
}
}
}
class Session {
constructor () {
this.totalTargets = 0;
this.players = {};
this.restartBtn = document.querySelector('#restart');
this.restartBtn.addEventListener('click', function() {
Session.restart();
});
}
static restart () {
Game.destroy();
var game = new Game(25, 10, 10);
}
}
var session = new Session();
};
#map {
width: 500px;
height: 500px;
background: lightgrey;
position: relative;
margin: auto;
}
#game {
width: 500px;
height: 500px;
position: relative;
margin: auto;
}
#map .tile {
width: 50px;
height: 50px;
background: grey;
position: absolute;
outline: 1px solid #eee;
}
#map .target {
width: 50px;
height: 50px;
background: red;
position: absolute;
outline: 1px solid #eee;
}
#map #player {
border-radius: 25%;
width: 50px;
height: 50px;
position: absolute;
background: #222222;
z-index: 1;
transition: 0.1s;
}
.bomb {
border-radius: 100%;
width: 50px;
height: 50px;
position: absolute;
background: #333;
z-index: 1;
transition: 0.3s ease;
}
.bomb.waiting {
animation: waiting 2s infinite;
}
.bomb.before {
animation: before 1s infinite;
}
.bomb.explode {
animation: explode 1s infinite;
}
#score p, #score span {
font-family: sans-serif;
color: #333;
font-size: 16px;
display: inline;
}
#keyframes waiting {
0% {
transform: scale(0.9);
}
100% {
transform: scale(1.1);
}
}
#keyframes before {
0% {
transform: scale(1.0);
background: orange;
}
100% {
transform: scale(1.2);
background: red;
}
}
#keyframes explode {
0% {
transform: scale(1.0);
background: red;
opacity: 1;
}
100% {
transform: scale(2);
background: yellow;
opacity: 0;
}
}
#keyframes win {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
66% {
opacity: 1;
}
100% {
opacity: 0;
}
}
h4 {
font-family: sans-serif;
color: #333;
text-align: center;
}
p, strong {
font-family: sans-serif;
color: #333;
text-align: left;
font-size: 12px;
}
#win {
position: fixed;
left: 0;
right: 0;
top:0;
bottom: 0;
z-index: 9999999;
background: rgba(181, 181, 195, 0.1);
pointer-events: none;
opacity: 0;
}
#win p {
color: red;
font-size: 130px;
text-align: center;
font-family: sans-serif;
text-transform: uppercase;
height: 100%;
margin: 0;
top: 50%;
position: absolute;
left: 50%;
transform: translate(-50%, -25%);
right: 0;
bottom: 0;
font-weight: bold;
text-shadow: 5px 5px #333;
}
#win.show {
animation: win 4s ease;
}
#restart {
text-align: center;
padding: 10px 20px;
font-family: sans-serif;
color: #333;
outline: #ccc 1px solid;
display: table;
margin: auto;
margin-top: 20px;
cursor: pointer;
transition: 0.1s ease;
}
#restart:hover {
background: #eee;
}
<!DOCTYPE html>
<html>
<head>
<title>Bomberman</title>
<link href="bomber.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="1.js"></script>
</head>
<body>
<h4>Space bar to plant a bomb / Arrows to move </h4>
<div id="win"><p>WIN !</p></div>
<div id="restart"> RESTART </div>
<div id="score"><p>Score: </p><span>0</span><strong> / 0</strong></div>
<section id="game">
<div id="map">
<div id="player"></div>
</div>
</section>
</body>
</html>
I'm not certain I understand your question, but I think you're trying to debug the createTargets method in the Targets class. The problem there is an extra closing bracket (}) right before the line with //Show Total Targets.
I have a square, when clicked it appears in a random location and it also change size (so for example if I have a 30px box but it is 10px from the left border I still get 10px outside the gamespace).
sometimes the square exceed his container border
How can I make sure that the square will never exceed his container?
function position() {
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
var position = "position:relative;top:" + positionTop + "%;left:" + positionLeft + "%;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin: 0;
padding-top: 30px;
}
#playSpace {
width: 90%;
height: 90%;
margin: 0 auto;
margin-top: 10px;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
You need to set position: relative; to the parent element and position: absolute; to the shape element. Then use max min value for random where max is the parent width/height and subtract the shape width/height ...
This is snippet before update
function position() {
var playSpace = document.querySelector('#playSpace');
var shape = document.getElementById("shape");
var maxHeight = playSpace.offsetHeight - shape.offsetHeight;
var maxWidth = playSpace.offsetWidth - shape.offsetWidth;
var positionTop = Math.random() * (maxHeight - 0) + 0;
var positionLeft = Math.random() * (maxWidth - 0) + 0;
// think of this like so:
// var positionTop = Math.random() * (max - min) + min;
// more information about it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
var position = "position:absolute;top:" + positionTop + "px;left:" + positionLeft + "px;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin:0;
padding-top: 30px;
}
#playSpace {
position: relative; /* add this line */
width: 90%;
height: 90%;
margin: 0 auto;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
Updated after comment
Not sure how you added the size() function but probably the problem was with using ...cssText that you overwrote the changes. So now I changed the code with passing the element to the functions and then only change the single CSS statements which need to be changed.
function position(element) {
var playSpace = document.querySelector('#playSpace');
var shape = document.getElementById("shape");
var maxHeight = playSpace.offsetHeight - shape.offsetHeight;
var maxWidth = playSpace.offsetWidth - shape.offsetWidth;
var positionTop = Math.random() * (maxHeight - 0) + 0;
var positionLeft = Math.random() * (maxWidth - 0) + 0;
// think of this like so:
// var positionTop = Math.random() * (max - min) + min;
// more information about it https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
element.style.position = 'absolute';
element.style.top = positionTop + "px";
element.style.left = positionLeft + "px";
}
function size(element) {
var sizeMath = (Math.random() * 200) + 50;
element.style.width = sizeMath + "px";
element.style.height = sizeMath + "px";
}
document.getElementById("shape").onclick = function() {
size(document.getElementById("shape"));
position(document.getElementById("shape"));
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin:0;
padding-top: 30px;
}
#playSpace {
position: relative; /* add this line */
width: 90%;
height: 90%;
margin: 0 auto;
border: 1px black solid;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
You can use a specify the range (min/max) in Math.random function and then use this function Math.floor(Math.random() * (max - min + 1)) + min; to limit the returned value of the random function between min and max.
maxTop : height of the container - height of shape
maxLeft : width of the container - width of shape
minTop : 0
minLeft : 0
You need to use position:absolute and px value on shape for this to work
See code snippet:
function position() {
var minTop = 0;
var maxTop = document.getElementById("playSpace").clientHeight - document.getElementById("shape").clientHeight;
var minLeft = 0;
var maxLeft = document.getElementById("playSpace").clientWidth - document.getElementById("shape").clientWidth ;
var positionTop = Math.floor(Math.random() * (maxTop - minTop + 1) + minTop);
var positionLeft = Math.floor(Math.random() * (maxLeft - minLeft + 1) + minLeft);
var position = "position:absolute;top:" + positionTop + "px;left:" + positionLeft + "px;"
return position;
}
document.getElementById("shape").onclick = function() {
document.getElementById("shape").style.cssText = position();
}
#gameSpace {
width: 100%;
height: 470px;
background: blue;
margin: 0;
padding-top: 30px;
text-align:center;
}
#playSpace {
width: 90%;
height: 90%;
border: 1px black solid;
position:relative;
display:inline-block;
}
#shape {
width: 100px;
height: 100px;
background-color: red;
}
<div id="gameSpace">
<div id="playSpace">
<!-- here we put the shape -->
<div id="shape"></div>
</div>
</div>
With CSS calc, limit the position inside playSpace area (you can use different units, here % and px).
Then with offsetTop/offsetLeft, get the real position of the square and avoid negative positions (when positionTop < 100px or positionLeft < 100px).
function position() {
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
var position = "position:relative;top: calc(" + positionTop + "% - 100px);left: calc(" + positionLeft + "% - 100px);";
return position;
}
document.getElementById("shape").onclick = function() {
var shapeDiv = document.getElementById("shape");
shapeDiv.style.cssText = position();
var top = shapeDiv.offsetTop;// Result of calc(" + positionTop + "% - 100px) in px
if(top < 0) {
shapeDiv.style.top = '0px';
}
var left = shapeDiv.offsetLeft;// Result of calc(" + positionLeft + "% - 100px) in px
if(left < 0) {
shapeDiv.style.left = '0px';
}
}
Don't forget to add position: relative to #playSpace, to get offsetTop/left correct
#playSpace {
position:relative;/* mandatory */
}
You can get the parent element size, so that in your scirpt, use a condition to prevent the square to exceed.
function position() {
var maxWidth = document.getElementById("playSpace").offsetWidth;
var maxTop = document.getElementById("playSpace").offsetHeight;
var positionTop = Math.random() * 100;
var positionLeft = Math.random() * 100;
if (positionTop > maxTop) { positionTop = maxTop;)
if (positionLeft > maxWidth) { positionLeft = maxWidth;)
var position = "position:relative;top:" + positionTop + "%;left:" + positionLeft + "%;"
return position;
}
I'm not sure if .offsetWidth and .offsetHeight works well, but you got the idea :)
By tweaking just a little your positionTop and positionLeft variable, I managed to keep the square inside. You just need to change the maximum % that it needs to have to not exceed the container. I found that 75% for the top and 80% for the left seems to be the max!
var positionTop = Math.floor(Math.random() * 75) ;
var positionLeft = Math.random() * 80;
Here's a fiddle
If you set the containing element to position: relative; and the inner element with position: absolute; the inner elements top left right and bottom properties will calculate from the borders of the containing element.
Here is a good source of css positioning.
In your case additional validation should be set to positionTop and positionLeft.
positionTop should be in the interval [( shapeHeight/2 ) - (100 - shapeHeight/2 ) ]
positionLeft should be in the interval [( shapeWidth/2 ) - (100 - shapeWeight/2 ) ]