I'm eleven and new to programming, and I'm making a simple platformer for a game comp at my school using javascript.
Right now I'm working on the code that makes the character jump. It's more complex than the character just going up and then down, because I want the movements to be fluent and look realistic. When the character jumps, it leaves the ground fast, then slows down as it goes higher, and when it reaches a certain point, it will start to fall slowly. It will speed up as it falls (probably by using some type of acceleration variable), and then hit the ground and stop completely.
I want the character to be able to move left and right in the air, and if the key is held, jump once, and then when the character hits the ground, if the key is still held, to jump again. (the in-game character should be able to jump quite high)
I've tried to do this already, but I had some hilarious errors happening.
Here's my (very broken) code:
//movement (x)
var maxSpeed = 12.5;
var xForce = 0;
var kingXPos = 0;
//movement (y)
var yForce = 0;
var kingYPos = 202;
//LV design
var floorHeight = 150;
var draw = function() {
//background and basics
background(255, 0, 0);
image(getImage("creatures/Winston"), kingXPos, kingYPos, 50, 50);
//level features (only the floor right now)
fill(0, 0, 0);
rect(0, 250, 400, floorHeight);
//right movement
if (keyIsPressed && keyCode === RIGHT) {
kingXPos = kingXPos + xForce;
xForce = xForce + 0.25;
if (xForce >= maxSpeed && keyIsPressed) {
xForce = maxSpeed;
}
}
//left movement
if (keyIsPressed && keyCode === LEFT) {
kingXPos = kingXPos + xForce;
xForce = xForce - 0.25;
if (xForce <= -maxSpeed && keyIsPressed) {
xForce = -maxSpeed;
}
}
//jump (not yet functional)
if (keyTyped && keyCode === UP && kingYPos === floorHeight + 50) {
kingYPos = kingYPos + yForce;
yForce = yForce - 0.5;
}
//other physics
if (!keyIsPressed) {
kingXPos = kingXPos + xForce;
if (xForce > 0) {
xForce = xForce - 0.25;
}
else if (xForce < 0) {
xForce = xForce + 0.25;
}
}
};
That's fairly impressive for someone just starting. You seem to have an intuitive understanding of geometry. However, there are some domain knowledge you may not be aware of due to how much education you've had.
In physics, the correct set of equations that describes motion is:
1. velocity = change_in_location / time
2. acceleration = change_in_velocity / time
Another thing you need to be aware of is that gravity is a form of acceleration. Specifically it is a downward acceleration of 9.8m/s/s
So rewriting all of the above:
new_location = (velocity * time) + old_location
new_velocity = (acceleration * time) + old_velocity
If you assume a constant time animation loop you can assume that time = 1. So that simplifies it to:
new_location = velocity + old_location
new_velocity = acceleration + old_velocity
This is enough to simulate gravity. Since gravity is just an acceleration:
gravity = SOME_NUMBER; // tune this to get the gravity you want
kingYPos = kingYPos + kingYVelocity;
kingYVelocity = kingYVelocity + gravity;
To jump just give the object an instant boost in velocity:
// jump:
kingYVelocity = -SOME_OTHER_NUMBER; // negative because "up"
Note: Domain knowledge is knowledge outside of programming that a programmer must understand in order to solve a particular problem. For example, a programmer who writes an accounting software should have some knowledge of accounting. In practice, not all programmers in the industry make the effort to acquire domain knowledge because sometimes there's a systems analyst/consultant writing the requirements for the software. But when you write your own software you have no choice but to acquire some domain knowledge.
Related
So, I am currently reinventing the wheel (and learning a lot) by trying my hand at making a simple physics engine for my game engine. I have been searching the internet, trying (and failing) to fix my current problem. There are a lot of resources out there on the subject, but none of those that I have found seem to apply to my case.
THE PROBLEM IN SHORT: The collision resolution does not work as intended on some of the corners when two rectangles are colliding. How it fails varies based on the dimensions of the rectangles. What I am looking for is a "shortest overlap" kind of resolution for the collision or another fairly simple solution (I am open for suggestions!). (Scroll down for a better explaination and illustrations).
WARNING: The following code is probably not very efficient...
First of all, here is my physics loop. It simply loops through all of the game entities and checks if they collide with any other game entities. It is not efficient (n^2 and all of that), but it works for now.
updatePhysics: function(step) {
// Loop through entities and update positions based on velocities
for (var entityID in Vroom.entityList) {
var entity = Vroom.entityList[entityID];
if (entity.physicsEnabled) {
switch (entity.entityType) {
case VroomEntity.KINEMATIC:
entity.pos.x += entity.vel.x * step;
entity.pos.y += entity.vel.y * step;
break;
case VroomEntity.DYNAMIC:
// Dynamic stuff
break;
}
}
}
// Loop through entities and detect collisions. Resolve collisions as they are detected.
for (var entityID in Vroom.entityList) {
var entity = Vroom.entityList[entityID];
if (entity.physicsEnabled && entity.entityType !== VroomEntity.STATIC) {
for (var targetID in Vroom.entityList) {
if (targetID !== entityID) {
var target = Vroom.entityList[targetID];
if (target.physicsEnabled) {
// Check if current entity and target is colliding
if (Vroom.collideEntity(entity, target)) {
switch (entity.collisionType) {
case VroomEntity.DISPLACE:
Vroom.resolveTestTest(entity, target);
break;
}
}
}
}
}
}
}
},
Here is the code for the actual collision detection. This also seems to work alright.
collideEntity: function(entity, target) {
if (entity.getBottom() < target.getTop() || entity.getTop() > target.getBottom() || entity.getRight() < target.getLeft() || entity.getLeft() > target.getRight()) {
return false;
}
return true;
},
Here is where the problems start to pop up. I want the entity to simply be "pushed" out of the target entity and have the velocity set to 0. This works fine as long as both the entity and the target are perfect squares. If let's say the entity (the player figure in the gif) is a rectangle, then the collision will "slipp" when colliding the longest sides (the X axis) with the target (the square). If I swap the player dimensions so that it is short and wide, then the same problem appears for the Y axis instead.
resolveTestTest: function(entity, target) {
var normalizedX = (target.getMidX() - entity.getMidX());
var normalizedY = (target.getMidY() - entity.getMidY());
var absoluteNormalizedX = Math.abs(normalizedX);
var absoluteNormalizedY = Math.abs(normalizedY);
console.log(absoluteNormalizedX, absoluteNormalizedY);
// The collision is comming from the left or right
if (absoluteNormalizedX > absoluteNormalizedY) {
if (normalizedX < 0) {
entity.pos.x = target.getRight();
} else {
entity.pos.x = target.getLeft() - entity.dim.width;
}
// Set velocity to 0
entity.vel.x = 0;
// The collision is comming from the top or bottom
} else {
if (normalizedY < 0) {
entity.pos.y = target.getBottom();
} else {
entity.pos.y = target.getTop() - entity.dim.height;
}
// Set velocity to 0
entity.vel.y = 0;
}
},
Collision on the Y axis works with these shapes
Collision on the X axis slips with these shapes
What can I do to fix this slipping problem? I have been bashing my head against this for the last 5 days, so I would be immensely grateful if some one could help push me in the right direction!
Thank you :)
-- EDIT: --
The slipping also happens if only moving in one direction along the left or right side.
-- EDIT 2 WORKING CODE: --
See my answer below for an example of the working code!
The important logical error you have made is this line:
if (absoluteNormalizedX > absoluteNormalizedY) {
This only works if both entities are square.
Consider a near-extremal case for your X-slipping example: if they almost touch at the corner:
Although the diagram is a little exaggerated, you can see that absoluteNormalizedX < absoluteNormalizedY in this case - your implementation would move on to resolve a vertical collision instead of the expected horizontal one.
Another error is that you always set the corresponding velocity component to zero regardless of which side the collision is on: you must only zero the component if is it in the opposite direction to the collision normal, or you won't be able to move away from the surface.
A good way to overcome this is to also record the collided face(s) when you do collision detection:
collideEntity: function(entity, target) {
// adjust this parameter to your liking
var eps = 1e-3;
// no collision
var coll_X = entity.getRight() > target.getLeft() && entity.getLeft() < target.getRight();
var coll_Y = entity.getBottom() > target.getTop() && entity.getTop() < target.getBottom();
if (!(coll_X && coll_Y)) return 0;
// calculate bias flag in each direction
var bias_X = entity.targetX() < target.getMidX();
var bias_Y = entity.targetY() < target.getMidY();
// calculate penetration depths in each direction
var pen_X = bias_X ? (entity.getRight() - target.getLeft())
: (target.getRight() - entity.getLeft());
var pen_Y = bias_Y ? (entity.getBottom() - target.getUp())
: (target.getBottom() - entity.getUp());
var diff = pen_X - pen_Y;
// X penetration greater
if (diff > eps)
return (1 << (bias_Y ? 0 : 1));
// Y pentration greater
else if (diff < -eps)
return (1 << (bias_X ? 2 : 3));
// both penetrations are approximately equal -> treat as corner collision
else
return (1 << (bias_Y ? 0 : 1)) | (1 << (bias_X ? 2 : 3));
},
updatePhysics: function(step) {
// ...
// pass collision flag to resolver function
var result = Vroom.collideEntity(entity, target);
if (result > 0) {
switch (entity.collisionType) {
case VroomEntity.DISPLACE:
Vroom.resolveTestTest(entity, target, result);
break;
}
}
// ...
}
Using a bit flag instead of a boolean array for efficiency. The resolver function can then be re-written as:
resolveTestTest: function(entity, target, flags) {
if (!!(flags & (1 << 0))) { // collision with upper surface
entity.pos.y = target.getTop() - entity.dim.height;
if (entity.vel.y > 0) // travelling downwards
entity.vel.y = 0;
}
else
if (!!(flags & (1 << 1))) { // collision with lower surface
entity.pos.y = target.getBottom();
if (entity.vel.y < 0) // travelling upwards
entity.vel.y = 0;
}
if (!!(flags & (1 << 2))) { // collision with left surface
entity.pos.x = target.getLeft() - entity.dim.width;
if (entity.vel.x > 0) // travelling rightwards
entity.vel.x = 0;
}
else
if (!!(flags & (1 << 3))) { // collision with right surface
entity.pos.x = target.getRight();
if (entity.vel.x < 0) // travelling leftwards
entity.vel.x = 0;
}
},
Note that unlike your original code, the above also allows corners to collide - i.e. for velocities and positions to be resolved along both axes.
MY WORKING CODE
So with some help and guidance from the amazing #meowgoesthedog I finally got on the right track and found what I was looking for. The problem (as #meowgoesthedog pointed out) was that my code was really only going to work with squares. The solution was to check the intersection of the colliding bodies and solve based on the shortest intersection. Note: this will probably not be a suitable solution if you need accurate physics with small and fast moving objects. The code for finding the intersection depth is based on this: https://github.com/kg/PlatformerStarterKit/blob/0e2fafb8dbc845279fe4116c37b6f2cdd3e636d6/RectangleExtensions.cs which is related to this project: https://msdn.microsoft.com/en-us/library/dd254916(v=xnagamestudio.31).aspx.
Here is my working code:
My physics loop has not been changed much, except for some better names for some functions.
updatePhysics: function(step) {
// Loop through entities and update positions based on velocities
for (var entityID in Vroom.entityList) {
var entity = Vroom.entityList[entityID];
if (entity.physicsEnabled) {
switch (entity.entityType) {
case VroomEntity.KINEMATIC:
entity.pos.x += entity.vel.x * step;
entity.pos.y += entity.vel.y * step;
break;
case VroomEntity.DYNAMIC:
// Dynamic stuff
break;
}
}
}
// Loop through entities and detect collisions. Resolve collisions as they are detected.
for (var entityID in Vroom.entityList) {
var entity = Vroom.entityList[entityID];
if (entity.physicsEnabled && entity.entityType !== VroomEntity.STATIC) {
for (var targetID in Vroom.entityList) {
if (targetID !== entityID) {
var target = Vroom.entityList[targetID];
if (target.physicsEnabled) {
// Check if current entity and target is colliding
if (Vroom.collideEntity(entity, target)) {
switch (entity.collisionType) {
case VroomEntity.DISPLACE:
Vroom.resolveDisplace(entity, target);
break;
}
}
}
}
}
}
}
},
The collision detection remains the same as well.
collideEntity: function(entity, target) {
if (entity.getBottom() < target.getTop() || entity.getTop() > target.getBottom() || entity.getRight() < target.getLeft() || entity.getLeft() > target.getRight()) {
return false;
}
return true;
},
Here is the code that basically fixes the problem. The comments in the code should explain what it does pretty well.
getIntersectionDepth: function(entity, target) {
// Calculate current and minimum-non-intersecting distances between centers.
var distanceX = entity.getMidX() - target.getMidX();
var distanceY = entity.getMidY() - target.getMidY();
var minDistanceX = entity.halfDim.width + target.halfDim.width;
var minDistanceY = entity.halfDim.height + target.halfDim.height;
// If we are not intersecting at all, return 0.
if (Math.abs(distanceX) >= minDistanceX || Math.abs(distanceY) >= minDistanceY) {
return {
x: 0,
y: 0,
};
}
// Calculate and return intersection depths.
var depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
var depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
return {
x: depthX,
y: depthY,
};
},
Here is the updated resolving function. It now takes intersection depth in to account when determining axis of collision and then uses the sign of the intersection depth for the colliding axis when determining the direction to resolve.
resolveDisplace: function(entity, target) {
var intersection = Vroom.getIntersectionDepth(entity, target);
if (intersection.x !== 0 && intersection.y !== 0) {
if (Math.abs(intersection.x) < Math.abs(intersection.y)) {
// Collision on the X axis
if (Math.sign(intersection.x) < 0) {
// Collision on entity right
entity.pos.x = target.getLeft() - entity.dim.width;
} else {
// Collision on entity left
entity.pos.x = target.getRight();
}
entity.vel.x = 0;
} else if (Math.abs(intersection.x) > Math.abs(intersection.y)) {
// Collision on the Y axis
if (Math.sign(intersection.y) < 0) {
// Collision on entity bottom
entity.pos.y = target.getTop() - entity.dim.height;
} else {
// Collision on entity top
entity.pos.y = target.getBottom();
}
entity.vel.y = 0;
}
}
},
Thank you all for your help!
The problem may be that you're correcting both X and Y collision based on the same position:
Player is at a certain position. Let's check collision.
Player's bottom right corner overlaps top left corner of object.
X position is corrected: Player is moved to the left.
Player's bottom right corner overlaps top left corner of object.
Y position is corrected: Player is moved up.
End result: The player is moved up and to the left.
You probably need to "get" the player's position again, between checks.
I don't know a lot about JS, but i have to do assignments with it. right now i have a ball that bounces from one side of the screen to the other. with every bounce the colour of the screen and the ball change. but i'd like a slight increase of speed with every bounce as well(or a random speed every time it bounces if that's easier). this is the code I have for moving, the bouncing and the colour changing now:
fill(r,g,b);
ellipse(circleX, circleY, circleSize, circleSize);
circleX += moveX;
if (circleX > width - circleSize / 2 || circleX < circleSize / 2) {
moveX = -moveX;
r = random(255);
g = random(255);
b = random(255);
}
moveX is always 5 now and changes to -5 when turning back. but i'd like it if it turned into -6 and then +7 when going forward again. or something like that at least.
I thank you guys in advance for helping me and please explain it like you're explaining it to a child.
First, lets make a function which takes a number and returns +1 for non-negative numbers (positive or 0) and -1 for negative numbers, i.e. it's sign
function sign(x) {
if (x < 0) return -1;
return 1;
}
A full implementation of sign would have a special case for 0, and is available natively in ES6
Next, when it becomes time to change moveX separate it's magnitude (absolute value) and sign, increment it's magnitude and put the two pieces back together again before flipping the sign over
moveX = -sign(moveX) * (Math.abs(moveX) + 1);
You'll want to add another test inside your collision detection code to increase the speed. If the velocity is positive, then you want to add 1. If the velocity is negative, you want to subtract 1. Your code would look something like this...
...
moveX = -moveX
if (moveX < 0) {
--moveX;
} else {
++moveX;
}
...
Keep track of how many times the circle has "bounced" and add it to the speed.
var base_speed = 5;
var bounces = 0;
var direction = 1; //positive for moving right, negative for moving left
var moveX = base_speed + bounces * direction;
circleX += moveX;
if (circleX > width - circleSize / 2 || circleX < circleSize / 2) {
direction = -direction;
bounces++;
r = random(255);
g = random(255);
b = random(255);
}
I’m fairly new to web development and I’ve only ever used jQuery to write my scripts. Today however, I’d like to improve my skills and build a little game that could be used on a smartphone as a web app in vanilla JS.
The game’s pretty straightforward:
You hold your phone in portrait mode and control a character that stays at the bottom of the screen and has to dodge objects that are falling on him. The character can only move left or right and thus always stays on the same x-axis. In order to control him, your finger has to stay on the screen. Once you take it off, you lose. Also, the move isn’t triggered by tapping the screen, but by moving your finger left or right.
For now, I’ve only been experimenting to get the hang of touchevents and was able to make the character move when swiping:
document.addEventListener('touchmove',function(e){
e.preventDefault(); //disable scroll
var board = document.getElementById(‘board);
var character = document.getElementById(‘character’);
if (e.targetTouches.length === 1) {
var touch = e.targetTouches[0];
board.classList.add(‘moving’);
character.style.left = touch.pageX + 'px';
}
}, false);
(The ‘moving’ class is used to move the background-position of the board and animate the character’s sprite in plain CSS.)
Separately, I made a little script that puts objects with random classes in a container with a set interval. These objects are then animated in css and fall from the top to the bottom of the screen.
Now, here comes the tricky part: the collision detection.
As I said, I’m new to development and vanilla JS, so I searched a bit to figure out how to detect when two objects collide, and it seems that most tutorials do this using canvases. The thing is, I’ve never used them and they scare me quite a bit. What’s more, I think it would render what I’ve done so far useless.
I’m okay with trying the canvas way, but before I do, I’d like to know if there’s any other way to detect if two moving objects collide?
Also, if there turns out to be no real way to do this without canvas, I plan on using this tutorial to learn how to build the app. However, this game wasn’t built for touchscreen devices, and the spaceship’s position changes on certain keystrokes (left & right) :
function update() {
if (keydown.left) {
player.x -= 5;
}
if (keydown.right) {
player.x += 5;
}
player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}
My question is: how should I do to update the position using touchmove instead of keystrokes?
Thank you all in advance.
1) the idea : 'if you stop touching, you loose', is just a bad idea, drop it.
2) most convenient way to control is to handle any touch event (touch start/move/end/cancel), and to have the character align on the x coordinate of this event.
3) the intersection test is just a basic boundig box intersection check.
I made a very basic demo here, that uses touch, but also mouse to ease testing :
http://jsbin.com/depo/1/edit?js,output
a lot of optimisations are possible here, but you will see that touches adjust the ship's position, and that collisions are detected, so it will hopefully lead you to your own solution
Edit : i added default to 0 for left, top, in case they were not set.
boilerplate code :
var collisionDisplay = document.getElementById('collisionDisplay');
// hero ship
var ship = document.getElementById('ship');
ship.onload = launchWhenReady ;
// bad ship
var shipBad = document.getElementById('shipBad');
shipBad.onload = launchWhenReady ;
// image loader
imagesCount = 2 ;
function launchWhenReady() {
imagesCount --;
if (imagesCount) return;
setInterval(animate, 20);
}
var shipBadY = 0;
touch events :
// listen any touch event
document.addEventListener('touchstart', handleTouchEvent, true);
document.addEventListener('touchmove', handleTouchEvent, true);
document.addEventListener('touchend', handleTouchEvent, true);
document.addEventListener('touchcancel', handleTouchEvent, true);
// will adjust ship's x to latest touch
function handleTouchEvent(e) {
if (e.touches.length === 0 ) return;
e.preventDefault();
e.stopPropagation();
var touch = e.touches[0];
ship.style.left = (touch.pageX - ship.width / 2) + 'px';
}
animation :
// animation loop
function animate() {
// move ship
shipBadY += 1;
shipBad.style.top = Math.ceil(shipBadY) + 'px';
// test collision
var isColliding = testCollide(shipBad);
collisionDisplay.style.display = isColliding ? 'block' : 'none';
}
collision :
// collision test when the enemy and the ship are images
function testCollide(enemi) {
var shipPosX = parseInt(ship.style.left) || 0 ;
var shipPosY = parseInt(ship.style.top) || 0 ;
var shipWidth = ship.width ;
var shipHeight = ship.height;
var badX = parseInt(enemi.style.left) || 0 ;
var badY = parseInt(enemi.style.top) || 0 ;
var badWidth = enemi.width;
var badHeight = enemi.height;
return bBoxIntersect(shipPosX, shipPosY, shipWidth, shipHeight,
badX, badY, badWidth, badHeight);
}
EDIT : in case you're not using images :
// collision test when the enemy and the ship are ** NOT ** images
function testCollide(o) {
var characterPosX = parseInt(character.style.left);
var characterPosY = parseInt(character.style.top);
var characterWidth = parseInt(character.style.width);
var characterHeight = parseInt(character.style.height);
var obstacleX = parseInt(o.style.left) || 0 ;
var obstacleY = parseInt(o.style.top) || 0 ;
var obstacleWidth = parseInt(o.style.width);
var obstacleHeight = parseInt(o.style.height);
return boundingBoxIntersect(characterPosX, characterPosY, characterWidth, characterHeight, obstacleX, obstacleY, obstacleWidth, obstacleHeight);
}
function bBoxIntersect(x1, y1, w1, h1, x2, y2, w2, h2) {
return !(x1 + w1 < x2 || x1 > x2 + w2 || y1 + h1 < y2 || y1 > y2 + w2);
}
mouse events :
// -----------------------------------------------------
// Handle mouse event for easy testing on Browser
document.addEventListener('mousemove', handleMouseEvent);
function handleMouseEvent(e) {
ship.style.left = (e.pageX - ship.width / 2) + 'px';
}
http://jsfiddle.net/5DB6K/
I have this game being made where you shoot enemies from the sides of the screen. I've got the bullets moving and being removed when they reach the end of the screen (if they didn't hit any enemy) and removing the enemy when they collide with it.
//------------collision----------------//
if(shot === true){
bulletY = $('.bullet').position().top + 2;
bulletX = $('.bullet').position().left + 2;
$('.enemy').each(function(){
if($('.enemy').hasClass('smallEnemy')){
enemyY = $(this).position().top + 7;
enemyX = $(this).position().left + 7;
if(Math.abs(bulletY - enemyY) <= 9 && Math.abs(bulletX - enemyX) <=9){
$(this).remove();
score = score + 40;
bulletDestroy();
}
}
});
}
However, the bullet destroys every enemy if the collision check is right which isn't what I want. I want to check if the enemy has the class of either smallEnemy, medEnemy, or lrgEnemy and then do the collision check which is what I thought I had but it doesn't seem to work.
Also, the game starts to lag the more and more time goes on. Would anyone know the reason for that?
This will remove all enemies any time a small enemy is present, due to your .each conditions. Try this:
if($(this).hasClass('smallEnemy')){
enemyY = $(this).position().top + 7;
enemyX = $(this).position().left + 7;
if(Math.abs(bulletY - enemyY) <= 9 && Math.abs(bulletX - enemyX) <=9){
$(this).remove();
score = score + 40;
bulletDestroy();
}
As for lag, it's due to memory availability and overhead. Instead of looping through your "enemeies", I would attach an observer to your bullets, and whenever they intersect with .enemy you should fire a custom event to remove this enemey. Much less code too.
I'm working on a simple html5 platformer, building of a previous game but having trouble with collisions and physics. below is a sample of code regarding the floor and how it handles collisions. the full code is here. http://www.ambitiongames.co.uk/dev/game.php with the game being here http://www.ambitiongames.co.uk/dev/
the problem I'm having is the collisions are based on events grabbing which sometimes leaves the player in the floor not on it.
also, due to the way jumping and falling work there's no gravity, meaning a player can simply jump on a higher ledge and then walk off into the air.
whats the a good way to set up a permanent state of gravity ?
whats a good way to interact / collide with the floor or other objects ?
that.draw = function(){
try {
ctx.drawImage(that.image, that.x, that.y, that.width, that.height);
} catch (e) {
}
}
return that;
};
var nrOffloors = 40,
floors = [],
floorWidth = 20,
floorHeight = 40;
var generatefloor = function(){
for (var i = 0; i < 10; i++) {
floors[i] = new Floor(i * 20,280);
}
for (var i = 10; i < 12; i++) {
floors[i] = new Floor(i * 20,260);
}
}();
var checkCollisionfloor = function(){
floors.forEach(function(e, ind){
if (
(player.X < e.x + floorWidth) &&
(player.X + player.width > e.x) &&
(player.Y + player.height > e.y) &&
(player.Y + player.height < e.y + floorHeight)
) {
e.onCollide();
}
});
}
You can try a library like Box2D.js. It handles everything from collision detection to gravity.
Check out it's demos.