I need to make a ball grow until it reaches 400, which thereafter it would shrink the same way. Would really appreciate feedback what I'm doing wrong in my code:
var
ball1Size = 100
, ball2Size = 100
, ball2SizeStep = 50
;
function onBall2Click()
{
var ball2 = document.querySelector('.ball2');
ball2Size = ball2Size + 50;
if (ball2Size > 400) {
ball2Size = ball2Size - 100;
}
else {
ball2Size - 150;
}
ball2.innerText = ball2Size;
ball2.style.width = ball2Size;
ball2.style.height = ball2Size;
}
body {
background-color : black;
text-align : center;
}
h1 {
color : white;
}
div {
width : 100px;
height : 100px;
margin : auto;
margin-bottom : 10px;
border-radius : 50%;
transition : 0.3s;
line-height : 50px;
}
.ball2 {
background-color : orange;
}
<div class="ball2" onclick="onBall2Click()">
SIZE
</div>
See code fix and syntax fixes
here:
var ball1Size = 100;
var ball2Size = 100;
var ball2SizeStep = 50;
function onBall2Click() {
var ball2 = document.querySelector('.ball2');
ball2Size = ball2Size + ball2SizeStep;
if (ball2Size >= 400) {
ball2SizeStep = -50
} else if (ball2Size <= 50) {
ball2SizeStep = 50
}
ball2.innerText = ball2Size;
ball2.style.width = ball2Size + "px";
ball2.style.height = ball2Size + "px";
}
body {
background-color: black;
text-align: center;
}
h1 {
color: white;
}
div {
width: 100px;
height: 100px;
margin: auto;
margin-bottom: 10px;
border-radius: 50%;
transition: 0.3s;
line-height: 50px;
}
.ball2 {
background-color: orange;
}
<div class="ball2" onclick="onBall2Click()" >
SIZE
</div>
This is what you want to do, increase the balls size for each click that it can be increased for, i.e., is under 400, when it reaches 400, decrease the ball size for each click until it reaches its original size. Rinse and repeat.
var ball1Size = 100;
var ball2Size = 100;
var ball2SizeStep = 50;
let isBallDecreasing = false;
function onBall2Click() {
var ball2 = document.querySelector('.ball2');
if (ball2Size === 100) isBallDecreasing = false;
if (ball2Size >= 400 || isBallDecreasing) {
ball2Size -= 50;
isBallDecreasing = true;
} else {
ball2Size += 50
isBallDecreasing = false;
}
ball2.innerText = ball2Size;
ball2.style.width = ball2Size;
ball2.style.height = ball2Size
}
<div class="ball2" onclick="onBall2Click()">
SIZE
</div>
Using a boolean to track the direction can simplify it
let direction = 1;
const min = 100;
const max = 400;
const step = 50;
let current = 100;
var ball = document.querySelector(".ball2");
ball.addEventListener("click", function() {
current += direction * step;
if (current >= max) {
current = max;
direction = -1;
} else if (current <= min) {
current = min;
direction = 1;
}
updateElem();
});
function updateElem() {
ball.textContent = current;
ball.style.width = current + 'px';
ball.style.height = current + 'px';
}
updateElem();
body {
background-color: black;
text-align: center;
}
h1 {
color: white;
}
.ball {
width: 100px;
height: 100px;
margin: auto;
margin-bottom: 10px;
border-radius: 50%;
transition: 0.3s;
line-height: 50px;
}
.ball2 {
background-color: orange;
}
<div class="ball ball2">
SIZE
</div>
If you are going to have more than one of these you probably want to have some sort of way to keep track. Using data attributes can help out so you do not need more than one copy of the code.
document.querySelectorAll(".ball2").forEach(function (ball) {
ball.addEventListener("click", function () {
let direction = +ball.dataset.direction;
const min = +ball.dataset.min;
const max = +ball.dataset.max;
const step = +ball.dataset.step;
const current = +ball.dataset.current;
let updated = current + direction * step;
if (updated >= max) {
updated = max;
direction = -1;
} else if (updated <=min) {
updated = min;
direction = 1;
}
updateElem();
ball.dataset.direction = direction;
ball.dataset.current = updated;
});
function updateElem() {
const num = ball.dataset.current;
ball.textContent = num;
ball.style.width = num + 'px';
ball.style.height = num + 'px';
}
updateElem();
});
body {
background-color: black;
text-align: center;
}
h1 {
color: white;
}
.ball {
width: 100px;
height: 100px;
margin: auto;
margin-bottom: 10px;
border-radius: 50%;
transition: 0.3s;
line-height: 50px;
}
.ball2 {
background-color: orange;
}
<div
class="ball ball2"
data-direction="1"
data-min="100"
data-max="400"
data-step="50"
data-current="100">
SIZE
</div>
<div
class="ball ball2"
data-direction="-1"
data-min="100"
data-max="400"
data-step="50"
data-current="400">
SIZE
</div>
<div
class="ball ball2"
data-direction="1"
data-min="0"
data-max="1000"
data-step="100"
data-current="200">
SIZE
</div>
you can also Use CSS custom properties for simplifying your code:
const ball2 = document.querySelector('.ball2');
var
ballSz = 100
, ball2SizeStep = 50
;
ball2.onclick =()=>
{
ballSz += ball2SizeStep
ball2.textContent = ballSz
ball2.style.setProperty('--szHW', ballSz + 'px')
if (ballSz >= 400) ball2SizeStep = -50
if (ballSz <= 100) ball2SizeStep = +50
}
body {
background-color : black;
text-align : center;
}
h1 {
color : white;
}
div {
--szHW : 100px; /* <--- CSS custom properties */
width : var(--szHW);
height : var(--szHW);
margin : auto;
margin-bottom : 10px;
border-radius : 50%;
transition : 0.3s;
line-height : 50px;
}
.ball2 {
background-color : orange;
}
<div class="ball2">
SIZE
</div>
the same, for multiples balls
document.querySelectorAll('.ball2').forEach( ball2 =>
{
ball2.style.setProperty('--szHW', ball2.dataset.size + 'px') // init sizes according to data-size value
ball2.onclick =_=>
{
let
min = Number(ball2.dataset.min)
, max = Number(ball2.dataset.max)
, step = Number(ball2.dataset.step)
, size = Number(ball2.dataset.size)
;
if ( size === min && step < 0
|| size === max && step > 0 )
{
step *= -1
ball2.dataset.step = step
}
ball2.dataset.size = size += step
ball2.style.setProperty('--szHW', size + 'px')
}
})
body {
background-color : black;
text-align : center;
}
div.ball2 {
--szHW : 100px; /* <--- CSS custom properties */
width : var(--szHW);
height : var(--szHW);
margin : auto;
margin-bottom : 10px;
border-radius : 50%;
transition : 0.3s;
line-height : 50px;
background : orange;
}
div.ball2::before {
content: attr(data-size)
}
<div class="ball2" data-min="100" data-max="400" data-step="50" data-size="100"></div>
<div class="ball2" data-min="100" data-max="400" data-step="50" data-size="400"></div>
<div class="ball2" data-min="100" data-max="1000" data-step="100" data-size="200"></div>
Related
Here, I have code a program that revolves the targeted div in a rectangular path using CSS positions properties in setInterval() method.
Firstly, the div indeed moves rightwards (using left CSS property) and then downwards (using top CSS property) but when the thirds step comes it doesn't move leftwards (using CSS right property). Why is that so?
let a = 0;
let node = document.querySelector(".node");
let inter1 = setInterval(function() {
if (a == 260) {
clearInterval(inter1);
a = 0;
let inter2 = setInterval(function() {
if (a == 639) {
clearInterval(inter2);
a = 260;
let inter3 = setInterval(function() {
if (a == 0) {
clearInterval(inter3);
} else {
a -= 1;
node.style.right = a + "px";
}
}, 1)
} else {
a += 1;
node.style.top = a + "px";
}
}, 1)
} else {
a += 1;
node.style.left = a + "px";
}
}, 1)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: serif;
}
body {
background: black;
color: white;
width: 100vw;
}
.node {
background: dodgerblue;
color: white;
display: inline-block;
width: 100px;
height: 100px;
position: absolute;
}
<div class="node"></div>
Like the user #JavaScript wrote, you should decide for one - left or right.
Therefor you could change right to left in the inter3 statement:
let inter3 = setInterval(function() {
if (a == 0) {
clearInterval(inter3);
} else {
a -= 1;
node.style.left = a + "px";
}
}, 1);
let a = 0;
let node = document.querySelector(".node");
let inter1 = setInterval(function() {
if (a == 260) {
clearInterval(inter1);
a = 0;
let inter2 = setInterval(function() {
if (a == 639) {
clearInterval(inter2);
a = 260;
let inter3 = setInterval(function() {
if (a == 0) {
clearInterval(inter3);
} else {
a -= 1;
node.style.left = a + "px";
}
}, 1)
} else {
a += 1;
node.style.top = a + "px";
}
}, 1)
} else {
a += 1;
node.style.left = a + "px";
}
}, 1)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: serif;
}
body {
background: black;
color: white;
width: 100vw;
}
.node {
background: dodgerblue;
color: white;
display: inline-block;
width: 100px;
height: 100px;
position: absolute;
}
<div class="node"></div>
i have provided all my codes here all seems good the problem is when i change from last slide to first or the opposite in both case all slides flips differently instead rotating like with other sildes
render() function is the place where all co-ordinates are calculating
i think the issue is with CSS transition since its the main thing which is animating slides, i dont see any easy fix for this if you can find any tell me please looking for easy solution or possibility without messing too much with co-ordinates . thanks in advance
class slider {
constructor(){
if(typeof arguments[0] != "undefined"){
this.init()
arguments[0].appendChild(this.html)
this.calculate()
this.render(1)
}
else{this.init()}
}
init(){
let obj = this
this.html = `
<div class="root border-2 p-5 border-black m-auto">
<div class="each border border-black absolute text-center">item name 1</div>
</div>
`
let el = document.createElement("div")
el.innerHTML = this.html
this.html = el.querySelector("*")
this.root = this.html
let eEl = this.root.querySelector(".each")
this.eachTemp = eEl.cloneNode(true)
eEl.remove()
this.fillBoxes(6)
this.html.addEventListener("click",function(e){
obj.onclick(obj,e)
})
}
onclick(obj,e){
let t = e.target
if(t.closest(".each")){
obj.render(t.index)
}
}
fillBoxes(num){
for(let i=0;i<num;i++){
let newEl = this.eachTemp.cloneNode(true)
newEl.index = i+1
newEl.innerText = "Item " + (i+1)
this.html.appendChild(newEl)
}
this.els = this.html.querySelectorAll(".each")
}
calculate(){
this.eCor = this.els[0].getClientRects()[0]
this.mag = this.eCor.width
this.per = Math.PI / (this.els.length / 2)
this.deg = this.rtod(this.per)
}
render(index){
this.els.forEach((each,i)=>{
let rad = (this.per * i) - this.per*(index-1),
x = Math.sin(rad)*this.mag,
y = Math.cos(rad)*this.mag
if(i+1 == index){each.classList.add("active")}
else{each.classList.remove("active")}
each.style.transform = `translate3d(${x}px,0%,${y}px)`
each.style.transform += `rotateY(${this.rtod(rad)}deg)`
})
}
rtod(radians){
return radians * (180/Math.PI)
}
}
const s = new slider(document.body)
.each{
height: 250px;
width: 250px;
background: skyblue;
opacity: 0.8;
transform-origin: 50% 50%;
transform-style: preserve-3d;
user-select: none;
filter: brightness(80%);
transition: all 1s cubic-bezier(0, 1.22, 0.53, 1.02);
/* box-shadow: 0px 0px 10px 1px black; */
}
.each:nth-child(odd){background:lightsalmon}
.root{
height: 280px;
width: 280px;
position: relative;
margin-top: 10%;
perspective: 1000px;
transform-style: preserve-3d;
transition: transform 0.5s;
/* animation: loop 4s infinite linear; */
}
.each:hover{
z-index: 1000 !important;
filter:brightness(110%);
}
.active{
opacity: 1 !important;
filter:brightness(100%) !important;
}
<link href="https://unpkg.com/tailwindcss#^2/dist/tailwind.min.css" rel="stylesheet">
When you switch between 1 and 6 slides, your calculated rotatedY value changes from 0deg to 300deg (or from 300deg to 0deg). But actually you need only ±60deg update. So you need a mechanism to increase/decrease your rotatedY endlessly in both ways, for example 240 -> 300 -> 360 -> 420 -> 480 ... (not 240 -> 300 -> 0 -> 60 -> ...)
I suggest you to have these properties in your class:
currentIndex = 1;
radOffset = 0;
Then, when you click on element, you need to calculate radOffset (it increases/decreases endlessly):
const totalElements = this.els.length;
const rightDiff = t.index > this.currentIndex ? t.index - this.currentIndex : totalElements + t.index - this.currentIndex;
const leftDiff = totalElements - rightDiff;
const closestDiff = rightDiff < leftDiff ? - rightDiff : leftDiff;
this.currentIndex = t.index;
this.radOffset += this.per * closestDiff;
Then use it in your render function:
let rad = (this.per * i) + this.radOffset,
class slider {
currentIndex = 1;
radOffset = 0;
rotateOffset = 0;
constructor(){
if(typeof arguments[0] != "undefined"){
this.init()
arguments[0].appendChild(this.html)
this.calculate()
this.render(1)
}
else{this.init()}
}
init(){
let obj = this
this.html = `
<div class="root border-2 p-5 border-black m-auto">
<div class="each border border-black absolute text-center">item name 1</div>
</div>
`
let el = document.createElement("div")
el.innerHTML = this.html
this.html = el.querySelector("*")
this.root = this.html
let eEl = this.root.querySelector(".each")
this.eachTemp = eEl.cloneNode(true)
eEl.remove()
this.fillBoxes(6)
this.html.addEventListener("click",function(e){
obj.onclick(obj,e)
})
}
onclick(obj,e){
let t = e.target
if(t.closest(".each")){
const totalElements = this.els.length;
const rightDiff = t.index > this.currentIndex ? t.index - this.currentIndex : totalElements + t.index - this.currentIndex;
const leftDiff = totalElements - rightDiff;
const closestDiff = rightDiff < leftDiff ? - rightDiff : leftDiff;
this.currentIndex = t.index;
this.radOffset += this.per * closestDiff;
obj.render(t.index);
}
}
fillBoxes(num){
for(let i=0;i<num;i++){
let newEl = this.eachTemp.cloneNode(true)
newEl.index = i+1
newEl.innerText = "Item " + (i+1)
this.html.appendChild(newEl)
}
this.els = this.html.querySelectorAll(".each")
}
calculate(){
this.eCor = this.els[0].getClientRects()[0]
this.mag = this.eCor.width
this.per = Math.PI / (this.els.length / 2)
this.deg = this.rtod(this.per)
}
render(index, rotateDiff){
this.els.forEach((each,i)=>{
let rad = (this.per * i) + this.radOffset,
x = Math.sin(rad)*this.mag,
y = Math.cos(rad)*this.mag
if(i+1 == index){each.classList.add("active")}
else{each.classList.remove("active")}
each.style.transform = `translate3d(${x}px,0%,${y}px)`
each.style.transform += `rotateY(${this.rtod(rad)}deg)`
})
}
rtod(radians){
return Math.round(radians * (180/Math.PI));
}
}
const s = new slider(document.body)
.each{
height: 250px;
width: 250px;
background: skyblue;
opacity: 0.8;
transform-origin: 50% 50%;
transform-style: preserve-3d;
user-select: none;
filter: brightness(80%);
transition: all 1s cubic-bezier(0, 1.22, 0.53, 1.02);
/* box-shadow: 0px 0px 10px 1px black; */
}
.each:nth-child(odd){background:lightsalmon}
.root{
height: 280px;
width: 280px;
position: relative;
margin-top: 10%;
perspective: 1000px;
transform-style: preserve-3d;
transition: transform 0.5s;
/* animation: loop 4s infinite linear; */
}
.each:hover{
z-index: 1000 !important;
filter:brightness(110%);
}
.active{
opacity: 1 !important;
filter:brightness(100%) !important;
}
<link href="https://unpkg.com/tailwindcss#^2/dist/tailwind.min.css" rel="stylesheet">
I am trying to develop a very simple game where the ship (red box) will move left-right when user clicks on playground.
There are some moving walls (black boxes) as obstacles that the ship should avoid colliding with.
If any collision happens, the walls will stop moving and a text will be printed out in console.
I have succeeded to get this as close as I can. But its working sometime, not always. You can see it in the code below, try to collide with wall. Sometime it will stop them and print text, sometime it will just ignore the collision as if nothing happens.
I have no clue why this is happening.
Here is the code.
$('document').ready(function() {
var $totalHeight = $('.inner').height(); //of walls
var $maxHeight = Math.ceil(Math.ceil($totalHeight / 3) - (Math.ceil($totalHeight / 3) * 30) / 100); //30% of total wall height
$('.wall').each(function(i, obj) {
$(this).height($maxHeight);
$('.wall.four').css({
'height': $wallGap
});
})
var $wallGap = Math.ceil($totalHeight / 3) - $maxHeight;
var $wallOneTop = 0;
var $wallTwoTop = $maxHeight + $wallGap;
var $wallThreeTop = ($maxHeight * 2) + ($wallGap * 2);
var $wallFourTop = -$('.wall.four').height() - $wallGap;
$('.wall.one').css({
'top': $wallOneTop
});
$('.wall.two').css({
'top': $wallTwoTop
});
$('.wall.three').css({
'top': $wallThreeTop
});
$('.wall.four').css({
'top': $wallFourTop
});
function moveWall(wallObj) {
var $currentTop = wallObj.position().top;
var $limitTop = $('.inner').height();
if ($currentTop >= $limitTop) {
var $rand = Math.floor(Math.random() * ($maxHeight - $wallGap + 1) + $wallGap);
wallObj.height($rand);
var $top = -(wallObj.height());
} else {
var $top = (wallObj.position().top) + 5;
}
var $collide = checkCollision(wallObj);
wallObj.css({
'top': $top
});
return $collide;
}
var $wallTimer = setInterval(function() {
$('.wall').each(function(i, obj) {
var $status = moveWall($(this));
if ($status == true) {
clearInterval($wallTimer);
}
})
}, 40);
function checkCollision(wallObj) {
var $ship = $('.ship');
var $shipWidth = $ship.width();
var $shipHeight = $ship.height();
var $shipLeft = $ship.position().left;
var $shipRight = $shipLeft + $shipWidth;
var $shipTop = $ship.position().top;
var $shipBottom = $shipTop + $shipHeight;
var $wall = wallObj;
var $wallWidth = wallObj.width();
var $wallHeight = wallObj.height();
var $wallLeft = wallObj.position().left;
var $wallRight = $wallLeft + $wallWidth;
var $wallTop = wallObj.position().top;
var $wallBottom = $wallTop + $wallHeight;
if (
$shipLeft >= $wallRight ||
$shipRight <= $wallLeft ||
$shipTop >= $wallBottom ||
$shipBottom <= $wallTop
) {
return false;
} else {
console.log("dhumm!");
return true;
}
}
$('.outer .inner').click(function() {
var $ship;
$ship = $('.ship');
$shipLeft = $ship.position().left;
$shipRight = $shipLeft + $ship.width();
$inner = $('.inner');
$innerLeft = $inner.position().left;
$innerRight = $innerLeft + $inner.width();
if (($shipLeft < $inner.width() - $ship.width())) {
$ship.animate({
"left": $inner.width() - $ship.width()
}, 500, "linear");
} else if (($shipRight >= $inner.width())) {
$ship.animate({
"left": '0'
}, 500, "linear");
}
});
});
.outer {
background: #fff;
border: 20px solid #efefef;
width: 400px;
height: 600px;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
overflow: hidden;
}
.outer .inner {
background: #fff;
height: 100%;
width: 100%;
margin: auto;
position: relative;
overflow: hidden;
}
.outer .inner .wall {
width: 5px;
position: absolute;
left: 50%;
transform: translateX(-50%);
background: #000;
}
.outer .inner .ship {
width: 15px;
height: 15px;
background: red;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
<div class="wall one"></div>
<div class="wall two"></div>
<div class="wall three"></div>
<div class="wall four"></div>
<div class="ship"></div>
</div>
</div>
As freefomn-m already said.
Check for collision in the animation cycle of the ship, not the walls.
For this I use the second type of parameters for jQuery's .animate method
.animate( properties, options )
I use the "progress" option to check the collision in every movement cycle of the ship.
console.clear();
$('document').ready(function() {
var collided = false;
var collidedWith = null;
var $ship = $('.ship');
var $walls = $('.wall')
var $totalHeight = $('.inner').height(); //of walls
var $maxHeight = Math.ceil(Math.ceil($totalHeight / 3) - (Math.ceil($totalHeight / 3) * 30) / 100); //30% of total wall height
$('.wall').each(function(i, obj) {
$(this).height($maxHeight);
$('.wall.four').css({
'height': $wallGap
});
})
var $wallGap = Math.ceil($totalHeight / 3) - $maxHeight;
var $wallOneTop = 0;
var $wallTwoTop = $maxHeight + $wallGap;
var $wallThreeTop = ($maxHeight * 2) + ($wallGap * 2);
var $wallFourTop = -$('.wall.four').height() - $wallGap;
$('.wall.one').css({
'top': $wallOneTop
});
$('.wall.two').css({
'top': $wallTwoTop
});
$('.wall.three').css({
'top': $wallThreeTop
});
$('.wall.four').css({
'top': $wallFourTop
});
function moveWall(wallObj) {
var $currentTop = wallObj.position().top;
var $limitTop = $('.inner').height();
if ($currentTop >= $limitTop) {
var $rand = Math.floor(Math.random() * ($maxHeight - $wallGap + 1) + $wallGap);
wallObj.height($rand);
var $top = -(wallObj.height());
} else {
var $top = (wallObj.position().top) + 5;
}
// var $collide = checkCollision(wallObj);
wallObj.css({
'top': $top
});
// return $collide;
}
var $wallTimer = setInterval(function() {
$walls.each(function(i, obj) {
moveWall($(this));
if (collided) {
clearInterval($wallTimer);
}
})
}, 40);
function checkCollision() {
var $shipWidth = $ship.width();
var $shipHeight = $ship.height();
var $shipLeft = $ship.position().left;
var $shipRight = $shipLeft + $shipWidth;
var $shipTop = $ship.position().top;
var $shipBottom = $shipTop + $shipHeight;
$('.wall').each(function(i) {
var $wall = $(this);
var $wallWidth = $wall.width();
var $wallHeight = $wall.height();
var $wallLeft = $wall.position().left;
var $wallRight = $wallLeft + $wallWidth;
var $wallTop = $wall.position().top;
var $wallBottom = $wallTop + $wallHeight;
if (
$shipLeft < $wallRight &&
$shipRight > $wallLeft &&
$shipTop < $wallBottom &&
$shipBottom > $wallTop
) {
console.log("dhumm!");
collided = true;
collidedWith = $wall
$wall.addClass('crashed')
$ship.addClass('crashed')
$ship.stop();
return false;
}
})
}
$('.outer .inner').click(function() {
var $ship;
$ship = $('.ship');
$shipLeft = $ship.position().left;
$shipRight = $shipLeft + $ship.width();
$inner = $('.inner');
$innerLeft = $inner.position().left;
$innerRight = $innerLeft + $inner.width();
if (($shipLeft < $inner.width() - $ship.width())) {
$ship.animate({
"left": $inner.width() - $ship.width()
}, {
"duration": 500,
"easing": "linear",
"progress": checkCollision,
});
} else if (($shipRight >= $inner.width())) {
$ship.animate({
"left": '0'
}, {
"duration": 500,
"easing": "linear",
"progress": checkCollision,
});
}
});
});
.outer {
background: #fff;
border: 20px solid #efefef;
width: 400px;
height: 600px;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
overflow: hidden;
}
.outer .inner {
background: #fff;
height: 100%;
width: 100%;
margin: auto;
position: relative;
overflow: hidden;
}
.outer .inner .wall {
width: 5px;
position: absolute;
left: 50%;
transform: translateX(-50%);
background: #000;
}
.outer .inner .wall.crashed {
background: red;
}
.outer .inner .ship {
width: 15px;
height: 15px;
background: orange;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.outer .inner .ship.crashed {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
<div class="wall one"></div>
<div class="wall two"></div>
<div class="wall three"></div>
<div class="wall four"></div>
<div class="ship"></div>
</div>
</div>
As a recommendation how I would do this from scratch.
Use an update cycle that is called by either setInterval or setTimeout, or even better with requestAnimationFrame. The updatecycle would be responsible for the time progress and orchestrate the different objects. The structure would be like this.
jQuery(function($) { // same as $('document').ready()
var ship = ...;
var boundaries = ...;
var walls = ...;
var clickEvents = [];
document.addEventListener('click', function(e) {clickEvents.push(e)})
var handleEvents = function() {}
var setupWalls = function () {}
var setupShip= function () {}
var moveWalls = function () {}
var moveShip = function () {}
var checkCollision() {}
var setup = function() {
setupWalls();
setupShip();
// set the initial positions of the ships and the walls
}
var update = function() {
handleEvents();
moveWalls();
moveShips();
var collided = checkCollision();
if (!collided) {
setTimeout(update, 30);
}
}
setup();
update();
})
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.
Why I cannot get value inside the loop
Can use javascript only
Pause text for 2000ms on hover
reverse work on hover but should pause it first and then reverse the sequence until mouse out.
loop on reading text from textarea "input"
find this line in javascript to control delay
if(document.getElementById('flag2').value == "0"){
/*
1 : center
2 - 4 : center 2
5 - 7 : center 3
8 - 10 : center 4
11 - 13 : center 5
14 - 16 : center 6
17 - 19 : center 7
*/
stopNow= false;
function Loop(txt, wpm) {
txt = txt.replace(/\n/g, ' ');
var a = txt.split(' '),
n = a.length,
i = 0,
b = document.getElementById('bw'),
tw = document.getElementById('tw'),
tx = {
L: document.getElementById('txt_L'),
C: document.getElementById('txt_C'),
R: document.getElementById('txt_R')
}
;
function width(w) {
tw.textContent = w;
return tw.offsetWidth;
}
function middle(w) {
var x = 0;
var n = w.length,
// Center char calculation. 1=1, 2-4=2, 5-7=3, ...
c = ~~((n + 1) / 3) + 1,
z = {};
if (!n)
return;
z.a = width(w.substr(0, c - 1));
z.b = width(w.substr(0, c));
z.c = (z.b - z.a) / 2;
b.style.paddingLeft = ~~(110 - (z.a + z.c)) + 'px';
tx.L.textContent = w.substr(0, c - 1);
tx.C.textContent = w.substr(c - 1, 1);
tx.R.textContent = w.substr(c);
}
function word() {
if(stopNow){
middle(a[i])
if (--i === n)
i = 0;
return 0;
}
else{
middle(a[i])
if (++i === n)
i = 0;
return 0;
}
}
this.whiteout = function(w) {
if (w) {
tx.L.style.color = '#fff';
tx.R.style.color = '#fff';
} else {
tx.L.style.color = '#080';
tx.R.style.color = '#000';
}
};
wpm = wpm || 200;
var __time = 2000;
//can not get changes value here
if(document.getElementById('flag2').value == "0"){
__time = (60/wpm) * 1000;}
document.getElementById('flag1').innerHTML += document.getElementById('flag2').innerHTML ;
var tt = setInterval(function (){
document.getElementById('flag1').innerHTML = word();
}, __time);
}
var txt = document.getElementById('input').value;
var ww = new Loop(txt, 250);
document.getElementById('bw').addEventListener('change', function() {
ww.whiteout(this.checked);
});
document.getElementById('txtHolder').addEventListener('mouseover', function () {
stopNow = true;
document.getElementById('flag2').innerHTML = "1";
});
document.getElementById('txtHolder').addEventListener('mouseout', function () {
stopNow = false;
document.getElementById('flag2').innerHTML = "0";
});
* {
padding: 0;
margin:0;
}
.hide {
display: none;
}
#tw {
position: absolute;
visibility: hidden;
white-space: nowrap;
}
#tw,
#txt_L,
#txt_C,
#txt_R
{
font: bold 18px Arial;
line-height: 1;
}
#txt_L { color: #000; }
#txt_C { color: #f00; }
#txt_R { color: #000; }
#wrap {
position: relative;
width: 220px;
height: 50px;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
}
#b1 {
width: 110px;
height: 50px;
border-right: 1px solid #000;
float:left;
}
#bw {
position: absolute;
width: 220px;
top: 10px;
background: #fff;
padding: 5px 0;
line-height: 1;
vertical-align: middle;
}
<!--
EXTRA POINTS---------
Pause text for 2000ms on hover and reverse the sequence until mouse out.
-->
<div id="flag1">
</div>
<div id="flag2">
</div>
<div id="txtHolder">
<span id="tw"></span>
<div id="wrap">
<div id="b1"></div>
<div id="bw"><span id="txt_L"> </span><span id="txt_C"></span><span id="txt_R"></span></div>
</div>
</div>
<textarea id="input" class="hide">
Oh, hey there, TIDWRTWHUFOO fans. Thinking about going for a little dip this summer? How about you go for a swim with a one-ton crab that will smash you under its massive legs? Sound fun? Definitely!
Crabster is a wild crab-like robot designed to explore the deepest oceans without smashing itself into a squashed tin can. It has massive legs, a large body, and lots of cameras so it can find you even if you’re the dude from The Big Blue and can dive really deep. There’s no escaping our future robotic-aquatic overlords
</textarea>