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!
Related
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 ;)
I am trying to move an object smoothly from point A to point B using HTML canvas and regular javascript.
Point A is a set of coordinates
Point B is in the case the cursor location.
I made a jsfiddle of what I have so far: https://jsfiddle.net/as9fhmw8/
while(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
ctx.save();
ctx.beginPath();
ctx.translate(projectile.x, projectile.y);
ctx.arc(0,0,5,0,2*Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.stroke();
ctx.restore();
if(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
var stepsize = (projectile.mouseX - projectile.x) / (projectile.y - projectile.mouseY);
projectile.x += (stepsize + 1);
}
if(projectile.mouseY < projectile.y)
{
var stepsize = (projectile.y - projectile.mouseY) / (projectile.mouseX - projectile.x);
projectile.y -= (stepsize + 1);
}
}
Essentially what I can't figure out to do is to make the while loop slower (so that it appears animated in stead of just going through every iteration and showing the result).
I also can't figure out how to prevent the Arc from duplicating so that it creates a line that is permanent, instead of appearing to move from point a to point b.
Smooth animation here is really about determining how far to move your object for each iteration of the loop.
There is a little math involved here, but it's not too bad.
Velocity
Velocity in your case is just the speed at which your particles travel in any given direction over a period of time. If you want your particle to travel 200px over the course of 4 seconds, then the velocity would be 50px / second.
With this information, you can easily determine how many pixels to move (animate) a particle given some arbitrary length of time.
pixels = pixelsPerSecond * seconds
This is great to know how many pixels to move, but doesn't translate into individual X and Y coordinates. That's where vectors come in.
Vectors
A vector in mathematics is a measurement of both direction and magnitude. For our purposes, it's like combining our velocity with an angle (47°).
One of the great properties of vectors is it can be broken down into it's individual X and Y components (for 2-Dimensional space).
So if we wanted to move our particle at 50px / second at a 47° angle, we could calculate a vector for that like so:
function Vector(magnitude, angle){
var angleRadians = (angle * Math.PI) / 180;
this.magnitudeX = magnitude * Math.cos(angleRadians);
this.magnitudeY = magnitude * Math.sin(angleRadians);
}
var moveVector = new Vector(50, 47);
The wonderful thing about this is that these values can simply be added to any set of X and Y coordinates to move them based on your velocity calculation.
Mouse Move Vector
Modeling your objects in this way has the added benefit of making things nice and mathematically consistent. The distance between your particle and the mouse is just another vector.
We can back calculate both the distance and angle using a little bit more math. Remember that guy Pythagoras? Turns out he was pretty smart.
function distanceAndAngleBetweenTwoPoints(x1, y1, x2, y2){
var x = x2 - x1,
y = y2 - y1;
return {
// x^2 + y^2 = r^2
distance: Math.sqrt(x * x + y * y),
// convert from radians to degrees
angle: Math.atan2(y, x) * 180 / Math.PI
}
}
var mouseCoords = getMouseCoords();
var data = distanceAndAngleBetweenTwoPoints(particle.x, particle.y, mouse.x, mouse.y);
//Spread movement out over three seconds
var velocity = data.distance / 3;
var toMouseVector = new Vector(velocity, data.angle);
Smoothly Animating
Animating your stuff around the screen in a way that isn't jerky means doing the following:
Run your animation loop as fast as possible
Determine how much time has passed since last time
Move each item based on elapsed time.
Re-paint the screen
For the animation loop, I would use the requestAnimationFrame API instead of setInterval as it will have better overall performance.
Clearing The Screen
Also when you re-paint the screen, just draw a big rectangle over the entire thing in whatever background color you want before re-drawing your items.
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
Putting It All Together
Here is a Fiddle demonstrating all these techniques: https://jsfiddle.net/jwcarroll/2r69j1ok/3/
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).
I am developing a casino based game using html5. The animation is working properly but this is not quite smooth i.e. once the wheel stops rotation I move ball as a final repositioning to smoothen the transition but it is not upto the expectation. Complete Code here
BallReposition Function - runs after I wheel stops movement for the final repositioning of the ball to give some reality to the animation.
function ballReposition(){
curX = findNearestOnCircle(curX);
if(curX > deadXRight){
sign = "-";
}else if(curX < deadXLeft){
sign = "+";
}
if(sign == "+"){
curX = parseInt(curX) + ballRepositionIncVal;
curY = Math.floor(Math.abs(getYOnCircle(curX, 130, 1)) + 0.5);
}else{
curX = parseInt(curX) - ballRepositionIncVal;
curY = Math.floor(Math.abs(getYOnCircle(curX, 130, 0)) + 0.5);
}
var xy = normalizeXY(curX, curY);
curX = parseInt(xy.split("-")[0]);
curY = parseInt(xy.split("-")[1]);
surface = document.getElementById("myCanvas");
var surfaceContext = surface.getContext("2d");
//removing older ball image.
surfaceContext.save();
// Translate to the center point of our image
surfaceContext.translate(happy.width * 0.5, happy.height * 0.5);
// Perform the rotation
surfaceContext.rotate(DegToRad(angle));
// Translate back to the top left of our image
surfaceContext.translate(-happy.width * 0.5, -happy.height * 0.5);
surface.getContext("2d").drawImage(happy, 0, 0);
surface.getContext("2d").drawImage(ball, curX, curY);
console.log(curX + curY);
surfaceContext.restore();
ballRepositionIncVal-=5;
if(ballRepositionIncVal <= 0){
clearInterval(myIntervalVar);
}
}
Other function details -
drawCanvas - loads the images and once the images are loaded it will start calling loop function which will rotate the wheel and move the ball in anticlockwise direction.
normalizeXY - used to put the ball at some discrete positions i.e. proper positions below numbers of wheel.
EDIT - Fiddle Configuration updated here
To create a realistic spinning wheel you can use a logarithmic-ish approach to reduce the speed of the wheel.
This means the angle is decremented by small per-centage for each frame. As it is per-centage you will get a smooth ending spin (you will also notice you get the infamous wagon wheel aliasing effect).
This online demo shows the loop isolated (implement as you please):
var angle = 2; /// start angle in radians
ctx.translate(w, h); /// prepare canvas for rotation (w and h = 50%)
ctx.globalAlpha = 0.67; /// optional bonus: motion blur(-ish)
loop(); /// start loop
function loop() {
ctx.rotate(a); /// use incremental rotation
ctx.drawImage(img, -w , -h);
/// spin down and only loop if angle > certain value
a *= 0.995;
/// continue if there is enough "inertia"
if (a > 0.001) requestAnimationFrame(loop);
}
The threshold value for continue the loop determines how "brutal" you want the stop to be. If you want the wheel to appear heavier (more mass) you can decrement the angle with an even tinier increment (eg. try 0.998).
For the ball to bounce around you need to resort to physics modelling, or at least pseudo-physics-modelling. This includes collision detections for all the small details on the wheel as well as sub-time-steps (ray casting) checking and positioning in z-axis.
I feel this is a bit broad to describe here on SO but find a good article on collision detection and physics simulation. Here is a good start with the basics.
I'm making a 2d side scroller and for the life of me I can't get jumping to work. This is how I'm doing moving left and right:
for(var i = 0; i < time; i++)
newVelocityX = (oldVelocityX + accelerationX) * frictionX;
then to update my player position I do
positionX = oldPositionX + newVelocityX;
This works great, and the variable "time" just has the amount of ms it's been since I last ran the function. Friction works great and I'm happy it's all good in the X direction. This is what I have in the Y direction:
for(var i = 0; i < time; i++) {
accelerationY += gravityAccelerationY;
newVelocityY = oldVelocityY + accelerationY;
}
The object falls down due to gravity just fine. If I set a negative accelerationY when the user hits the up arrow then I can even make the player jump, but on a fast computer they jump very high, and on an old computer they jump very low. I'm not sure how to fix this, I thought I already was accounting for this by putting it in the foor loop like I did.
You will need to do several things to change your code to work properly. There are numerous bugs/performance hits in the code you posted.
Here is some code to do the basics of the game.
Sample code for the jumping:
if (jump) {
velocityY = -jumpHeightSquared; // assuming positive Y is downward, and you are jumping upward
}
velocityY += gravityAccelerationY * time;
positionY += velocityY * time;
if (positionY > 0) {
positionY = 0; // assuming the ground is at height 0
velocityY = 0;
}
Sample code for moving sideways:
velocityX += accelerationX * time;
velocityX *= Math.pow(frictionX, time);
positionX += velocityX * time;
Some comments on the code:
The velocity and position variables need to keep their values in between frames (I'm assuming you've got that figured out).
gravityAccelerationY and frictionX are constant values, unless gravity or friction changes.
Where I replaced your for loops with * time, using a single multiplication will be faster than a loop. The only difference would be at low frame rates, or high rates of acceleration, where the acceleration would seem to be 'sped up' from what it should be. You shouldn't have problems with that though.