Im currently working on getting my player sprite to move around my screen, but when a key is pressed all the sprite seems to do is disappear! I have no errors coming up in firebug, so i am assuming that the sprite isn't being redrawn correctly or something along those lines.
Here is my code for my player:
function Player()
{
var sprite = new Sprite(),
player,
x,
y,
w = sprite.width,
h = sprite.height,
speed = 4;
this.init_Player = function(pos_X, pos_Y){
player = sprite.load("player");
x = pos_X;
y = pos_Y;
};
this.update = function(delta) {
var calculated_speed = (speed * delta) * (60/1000);
$(document).keydown(function(e)
{
var cancel_default = (e.which === 32 || (e.which > 36 && e.which < 41));
cancel_default && e.preventDefault();
if(e.keyCode == 37){
x -=calculated_speed;
}
else if(e.keyCode == 38){
y -=calculated_speed;
}
else if(e.keyCode == 39){
x +=calculated_speed;
}
else if(e.keyCode == 40){
y +=calculated_speed;
}
});
};
this.draw = function() {
ctx.drawImage(player,x, y, w ,h);
};
}
The player is created in my main game javascript file like so:
player.init_Player(location_X,location_Y);
And then in my main game loop i have the now, delta and last times being made as well as the call to player.update and player.render like so:
function update(){
now = Date.now();
delta = now - last_update;
ctx.clearRect(0,0,canvas.width,canvas.height);
gameGUI.update();
player.update(delta);
player.draw();
last_update = now;
setTimeout(update,1);
}
Like i said at the top, all my sprite does on a key press is disappear. The code you can see above is all the code i have for the player so somewhere in here is the bug!
How would i accomplish making my sprite move on screen with a time-based animation like the one i've set up?
Thanks
EDIT
Also to let you know, i have last_update equal to Date.now() the line before my update call gets made initially like so:
function game_init(state) {
game_settings(state);
last_update = Date.now();
update();
}
Edit 2
On continued inspection, it doesn't seem like the sprite is disappearing after all, just moving very far e.i off the game screen... so another guess is that my calculations are wrong somewhere?
All sorted guys, i have my character moving using this little tutorial! Real easy to read and understand for the beginners out there.
LINK
What do the pros think of this tutorial?
Related
I want to control the amount of times draw() is being called, basically lets immagine that i have that basic code:
var e = 1;
function setup() {
window.canvas = createCanvas(200, 200);
}
function draw() {
fill(255, 255, 0);
ellipse(50 + e, 50, 30);
e++;
}
and I want to make a function moveOneStep() that will active draw() once, so let's assume I'm doing a for loop 5 times, then draw will be called 5 times and the circle will move 5 steps ( pixels ) to the right,
how can it be done?
Do you want to fixe the framerate in your code or to call draw() function in a specific time? If it's the case I don't think you can because the draw function is, as mentioned in the documentation
the draw() function continuously executes the lines of code contained inside its block until the program is stopped or noLoop() is called
But if you want to fixe the frame rate u can call the frameRate(number) in the setup() function. So, now if you want to have draw() called 30 times per second
(or 30 fps for a gaming reference) your code will look like this.
var e = 1;
function setup() {
window.canvas = createCanvas(200, 200);
frameRate(30);
}
function draw() {
fill(255, 255, 0);
ellipse(50 + e, 50, 30);
e++;
}
Check the dcumentation for further references.
Happy coding ^^.
Instead of controlling the number of times that draw gets called you can control what happens inside of draw.
To use draw in a way that allows user interaction and works well with the p5js lib you can listen for user interaction with a keyPressed method and record what the user is telling the system to do. Back in the draw method you can update positions and then render the sketch.
This approach breaks the direct connection between frame rate and user interaction. For example we could slow the frame rate down but still allow the user to click buttons as quickly as the key board would allow. Positions would still get adjusted and draw would catch up.
Here is a simple example that allows a user to move a circle with a ,s, d, w keys or up, down, left, right arrow keys.
var xPos = 0;
var yPos = 0;
var moveRightCount = 0;
var moveLeftCount = 0;
var moveUpCount = 0;
var moveDownCount = 0;
function setup() {
window.canvas = createCanvas(200, 200);
}
function keyPressed() {
if (keyCode === RIGHT_ARROW || keyCode === 68) {
moveRightCount+=1;
} else if (keyCode === LEFT_ARROW || keyCode === 65) {
moveLeftCount+=1;
} else if (keyCode === DOWN_ARROW || keyCode === 83) {
moveDownCount+=1;
}else if (keyCode === UP_ARROW || keyCode === 87) {
moveUpCount+=1;
} else if (keyCode === 70){
// console.log(keyCode);
}
function draw() {
background(255);
if (moveRightCount > 0){
xPos++;
moveRightCount--;
}
if (moveLeftCount > 0){
xPos--;
moveLeftCount--;
}
if (moveUpCount > 0){
yPos--;
moveUpCount--;
}
if (moveDownCount > 0){
yPos++;
moveDownCount--;
}
fill(255, 255, 0);
ellipse(50 + xPos, 50 + yPos, 30);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js"></script>
Now if you have a method called moveOneStep() it could adjust the appropriate move count and as draw gets called according to its frameRate the image would be moved. Say we call moveOneStep() in a loop that executes 5 times the image would be moved one position per execution of draw 5 times.
I'm trying to make a basic FPS view using CSS.
Here's a demo of what I have so far: https://jsfiddle.net/w8q7xtmL/
In particular, movement is as simple as detecting keypresses, then:
// "self" is if the player object
requestAnimationFrame(step);
function step() {
if( keys[37]) self.direction += 2;
if( keys[39]) self.direction -= 2;
if( keys[38]) {
self.x += Math.cos(self.direction/180*Math.PI) * 4;
self.y -= Math.sin(self.direction/180*Math.PI) * 4;
}
if( keys[40]) {
self.x -= Math.cos(self.direction/180*Math.PI) * 4;
self.y += Math.sin(self.direction/180*Math.PI) * 4;
}
self.camera.style.transform = "rotateX(90deg) rotateZ("+(self.direction-90)+"deg) translate(-"+self.x+"px,-"+self.y+"px)";
requestAnimationFrame(step);
}
This works quite well, but there are a couple of issues.
Sometimes, elements don't stack correctly. The floor will be visible when walls should be blocking it from view, for instance.
Other times, the view will freeze completely, despite there being no errors in the console or anything that would indicate failure. It just... stops. Sometimes I can get it un-stuck by trying to move around a bit to "unstick" it, but other times I just have to reload the page.
Are there any discernible errors in my approach, or is the state of 3D transforms just not there yet for this kind of thing?
For the record, in case it matters, I'm developing with Google Chrome 49.
I can't believe I missed this.
Before:
self.camera.style.transform = "rotateX(90deg) rotateZ("+(self.direction-90)+"deg)
translate(-"+self.x+"px,-"+self.y+"px)";
After:
self.camera.style.transform = "rotateX(90deg) rotateZ("+(self.direction-90)+"deg)
translate("+(-self.x)+"px,"+(-self.y)+"px)";
Because, funnily enough, when self.x is negative, you get translate(--12px,0px) which is invalid.
I believe it is because you are detecting keys in a loop.
Instead, use this:
var rotval = 0;
window.addEventListener('keydown', function(e) {
key = e.keyCode
if(key === "left")
{
rotval = 1;
}
}, true);
window.addEventListener('keyup', function(e) {
key = e.keyCode
if(key === "left")
{
rotval = 0;
}
}, true);
then just add a variable to the loop function and when it is more or less than 0, it moves or rotates the camera!
function loop()
{
camera.rotation.y += rotval
camera.position.x //and so on
}
setInterval(loop,30)
Hope this helps :)
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';
}
Let's say we have a ball that can be moved left and right around the screen. When you click space, the ball should jump.
I got the ball to move left and right in a canvas. However, when the ball is moving left (for example) and I hit the space bar before anything, the ball stops moving left.
Check out my example so far!
I am using the KeyboardJS library to handle my key events:
KeyboardJS.on("left", function () {
cc();
x -= xv;
if (x < r) {
circle(x + width, y, r);
if (x + width <= width - r) {
x = x + width;
}
}
circle(x, y, r);
});
KeyboardJS.on("space", null, function () {
console.log("space!");
});
How could I get this behavior to stop so that when the space bar is hit, the ball jumps up but at the same time still moves to the left?
One thought added to everyone else's good ideas:
Separate your user input from your drawing.
Keyboarding:
If you’re having problems with KeyboardJS, check out Keydrown: http://jeremyckahn.github.io/keydrown/
Don’t do any drawing when capturing keys…just capture the user’s input of which direction they want the circle to go.
Set up an “direction” variable to hold how many times the user has pressed [left] or [right]:
var direction=0;
When [left] is pressed:
direction--;
When [right] is pressed:
direction++;
Direction is a net number. So if the user holds down the left key for 20 strokes and the right key for 15 strokes, direction will be -5 ( -20 + 15 ).
Set up an “altitude” variable to hold how many times the user has pressed [space]:
var altitude=0;
When [space] is pressed:
altitude-=10;
Altitude is a net number also.
Drawing:
Do all your drawing in a separate animation loop. Rather than using javascript’s setInterval, use the new and improved way of creating an imation loop -- requestAnimationFrame.
// set the starting circle positions
var currentX=canvas.width;
var currentY=canvas.height-r;
function animate(){
// even as we're executing this current animation loop
// request another loop for next time
requestAnimationFrame(animate);
// change the currentX position by the accumulated direction
currentX+=direction;
direction=0;
// change the currentY position by the accumulated altitude
currentY+=altitude;
altitude=0;
// draw the circle at its current position
cc();
circle(currentX,currentY,r);
// apply gravity to the circle
// to make it fall if its in the air
if(currentY<canvas.height-r){
currentY++;
}
}
Good Luck with your project!
What the problem is, is that if you press another key after pressing the first key, it will trigger that event, and stop triggering the other keydown event. This can be seen in this simplified example:
addEventListener('keydown',function(e) {console.log(e.keyCode, e.keyIdentifier)});
If you run that script, and then press left and then up, it will first show 37 Left a bunch of times, and then it'll show 32 U+0020 once and stop logging the left keydowns.
This is simply how the browser (and most other basic programs too) work. You can try doing the same thing in for example notepad, if you press the A key first, and then press space, it'll stop adding more As. This also means that you can't rely on key events (or key event libraries) to do this for you.
What you could do though, is make a global object that holds all keys that are pressed. For example:
window.KeysDown = {
37: false, //Left
39: false, //Right
38: false, //Up
40: false, //Down
32: false, //Space
};
addEventListener('keydown', function(e) {
var keyCode = e.keyCode||e.charCode||e.which;
if (keyCode == 32 && !window.KeysDown[keyCode])
onSpace();//This will only run when the spacebar is first pressed down.
if (window.KeysDown.hasOwnProperty(keyCode))
window.KeysDown[keyCode] = true;
});
addEventListener('keyup', function(e) {
var keyCode = e.keyCode||e.charCode||e.which;
if (window.KeysDown.hasOwnProperty(keyCode)) window.KeysDown[keyCode] = false;
});
var interval = setInterval(function() {
for (var i in window.KeysDown) {
if (window.KeysDown[i]) switch (i+'') {
case '37': onLeft(); break;
//case '38': window.KeysDown[i] && onUp(); break;
case '39': onRight(); break;
//case '40': window.KeysDown[i] && onDown(); break;
}
}
}, 50);
The syntax window.KeysDown[i] && onLeft() causes the onLeft function only to run if window.KeysDown[i] is true. I hope this solution works for you.
EDIT: I've changed the code to the working one. I've also made a JSFiddle that demonstrates this. The problem in my previous code was that apparently a switch doesn't handle integer values well, so I needed to convert i to a string.
EDIT: I've also added an extra part to the script that makes the onSpace function only run when the spacebar is first pressed down, and so that it won't run again until the spacebar is released and pressed again. I've also updated my JSFiddle to include these changes.
I would create a main function, which runs at a regular interval, and each time it runs, it updates the position of the circle based on what keys are currently down.
The main function can be done like this:
var keyDown = {};
function mainLoop() {
cc();
//pseudo code
if (keyDown["left"]) {
x -= 5;
}
if(keyDown["space"]) {
y -= 10;
}
// redraw circle at new location
circle(x,y,r);
}
setInterval(mainLoop, 30) //sets the function to be called every 30 milliseconds
// key event handler, first function handles the keydown, second function handles keyup
KeyboardJS.on("left", function() {
keyDown["left"] = true;
}, function() {
keyDown["left"] = false;
});
With this example, if the user had the left arrow key and space bar pressed when the mainLoop function ran, then the circle would move to the left 5 pixels, and up 10 pixels.
jsFiddle Demo
You are going to have to manually create a framework for this. KeyboardJS just wasn't cutting it. I guess I kind of set that up here. It uses an Action "class" coupled with key event triggers.
Action "class"
function Actions(){
this.count = 0;
this.running = {};
this.interval = undefined;
}
Actions.prototype.start = function(action){
if( typeof(this.running[action]) == "undefined"){
this[action]();
this.running[action] = action;
this.count++;
}
var me = this;
if( typeof(this.interval) == "undefined"){
this.interval = setInterval(function(){
for( var act in me.running ){
me[act]();
}
},50);
}
};
Actions.prototype.stop = function(action){
this.running[action] = void 0;
delete this.running[action];
this.count--;
if( this.count == 0 ){
clearInterval(this.interval);
this.interval = void 0;
};
};
Actions.prototype.left = function(){
cc();
x -= xv;
if (x < r) {
circle(x + width, y, r);
if (x + width <= width - r) {
x = x + width;
}
}
circle(x, y, r);
};
Actions.prototype.right = function(){
cc();
x += xv;
if (x >= width - r) {
circle((x - r) - (width - r), y, r);
if ((x - r) - (width - r) > r) {
x = (x - r) - (width - r);
}
}
circle(x, y, r);
};
Actions.prototype.space = function(){
cc();
y -= yv;
circle(x, y, r);
};
key event triggers
document.onkeydown = checkKeyDown;
function checkKeyDown(e) {
e = e || window.event;
if (e.keyCode == '37') {
// left arrow
actions.start("left");
}
if (e.keyCode == '39') {
// right arrow
actions.start("right");
}
if (e.keyCode == '32') {
// space bar
actions.start("space");
}
}
document.onkeyup = checkKeyUp;
function checkKeyUp(e) {
e = e || window.event;
if (e.keyCode == '37') {
// left arrow
actions.stop("left");
}
if (e.keyCode == '39') {
// right arrow
actions.stop("right");
}
if (e.keyCode == '32') {
// space bar
actions.stop("space");
}
}
My newest Hobby Project is a very simple Jump'n'Run Game using JavaScript. I already wrote some code (with the help of a tutorial at lostdecadegames) and read everything about the GameLoop.
var start = true;
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 1200;
canvas.height = 480;
document.body.appendChild(canvas);
var jumping = false;
var gravity = 1.5;
var pressed = true;
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "background.png";
// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "hero.png";
// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function () {
monsterReady = true;
};
monsterImage.src = "monster.png";
// Game objects
var hero = {
speed_x: 50,
speed_y_up: 50,
speed_y_down: 50, // movement in pixels per second
velocity_x: 50,
velocity_y: 50
};
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
// Update game objects
var update = function (modifier) {
if(38 in keysDown) { // Player holding up
jumping = true;
//hero.y -= hero.speed_y_up * modifier;
}
if (40 in keysDown) { // Player holding down
hero.y += hero.speed_y_down * modifier;
}
if (37 in keysDown) { // Player holding left
hero.x -= hero.speed_x * modifier;
}
if (39 in keysDown) { // Player holding right
hero.x += hero.speed_x * modifier;
}
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (heroReady) {
if(hero.y > 0 && hero.y < 480 && hero.x <= -32)
{
hero.x = hero.x + 1232;
ctx.drawImage(heroImage, hero.x, hero.y);
}
else if(hero.y > 0 && hero.y < 480 && hero.x >= 1200)
{
hero.x = hero.x - 1232;
ctx.drawImage(heroImage, hero.x, hero.y);
}
else if(jumping)
{
ctx.drawImage(heroImage, hero.x, hero.y-100);
jumping = false;
}
else ctx.drawImage(heroImage, hero.x, hero.y);
}
if (monsterReady) {
ctx.drawImage(monsterImage, monster.x, monster.y);
}
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 500);
render();
then = now;
};
// Starting the game!
reset();
var then = Date.now();
setInterval(main, 1); // Execute as fast as possible
As you can see, I already added a fix gravity var and some speed vars. The Hero moves very smooth, so this is no problem.
I have 2 problems with the jump-Animation:
The Hero stays in the air, when the Up-Key is keep being pressed. I tried to fix this with some boolean vars, but I couldn't figure it out how to get the Hero down again.
Right now, I implemented a "dirty hack" which causes the Hero to be repainted 50px higher, but I want a smooth Jump, so that the Hero gets slower while going up and speeds up while falling. I looked up so many Tutorials and so much Example Code, but I'm too stupid to figure it out, how I get my desired Animation.
Hope you guys can give me some advice for my problem (I'm not asking for the final code, I just need some tips).
It's hard to understand exactly what the if statements inside of if (heroReady) are doing because the numbers don't mean anything to me, but it seems to me like your problem is in there.
First of all, it seems to me like jumping should the first condition checked. If one of the first conditions is true, then it doesn't matter whether or not he's jumping. I can't easily tell when each condition is true, though, so I'm going to assume that when the player is holding up,
else if(jumping)
{
ctx.drawImage(heroImage, hero.x, hero.y-100);
jumping = false;
}
gets executed like normal.
Now, assuming that, I think your issue is that jumping is determined solely by whether or not the player is holding up, because as soon as jumping is true, it becomes false. This is incorrect.
Jumping should be set to true when the player presses the up key, but it should be set to false when they remove it. It should be set to false when the animation hits the ground.
Another issue that you have is the fact that you aren't actually using the hero's attributes to render its jumping location, you're simply offsetting it. Perhaps that is just your workaround until the problem is solved, but it makes it hard to tell when the character hits the ground, because you can't start lower the character (increasing the y value) after they jump, since you never raised them by decreasing the y value.
So how do we fix this?
Here are my recommendations. You might find more elegant ways to do it by the time you're done due to refactoring, but the way you have it set up right now I think it will work fine:
Set jumping as soon as they press up, like you're doing, but only if jumping == false, because presumably your hero can't do mid-air jumps.
Immediately after you set jumping (and inside the same if statement), update their velocity.
In your update section, add another if for whether or not the player is jumping, regardless of whether or not they are pressing any keys. If they are, decrease their momentum based on gravity. Then, add a check for if their momentum is the opposite of how much you increase it when they start jumping. In other words, check if they are moving down at exactly the same rate they were moving up when they started jump. This happens at exactly the y-coordinate that they began the jump from. (This is more reliable that just checking their position, because it will work from multiple y-locations.) The alternative would be to store a variable with the y-coordinate they were at when they jumped. Either way, if their jump has ended, set jumping to false.
Since you're updating their coordinates based on jumping, in your render function, you can eliminate any jumping logic and just draw the image based on the coordinates.
Does that help at all?