Screen boundary bouncing effect upon reaching the edge

Currently, I am working on an animated project using canvas. I have successfully implemented the functionality to control the image (ship.png) with the arrow keys for different directions. However, I am facing challenges with creating a bounce effect when the image reaches the edges of the screen. Can someone provide me with suggestions or guidance on how to achieve this?

In my code snippet, I have attempted to incorporate the bounce effect within this section: this.displacement = function(e)

One idea that came to mind was to add an OR condition like so: (e.keyCode == '38'), but I am struggling to find the right approach.

Answer №1

Within the function update, it is crucial to monitor the direction of your ship's movement and whether it comes into contact with the boundaries of the canvas. If the ship touches a boundary, reverse its speed by multiplying it by -1.

All necessary checks have been outlined for you in the snippet provided. To enhance efficiency, consider incorporating additional if else statements. For instance, if you are certain that the ship is moving left, there is no need to perform boundary checks other than the one for the left side.

// Boundary check
const movingLeft = this.ship.get_direction === this.ship.getX && this.ship.getSpeed() < 0;
const touchingLeftBound = this.ship.x <= 0;

const movingRight = this.ship.get_direction === this.ship.getX && this.ship.getSpeed() > 0;
const touchingRightBound = this.ship.x >= this.canvas.width - this.ship.image.width;

const movingUp = this.ship.get_direction === this.ship.getY && this.ship.getSpeed() < 0;
const touchingTopBound = this.ship.y <= 0;

const movingDown = this.ship.get_direction === this.ship.getY && this.ship.getSpeed() > 0;
const touchingBottomBound = this.ship.y >= this.canvas.height - this.ship.image.height;

if (
  (movingLeft && touchingLeftBound) ||
  (movingDown && touchingBottomBound) ||
  (movingUp && touchingTopBound) ||
  (movingRight && touchingRightBound)
) {
  this.ship.setSpeed(this.ship.getSpeed() * -1);
}

const CREATION = 100;
const PRECARGE = 200;
const START   = 300;

class spaceship{

   constructor(x, y,image){
      this.x = x;
      this.y = y;
      this.image=image;
      this.speed = 20;//initial speed, before any key
      this.get_direction=null;
      this.set_direction=null;
   }        
   getX() {
     return this.x;
   }
   getY(){
     return this.y;
   }
   getSpeed(){
      return this.speed;
   }    
   setX(x){
      this.x = x;
   }
   setY(y) {
     this.y = y;
   }  
   setSpeed(speed){
      this.speed=speed;
   }     
   setimage(image) {
      this.image = image;
   }
   getimage() {
      return this.image;
   }    
   draw(ctx) {
     ctx.drawImage(this.getimage(),0,0,100,50,this.getX(),this.getY(),100,50);
   }
 }//end of spaceship class 


