Incorporating interactive buttons into a JavaScript-based adventure game

I have developed a JavaScript platform game where the player can navigate by moving left, right, or jumping using the arrow keys on the keyboard. I am interested in implementing this functionality using JavaScript buttons that I have created.

Below are the JavaScript buttons:

<button id="left" type="button">Left</button>
<button id="up" type="button">Jump</button>
<button id="right" type="button">Right</button> 

Here is my original JavaScript code that enables the character to jump, move left, or move right using the keyboard arrow keys.

var playerXSpeed = 7;
var gravity = 30;
var jumpSpeed = 17;


Player.prototype.update = function(time, state, keys) {
  let xSpeed = 0;
  if (keys.ArrowLeft) xSpeed -= playerXSpeed;
  if (keys.ArrowRight) xSpeed += playerXSpeed;
  let pos = this.pos;
  let movedX = pos.plus(new Vec(xSpeed * time, 0));
  if (!state.level.touches(movedX, this.size, "wall")) {
    pos = movedX;
  }

  let ySpeed = this.speed.y + time * gravity;
  let movedY = pos.plus(new Vec(0, ySpeed * time));
  if (!state.level.touches(movedY, this.size, "wall")) {
    pos = movedY;
  } else if (keys.ArrowUp && ySpeed > 0) {
    ySpeed = -jumpSpeed;
  } else {
    ySpeed = 0;
  }
  return new Player(pos, new Vec(xSpeed, ySpeed));
};

This section of the code determines whether the arrow keys are pressed or released. If the arrow keys are held down, the character continues to move until they are released. I understand that additional modifications are needed for it to work with my JavaScript buttons, but I'm unsure of how to proceed.

function trackKeys(keys) {
  let down = Object.create(null);
  function track(event) {
    if (keys.includes(event.key)) {
      down[event.key] = event.type == "keydown";
      event.preventDefault();
    }
  }
  window.addEventListener("keydown", track);
  window.addEventListener("keyup", track);
  return down;
}

var arrowKeys =
  trackKeys(["ArrowLeft", "ArrowRight", "ArrowUp"]);

Answer №1

To implement these functionalities, you can easily set up event listeners for your buttons' onmousedown and onmouseup events.

In addition, it's advisable to refrain from using the new keyword inside your player.update() function since it can lead to performance issues as the browser has to allocate memory and the garbage collector needs to clean up old objects.

Below is a snippet that demonstrates how you can achieve this:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}

canvas {
display: block;
margin: auto;
margin-bottom: 15px;
border: solid 1px white;
border-radius: 10px;
}

div {
display: block;
margin: auto;
width: 170px;
height: 30px;
}

button {
width: 75px;
height: 30px;
text-align: center;
font-style: Lucida Console;
font-size: 20px;
border: solid 1px white;
border-radius: 10px;

color: #FFFFFFFF;
background-color: #333333FF;
transition-duration: 0.1s;
}

button:hover {
background-color: #777777FF;
}

button:active {
background-color: #AAAAAAFF;
}

.top {
display: block;
margin: auto;
margin-bottom: 10px;
}

.bottom {
display: inline-block;
margin: auto;
margin-left: 5px;
margin-right: 1px;
}

</style>
</head>

<body>
<canvas id="canvas"></canvas>
<button id="jumpButton" class="top">↑</button>
<div>
<button id="leftButton" class="bottom">←</button>
<button id="rightButton" class="bottom">→</button>
</div>
<script type="application/javascript">

