I am making a game with javascript/jquery and I am trying to make a gravity effect. I have <div id="block"><img src="block/block1.png"/><div> and I want it to constantly move down but I also want it just to sit on top of other divs instead of going right through them. So far I have tried:
var obj = $('#block');
function down()
{
obj.animate({top:'-=20'}, 1000, down);
}
down();
This (fiddle) is not elegant and can be improved a lot, but it works. It uses a very simple collision model and an interval timer. You will need to adapt some parts (and you will hopefully improve it).
HTML:
<div class="gravity" style="width: 90px; height: 15px; background-color: red; position: absolute; top: 10px; left: 20px;"></div>
<div class="gravity" style="width: 90px; height: 25px; background-color: green; position: absolute; top: 60px; left: 30px;"></div>
<div class="gravity" style="width: 90px; height: 25px; background-color: gray; position: absolute; top: 30px; right: 45px;"></div>
<div class="obstacle" style="width: 230px; height: 40px; background-color: blue; position: absolute; top: 240px; right: 19px;"></div>
<div class="obstacle" style="width: 180px; height: 40px; background-color: blue; position: absolute; top: 90px; left: 30px;"></div>
JavaScript:
(function() {
// All falling objects
var gravity = $('.gravity'),
// All static objects
obstacle = $('.obstacle');
var all = gravity.add(obstacle);
setInterval(function() {
// Calculate positions of all falling objects
gravity.each(function() {
var e = this,
g = $(this),
ypos = g.offset().top,
xpos = g.offset().left,
h = g.height(),
w = g.width();
// Check whether something is in our way
var conflicts = false;
all.each(function() {
if(this === e) return;
var a = $(this);
if(xpos < a.offset().left + a.width() && xpos + w > a.offset().left) {
if(ypos + h > a.offset().top && ypos + h < a.offset().top + a.height()) {
conflicts = true;
}
}
});
if(!conflicts) {
// Move down (real gravitation would be v = a * t)
g.css('top', g.offset().top + 3);
}
});
}, 50);
})();
To prevent negative comments and such stuff: Yes, you should call this once the document has been loaded. Yes, this code is dirty and should not be used in a production environment. It is just what it claims to be - a working example.
Related
I am resizing and positioning a box using the mousemove event. Those. i change transform translate and width (height) with pageX (pageY). But due to the fact that the mouse event mousemove does not always have time to be processed (for example, if you move the mouse quickly) or does not have time to read conditions, the block goes out of bounds.
Question: what do I need to do in this case so that the block does not go beyond the boundaries?
This is how it looks roughly. Those. in this example, the second_block is outside the first_block (500px), i.e. it does not have time to read the condition. How should this issue be resolved? Also for convenience https://jsfiddle.net/ManuOP/t1r4szdx/3/
<div id="first_block" class="first_block">
<div id="auxiliary_block">
<div id="second_block" class="second_block"></div>
<input id="point" class="point" name="name_point" type="button">
</div>
</div>
<script src="1.block_in_center_question.js"></script>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div {
display: flex;
flex-direction: column;
}
div.first_block {
height: 300px;
width: 500px;
background: green;
}
div#auxiliary_block {
position: absolute;
}
div.second_block {
height: 200px;
width: 300px;
background: orange;
}
input.point {
position: absolute;
cursor: pointer;
height: 14px;
width: 14px;
border: none;
background: black;
right: -7px;
top: 50%;
}
"use strict";
let second_block = document.getElementById('second_block');
let point = document.getElementById('point');
function change_second_block() {
if(second_block.clientWidth < 500) {
second_block.style.width = `${start_x + event.pageX}px`;
}
}
point.addEventListener('mousedown', (event) => {
window.start_x = second_block.clientWidth - event.pageX;
document.addEventListener('mousemove', change_second_block);
});
You could just test the new width and if it's too large then constrain it to be no more than the maximum.
This snippet does this for the x direction and forces it to remain at or below 500px.
"use strict";
let second_block = document.getElementById('second_block');
let point = document.getElementById('point');
function change_second_block() {
if (second_block.clientWidth < 500) {
second_block.style.width = (start_x + event.pageX) < 500 ? `${start_x + event.pageX}px` : '500px';
}
}
point.addEventListener('mousedown', (event) => {
window.start_x = second_block.clientWidth - event.pageX;
document.addEventListener('mousemove', change_second_block);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div {
display: flex;
flex-direction: column;
}
div.first_block {
height: 300px;
width: 500px;
background: green;
}
div#auxiliary_block {
position: absolute;
}
div.second_block {
height: 200px;
width: 300px;
background: orange;
}
input.point {
position: absolute;
cursor: pointer;
height: 14px;
width: 14px;
border: none;
background: black;
right: -7px;
top: 50%;
}
<div id="first_block" class="first_block">
<div id="auxiliary_block">
<div id="second_block" class="second_block"></div>
<input id="point" class="point" name="name_point" type="button">
</div>
</div>
You can work around this issue if the size of the change in the item is above a certain limit, or by checking the limit and stopping the update. I prevented the overflow caused by rapid mouse movement by updating its code as follows:
function change_second_block()
{
console.log("Event.PageX: " + event.pageX);
if(event.pageX < 500 )
{
if(second_block.clientWidth < 500)
{
second_block.style.width = `${start_x + event.pageX}px`;
}
}
}
References
Javascript mouse event not captured properly when mouse moved very fast
I'm using a small script to follow the cursor with a div element.
This script makes the element strictly follow the cursor.
What I'm trying to do is to add some kind of duration to the process of "following" the cursor. I tried CSS transitions but the animation always ended up breaking. Can somebody please help me with this?
Let's say mouse is somewhere, and then it changes position by around 100px. I want to specify the duration like if i was using CSS... But the thing is that I can not use any transitions but only some javascript magic instead...
document.body.addEventListener("mousemove", function(e) {
var curX = e.clientX;
var curY = e.clientY;
document.querySelector('mouse').style.left = curX - 10 + 'px';
document.querySelector('mouse').style.top = curY - 10 + 'px';
});
body {
background: #333;
height: 500px;
width: 500px;
}
mouse {
display: block;
position: fixed;
height: 20px;
width: 20px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
I was wondering how to add a transition without using the CSS but I'm not the most advanced when it comes to JavaScript.
[edit] : I don't wanna use window.setTimeout.
[edit 2] : I wanted to use transition: 0.1s; but as I said it broke the effect when user moved the mouse too quickly.
There's a whole bunch of ways to do this, as you can see in the other answers, each with its own "feel". I'm just adding one more, where the dot approaches the cursor by a percentage of the remaining distance.
let curX = 0, curY = 0, elemX = null, elemY = null;
document.body.addEventListener("mousemove", function(e) {
curX = e.clientX;
curY = e.clientY;
if (elemX === null) [ elemX, elemY ] = [ curX, curY ];
});
let amt = 0.1; // higher amount = faster tracking = quicker transition
let elem = document.querySelector('mouse');
let frame = () => {
requestAnimationFrame(frame);
elemX = (elemX * (1 - amt)) + (curX * amt);
elemY = (elemY * (1 - amt)) + (curY * amt);
elem.style.left = `${elemX}px`;
elem.style.top = `${elemY}px`;
};
frame();
body {
position: absolute;
background: #333;
left: 0; top: 0; margin: 0; padding: 0;
height: 100%;
width: 100%;
}
mouse {
display: block;
position: absolute;
height: 20px; margin-left: -10px;
width: 20px; margin-top: -10px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
You can use setTimeout() function, to introduce a delay:
document.body.addEventListener("mousemove", function(e) {
var delay=250 //Setting the delay to quarter of a second
setTimeout(()=>{
var curX = e.clientX;
var curY = e.clientY;
document.querySelector('mouse').style.left = curX - 10 + 'px';
document.querySelector('mouse').style.top = curY - 10 + 'px';
},delay)
});
body {
background: #333;
height: 500px;
width: 500px;
}
mouse {
display: block;
position: fixed;
height: 20px;
width: 20px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
Or, to avoid trailing, use an interval and move the cursor to the correct direction (change ratio to set the speed ratio):
var curX,curY
document.body.addEventListener("mousemove", function(e) {
curX = e.clientX;
curY = e.clientY;
});
setInterval(()=>{
var ratio=5
var x=document.querySelector('mouse').offsetLeft+10
var y=document.querySelector('mouse').offsetTop+10
document.querySelector('mouse').style.left=((curX-x)/ratio)+x-10+"px"
document.querySelector('mouse').style.top=((curY-y)/ratio)+y-10+"px"
},16)
body {
background: #333;
height: 500px;
width: 500px;
}
mouse {
display: block;
position: fixed;
height: 20px;
width: 20px;
background: #fff;
border-radius: 50%;
}
<body>
<mouse></mouse>
</body>
My code allows scrolling vertically in the bottom section to control scrolling horizontally in the top section.
My jsfiddle
You'll see the colors shift through a gradient. Works pretty well. Problem is that I can't quite seem to get the inverse to work. Scrolling horizontally in the top controls scrolling in the bottom.
Any ideas?
Here's the script that makes it work:
// Add event listener for scrolling
$("#bottom").on("scroll", function bottomScroll() {
var scrolledleft = parseInt($("#bottom").scrollTop()) * 1;
console.log(scrolledleft + scrolledright)
$("#top").scrollLeft(scrolledleft + scrolledright)
})
//Move right column to bottom initially
$("#top").scrollLeft($("#top").height())
//Get actual distance scrolled
var scrolledright = parseInt($("#top").scrollLeft())
Your event handlers need to temporarily cancel each other so that they don't both fire at once. You want to calculate your position percentage based on the current scrollLeft / (width of child div - width of container), then apply that percentage to the other element, and likewise for top/height. Also I changed the height of #top to 50% in CSS.
var handler = function (e) {
var src = e.target;
// the first element that triggers this function becomes the active one, until it's done
if (!activeScroller) activeScroller = src.id;
else if (activeScroller != src.id) return;
var $b = $("#bottom");
var $t = $("#top");
var scrollH = $("#bottom-content").height() - $b.height();
var scrollW = $("#top-content").width() - $t.width();
var scrollPct = 0;
if (src.id == "top") {
if (scrollW > 0) {
scrollPct = $t.scrollLeft() / scrollW;
}
$b.scrollTop(scrollH * scrollPct);
} else {
if (scrollH > 0) {
scrollPct = $b.scrollTop() / scrollH;
}
$t.scrollLeft(scrollW * scrollPct);
}
// give all animations a chance to finish
setTimeout(function () { activeScroller = ""; }, 100);
};
var activeScroller = "";
$("#top,#bottom").on("scroll", handler);
#top {
position: absolute;
margin: auto;
top: 0;
right: 0;
left: 0;
width: 100%;
height: 50%;
position: fixed;
overflow: auto;
background: red;
}
#top-content {
height: 100%;
width: 2000px;
background: linear-gradient(90deg, red, blue);
}
#bottom {
position: absolute;
margin: auto;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 50%;
position: fixed;
overflow: auto;
background: green;
z-index: 100;
}
#bottom-content {
height: 2000px;
width: 100%;
background: linear-gradient(0deg, orange, green);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="top">
<div id="top-content"></div>
</div>
<div id="bottom">
<div id="bottom-content"></div>
</div>
Check out this:
https://jsfiddle.net/1p7gp72h/1/
I'm not sure what your end goal is here.
$("#top").on("scroll", function topScroll() {
var scrolledleft = parseInt($("#top").scrollTop()) * 1;
$("#bottom").scrollLeft(scrolledleft + scrolledright)
});
#top {
top: 0;
right: 0;
left: 0;
width: 5000px;
height: 100%;
overflow: auto;
background: red;
overflow-x: scroll;
overflow-y: hidden;
white-space:nowrap;
}
Scroll to left ::
$('div').scrollLeft(1000);
Scroll back to normal/ scroll to right ::
$('div.slick-viewport').scrollLeft(-1000);
I have created a lightbox in javascript and I have placed inside it a progress bar that I have also created it in javascript. My problem is that when I was trying to insert a second progress bar inside my lightbox only the first works. Any idea how to fix this?
this is my jsfiddle :http://jsfiddle.net/QHMKk/3/
and my code is this:
my javascript is:
function show() {
document.getElementById('light').style.display='block';
document.getElementById('fade').style.display='block';
}
function start() {
var stepSize = 50;
setTimeout((function() {
var filler = document.getElementById("filler"),
percentage = 0;
return function progress() {
filler.style.height = percentage + "%";
percentage +=1;
if (percentage <= 100) {
setTimeout(progress, stepSize);
}
}
}()), stepSize);
}
function start() {
var stepSize = 50;
setTimeout((function() {
var filler2 = document.getElementById("filler2"),
percentage = 0;
return function progress() {
filler.style.height = percentage + "%";
percentage +=1;
if (percentage <= 100) {
setTimeout(progress, stepSize);
}
}
}()), stepSize);
}
this is my html:
OPEN
<div id="light" class="white_content_stats">
<div class="prog">
<div id="filler" class="filler"></div>
</div>
</br>
<div class="prog2">
<div id="filler2" class="filler2"></div>
</div>
<a href = "javascript:void(0)" onclick = " document.getElementById('light').style.display='none';document.getElementById('fade').style.display='none'; ">
</br>CLOSE</a>
and this is my CSS:
.black_overlay_stats{
display: none;
position: absolute;
top: 0%;
left: 0%;
width: 100%;
height: 50%;
z-index:1001;
-moz-opacity: 0.6;
opacity:.70;
filter: alpha(opacity=70);
}
.white_content_stats {
display: none;
position:fixed;
top: 15%;
width: 300px;
padding: 30px;
margin-left:10px;
background-color:#F2F2F2;
border-radius: 0px;
box-shadow: 0px 0px 0px 20px rgba(0,0,0,0.6);
z-index:1002;
}
.prog {
height: 100px;
width: 30px;
border: 1px solid white;
position: relative;
}
.filler {
height: 0%;
width: 30px;
position: absolute;
bottom: 0;
background-color: grey;
}
.prog2 {
height: 100px;
width: 30px;
border: 1px solid white;
position: relative;
}
.filler2 {
height: 0%;
width: 30px;
position: absolute;
bottom: 0;
background-color: grey;
}
You define 2 functions with the same name start, so the second will be used and only it will be run, hence you can see only 1 progress bar works. You can modify the function start to make it accept an argument of id like this:
function start(id) {
//...
var filler = document.getElementById(id)
//...
}
Then call both start('filler') and start('filler2'):
OPEN
Updated Demo.
Note that you should not use inline event property.
these javascript functions are working perfectly separate, however when i try to write them in the same page they become inactive. All of the id and class names are correct. I have been fiddleing with it for a while
part 1:
<script>
$("#pic1").click(function(){
var div=$("#pic1");
div.animate({top:'-100px',opacity:'0.4'},"slow");
div.animate({height:'100%',opacity:'1'},"slow");
});
</script>
Part 2:
<script>
var mouseX = 0;
var mouseY = 0;
var offsetWidth = $('.area').width()/2;
var offsetHeight = $('.area').height()/2;
var origBoxTop = parseInt($('.box').css('top'));
var origBoxLeft = parseInt($('.box').css('left'));
$('.area').mousemove( function(e) {
mouseX = offsetWidth - e.pageX;
mouseY = offsetHeight - e.pageY;
$('.box').css('top', origBoxTop + mouseY);
$('.box').css('left', origBoxLeft + mouseX);
$('.info').attr('value', 'x: ' + mouseX + ', y: ' + mouseY);
});
</script> `
I am pretty positive my html and css is correct since both these parts work alone. I just want both to be active on the same page.
By putting them together all i've tried stacking them inside the script tag, i don't know what i don't know so its probably very simple, i'm new to javascript and jQuery. I have just posted the entire code under.
<!DOCTYPE html>
<html>
<head></head>
<script src="jquery2.js"></script>
<style>
body {
background: url("back1.gif");
}
#tree {
position: absolute;
top: 100px;
left: -20px;
}
#tree2 {
position: absolute;
top: -10px;
right: -90px;
}
.box2 {
position: absolute;
height: 200px;
width: 200px;
}
#hi {
cursor: pointer;
top: 600px;
left: 1075px;
position: absolute;
clear: all;
}
#re {
position: absolute;
top: 500px;
left: 500px;
cursor: pointer;
clear all;
}
#st {
position: absolute;
top: 500px;
left: 300px;
cursor: pointer;
clear: all;
}
.info {
position: absolute;
z-index: 99;
}
.box {
position: absolute;
top: 100%;
left: 100%;
margin-top: -50px;
margin-left: -50px;
}
.box:hover {
cursor: pointer;
}
.area {
position: absolute;
width: 100%;
height: 100%;
}
</style>
<body>
<script>
$(document).ready(function(){
$("#re").click(function(){
var div=$("#re");
div.animate({top:'-100px',opacity:'0.4'},"slow");
div.animate({height:'100%',opacity:'1'},"slow");
});
$("#st").click(function(){
var div=$("#st");
div.animate({right:'-100',opacity:'0.4'},"slow");
div.animate({width:'100%',opacity:'1'},"slow");
});
$("#hi").click(function(){
var div=$("#hi");
div.animate({left:'-400px',opacity:'0.4'},"slow");
div.animate({width:'100%',opacity:'1'},"slow");
});
var mouseX = 0;
var mouseY = 0;
var offsetWidth = $('.area').width()/2;
var offsetHeight = $('.area').height()/2;
var origBoxTop = parseInt($('.box').css('top'));
var origBoxLeft = parseInt($('.box').css('left'));
$('.area').mousemove( function(e) {
mouseX = offsetWidth - e.pageX;
mouseY = offsetHeight - e.pageY;
$('.box').css('top', origBoxTop + mouseY);
$('.box').css('left', origBoxLeft + mouseX);
$('.info').attr('value', 'x: ' + mouseX + ', y: ' + mouseY);
});
});
</script>
<div id="wrapper">
<img src="tree.gif" id="tree">
<img src="tree2.gif" id="tree2">
<img src="1.gif" class="box2" id="st">
<img src="3.gif" class="box2" id="hi">
<img src="2.gif" class="box2" id="re">
</div>
<section class="area">
<div class="box" id="what"><img src="what.png"></div>
</section>
</div>
</body>
</html>
I've tried the code in a browser, and I can tell that the script ran. Try adding this in your css, and see if it works better:
.area {
z-index: -1;
}
If it doesn't help, press F12 and F5, and see if there are any errors in the console.
Also you shouldn't put tags between </head> and <body>.