Search code examples
javascripthtmlcsscanvas

Bounce effect when reaching the limit of the screen


I am making an animation with canvas, I have managed to make the image (ship.png) to be controlled with the up, right, down and left keys. But I have problems with the bounce effect when reaching the limit of the screen. Could you help me if you could give me some suggestions on how to do it please.

I have tried to make the bounce effect in this part of the code: this.displacement = function(e)

I was specifically thinking of putting an OR conditional here: (e.keyCode == '38') but I can't think of a way to do it.


Solution

  • In update, you can check the direction your ship is moving in and whether it is touching the sides of the canvas. If it is, you flip the speed by multiplying with -1.

    I wrote out all the checks for you (see the snippet). You can optimize it a bit by including some more if else statements. For example: if you know the ship is moving left, you don't have to do any other bound checks than the left bound one.

    // 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);
    }
    

    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>