I'm trying to do a copy of the original super mario game using html5 canvas just for fun and to learn more about the canvas tool and it's animation but i am stuck at making Mario do it's jump here is my jsfiddle : http://jsfiddle.net/2tLCk/1/
how should i fix my up function to make mario jump and return back to the ground like in this website http://blog.nihilogic.dk/ i tried to understand it's code but i couldn't ?
if (keydown.up) {
vy += gravity;
character.CurentPos = 11;
character.x += character.speed;
character.y += vy;
}
Here's a jumping Mario http://jsfiddle.net/2tLCk/22/.
If jumping is 1 - going up. If jumping is 2 - going down.
if(jumping){
if(jumping == 1) {
if(character.y > 140) character.y -= gravity;
else jumping = 2;
} else if(jumping == 2) {
if(character.y < 184) character.y += gravity;
else{
character.y = 184;
jumping = false;
character.CurentPos = 6;
}
}
}else if(keydown.up) {
jumping = 1;
character.CurentPos = 11;
}
And you would probably want to use this https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame instead of setInterval().
You basically want the gravitiy to be always active, not only when pushing the down key.
When jumping (key up) you have to add to vy. Like this:
if(keydown.up) {
vy += -2;
}
vy += gravity;
if(character.y > 184) { // simple collision detection for ground floor
vy = 0;
character.y = 184;
}
//character.CurentPos = 11;
//character.x += character.speed;
character.y += vy;
see http://jsfiddle.net/pjQb3/
I would do something like this:
// Global forces
character.vy += gravity;
// User input
if (keydown.up) {
character.vy += -2;
}
// Final location
if (character.y + character.vy >= 184) {
// Update player location.
character.y += character.vy;
} else {
// Player was about to move past ground so place player directly on ground
// and reset velocity.
character.y = 184;
character.vy = 0;
}
Related
this is my first post! With that in mind, if I need to add anything more than what is below, please let me know. Thank you!
I am currently working to make a platformer game in Javascript where a player can move using arrow keys. Currently, my left and right movements, as well as my player gravity, works. However, when I jump, I am unable to provide smooth jumping movements. originally, I tried simply moving my player's y value higher.
if (up) {
this.y -= 100;
}
However, this makes the player "teleport" upwards, rather than look like an actual jump. To fix this, I reused my gravity code to overcome the gravitational force until a certain limit, making the player look like they are smoothly jumping until they reach a certain height. Below is my code.
if (up) { // This if statement is apart of another function, did not include
this.can_jump = false;
this.jumping = true; this.jump();
}
jump() { // Overcome the gravitational force, but jump force slowly lowers
this.y -= (this.gravity * this.velocity) * 3;
this.gravity -= 0.1;
this.velocity -= 0.1;
this.check();
this.check_jump(this.jumping);
}
check_jump(jumping) {
if (jumping) {
if (this.x < 500) { // While player is less than 500, keep jumping
this.jumping = false;
this.gravity = 2;
this.velocity = 2;
this.can_jump = true;
}
}
}
Additionally, here is the code regarding player collisions and gravity.
gravityEffect() {
this.y += (this.gravity * this.velocity);
this.check();
}
check() {
// Too far up
if (this.y <= 70) { this.y = 70; }
// Too far down
if (this.y >= 600) { this.y = 600; }
// Too far left, teleports to other side
if (this.x < 0) { this.x = 1200; }
// Too far right, teleports to other side
if (this.x > 1200) { this.x = 0; }
}
However, when testing this, my player not only keeps jumping upwards, but also does not do so smoothly (it looks like it is glitching). Here is a link to an mp4 file download (screen recording) showcasing the glitch: https://www.mediafire.com/file/jtqh3lca72vj8nz/%25F0%259D%2590%258C%25F0%259D%2590%25B2_%25F0%259D%2590%2586%25F0%259D%2590%25AB%25F0%259D%2590%259A%25F0%259D%2590%25AF%25F0%259D%2590%25A2%25F0%259D%2590%25AD%25F0%259D%2590%25B2_-_Google_Chrome_2021-04-28_19-59-08.mp4/file
Also, here is a copy of my current code (zipped), if running the program helps: https://www.mediafire.com/file/r5ewoxtb4n57htz/game.zip/file
Please let me know what is wrong. Also, if there is a different or more efficient method of simulating player jumping, please make me aware of it. Thank you for your time.
While trying to keep the code mostly the same I made some changes.
First and formost I changed how you had the controller written. Unless your intention was for the up/down/left/right arguments to stay true then you need a method for them to kick back to false. This controller class will do that.
// Apply classes to empty variables
console.log("Creating player...");
player = new Player();
console.log("Creating world...");
world = new World();
console.log("Creating Controller...")
controller = new Controller();
// Draw canvas with set size
console.log("Creating game screen...");
createCanvas(1000, 750);
}
class Controller {
constructor() {
this.up = false;
this.down = false;
this.right = false;
this.left = false;
let keyEvent = (e) => {
if (e.code === 'ArrowUp') { this.up = e.type === 'keydown' }
if (e.code === 'ArrowRight') { this.right = e.type === 'keydown' }
if (e.code === 'ArrowDown') { this.down = e.type === 'keydown' }
if (e.code === 'ArrowLeft') { this.left = e.type === 'keydown' }
}
window.addEventListener('keydown', keyEvent)
window.addEventListener('keyup', keyEvent)
}
}
Since we changed that we'll have to change the Player Class very slightly.
I've set the X and Y velocity to 0 and we'll increment those once a button is pressed. The additional update function will update your X and Y based on that.
Player Class
class Player {
// Setup player attributes
constructor() {
this.x = 100;
this.y = 395;
this.width = 50;
this.height = 50;
this.jumping = false;
this.color = "#ffdb15";
this.gravity = 2;
this.velocityY = 0;
this.velocityX = 0; //changed this from speed
this.points = 0;
}
move() {
// Reverse gravity to upwards, change player's color
if (controller.up && !this.jumping) { this.jumping = true; this.jump(); this.color = this.getRandomColor(true); }
// Reverse gravity to downwards, change player's color
if (controller.down) { this.color = this.getRandomColor(false); }
// Go left
if (controller.left) { this.velocityX -= 1 }
// Go right
if (controller.right) { this.velocityX += 1 }
}
jump() {
this.velocityY -= 35;
}
check() {
// Too far up
if (this.y <= 70) { this.y = 70; }
// Too far down
if (this.y >= 600) { this.y = 600; this.jumping = false } //once collision player can jump again
// Too far left, teleports to other side
if (this.x < 0) { this.x = 1200; }
// Too far right, teleports to other side
if (this.x > 1200) { this.x = 0; }
}
// Get a random player color
getRandomColor(isMoving) {
if ((this.y === 70 || this.y === 600) && isMoving) {
// Explanation: Each color has RGB values from 0 to 255, or 256 total options
// Since colors start from "000000" and go until "FFFFFF", there are ((256^3) - 1) possibilities
// (256^3) - 1 = 16777215
// Use this number, and a random number from Math.Random(), to get a random color
// Idea from: https://css-tricks.com/snippets/javascript/random-hex-color/
this.color = Math.floor(Math.random() * 16777215).toString(16);
return "#" + this.color;
} else { return this.color; }
}
show() {
// Show player
fill(this.color);
strokeWeight(0);
rect(this.x, this.y, this.width, this.height);
}
update() {
this.velocityY += this.gravity;
this.x += this.velocityX;
this.y += this.velocityY;
this.velocityY *= 0.9;
this.velocityX *= 0.9; //provides a sliding slow down once button is released.
this.move();
this.check();
}
}
The draw function is the same but replace gravity with update
function draw() {
world.generate();
player.update();
player.show();
}
This should get you where you want to go with it.
Do you have a variable for y speed? i've found the best way to create a fairly normal looking jump would be to set the y speed to a set number, EG: -4. My personal favorite method for realistic player jumping and gravity would be as follows, but can be easily modified for your uses:
//Initial y position
var y=height/2;
//This is how far the player moves each frame
var ys=0;
//This is how intense the gravity is.
var yss=0.1;
function draw(){
y+=ys;
//yss can be replaced with some arbitrary number if you don't plan on changing it(EG: for collisions)
ys+=yss;
//Then to jump, something like this
if(mouseIsPressed){
ys=-4;
}
//Heck, if you wanted to flip gravity you could do this
//yss*=-1;
//and bouncing would look like this
//ys*=-0.9;
}
Let me know if there is anything I can clarify or help with!
So, i've coded this canvas animation and I would like the shape to move faster though when doing so the shapes desync.
When I increment the values show below, so that the shapes would faster, they do so but eventually move away from eachother and desync.
if (this.dir[i][j] === 'downright') { //go down and right
this.boxLines[i][j].y += 1;
this.boxLines[i][j].x += 1;
}
if (this.dir[i][j] === 'downleft') { //go down and left
this.boxLines[i][j].y += 1;
this.boxLines[i][j].x -= 1;
}
if (this.dir[i][j] === 'upright') { //go up and right
this.boxLines[i][j].y -= 1;
this.boxLines[i][j].x += 1;
}
if (this.dir[i][j] === 'upleft') { //go up and left
this.boxLines[i][j].y -= 1;
this.boxLines[i][j].x -= 1;
}
Any way to fix that or could i go about it some other way?
Link to jsfiddle: https://jsfiddle.net/frankpettersson/nqmy3fkd/7/
How would one go about coding a jump like in this game? I've got some working code already (made in Adobe Edge) but the way it's programmed it won't start another jump while mid-air. This is what I've got atm:
var velocityY = 0;
var gravity = 0.5;
var onGround = false;
var fps = 60;
function StartJump()
{
if(onGround)
{
velocityY = -13.0;
onGround = false;
}
}
function EndJump()
{
if(velocityY < -6,0)
velocityY = -6,0;
}
var positionY = sym.$("ball").position().left;
Loop();
function Loop()
{
Update();
setTimeout(Loop, 1000/fps);
}
function Update()
{
velocityY += gravity;
positionY += velocityY;
if(positionY > 730)
{
positionY = 730;
velocityY = 0;
onGround = true;
}
sym.$("ball").css("top", positionY + "px");
console.log(velocityY);
}
The top value 730 is where "ball" starts on the ground. StartJump() is called on the event 'mousedown' and EndJump() on 'mouseup'. I can't figure out how to change the code so I can make it jump while mid-air (as in when it collides with sth, like how in the game the bunny hits the bell).
http://jsfiddle.net/xknbn/
http://jsfiddle.net/xknbn/embedded/result/
Hey guys. I'm having issues getting my collision system to function without problems. At the moment, if I'm going too fast, I get embedded in the object and my collision resolution fails. I'm fairly certain that the problem happens because of how I have velocity set up, but I don't know how I can go about fixing the issue. Any help would be greatly appreciated.
friction = 0.9,
gravity = 0.3;
function keycheck() {
if (keys[32]) {
if (!player.jumping) {
player.jumping = true;
player.vely = -player.speed;
}
}
if (keys[68]) {
if (player.velx < player.speed) {
player.velx++;
}
}
if (keys[65]) {
if (player.velx > -player.speed) {
player.velx--;
}
}
}
ctx.startx = player.x;
ctx.starty = player.y;
function playerupdate() {
player.Intersects = function(object) {
return player.x < object.x + object.width + 1 &&
player.x + player.width + 1 > object.x &&
player.y < object.y + object.height + 1 &&
player.y + player.height + 1 > object.y;
}
solidcount = 0;
for (i = 0; i < tgen.length; i++) {
for (ii = 0; ii < tgen[i].length; ii++) {
if ( player.Intersects(tgen[i][ii]) && tgen[i][ii].solid ) {
var pright = player.x + player.width,
pleft = player.x,
ptop = player.y,
pbottom = player.y + player.height,
oright = tgen[i][ii].x + tgen[i][ii].width,
oleft = tgen[i][ii].x,
otop = tgen[i][ii].y,
obottom = tgen[i][ii].y + tgen[i][ii].height;
//if player is to the right of his previous position, and his right side has collided with objects left
if (player.x >= ctx.startx && pright > oleft - 1) {
player.x--;
}
//if player is to the left of his previous position, and his left side has collided with objects right
if (player.x <= ctx.startx && pleft < oright + 1) {
player.x++;
}
//if player is above his previous position, and his top side has collided with objects bottom
if (player.y <= ctx.starty && ptop < obottom + 1) {
player.y++;
}
//if player is below his previous position, and his bottom side has collided with objects top
if (player.y >= ctx.starty && pbottom > otop - 1) {
player.y--;
player.vely = 0;
player.jumping = false;
}
solidcount++;
}
}
if ( i == tgen.length - 1 && solidcount == 0 ) {
player.jumping = true;
}
}
ctx.diffx = player.x - ctx.startx;
ctx.diffy = player.y - ctx.starty;
if (player.x <= bgimg.width - width/2 && player.x >= width/2) {
ctx.translate(-ctx.diffx,0);
}
if (player.y <= bgimg.height - 360 - player.height) {
ctx.translate(0,-ctx.diffy);
}
ctx.startx = player.x;
ctx.starty = player.y;
ctx.clearRect(player.x-width/2,player.y-height/2,width,height);
ctx.fillStyle = 'red';
ctx.fillRect(player.x,player.y,player.width,player.height);
keycheck();
player.velx *= friction;
if (player.jumping) {player.vely += gravity;}
player.x += player.velx;
player.x = Math.round(player.x);
player.y += player.vely;
player.y = Math.round(player.y);
if (player.y >= bgimg.height - player.height - 1) {
player.y = bgimg.height - player.height - 1;
player.vely = 0;
player.jumping = false;
}
if (player.x > bgimg.width - player.width) {
player.x = bgimg.width - player.width;
player.velx = 0;
};
if (player.x < 0) {
player.x = 0;
player.velx = 0;
}
if (!keys[65] && !keys[68] && (player.velx < 0.2 && player.velx > -0.2)) {player.velx = 0};
console.log(player.x,player.y)
requestAnimationFrame(playerupdate);
}
So this is a common platform engine problem. If your player was moving too fast, it would go straight though the obstacles, because no collision testing occurs between the current position and the next position. Your aim is to test collisions as few times as possible but so that all possible collisions between the start position and the target are tested. Also when you detect a collision in the path, you have to handle it properly.
Moving objects safely
To move any objects safely you need to move them in steps, and test for collisions at each step. The simplest choice is to move the player by 1 pixel at a time, and then test for a collision. This does mean doing a lot of collision tests though.
To improve this, if you are only doing box collision testing, you can move the player by a maximum of the width of the player each time.
Dealing with collisions
So in your example, you move the player back 1 pixel depending on the direction of the player. If the player were to sink 5 pixels into the obstacle, then your collision handling mechanism only moves the player back to 4 pixels into the obstacle. It appears as if the player slowly moves through the obstacle.
If you move the player 1 pixel at a time, the approach you have taken works. If you move the player more than 1 pixel at a time then you have to move the player back until it no longer overlaps an obstacle. Something like while (overlapping) -> move back one pixel
I am making a platform game in JavaScript and I need some help.
How do I make an image jump up 50px in JavaScript when the spacebar pushed then fall back to a certain position?
If you mean jumping as in jumping with gravity - you'd need a parabola formula.
E.g.: http://jsfiddle.net/pimvdb/7JFU3/.
var x = 0;
var interval = setInterval(function() {
x++;
image.style.top = 50 - (-0.1 * x * (x - 50)) + 'px';
if(x >= 50) clearInterval(interval);
}, 20);
I'm working on exact the same thing. Here's my github project link https://github.com/beothorn/webcomicsgame
Look at MainCharacter.js at
if(gameCommandState.up){
if(this.canJump(game))
this.element.yAccelerate(-this.yAcceleration);
}
You can fork it if you want, but I'm doing it using canvas.
We had fun extending this to have an image keep bouncing up and down
var x = 0;
var goingUp = true;
var interval = setInterval(function() {
if(goingUp==true) {
x++;
if(x >= 50) {
goingUp=false;
//alert("go down")
}
} else {
x--;
if(x <= -50) {
goingUp=true;
//alert("go up")
}
}
$('#demo').css('top', 50 - (-0.1 * x * (x - 50)));
}, 20);