void function() {

"use strict";

// Variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var player = null;

var jumpButton = null;
var leftButton = null;
var rightButton = null;

// Classes
function Player(x,y) {
// Position
this.x = x || 0.0; // Using || in JS means use this second value if the first is null or undefined
this.y = y || 0.0;

// Velocity
this.dx = 0.0;
this.dy = 0.0;

// Input
this.isJumping = false; // Extra boolean to stop the player from jumping in mid-air
this.isJumpDown = false;
this.isLeftDown = false;
this.isRightDown = false;
}

Player.prototype = {
WIDTH: 10.0,
HEIGHT: 20.0,

SIDE_SPEED: 1.0,
JUMP_SPEED: 4.0,
FALL_SPEED: 0.2,

tick: function() {
// Input
if (this.isLeftDown) {
this.dx = -this.SIDE_SPEED;
} else if (this.isRightDown) {
this.dx = +this.SIDE_SPEED;
} else {
this.dx = 0.0;
}

if (this.isJumpDown && !this.isJumping) {
this.isJumping = true;
this.dy = -this.JUMP_SPEED;
}

// Falling
if (this.isJumping) {
this.dy += this.FALL_SPEED;

if (this.y + this.dy > canvasHeight - this.HEIGHT) {
this.y = canvasHeight - this.HEIGHT;
this.dy = 0.0;
this.isJumping = false;
}
}

// Left/Right boundaries
if (this.x < -this.WIDTH) {
this.x = canvasWidth;
} else if (this.x > canvasWidth) {
this.x = -this.WIDTH;
}

this.x += this.dx;
this.y += this.dy;
},

render: function(ctx) {
ctx.strokeStyle = "black";
ctx.fillStyle = "darkred";
ctx.beginPath();
ctx.rect(this.x,this.y,this.WIDTH,this.HEIGHT);
ctx.fill();
ctx.stroke();
}
};

// Button event listeners
function onJumpDown(e) {
player.isJumpDown = true;
}

function onJumpUp(e) {
player.isJumpDown = false;
}

function onLeftDown(e) {
player.isLeftDown = true;
}

function onLeftUp(e) {
player.isLeftDown = false;
}

function onRightDown(e) {
player.isRightDown = true;
}

function onRightUp(e) {
player.isRightDown = false;
}

// Game loop
function loop() {
// Tick
player.tick();

// Render
ctx.fillStyle = "gray";
ctx.fillRect(0,0,canvasWidth,canvasHeight);

player.render(ctx);

//
requestAnimationFrame(loop);
}

// Entry point (this function runs first, window.onload)
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;

ctx = canvas.getContext("2d");

jumpButton = document.getElementById("jumpButton");
leftButton = document.getElementById("leftButton");
rightButton = document.getElementById("rightButton");

jumpButton.onmousedown = onJumpDown;
jumpButton.onmouseup = onJumpUp;

leftButton.onmousedown = onLeftDown;
leftButton.onmouseup = onLeftUp;

rightButton.onmousedown = onRightDown;
rightButton.onmouseup = onRightUp;

player = new Player(85.0,140.0);

loop();
}

}();

</script>
</body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

PHP encountered an unexpected end of file error on line 48, causing a parsing syntax error

Good afternoon, I am struggling to identify the error in this code and would appreciate some assistance. Whenever I run the code, an error is returned but I can't pinpoint the exact issue. <?php include('functions.php'); if (!isLogg ...

What is the best way to handle promises within the context of updating state in React

Recently, I've been working on a React code snippet focused on creating a text input field. onChangeDestination(url, index) { this.setState(prevState => { const rules = [...prevState.rules]; rules[index] = { ...rules[index], url}; ...

What is the distinction between revealing environment variables in Next.js using the next.config.js as opposed to utilizing the NEXT_PUBLIC prefix?

As stated in the nextjs documentation, to make my environment variables accessible in the browser, I can simply prepend them with NEXT_PUBLIC in my .env.local file, like this: NEXT_PUBLIC_VAR=7 However, it seems that another approach is available where I ...

Utilizing Device Detection with CSS Media Queries and Flask/Jinja

Using CSS media queries in combination with Jinja and Flask, I am attempting to identify the device type and deliver images of appropriate sizes based on this information. In this setup, requests from mobile phones are intended to receive smaller images co ...

The <span> tag with content-editable attribute loses selection when the mouse button is released

I'm attempting to utilize a content-editable span tag as an inline text input box with variable width. Everything is functioning properly, except for the issue of not being able to select the entire text when focusing on the box. When tabbing to the e ...

