Circle Line Collision Demo

Use wasd to move the yellow circle.

The HTML file:

<head>
 <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
  <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"> </script>
 <script type="text/x-mathjax-config">
  MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}});
</script>

 <link rel="stylesheet" href="http://mirkwood.cs.edinboro.edu/~bennett/style/hw.css">
</head>

<body>

<h1> Circle Line Collision Demo</h1>
<canvas id="lineMove" width="400" height="400" style="border:1px solid #000000;"></canvas>
<script type="text/javascript" src="guy.js"></script>
<script type="text/javascript" src="lineCode.js"></script>
<script type="text/javascript">
canvas = document.getElementById("lineMove");
canvas.tabIndex = 0;

canvas.addEventListener("keydown", MyHandler);

let blocks = new Lines("lineMove", 50, 30);

let guy = new Guy("lineMove");
guy.Radius = 10;

DrawScene("lineMove", blocks, guy);
</script>
<p>
Use <b>wasd</b> to move the yellow circle.
</body>
</html>

guy.js

"use strict"

class Guy {
    
    constructor(canvasName, x=0,  y=0, r = 20) {
       this.canvas = document.getElementById(canvasName);
       this.ctx = canvas.getContext('2d');

       this.xpos = x;
       this.ypos = y;
       this.radius = r;
    }

    get Pos() {
       return [this.xpos,this.ypos];
    }

    get Radius() {
       return this.radius;
    }

    set Pos(p){
        this.xpos = p[0];
        this.ypos = p[1];
    }

    set Radius(r){
       this.radius = r;
    }

    Draw() {
       let cx, cy;

       this.ctx.beginPath();
       this.ctx.fillStyle = "yellow";
       this.ctx.arc(this.xpos, this.ypos, this.radius, 0 , 2*Math.PI);
       this.ctx.fill();
       this.ctx.strokeStyle = "black";
       this.ctx.arc(this.xpos, this.ypos, this.radius, 0 , 2*Math.PI);
       this.ctx.stroke();
    }
}

lineCode.js

"use strict"

const HORIZ =1;
const VERT = 2;
const NORMAL = 3;

class Line {
    constructor(canvasName, a,b,c,d) {
       this.canvas = document.getElementById(canvasName);
       this.ctx = canvas.getContext('2d');
 
       this.x1 = a;
       this.x2 = c;
       this.y1 = b;
       this.y2 = d;
   
       if (a == c) {
           this.type = HORIZ;
           this.y1 = Math.min(b,d);
           this.y2 = Math.max(b,d);
       } else if ( b == d) {
           this.type = VERT;
           this.x1= Math.min(a,c);
           this.x2= Math.max(a,c);
       } else {
          if (c < a) {
             this.x1 = c;
             this.y1 = d;
             this.x2 = a;
             this.y2 = b;
          }

          this.type = NORMAL;
          this.m = (this.y2-this.y1)/(this.x2-this.x1);
          this.b = this.y1 - this.m*this.x1;
          this.denom = this.m*this.m + 1;
       }
    }

    Distance(x,y,a,b) {
       let dx = x-a;
       let dy = y-b;

       return Math.sqrt(dx*dx + dy*dy);
    }

    HorizClose(x,y,dist) {
       let d;

       if (y < this.y1) { 
           d = this.Distance(x,y, this.x1, this.y1);
       } else if (y > this.y2) { 
           d = this.Distance(x,y, this.x2, this.y2);
       } else {
           d = Math.abs(this.x1 - x);
       }

       return d <= dist;
    }

    VertClose(x,y,dist) {
       let d;

       if (x < this.x1) {
           d = this.Distance(x,y, this.x1, this.y1);
       } else if (x > this.x2) {
           d = this.Distance(x,y, this.x2, this.y2);
       } else { 
           d = Math.abs(this.y1 - y);
       }
       return d <= dist;
    }

    Between(pt, a,b) {
       let t1 = Math.min(a,b);
       let t2 = Math.max(a,b);
       return (pt <= t2 && pt >= t1) ;
    }

    OtherClose(x,y,dist) {

       let num = x - this.m* this.b + this.m * y;
       let xi = num/this.denom;
       let yi = this.m*xi + this.b
       let d, d1, d2;

       if ( this.Between(xi, this.x1, this.x2)
            && this.Between(yi, this.y1, this.y2)) {
              d = this.Distance(xi, yi, x,y);
       } else {
           // we don't know the order of the y points.
           d1 = this.Distance(this.x1, this.y1, x, y);
           d2 = this.Distance(this.x2, this.y2, x, y);
           d = Math.min(d1,d2);
       }
       return d <= dist;

    }

    Close(x,y,dist){
       let rv;

        
       switch(this.type) {
          case NORMAL:
              rv = this.OtherClose(x,y,dist);
              break;
          case HORIZ:
              rv =  this.HorizClose(x,y,dist);
              break;
          case VERT:
              rv = this.VertClose(x,y,dist);
              break;
       }
       return rv;
    }

    Draw() {
      this.ctx.beginPath();
      this.ctx.strokeStyle = "blue";
      this.ctx.moveTo(this.x1, this.y1);
      this.ctx.lineTo(this.x2, this.y2);
      this.ctx.stroke();
    }
}

class Lines {
   lines = [];

   constructor (canvasName) {
       this.canvas = document.getElementById(canvasName);
       this.ctx = canvas.getContext('2d');

       this.w = this.canvas.width;
       this.h = this.canvas.height;

       this.lines.push(new Line(canvasName,  20, 20,  20, 200));
       this.lines.push(new Line(canvasName, 100, 80, 320,  80));
       this.lines.push(new Line(canvasName, 20,  300, 320,  120));

       this.Display();

    }

   Display() {
       var i;

       for(i = 0; i< this.lines.length; i++) {
          this.lines[i].Draw();
       }

       return;
   }

   Safe(x,y, dist ) {
      let i;
      let rv = true;

      for(i =0; i < this.lines.length; i++) {
         if (this.lines[i].Close(x, y, dist)) {
            rv = false;
         }
      }

      return rv;
   }
}

function DrawScene(canvasName, lines, guy) {
     let canvas = document.getElementById(canvasName);
     let ctx = canvas.getContext('2d');
   
     ctx.clearRect(0,0,canvas.width, canvas.height);

     lines.Display();
     guy.Draw();

     return;
}

function Crash(guy, lines) {
    let guyRad = guy.Radius;
    let pos = guy.Pos;
    let rv;

    // two pixel border between the two.
    let dist = guyRad+ 2;

    rv = !lines.Safe(pos[0],pos[1], dist)

    return rv;
}

function MyHandler(evnt) {
   let pos;

   pos = guy.Pos;

   let oldx = pos[0];
   let oldy = pos[1];

   switch(evnt.key) {
      case 'w':
      case 'k':
      case "ArrowUp":
         pos[1]--;
         break;
      case 's':
      case 'j':
      case "ArrowDown":
         pos[1]++;
         break;
      case 'a':
      case 'h':
      case "ArrowLeft":
         pos[0]--;
         break;
      case 'd':
      case 'l':
      case "ArrowRight":
         pos[0]++;
         break;
   }

    guy.Pos = pos;

   if (Crash(guy, blocks))  {
       guy.Pos = [oldx,oldy];
   }
   DrawScene("lineMove", blocks, guy);
   return;
}