function Animation(){    
   
   this.state = CREATION;
   this.images  = new Array();
   this.canvas = document.getElementById("canvas");
   this.context = this.canvas.getContext("2d");
   this.aux_canvas = document.createElement("canvas"); // "canvas" refer to the <canvas> tag.
   this.aux_context = this.aux_canvas.getContext("2d")
      
   this.canvas.width=document.body.clientWidth;  //current window size
   this.canvas.height=document.body.clientHeight;
   this.aux_canvas.width=document.body.clientWidth;
   this.aux_canvas.height=document.body.clientHeight;

   this.ship = null;
      
   var object=this;
   
   this.loadImages = function(){

      this.images["ship"] = new Image();
      this.images["ship"].name="ship";
      this.images["ship"].src= "https://i.sstatic.net/XQbAW.png";
   }

   this.update = function(){
      this.aux_context.clearRect(0, 0, this.canvas.width, this.canvas.height); //clean the canvas of ships
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);    // in both canvases the background is not erased
      this.ship.draw(this.aux_context);
      
      // Check bounds
      const movingLeft = this.ship.get_direction === this.ship.getX && this.ship.getSpeed() < 0;
      const touchingLeftBound = this.ship.x <= 0;

      const movingRight = this.ship.get_direction === this.ship.getX && this.ship.getSpeed() > 0;
      const touchingRightBound = this.ship.x >= this.canvas.width - this.ship.image.width;

      const movingUp = this.ship.get_direction === this.ship.getY && this.ship.getSpeed() < 0;
      const touchingTopBound = this.ship.y <= 0;

      const movingDown = this.ship.get_direction === this.ship.getY && this.ship.getSpeed() > 0;
      const touchingBottomBound = this.ship.y >= this.canvas.height - this.ship.image.height;
      
      if (
        (movingLeft && touchingLeftBound) ||
        (movingDown && touchingBottomBound) ||
        (movingUp && touchingTopBound) ||
        (movingRight && touchingRightBound)
      ) {
        this.ship.setSpeed(this.ship.getSpeed() * -1);
      }
  
      this.context.drawImage(this.aux_canvas,0,0,this.aux_canvas.width,this.aux_canvas.height,0,0,this.canvas.width,this.canvas.height);
      this.ship.set_direction(this.ship.get_direction()+(this.ship.getSpeed()));

   }

   this.displacement = function(e) {

      e = e || window.event;

      if (e.keyCode == '38'|| e.keyCode == '40') {
         //up
         object.ship.set_direction=object.ship.setY;
         object.ship.get_direction=object.ship.getY;    
         if (e.keyCode == '38') //up
            object.ship.setSpeed(-20);
         else//down
            object.ship.setSpeed(20);    
      }
      else if (e.keyCode == '37' || e.keyCode == '39') {
         object.ship.set_direction=object.ship.setX;
         object.ship.get_direction=object.ship.getX;        
         if (e.keyCode == '37') //left
            object.ship.setSpeed(-20);
         else//right
            object.ship.setSpeed(20);         
      }

 }

   this.executeMachineStates = function(){
      var imagesUploaded=true;
      if (object.state == CREATION) {
         object.loadImages();
         object.state = PRECARGE;
         setTimeout(object.executeMachineStates, 100);

      } else {
         if(object.state==PRECARGE){

            console.log("state: PRECARGE");
            for(var i=0;i<object.images.length;i++)
               if(object.images[i].complete!=true)
                  imagesUploaded=false;                  
            if(imagesUploaded==true){
               //200 and 100 is the ship's initial position
               object.ship = new spaceship(200, 100,object.images["ship"]);
               object.ship.get_direction=object.ship.getX;  //initial movement
               object.ship.set_direction=object.ship.setX;  //on x-axis
               object.state = START;
               document.onkeydown = object.displacement;
            }
            setTimeout(object.executeMachineStates, 100);
         }else{
            if(object.state==START){
               object.update();
               setTimeout(object.executeMachineStates, 100);
            }
         }
      }
   }

}//end of class/function Animation

animation= new Animation();
animation.executeMachineStates();
body {
  background: black;
  border: 1px solid red;
  width: 400px;
  height: 400px;
}
<canvas id="canvas">
</canvas>

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

What is the best way to clear the textureCache in A-Frame's latest release?

Currently working on a project involving multi-camera streaming, I've noticed a continuous increase in memory usage after switching between cameras. I've managed to clean up on the hls.js side of things, but I haven't come across any methods ...

Ways to incorporate customizable text and images into three.js

Recently, I've been experimenting with adding new images and text as textures to a 3D object using fabric js for my 3D configurator. My codebase is inspired by this GitHub repository, and I'm also utilizing this code from CodePen. One key aspect ...

Executing npm variables dynamically (such as process.env.SERVER) on a Windows system with Cmder - a step-by-step guide

I've put together a NodeJs, Selenium, and WebdriverIO framework, but I'm having trouble with running npm variables at runtime (Oddly enough, it works fine on my Mac). Here's an excerpt from my wdio file: if(process.env.SERVER == "prod") { ...

Can the text linked to a specific element be shown on the screen?

I've been delving into the world of Selenium and C# lately, and I'm curious to know if there's a way to retrieve the text associated with a specific element. For instance, consider this snippet of HTML that contains the desired content: &l ...

Working with masonry does not involve filling tiny crevices

Check out the DEMO here Experience the FULL Screen DEMO An issue with Masonry: it's not filling small gaps even when there is available space. For example, in a main container with a width of 896px; next to the first container with an orange backgr ...