Store the position of a draggable object using JQuery into an SQL database

Because of the current crisis, my friends and I are unable to meet up in person. To stay connected, I've come up with a little game for us to play online. Each of us can move an object on my website, and when the page is refreshed, we'll see the ...

Are there any negatives to turning off create-react-app's SKIP_PREFLIGHT_CHECK option?

After setting up my create-react-app project, I added eslint as a dev dependency. My reasons for doing this include: 1) Running eslint as a pre-commit check using husky and lint-staged 2) Extending CRA's eslint with airbnb and prettier lint configs ...

Maintaining Radio Input Selection in Vue.js Mobile App Despite Rendering New Questions

Seeking an alternative method, I have devised a clever solution to display survey questions without utilizing v-for loop. The purpose of this approach in a mobile android app is to prevent all questions from being rendered simultaneously and causing excess ...

Tips for refreshing the chosen item following a redirect to a different page

My current project involves creating an app with the use of ionic item-divider. A key feature is that when a user clicks on the list header, they are redirected to a new view where they can update and delete the selected item. However, I am facing a challe ...

Tips for delaying page rendering until an AJAX call finishes

While AJAX calls are known for allowing the rest of a page to load before a certain element is ready, I have a unique business requirement that complicates things. I am mandated to use AJAX due to the architecture in place. However, I cannot give the appe ...

Is the confirm button failing to delete users from the list in the AngularJS application?

As I work on developing a web application, my goal is to have a page displaying a list of users and another page containing a form for each user with three buttons. One of these buttons, the confirm button, should allow the user to be removed from the list ...

JavaScript - Asynchronous JavaScript and XML

function sendRequest(settings) { settings = { type: settings.type || "POST", url: settings.url || "", timeout: settings.timeout || 5000, onComplete: settings.onComplete || function(){}, onError: settings.onError || function(){}, onSuccess: set ...

Is there an issue with this code? HTML5 canvas

I am attempting to create a mesmerizing animation of a black hole simulation using the canvas element. My goal is to make objects exit the black hole if their distance from its center is greater than the black hole's radius, and to do so at variable s ...

Avoid re-rendering the page in Nuxt when adjusting dynamic parameters

My page has two dynamic parameters that trigger the fetch method to run again when the URL params are changed. I want to avoid this behavior. Fetch Method: async fetch() { await this.getFlightResult(); } Get Result Method: async getResult() { th ...

Show a single jQuery Validation error

I am struggling with displaying an error message at the top if validation fails, without using the errorPlacement option. Instead, I want to showcase the message in a Bootstrap alert box. Below is the HTML code snippet: <form method="POST" action="/ro ...

Use multiple lines to create a stunning visualization using morris.js. Let your data

I need help creating a graph using morris.js with 2 lines. I have two sets of data in one array, but I can't seem to display both lines on the graph simultaneously. When I use todos[0], only the first line is visible, and when I use todos[1], only the ...

"Exploring the array functionality of Angular's Reactive Forms

I am encountering an issue when trying to access the products array that is located within opticanOrders inside the orderForm. Despite seeing in the console that I should reference the products array like this: orderForm.controls.opticianOrders.controls.p ...

What's causing the member to be undefined?

client.on('raw', (e) => { if (e.t === 'MESSAGE_REACTION_ADD' && e.d.message_id === '813150433651851265' && e.d.emoji.name === "✅" ) { const guild = client.guilds.cache.get(e.d.gui ...

Why isn't my watch function functioning properly within Vue?

In my JS file, I have two components. The file starts with this line: const EventBus = new Vue(); I am trying to pass two strings, 'username' and 'password', from the first component to the second component, but it's not working. ...

Designing a dynamic bar graph with intricate data sets through the utilization of D3

Exploring the world of D3 for the first time and following a tutorial on creating a flexible chart that adjusts to the width and height regardless of the number of bars ('The new Chart'). Struggling with using personal data, here's the simp ...