So I have elements that are position: absolute and then I use Math.random() to set their left:#random and top:#random position.
However a very weird thing is happening. It should be completely random, thus they should be placed completely randomly. However time and time again, they are placed very closely together. Instead of being spread apart.
however you can clearly see, their positions are indeed random:
Here is the code I use to generate them:
const Clouds = function(props) {
const clouds = []
for (let i = 0; i < props.cloudNum; i++) {
const style = {
position: 'absolute',
height: 50 * props.cloudSize + 'px',
top: Math.random() * 100 + '%',
left: Math.random() * 100 + '%',
}
clouds.push(<Cloud key={i} style={style} />)
}
return <div className={props.side}>{clouds}</div>
}
is there a temporal component to Math.random, and because they are generated in sequence their random numbers are similar?
In fact, although they look like similar numbers they are not (remember that you are multiplying by 100), this means that your space of random numbers goes from 0 to 100 (since the decimals in the drawing barely have value, as is the case that you ask).
Keep in mind that if your space is 100 clouds only generating 13 clouds there is more than a 50% probability that two clouds occupy the same position by the birthday problem.
https://en.wikipedia.org/wiki/Birthday_problem
It's a coincidence that you get similar value. Try as many times as you want with my snippet to test it your own.
Note that my objects are much smaller than yours, not having elements overlapping give a better sense of randomness. IMHO, if you are generating clouds (depends on purposes) it could be better to use perlin noise
const container = document.getElementById('container');
const Clouds = function() {
for (let i = 0; i <10; i++) {
let myCloud = document.createElement("div");
myCloud.style.height = '15px';
myCloud.style.width = '15px';
myCloud.style.position = 'absolute';
myCloud.style.background = '#fff';
myCloud.style.border = '1px solid #ccc';
myCloud.style.left = Math.random()*100+'%';
myCloud.style.top = Math.random()*100+'%';
container.appendChild(myCloud);
}
}
function generate() {
container.innerHTML = '';
Clouds();
}
#container {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: red;
}
button {
position: absolute;
z-index: 999;
}
<div id="container"></div>
<button onClick="generate()">Generate</button>
There's no temporal component - it's just generated by the system. Here's a good thread explaining it. The random algorithm depends on the JavaScript engine (there's a V8 answer in that thread) but the function always produces a floating-point number between 0 and 1 inclusive. It's an incredibly large coincidence that your code yielded two numbers that close.
Related
Hi I am using a hashmap that allows me to efficiently detect objects in the given coordinates. However it is working perfectly , the problem lies with using the mouse to gather the position of the mouse within the canvas down to the pixel. I have been using the offsetX and offsetY methods for the event to gather some offset but it seems there is an offset I am unaware of and may have something to do with either:
1.using scaling on the canvas , Note: ive tried to fix this by division of the renderscale, this works with everything else so should be fine here.
mouseoffset is not accounting for parts of the page or is missing pixels at a low level (maybe 20) but divided by the render scale thats massive.
3.I am using a cartesian coordinate system to simplify things for the future , so the game map is in cartesian and may have to do with the problem.
I will not be supplying all the code because it is allot of work to go through it all so i will supply the following :
the html/css canvas code
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Game</title>
</head>
<body onload="jsEngine = new JsEngine(24, 24, .1); " >
<div class ="wrapper">
<canvas id="canvas" width="1920" height="1080"></canvas>
</div>
<style>
.wrapper {
position: relative;
width: auto;
height: 900px;
}
.wrapper canvas {
position: absolute;
left: 90px;
top: 50px;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 90%;
height: 90%;}
.GUI{
top: -315px;
left: -302px;
position: absolute;
width: 300px;
height: 300px;
background-color: cadetblue;
opacity: .5;
word-wrap: break-word;}
img{
image-rendering: optimize-contrast;
}
</style>
<div id = GUI class = "GUI"></div>
<!-- Libraries -->
<script src="../myapi/JSONE.js"></script>
<script src="../myapi/engine/SpacialHash.js"></script>
</body>
</html>
2.the javascript click function
//Click on objects
let onClick = function(event){
let canvas_ctx = document.getElementById("canvas").getContext("2d");
let canvasOffsetX = canvas_ctx.canvas.width/2;
let canvasOffsetY = canvas_ctx.canvas.height/2;
let mousePosX = event.clientX;
let mousePosY = event.clientY;
let mouseX =jsEngine.cameraFocus.x-canvasOffsetX/jsEngine.renderScale+(mousePosX)/jsEngine.renderScale;
let mouseY = jsEngine.cameraFocus.y+(canvasOffsetY)/jsEngine.renderScale+((-mousePosY)/jsEngine.renderScale);
console.log("sum to",mouseX,mouseY);
//My hashMap to place the mouse coordinates on the game map
let clickPosition = hm.find({x:mouseX,y:mouseY,width:1,height:1});
if(clickPosition.length===1){
let gameObject = jsEngine.gameObjects[clickPosition[0].range.id];
//console.log(gameObject.transform.x,gameObject.transform.y,mouseX,mouseY);
let clickBox = {};
let picture = gameObject.texture;
guiCreateClickBox(clickBox,gameObject.id,1200,500,picture);
}else if(clickPosition.length>1) {
for (let i = 0; i < clickPosition.length; i++) {
let gameObject = jsEngine.gameObjects[clickPosition[i].range.id];
if (gameObject instanceof PlayerShip|| gameObject instanceof Bullet)
continue;
let clickBox = {};
let picture = gameObject.texture;
guiCreateClickBox(clickBox,gameObject.id,1200,500,picture);
//console.log(gameObject.transform.x,gameObject.transform.y,mouseX,mouseY)
}
}
};
// Listeners
//Click on objects
document.getElementById("canvas").addEventListener("click", onClick);
the making of the map and scale :Note: this is done via onPreRender
function drawBackground(canvas_ctx, renderScale, imageResource) {
let img = imageResource.mapBackground;
let mapWidth = 1000000;
let mapHeight= 1000000;
let zoom = 1;
mapWidth *= renderScale / zoom;
mapHeight *= renderScale / zoom;
// Render the Background
canvas_ctx.fillStyle = canvas_ctx.createPattern(img, 'repeat');
canvas_ctx.scale(zoom, zoom);
canvas_ctx.fillRect(-mapWidth / 2, - mapHeight / 2, mapWidth, mapHeight);
//if (jsEngine.cameraFocus.x > 1000000) {}
canvas_ctx.scale(1/zoom, 1/zoom);
}
The rendering method used for playership
renderGameObject(gameObject) {
let x = gameObject.transform.x * this.renderScale;
let y = -(gameObject.transform.y * this.renderScale);
let rotation = Math.radians(gameObject.transform.rotation);
let width = gameObject.transform.width;
width *= this.renderScale;
let height = gameObject.texture.height;
height *= this.renderScale;
// Render the gameObject
this.canvas_ctx.translate(x, y);
this.canvas_ctx.rotate(rotation);
this.canvas_ctx.drawImage(gameObject.texture, 0, 0, width / this.renderScale, height / this.renderScale, // Make sure the image is not cropped
-width/2 , // X
-height/2 , // Y
width, height); // width and height
this.canvas_ctx.rotate(-rotation);
this.canvas_ctx.translate(-x, -y);
}
the issue to solve is to make it so that when you click on any given quadrant of the canvas it will return -+ for top left, -- bottom left , -+ topright, +- bottomright, as well as being applied to the render scale which at the moment is .1 so just divide your mouse and canvas coords like shown above and you should be able to get the same results.
Things to keep in mind :
the jsEngine.cameraFocus is set to the playerships x and y coordinates(which are set to the 0,0 posiiton on the map) (which are also in the middle of the ship)
the top left of the canvas is still 0,0 and ++ is still toward the bottom right so theoretically minusing half the canvas width/height then adding the offsets X and Y. this should be working but at my map coordinate -4000,-4000 i get ~-3620,-3295 and at +4000,+4000 I get 3500,3500. (The reason why the canvas 0,0 is not where the ship is , is to make the ship in the middle of the screen)
If you have questions about anything based on code that needs to be supplied please ask via comment . Please note if you have problems with the format of the code supplied I have nothing to say about it . all I need is the click function working on the canvas model i set up in cartesian format.
ps: jQuery is not a solution its a problem please use vanilla js.
I found out why it was off , my canvas has a offset of 90 px and 50 px as well as the main problem that the canvas is only 90% of its origonal size (also in css). If anyone can give me help for how to adjust to these issues please reply in comment . until then I beleieve I have solved my own issue .
I'm trying to simulate the speed of a progress bar. The progress bar displays the current progress in percentages (0-100). What I am trying to achieve is a function/modifier that takes will modify the actual progress, to have it slow in the beginning and faster toward the end (as it reaches a 100%)
So for example, if the actual progress is 5% lets say our modifier would modify it to 6%, and when progress reaches 20% lets say our modifier modifies it to 35% and at 60% our modifier reports 80%....till it reaches a 100
So, its barely modifying in the beginning but steadily increasing in velocity toward the end...
I'm not sure how to approach this, I cannot tween because I don't have a time frame I can tween against. I imagine I'd have to apply a mathematical function that would modify the value on the go. The following does not work, but I'm adding it here just to illustrate my point:
console.clear()
let updated = 0;
for(i=0; i <= 100; i++){
updated = (1 - Math.pow(i/101,2))
console.log(i + updated)
}
I appreciate any direction about how to approach this. Thank you
Here are two ways.
var i = 0;
setInterval(function() {
if (i <= 100) {
updated = i * (Math.log10(i) / 2);
document.getElementById("bar1").style.width = i + "%";
document.getElementById("bar2").style.width = (i * (Math.log10(i) / 2)) + "%";
document.getElementById("bar3").style.width = (i * i * i / 10000) + "%";
i++;
}
}, 50)
.container {
background: #ccc;
width: 50vw;
}
.bar {
background: #faa;
height: 1em;
width: 0%;
border-top: thin solid #ccc;
}
<div class="container">
<div id="bar1" class="bar">Linear</div>
<div id="bar2" class="bar"></div>
<div id="bar3" class="bar"></div>
</div>
Tweening functions are easier if you move between values of 0.0 and 1.0. This will allow for code similar to your's.
For example:
for (let i = 0; i <= 1; i += .1) {
console.log((i ** 2 *100).toFixed(2))
}
Accelerates quite quickly. Since 0 ** n is always 0 and 1 ** n is alway 1 you can freely pick exponents to change your speed while still keeping values between 0 and 1. :
0.00
1.00
4.00
9.00
16.00
25.00
36.00
49.00
64.00
81.00
100.00
Let's suppose you have an f function and you have a t repeat time in milliseconds, that is, the progress bar will do a step on every t. You can work like this:
var intervalID = setTimeout(f, t);
Now, let's think about how f looks like. If we want the progress bar to be slow at the beginning, but quicker at the end, then we need a function which is monotonously increasing in a steeper manner than a linear function. A linear complexity looks like this:
l(x) = aX + b
Its derivative is
l'(x) = a
which is a constant. We need a function which is increasing faster. Let's look at this function:
f(x) = x^2
f'(x) = 2x
So this will be good for you
function f() {
var result = x * x;
//Set progress bar to Math.min(result, 100)
if (result >= 100) clearInterval(intervalID);
}
So, for our project, we have to make a Wheel of Fortune game (based on the game show), and I made everything (like checking if the word was correct and everything) but I still don't know how to do the animations. What I have to animate is similar to what is in the attached picture. Our teacher told us that we can't use canvas, so I can't use .rotate(). So, does anyone have any ideas as to how this can be accomplished? Remember, I don't even need the wheel to actually rotate; it would work even if just the pictures were to change positions.
Here is the picture of a sample wheel (pretend the numbers are all pictures). I have stored all of the pictures in a single array that contains all of the pictures:
https://en.m.wikipedia.org/wiki/Wheel_of_Fortune_(U.S._game_show)#/media/File%3AWheel_of_Fortune_Round_1_template_Season_31.png
PS: For academic honesty purposes, I will not be able to post my code here.
Thank you for your time, everyone!
This is a very basic way of doing it: http://codepen.io/AaronGeorge/pen/zoOWagDead link
What you utilise is the CSS transform property and use the rotate value.
You'll need to do some math to work out how much you need to rotate the image, but transform: rotate(amount); will do the trick without using canvas.
The following example is a slight remake of How to Draw a Wheel of Fortune - without using HTML Canvas
Create an array of the sectors values, starting from right - clockwise.
Generate a random ang (in radians)
Animate CSS's rotate property using JS's Animations API at a random duration
Create a function getIndex() to get the prize sector index
Assign a "finish" Event listener to get the landed prize sector
const sectors = [
"500", "700", "BMB", "600", "550", "500", "600", "B",
"650", "FP", "700", "LAT", "800", "500", "650", "500",
"900", "B", "2500", "W", "600", "700", "600", "650",
];
// Generate random float in range min-max:
const rand = (m, M) => Math.random() * (M - m) + m;
const tot = sectors.length;
const elWheel = document.querySelector("#wheel");
const elAng = document.querySelector("#ang");
const PI = Math.PI;
const TAU = 2 * PI;
let arc = TAU / tot;
let ang = 0; // Angle rotation in radians
let isSpinning = false;
const imageAngOffset = -arc / 2;
// Get index of current sector
const getIndex = () => Math.floor(tot - (ang % TAU) / TAU * tot) % tot;
const spin = () => {
if (isSpinning) return; // Do nothing
isSpinning = true;
ang += rand(20, 30); // Generate random angle
const anim = elWheel.animate([{rotate: `${ang}rad`}], {
duration: rand(4000, 5000),
easing: "cubic-bezier(0.23, -0.16, 0.2, 1)",
fill: "both"
});
anim.addEventListener("finish", (event) => {
isSpinning = false;
ang += imageAngOffset; // Fix for image rotation offset (half arc)
const index = getIndex();
const value = sectors[index];
console.clear();
console.log(value);
});
};
elWheel.addEventListener("pointerdown", spin);
* {margin: 0;}
#wheel-wrapper {
overflow: hidden;
position: relative;
margin: auto;
width: 90vmin;
aspect-ratio: 1;
display: flex;
/* rotate: -0.25turn; */
}
#wheel {
position: relative;
margin: auto;
width: 90%;
aspect-ratio: 1;
background-image: url(https://i.stack.imgur.com/mcuwP.png);
background-size: cover;
border-radius: 50%;
}
#wheel-wrapper::after {
content: "";
position: absolute;
right: 0;
width: 10%;
background: red;
height: 1%;
transform: translateY(-50%);
top: 50%;
}
<div id="wheel-wrapper">
<div id="wheel"></div>
</div>
Since the rightmost starting sector is not at a perfect 0 degree in the image, don't forget to fix for this by subtracting half arc to the end degree radians ang (see in example above the use of imageAngleOffset).
To rotate the entire wheel wrapper by negative quarter turn (so that the needle stays at the top), uncomment this line in CSS: rotate: -0.25turn;
First of all - please do not remove this post.
It's not a duplicate.
I know it covers a problem that was mentioned here multiple times but this time it's not "how to detect collisions" because as you will see later, it's already done. It's more about "how to write" this in as much optimized way as possible, because below detection will be triggered multiple times in a short delay of time.
Here's my fiddle: http://jsfiddle.net/slick/81y70h1f/
I generate random squares and detect if they collide with each other.
HTML is generated using below way. No rocket science:
<?php for ($i=1; $i<=$amount; $i++) { ?>
<div id="square_<?= $i; ?>" class="square" style="top: <?= rand(0, 800); ?>px; left: <?= rand(0, 800); ?>px;">
<div>square_<?= $i; ?></div>
</div>
<?php } ?>
In the fiddle, $amount is set to 16. As you can imagine, the possible amount of unique pair combination is equal to:
In the fiddle you will see that I perform the uniqueness calculation twice. Second time just for squares that don't collide.
var squares_without_collision = $(squares).not(garbage).get();
pairs_cleaned = get_unique_pairs(squares_without_collision);
The pairs_cleaned is my final array when I will perform the secret operation that is not a part of this problem. This array will be always slightly reduced with unnecessary crap.
When I will increase $amount to 100 I will get 4950 possible combination. When I refresh page it still works fine but I can observe the speed drops down. I even didn't try to set it to 200 because I don't want my browser to crash.
Question - is here still any space of the improvement and optimization? Because now I will reveal that these squares will be Google Map markers and my collision calculation will be triggered on events when:
Tiles are loaded
Map is dragged
Zoom is changed
In the final version, instead of changing background from green to red, I will be showing or hiding markers. I'm worried, that with more markers I will do a turtle script. I would like to keep it extra fast.
Ok had a look and you have way over complicated it. No need to find the pairs, you are querying the DOM way to often. You should only touch the DOM once for each element. The garbage array is redundant use a semaphore. Never use each() in time critical code as it is very slow.
Always keep variables in function scope (inside the main function) because leaving them in global scope will half the access speed.
Arrays are slow and should be avoided at all costs. Reuse array items if you can. Always ask do you really need a new array? is there a way not to use an array?
Dont test where not needed. You have some garbage but you retest those squares.
Avoid function calls inside loops of time critical code. Calling a function is CPU intensive it is way better to have code inline.
Avoid indexing into arrays. Reference the array item once and use the reference.
Avoid JQuery unless you have a clear and justified reason. JQuery is VERY slow and encourages excessive DOM manipulation.
Think that's it. Below is your Fiddle modified that will run a lot faster.
$(function () {
var squares = []; // keep arrays in function scope as out side the function
var pairs_cleaned = []; // they are in global scope and run at half the speed.
var x1,y1;
squares = $('.square'); // get the squares
var len = squares.length;
console.log('----- Squares away ' + len + '------');
console.log(squares);
var width = 80+10; // you can do this get the size and padding from the first square
var height = 80+10; // if each square is a different size then you will have to change the code a little
for(var i = 0; i < len; i += 1){ // itterate them. Avoid using Each in time critical code as it is slow
var div = squares[i];
squares[i] = { // replace the existing array with a new object containing all we will need. This reuses the array and avoids overheads when growing an array.
square:div, // save the square. Not sure if you need it?
garbage:false, // flage as not garbage
x: x1 = Number(div.offsetLeft), // get the squares location
y: y1 = Number(div.offsetTop), // and ensure all values are Numbers
b: y1 + height, // I have only included the static height and width.
r: x1 + width,
};
}
var s1,s2;
for (var i = 0; i < len; i++) { // instead of calling the function to get an array of pairs, just pair them on the fly. this avoid a lot of overhead.
s1 = squares[i]; // reference the item once outside the loop rather than many times inside the next loop
for (var j = i + 1; j < len; j++) {
if(!squares[j].garbage){ // ignore garbage
s2 = squares[j];
// do the test inside the loop rather than call a function. This avoids a lot of overhead
if (s1.x > s2.r || s1.y > s2.b || s1.r < s2.x || s1.b < s2.y){ // do test
pairs_cleaned.push([s1,s2]); // if passed save unique pairs
}else{
s2.square.style.backgroundColor = '#ff0040'; // this should not be here is Very very slowwwwwwwww
s2.garbage = true; // garbage
}
}
}
}
console.log('----- all pairs without garbage ------');
console.log(pairs_cleaned);
});
OK. Hope that helps. It's been run and works on chrome. You will need to look at the querying of the elements for position and size but I did not think it important for this example.
There are other optimizations you can do but this should see you to around 1000 squares in realtime if you get rid of the s2.square.style.backgroundColor = '#ff0040'; from the inner loop. It is the slowest part of the whole collision test loop. DOM is death for fast code requirements. Always keep all DOM contact out of critical code sections.
One last thing. To get the best performance always use strict mode, it will give you 20%+ increased performance on most code.
You may consider implementing a simple collision grid for the task. That is, take a conceptual 2D grid spanning over the whole collision field, where each grid cell has a size greater than or equal to the maximum size of the colliding nodes, and bin the center points of each collision node in a data structure representing the grid.
From there, for each given collision node, you only need to check for collisions against other nodes placed in any of the adjacent grid cells to the current collision node's grid cell.
For example:
Say the width and height of your map is 1000px, and the collision nodes are represented in squares of 50x50 pixels. You choose to implement a 100px by 100px grid.
So you would first create a data structure that consists of a 2D array where each cell holds an array that will store collision objects:
var gridSize = { w: 1000, h: 1000 }; // The predefined grid size
var blockSize = { w: 100, h: 100 }; // The predefined block size
var collisionGrid = [];
// Initialize a grid of blockSize blocks to fill the gridSize
var x, y, gridX, gridY;
for (x = 0; x < gridSize.w; x += blockSize.w) {
gridX = x/blockSize.w;
collisionGrid[gridX] = [];
for (y = 0; y < gridSize.h; y += blockSize.h) {
gridY = x/blockSize.h;
collisionGrid[gridX][gridY] = [];
}
}
Then, as you learn about the locations of collision nodes (fetched data from some API, for instance), you would populate the data structure with references to each of the collision nodes according to where it's center point is placed on the grid.
So a square collision node with { x: 726, y:211, w: 50, h:50 } would be placed like this:
var placeNode = function(node) {
var mid = {
x: node.x + node.w/2,
y: node.y + node.h/2
};
var cell = {
x: Math.floor(mid.x/blockSize.w),
y: Math.floor(mid.y/blockSize.h)
};
collisionGrid[cell.x][cell.y].push(node);
};
var node = { x: 726, y:211, w: 50, h:50 } // ...fetched from some API
placeNode(node);
After a few hundred or thousand nodes are placed in the grid (which takes very little overhead for each - just a division or two and pushing a reference to an array), checking for collisions for a given node is greatly reduced, since you only need to check for collisions against nodes in the current node's cell as well as the 8 adjacent cells.
In this example, nodes only within a 300x300px block will be checked against for a given node, but as the collision field size increases and the grid size/collision node sizes decrease, this technique can really shine.
In this blog post, I lightly explained the implementation of this kind of grid for collision for a game I was working on: http://blog.cheesekeg.com/prototype-just-the-basics-v0-2/
One thing to note is that there is a trade off here - when collision nodes move around, their corresponding references to moved from grid cell to grid cell as they travel over the grid. However, in the post I linked above, this fact doesn't cause any noticeable problems with performance when hundreds of collision nodes are moving about the grid.
As Brandon mentioned you are best to create some kind of grid to decrease the number of collisions that you actually detect.
I would suggest using plain javascript rather than jQuery for this if you really want the most performance but here is a jQuery solution I created.
var gridDimensions = {
x: 800,
y: 800
};
var boxDimensions = {
x: 80,
y: 80
};
var hashes = hashSquares($('.square'), gridDimensions, boxDimensions);
function hashSquares($squares, dimensions, squaresDimensions) {
var squaresHash = [];
for (var i = 0; i < Math.floor(dimensions.x / squaresDimensions.x); i++) {
var yHashes = Array(Math.floor(dimensions.y / squaresDimensions.y));
for (var j = 0; j < yHashes.length; j++) {
yHashes[j] = [];
}
squaresHash.push(yHashes);
}
$squares.each(function() {
var $this = $(this);
squaresHash[Math.floor($this.position().left / squaresDimensions.x)][Math.floor($this.position().top / squaresDimensions.y)].push($this);
});
return squaresHash;
}
function checkSameSquare(x, y, hash) {
//if they are both in the same hash square they definitely overlap
if (hash[x][y].length > 1) {
$.each(hash[x][y], function(i, $el) {
//skip the first element
if (i !== 0) {
$el.addClass('collided');
}
});
}
}
function checkSquareBelow(x, y, hash) {
$.each(hash[x][y], function(i, $el) {
$.each(hash[x][y + 1], function(i2, $el2) {
if (detectCollision($el, $el2)) {
$el2.addClass('collided');
}
});
});
}
function checkSquareRight(x, y, hash) {
$.each(hash[x][y], function(i, $el) {
$.each(hash[x + 1][y], function(i2, $el2) {
if (detectCollision($el, $el2)) {
$el2.addClass('collided');
}
});
});
}
function checkSquareDiagonalRightBelow(x, y, hash) {
$.each(hash[x][y], function(i, $el) {
$.each(hash[x + 1][y + 1], function(i2, $el2) {
if (detectCollision($el, $el2)) {
$el2.addClass('collided');
}
});
});
}
function detectCollision($div1, $div2) {
var x1 = $div1.offset().left;
var y1 = $div1.offset().top;
var h1 = $div1.outerHeight(true);
var w1 = $div1.outerWidth(true);
var b1 = y1 + h1;
var r1 = x1 + w1;
var x2 = $div2.offset().left;
var y2 = $div2.offset().top;
var h2 = $div2.outerHeight(true);
var w2 = $div2.outerWidth(true);
var b2 = y2 + h2;
var r2 = x2 + w2;
if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
return true;
}
for (var i = 0; i < hashes.length; i++) {
for (var j = 0; j < hashes[i].length; j++) {
checkSameSquare(j, i, hashes);
if (j < hashes[i].length - 1) {
checkSquareRight(j, i, hashes);
}
if (i < hashes.length - 1) {
checkSquareBelow(j, i, hashes);
}
if (j < hashes[i].length - 1 && i < hashes.length - 1) {
checkSquareDiagonalRightBelow(j, i, hashes);
}
}
}
body {
margin: 10px;
font-family: Arial, sans-serif;
}
#container {
background-color: #cccccc;
height: 880px;
position: relative;
width: 880px;
}
.square {
background-color: lawngreen;
height: 80px;
position: absolute;
width: 80px;
z-index: 10;
}
.square > div {
font-size: 12px;
padding: 5px;
}
.square:hover {
background-color: forestgreen;
z-index: 11;
cursor: pointer;
}
.collided {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="square_1" class="square" style="top: 31px; left: 141px;">
<div>square_1</div>
</div>
<div id="square_2" class="square" style="top: 56px; left: 726px;">
<div>square_2</div>
</div>
<div id="square_3" class="square" style="top: 555px; left: 391px;">
<div>square_3</div>
</div>
<div id="square_4" class="square" style="top: 725px; left: 330px;">
<div>square_4</div>
</div>
<div id="square_5" class="square" style="top: 398px; left: 642px;">
<div>square_5</div>
</div>
<div id="square_6" class="square" style="top: 642px; left: 794px;">
<div>square_6</div>
</div>
<div id="square_7" class="square" style="top: 521px; left: 187px;">
<div>square_7</div>
</div>
<div id="square_8" class="square" style="top: 621px; left: 455px;">
<div>square_8</div>
</div>
<div id="square_9" class="square" style="top: 31px; left: 549px;">
<div>square_9</div>
</div>
<div id="square_10" class="square" style="top: 677px; left: 565px;">
<div>square_10</div>
</div>
<div id="square_11" class="square" style="top: 367px; left: 120px;">
<div>square_11</div>
</div>
<div id="square_12" class="square" style="top: 536px; left: 627px;">
<div>square_12</div>
</div>
<div id="square_13" class="square" style="top: 691px; left: 312px;">
<div>square_13</div>
</div>
<div id="square_14" class="square" style="top: 93px; left: 757px;">
<div>square_14</div>
</div>
<div id="square_15" class="square" style="top: 507px; left: 720px;">
<div>square_15</div>
</div>
<div id="square_16" class="square" style="top: 251px; left: 539px;">
<div>square_16</div>
</div>
</div>
http://jsfiddle.net/81y70h1f/13/
Notice you only have to test collisions against the same square the square immediately to the right to the bottom right and below as all other collisions are already handled as you move along the grid.
var Y = 0.2; // Motion step
var X = 0.6;
(function go(){
$('#m').animate({
left: '+='+(X) ,
top: '+='+(Y)
}, 30, 'linear', go);
}());
Move an element diagonally but not under 45° (Y=1, X=1), rather by steps of a floated number.
Mozilla plays well, but all other browser won't move an element by a decimal px value.
What approach would you use?
Instead of trying to do it through recursion, why not set the left and top values as integers and do it in one animate() call. This way you don't have to deal with floating point numbers and it should still animate diagonally.
var Y = 20; // cannot be >1
var X = 60; // cannot be >1
function go(){
$('#m').animate({
left: '+='+(X) ,
top: '+='+(Y)
}, 300, 'linear');
}
go();
A pixel is, by definition, the smallest element that can be displayed (or not displayed) at the current screen resolution. You can use % and I believe it will work cross browser eg width: 45.5%, but pixels no. In addition you may not even notice the movement that small.
The issue is that when you're setting left and top they're getting rounded to pixels. You're seeing 45-degree motion because both X and Y get rounded to 1.
Why don't you increment two JS variables (which can store floating-point numbers) and then set left and top equal to them at the appropriate time (so the rounding will occur on the sum and not on the increment)?
var Y = 0.2; // cannot be >1
var X = 0.6; // cannot be >1
var cur_left = $('#m').left;
var cur_top = $('#m').top;
function go(){
cur_left += X;
cur_top += Y;
$('#m').animate({
left: '='+(cur_left),
top: '='+(cur_top)
}, 30, 'linear', go);
}
go();