I'm experimenting with HTML5 canvas scripting in JavaScript and am having an issue with 2D collision detection. I'm basically checking the coordinates of the "player" against the coordinates of a box I've placed on screen but a strange result is occurring. I know why it's happening, but I don't know how to solve the problem.
Some of my code:
function Arc()
{
// Coordinates.
this.x = 540 / 2;
this.y = 0;
// Radius
this.r = 50;
// Gravity / velicoty.
this.g = 3;
this.vy = 15;
// Bounce.
this.b = -0;
this.speed = 20;
this.max_speed = 20;
this.friction = 0.03444;
}
Arc.prototype.collision = function()
{
for(var i = 0; i < game.sprites.length; i++)
{
if
(
// If the right side of the player is greater than the left side of the object.
this.x + this.r > game.sprites[i].x &&
// If the bottom of the player is greater than (meaning lower than) the top of the object.
this.y + this.r > game.sprites[i].y &&
// If the left side of the player is greater than the right side of the object.
this.x - this.r < game.sprites[i].x + game.sprites[i].w &&
// if the top of the player is greater than (meaning lower than) the bottom of the object.
this.y - this.r < game.sprites[i].y + game.sprites[i].h
)
{
this.y = game.sprites[i].y - this.r;
this.vy *= this.b;
}
}
}
The anomaly is that when I move the player sprite over the left or right of the box, it jumps upwards on the Y-axis because the logical check above is always true. Obviously this is unexpected because the sprite should only interact with the top of the box if a jump has occurred.
Note: I'm not looking for a solution that adds collision to the sides of the box only (that's very simple). Rather, I'm looking for the solution that allows for collision on all sides of the box (including the top) in the same way it currently works but without the anomaly where the sprite suddenly jumps on top of the box upon touching it.
I've reproduced my entire project on JSFiddle for the purposes of demonstration (keys a, d and space bar): http://jsfiddle.net/h5Fun/
Whether or not this is what you want, it solves the problem:
this.x = game.sprites[i].x + 150;
this.vx *= this.b;
The issue was you were setting the incorrect component upon collision. If you want the circle to stop when it hits the rectangle, not go on top of it, then use x, not y.
150 is the size of the rectangle. This means it will stop at the right side of the sprite. The bouncing is already there due to modifying the velocity (this.vx).
Related
I have created the collision check function for my player to every time when the object (in this case vector - circle) touches the player (also a vector - circle) the game is over.
I have managed to create a logic and there is a collision check working, however it's not calculating the actual distance between elements (instead of ending game when they actually touch its ending when they are some distance from each other.
Both objects are moving - obstacle is moving x+=6 and the player is following the coursor so the speed varies.
I have tried adjusting distance slightly and I have managed to end the game when the x of obstacle is touch x of the player but could not managed actually to when boarders touch. I attach the code I have below;
class Player {
constructor(x, y, r) {
this.pos = createVector(x, y);
this.r = r;
this.vel = createVector(500, 500);
this.mag = 3;
this.velLerp = 0.1;
}
update() {
let mouse = createVector(mouseX - width / 2,
mouseY - height / 2);
mouse.setMag(this.mag);
this.vel.lerp(mouse, this.velLerp);
this.pos.add(this.vel);
collisionCheck(obstacle) {
let d = p5.Vector.dist(this.pos, obstacle.pos);
if (d < this.r + obstacle.r) {
console.log("GAME OVER");
return true;
}
The issue is caused by the fact that the movement of the circles is 3 (this.mag) pixel. You just get the exact point of contact by chance. Most time they are intersecting.
If a collision is detected, change the player's position slightly by an offset of this.r + obstacle.r - d:
collisionCheck(obstacle) {
let d = p5.Vector.dist(this.pos, obstacle.pos);
if (d < this.r + obstacle.r) {
let shift = p5.Vector.sub(this.pos, obstacle.pos);
shift.setMag(this.r + obstacle.r - d);
this.pos.add(shift);
console.log("GAME OVER");
return true;
}
}
I am trying to recreate the google-chrome offline Dino game.
In this game the Dino has a gravity-pull on himself and it has a jump velocity, an upwards speed applied when the user presses the space bar.
Over time the obstacles move faster and faster to the player.
When the obstacles move faster the Dino's jump should also be faster.
I tried to make a faster jump by increasing the gravity over time, so the Dino gets pulled down faster. But how do I get the Dino to jump the same height, let's say, 50 pixels upwards, no matter what the gravity is.
I tried working with the formula's:
y = 0.5*a*t^2 + v(0)*t
But I can't come to a correct answer.
The canvas this code is working as regards the top left corner as the origin(0,0). Therefore the jump velocity is negative and the gravity is positive.
This code is inside the Dino class, where this references to the Dino.
In the constructor of the Dino class I have the code
this.y = 0;
this.vy = 0;
this.gravity = 1;
this.speed = 0;
In the update function that is called each x amount of time:
this.speed += 0.001;
this.y += this.vy;
this.vy += this.gravity;
this.gravity += speed*0.001;
The jump function- executes when the spacebar is pressed:
this.vy = (-?);
The amount of pixels the dino jumps gets higher over time. How could I make the Dino jump the same amount of pixels every time no matter the gravity?
So I personally would do this a little differently. I would specify a maximum y; the highest point our object can jump. Then when the player hits the jump button, it will Linearly Interpolate to that position, this works perfectly for your problem as in p5 they've spoiled us with a lerp() function where you can specify the amount to lerp by, so the faster your game gets the quicker we want the player to jump so the higher we set the lerp.
To determine how fast we lerp I've used upSpeed which you will increment as the game progresses:
const MAX_Y = 150;
let y = 370;
let upSpeed = 0.1;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
fill(255, 100, 100);
y = lerp(y, MAX_Y, upSpeed);
ellipse(width / 2, y, 50, 50);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>
And then add your gravity magic to the equation and you've got yourself a game!
Right so I'm a bit new to JS and I wanted to know how to put a roof or height limit within this small canvas game. It's practically W3's code but the teacher told us to just model after it. I wanted to fix the annoying issue of just jumping over the map to avoid obstacles.
I don't really know what to try since the height is set by canvas. I tried to make a new function based of hitBottom() which failed.
Just wanted to put the roof or height limit. Here's the original source: Here. Everything is literally the same except colors.
What you want to do is see if the current y-position is lower than 0, since that would be the 'roof' of the room. If the player y position is lower than 0, reset it back to 0, and stop the acceleration.
this.hitTop = function() {
if (this.y < 0) {
this.y = 0;
this.gravitySpeed = 0;
}
}
And to the newpos function, you want to call this function, so add this:
this.hitTop();
Check for y position in newPos method after increasing the y position. If it is less than 0 then make it 0. Code should look like below;
this.newPos = function() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
this.y += this.speedY + this.gravitySpeed;
/* Add below 4 lines */
if (this.y <= 0) {
this.y = 0;
this.gravitySpeed = 0;
}
/* Add above 4 lines */
this.hitBottom();
}
Happy coding ;)
in the following code I'm trying to replicate some kind of the brick breaker game for Blackberry on Canvas and HTML 5. I created some classes in order to separate my code in a organized way so it coul be clear to everyone.
Initial vector class:
class Vector {
constructor(x, y){
this.x = x;
this.y = y;
}
getLength(){
return Math.sqrt(this.x*this.x + this.y*this.y);
}
Ball class:
class Ball extends Rect{
constructor(x, y, w, h){
super(x, y);
this.vel = new Vector(0, 0);
this.w = w;
this.h = h;
}
update(){
this.x += this.vel.x;
this.y += this.vel.y;
}
Rectangle class:
class Rect extends Vector{
contructor(x, y, w, h){
this.pos = new Vector(x,y);
this.w = w;
this.h = h;
}
getLeft(){
return this.x;
}
getRight(){
return this.x + this.w;
}
getTop(){
return this.y;
}
getBottom(){
return this.y + this.h;
}
static collition(player, ball){
return (player.getLeft() < ball.getRight() && player.getRight() > ball.getLeft()
&& player.getTop() < ball.getBottom() && player.getBottom() > ball.getTop());
}
static collitionX(player, ball){
return player.getLeft() < ball.getRight() && player.getRight() > ball.getLeft()
}
static collitionY(player, ball){
return player.getTop() < ball.getBottom() && player.getBottom() > ball.getTop();
}
As you can see, first in the main JS file I create instances of the classes and draw them on the canvas with the fillRect() method and add the bouncing so the ball it's wrapped inside the canvas with this code:
if(ball.getRight() > canvas.width || ball.getLeft() < 0){
ball.vel.x = -ball.vel.x;
}
if(ball.getTop() < 0 || ball.getBottom() > canvas.height){
ball.vel.y = -ball.vel.y;
}
Then I chek my collisions with this method:
static collition(player, ball){
return (player.getLeft() < ball.getRight() && player.getRight() > ball.getLeft()
&& player.getTop() < ball.getBottom() && player.getBottom() > ball.getTop());
}
That is a pretty normal collision test for rectangles, jus checks if the sides are colliding.
I'll add a snippet so you can see the code properly. The main problem here is that the game detects the collitions perfectly but given that I want to recreate a bouncing effect, everytime the ball hits a side if changes its speed in the X axis, and works perfectly but to prevent the ball from entering the rectangles I need to invert the speed on the Y axis aswell but if I do that the movement gets affected and creates an anormal bouncing effect. So the main question is: How to prevent this from happening without getting the bouncing effect affected, and with prevent I mean prevent the ball from getting inside the rectangles.
I already discovered that to create a X axis bouncing effect, I need to reverse the X speed only, and to create a Y axis one I need to reverse the Y speed only. But changing both at the same time affects the bouncing effect.
Complete snippet:
https://jsfiddle.net/95exq760/2/
All I need is to have this object travel left and right across the top of the canvas. Currently it spawns and travels right absolutely fine, then stops once it reaches the right edge of the canvas.
//mainEnemy Variables
var mainEnemy_x = 10;
var mainEnemy_y = 10;
var mainEnemyHeight = 50;
var mainEnemyWidth = 25;
var mainEnemyRight = true;
var mainEnemyLeft = false;
var mainEnemy_dx = 2;
//Drawing the Main Enemy
function drawMainEnemy()
{
ctx.beginPath();
ctx.rect(mainEnemy_x, mainEnemy_y, mainEnemyHeight, mainEnemyWidth);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
}
//Movement speed of mainEnemy
if(mainEnemyRight && mainEnemy_x < canvas.width-mainEnemyWidth)
{
mainEnemy_x += 5;
}
else if(mainEnemyLeft && mainEnemy_x > 0)
{
mainEnemy_x -= 5;
}
//mainEnemy moves across the top of the canvas
if(mainEnemy_x + mainEnemy_dx - mainEnemyWidth > canvas.width)
{
mainEnemy_dx = -mainEnemy_dx;
}
ball_x += dx;
ball_y += dy;
mainEnemy_x += mainEnemy_dx;
}
This is all the code relevant to the object I need help with. I've tried just reversing it's x movement, with the mainEnemy_dx = -mainEnemy_dx; line, but this isn't working. I can see this code is an absolute mess at the moment, I just need to get it working then time for some serious cleanup.
Any and all help would be greatly appreciated!
First of all, you have two movement systems. One with the left and right flags and constants added or subtracted from x and the other with dx. You should just use one or the other, the latter being simpler.
For the jitter, you have to either also check that the current dx is positive when going over the right by border (and negative on left) and then switch the sign, or move the object left when a collision with right border is found.
At the moment you are moving the object 7 units right every time, then when border is found only dx is used (2 or -2) but since your object can be over the border it might vibrate between 2 and -2 always. But at least the right branch will always try to move 5 units right even when dx is negative.
Using a debugger to step through the code and inspecting the variables and branches taken while vibrating on the right edge will show exactly how it behaves.