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.
Related
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!
this is my first question after having relied on this site for years!
Anyway, I'd like to accomplish something similar to this effect:
http://www.flashmonkey.co.uk/html5/wave-physics/
But on a circular path, instead of a horizon. Essentially, a floating circle/blob in the center of the screen that would react to mouse interaction. What I'm not looking for is gravity, or for the circle to bounce around the screen - only surface ripples.
If at all possible I'd like to apply a static texture to the shape, is this a possibility? I'm completely new to Canvas!
I've already tried replacing some code from the above example with circular code from the following link, to very limited success:
http://www.html5canvastutorials.com/tutorials/html5-canvas-circles/
If only it were that easy :)
Any ideas?
Thanks in advance!
I tried to figure out how wave simulation works using View Source and JavaScript console. It's working fine but threw some JS errors. Also, it seems physics update is entangled with rendering in the render() method.
Here is what I found about the code:
The mouseMove() method creates disturbances on the wave based on mouse position, creating a peak around the mouse. The target variable is the index of the particle that needs to be updated, it's calculated from mouse pos.
if (particle && mouseY > particle.y) {
var speed = mouseY - storeY;
particles[target - 2].vy = speed / 6;
particles[target - 1].vy = speed / 5;
particles[target].vy = speed / 3;
particles[target + 1].vy = speed / 5;
particles[target + 2].vy = speed / 6;
storeY = mouseY;
}
Then, the particles around target are updated. The problem I found is that it does no bounds checking, i.e. it can potentially particles[-1] when target == 0. If that happens, an exception is thrown, the method call ends, but the code does not stop.
The render() method first updates the particle positions, then renders the wave.
Here is its physics code:
for (var u = particles.length - 1; u >= 0; --u) {
var fExtensionY = 0;
var fForceY = 0;
if (u > 0) {
fExtensionY = particles[u - 1].y - particles[u].y - springs[u - 1].iLengthY;
fForceY += -fK * fExtensionY;
}
if (u < particles.length - 1) {
fExtensionY = particles[u].y - particles[u + 1].y - springs[u].iLengthY;
fForceY += fK * fExtensionY;
}
fExtensionY = particles[u].y - particles[u].origY;
fForceY += fK / 15 * fExtensionY;
particles[u].ay = -fForceY / particles[u].mass;
particles[u].vy += particles[u].ay;
particles[u].ypos += particles[u].vy;
particles[u].vy /= 1.04;
}
Basically, it's Hooke's Law for a chain of particles linked by springs between them. For each particle u, it adds the attraction to the previous and next particles (the if statements check if they are available), to the variable fForceY. I don't fully understand the purpose of the springs array.
In the last four lines, it calculates the acceleration (force / mass), updates the velocity (add acceleration), then position (add velocity), and finally, reduce velocity by 1.04 (friction).
After the physics update, the code renders the wave:
context.clearRect(0, 0, stageWidth, stageHeight);
context.fillStyle = color;
context.beginPath();
for (u = 0; u < particles.length; u++) {
...
}
...
context.closePath();
context.fill();
I'm not explaining that, you need to read a canvas tutorial to understand it.
Here are some ideas to get started, note that I didn't test these code.
To modify the code to draw a circular wave, we need introduce a polar coordinate system, where the particle's x-position is the angle in the circle and y-position the distance from center. We should use theta and r here but it requires a large amount of refactoring. We will talk about transforming later.
mouseMove(): Compute particle index from mouse position on screen to polar coordinates, and make sure the disturbance wrap around:
Define the function (outside mouseMove(), we need this again later)
function wrapAround(i, a) { return (i + a.length) % a.length; }
Then change
particles[target - 2] --> particles[wrapAround(target - 2, particles)]
particles[target - 1] --> particles[wrapAround(target - 1, particles)]
...
The modulo operator does the job but I added particles.length so I don't modulo a negative number.
render(): Make sure the force calculation wrap around, so we need to wrapAround function again. We can strip away the two if statements:
fExtensionY = particles[wrapAround(u - 1, particles)].y - particles[u].y - springs[wrapAround(u - 1, springs)].iLengthY;
fForceY += -fK * fExtensionY;
fExtensionY = particles[u].y - particles[wrapAround(u + 1, particles)].y - springs[warpAround(u, springs)].iLengthY;
fForceY += fK * fExtensionY;
Here is the result so far in jsfiddle: Notice the wave propagate from the other side. http://jsfiddle.net/DM68M/
After that's done, the hardest part is rendering them on a circle. To do that, we need coordinate transform functions that treat particle's (x, y) as (angle in the circle, distance from center), and we also need inverse transforms for mouse interaction in mouseMove().
function particleCoordsToScreenCoords(particleX, particleY) {
return [ radiusFactor * particleY * Math.cos(particleX / angleFactor),
radiusFactor * particleY * Math.sin(particleX / angleFactor) ];
}
function screenCoordsToParticleCoords(screenX, screenY) {
// something involving Math.atan2 and Math.sqrt
}
Where the ...Factor variables needed to be determined separately. The angleFactor is two pi over the highest x-position found among particles array
Then, in the coordinates supplied to the context.lineTo, context.arc, use the particleCoordsToScreenCoords to transform the coordinates.
I am new in Three.js.
I need to implement one 3D screen in which there are many objects in sky and there is one scale in screen.
I can move the scale in up or down direction. When I move scale up then all objects come closer in endless manner and same when I move scale down then all objects goes far.
So ultimately I want the effect like I am moving in space and I am bypassing the starts.
So for getting this effect I have used Three.js.
The problem I am facing is the when the objects come closer to me their size is increased and when the come very close than their size become very large in size. I need to increase size for some fixed parameters. After that it should not increase the size of object when it come close to screen. How I can implement that?
This is the code of object rendering:
function renderobjects() {
if(speed != 0) {
if(textArray.length > 0 && textArray[0].material.opacity == 1) {
for(var i = 0; i < textArray.length; i++) {
textArray[i].material.opacity = 0;
}
}
camera.position.y += - mouseY * 0.01;
if (camera.position.y > 60) {
camera.position.y = 60;
}
if (camera.position.y < 35) {
camera.position.y = 35;
}
camera.position.z = (camera.position.z + 8*speed);
}
Please provide me the solution by which I can restrict the size of objects.
The OrthographicCamera may be of help to you, it uses parallel projection. You can then do your own selective scaling of objects based on your needs.
I'm building a game using the canvas element powered by JavaScript. Part of my player class includes an update() method which is called once per tick. In this method, I'm doing some math to update the players velocity based on keyboard input and also to move the player. Here's a chunk of that code:
// Gradually make the players velocity 0
if(this.xv > 0) {
this.xv -= 0.1;
} else if(this.xv < 0) {
this.xv += 0.1;
}
if(this.yv > 0) {
this.yv -= 0.1;
} else if(this.yv < 0) {
this.yv += 0.1;
}
// Update player position based on velocity
this.x += this.xv;
this.y += this.yv;
// Update velocity based on keyboard inputs
if(keyState[87]) {
this.yv -= 0.5;
}
if(keyState[65]) {
this.xv -= 0.5;
}
if(keyState[83]) {
this.yv += 0.5;
}
if(keyState[68]) {
this.xv += 0.5;
}
Now in theory this should all work okay, if the player holds down the W key for 4 ticks their velocity will be 2, and then after 40 more ticks their velocity will be reduced down to 0.
This doesn't work in practice though, as JavaScript doesn't seem to be entirely accurate when it comes to working with floating point numbers. If I console.log() the velocity variables each game tick I get this kind of output:
x: -1.0241807402167069e-14 y: -1.379452108096757e-14
x: 0.09999999999998976 y: 0.09999999999998621
x: -1.0241807402167069e-14 y: -1.379452108096757e-14
x: 0.09999999999998976 y: 0.09999999999998621
So there's two things that look wrong here, one is that JavaScript never calculates the velocity with good precision, and the other is when the velocity is negative it's always at least -1, which is a problem because the player sprite will now move at 1 pixel per tick.
How can I get more accurate calculations for this task?
I recommend using an "exponential decay" approach to smoothing out your velocity transitions. Instead of the conditional block you currently use to reduce the velocity to zero, I'd use the following:
this.xv *= 0.9;
this.yv *= 0.9;
Note that this caps your maximum velocity at ten times your constant acceleration, and that changing the rate of decay will change that multiplier. This might be okay, but if it's not, you can tweak the equations to ease into a target velocity:
var p = 0.9;
var q = 1.0 - p;
this.xv = this.xv * p + this.txv * q;
this.yv = this.yv * p + this.tyv * q;
Disclaimer: This has no real basis in Newtonian physics; it's just something I came up with to help smooth out state transitions in a robot. But it worked great for me, and hopefully will for you, too.
I have a few divs that follow the mouse position slowly. In the begenning it starts off fine but the closer it gets to the mouse position the slower it gets. I have a very efficient code below but I want to improve it so that the div will always follow the mouse with a constant speed rather than a changing one.
var xp = x, yp = y;
var loop = setInterval(function(){
xp += ((mouseX - xp) ) / 100;
yp += ((mouseY - yp)) / 100;
object.css({left:xp, top:yp});
},20);}
since its diving it by a 100 when it gets closer the math gets smaller causing the X/Y to move slower. I want it to stay the same speed regardless where its coming from.
Here is the solution:
var loop = setInterval(
function()
{
speed = 20;
xp += (mouseX - xp)>speed ? speed : ((mouseX - xp)<-speed ? -speed : (mouseX - xp));
yp += (mouseY - yp)>speed ? speed : ((mouseY - yp)<-speed ? -speed : (mouseY - yp));
object.css({left:xp, top:yp});
},20
);
Have you tried using Web workers?
Using a web worker, you can send 'heavy' tasks to complete in a background-thread, so that your UI-thread does not become sluggish and your web application stays responsive.
It's very simple to set-up.
var worker = new Worker('someWorker.js');
Have a look:
https://developer.mozilla.org/En/Using_web_workers