What is the best way to store HTML in a variable as a string?

Imagine if I have a variable: let display_text = "Cats are pawsome!" I aim to show it as such: <div> <b>Cats</b> are pawsome! </div> To be clear, dynamically enclose the word "cats" whenever it shows up. ...

Tribal Code Typescript Compiler

Typescript is a great alternative to Javascript in my opinion, but it bothers me that it requires node.js as a dependency. Additionally, I find it frustrating that there seems to be only one compiler available for this language, and it's self-hosted. ...

Retrieve all records from the database using a Sequelize query that fall within the timeframe specified by the start

Currently, I'm attempting to retrieve data from a database using Sequelize, filtering for items that were created within a specific date range. Despite implementing the $between operator in my query, I'm facing difficulties as I'm not receiv ...

Is there a way to access Prestashop's Web service using a client's login credentials instead of a key?

Currently, I am delving into Prestashop's development and experimenting with creating a third-party application using react.js (specifically React Native). My goal is to retrieve Json data from the Prestashop webservice. However, my main focus is on a ...

Automatically scroll the element both up and down

I am working on a bootstrap table that needs to automatically scroll vertically. The table will be displayed on a screen and could have varying numbers of items, so I want it to continuously auto-scroll for the user's convenience. Once it reaches the ...

Is there a specific regular expression that can be used for validating Credit Card Expiry dates in Javascript/Ang

I am currently working on a textfield where users can enter their credit card expiry date in the format mm/yy. To ensure the validity of this input, I have implemented JavaScript validation using regular expressions. Here is an example of what I have tried ...

Adjust the size of an image based on the size of the screen

I am currently working on creating a navigation menu using icons that need to resize as the screen size changes. Here is my progress so far: http://jsbin.com/yesitepuwo/edit?html,css,output [it's possible that the link does not work in firefox?] Cur ...

Verifying Value Equality in all Documents with MongoDB

One feature on my website allows users to input a number into the field labeled subNum in a form. Upon submission of the form, I need to validate whether the entered value already exists within any existing document. This validation process is implemented ...

What are some recommended strategies for directives communication in AngularJS without relying on $rootScope?

I am currently facing a challenge with my nested directive where I need to establish communication with another directive on the same page, sharing the same controller. Although I initially attempted the isolate scope approach, the complexity of the nestin ...

Instructions for receiving user input and displaying it on the screen, as well as allowing others with access to the URL to view the shared input provided by the original user

<h1>Lalan</h1> <input type="text" name="text" id="text" maxlength="12"> <label for="text"> Please enter your name here</label> <br><input type="submit" value ...

After the rendering of the HTML, the value of the jQuery input does not change

Here we have a function that loads HTML onto the form class in a file. The quest[q] locates the appropriate HTML template to load from an array of templates. The HTML being loaded contains an input with an id of "p". I am attempting to set the value of th ...

What is the best way to update the data-url attribute with a new value using jQuery?

Initially, before the page loads: <a data-url="htts://xyz@..." class="mybuttons" data-type="facebook"> After page load, I dynamically update the data-url using jQuery: <a data-url="https://abc@..." class="mybuttons" data-type="facebook"> ...

What is the best way to align text and an arrow on the same line, with the text centered and the arrow positioned on the

.down { transform: rotate(45deg); -webkit-transform: rotate(45deg); } .arrow { border: solid black; border-width: 0 3px 3px 0; display: inline-block; padding: 30px; } <p>Down arrow: <i class="arrow down"></i></p> Looking to ...

Leverage the power of Node.js by utilizing http.get along with

I have been working on integrating a library (available here) into my project, which is capable of generating QR codes and various other types of codes. My current issue revolves around making a request where I can access both the req and res objects in o ...

What steps can be taken to adjust the alignment of a Bootstrap Dropright menu so that it opens in an upward direction instead of the standard downward

My dropdown menu is dropping towards the right correctly, but it is going downwards and getting hidden under my page. I want it to open upwards instead of downwards. I attempted to adjust the CSS, adding bottom:0 to the dropdown-menu, but unfortunately, i ...