Blanka's Stick Weapon Street Fighters

Copy & paste below to have your own little street fighter version for yourself (put your canvas html dom before your code ; its width and height are 500, and upload the images to the server).
      
     <div class='heading'>
      Stick Weapon Street Fighters
    </div>
    <canvas style="border:1px solid gray;width:800px;height:500px" id="canv" width="500" height="500"></canvas>
      let startGame = true;
      let cursorLevel = 0;
      let level = ['blanka', 'ryu', 'm bison', 'sagat', 'guile'];
      let levelColor = ['green', 'white', 'red', 'beige', 'lime'];
    
      class Canvas {
        constructor(dr) {
          this.dr = dr;
        }
        
        setDrawer(dr) {
          this.dr = dr;
        }
        
        getDrawer() {
          return this.dr;
        }
      }
      
      class Man {
        isPunching = true;
        point = 99;
        armLeftX = 0;
        armLeftY = 0;
        armRightX = 0;
        armRightY = 0;
        xx = 0;
        yy = 0;
        constructor(x, y) {
          this.xx = x;
          this.yy = y;
          this.armLeftX = this.xx - 50;
          this.armLeftY = this.yy + 75;
          this.armRightX = this.xx + 100;
          this.armRightY = this.yy + 75;
        }
      }

      // Animation Loop
        function animate1(ctx,centerX,centerY,radiusX,radiusY,rotationAngle) {
            // 1. Clear the canvas for the next frame
          
            // 2. Draw the spinning ellipse
            ctx.beginPath();
            
            // Syntax: ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle)
            ctx.ellipse(centerX, centerY, radiusX, radiusY, rotationAngle, 0, Math.PI * 2);
            
            ctx.strokeStyle = '#00ffcc';
            ctx.lineWidth = 5;
            ctx.stroke();

            // 3. Increment the angle to handle the "spin" velocity
            rotationAngle += 140; // Adjust this value to change speed

            // 4. Request the next animation frame
              centerX += 15;
            requestAnimationFrame(animate1);
        }
        
      function drawLine(ctx, startX, startY, endX, endY, color = 'black', thickness = 1) {
        ctx.beginPath();            // 1. Start a new path layout
        ctx.moveTo(startX, startY); // 2. Lift up the pen and move it to the start point
        ctx.lineTo(endX, endY);     // 3. Aim a straight line to the end point
  
        // Optional styling
        ctx.strokeStyle = color;    // Set line color
        ctx.lineWidth = thickness;  // Set line thickness
  
        ctx.stroke();               // 4. Actually draw the line on the canvas
      }

      function fillOval(ctx, x, y, width, height, color) {
        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.ellipse(x + width / 2, y + height / 2, width, height, 0, 0, 2 * Math.PI);
        ctx.fill();
      }
      
      let time = null;
      let enem = new Man(370, 250);
      let neat = new Man(130, 250);
      class Round {
        pl1wins = 0;
        pl2wins = 0;
        pl1 = 0;
        pl2 = 0;
        setRound = 0;
      
        reset() {
          this.pl1wins = 0;
          this.pl2wins = 0;
          this.setRound = 0;
        }
        
        setValues(v1, v2) {
          this.pl1 = v1;
          this.pl2 = v2;
        }
        
        inc1() {
          //alert("$$");
          this.pl1wins++;
          this.setRound++;
          //alert("&"+this.pl1wins);
        }
        
        inc2() {
          this.pl2wins++;
          this.setRound++;
        }
      }
  
      let rr = null;
      let rnd = new Round();   
      var sp = -10;
      var v = 1;
      var ef = 0;
      
      function youWin(ctx) {
        if(v == 1) {
          v = 0;
        
          time.t = 99;
          sp = 20;
          var ti = null;
          ef = 1;
          try {
            clearInterval(ti);
            ti = setInterval(()=>{
              if(sp >0) {
                ctx.fillStyle = "red";
                ctx.fillRect(0,0,500,500);
                ctx.font = '50px Arial';
                ctx.fillStyle = "black";
                ctx.fillText('You Win', 200, 80);
              
                sp--;
              }
              if(sp <= 0) {
                cursorLevel++;
                if(cursorLevel == level.length) {
                  cursorLevel = 0;
                }
              
                ef = 0;
                startGame = true;
                time.t = 99;
                sp = -10; 
                rr.reset();
                rnd.reset();
              }
            }, 1000);
            setInterval(()=>{
              if(sp <= 0)
                clearInterval(ti);
            },50);
          } catch(e) {}
        }
      }
      
      function youLoseRound(ctx) {
        if(v == 1) {
          v = 0;
          time.t = 99;
          sp = 20;
          var ti = null;
          ef = 1;
          try {
            clearInterval(ti);
            ti = setInterval(()=>{
              if(sp >0) {
                ctx.fillStyle = "beige";
                ctx.fillRect(0,0,500,500);
                ctx.font = '50px Arial';
                 ctx.fillStyle = "black";
                ctx.fillText('You Lose the Round', 20, 80);
              
              sp--;
              }
              if(sp <= 0) {
      
                ef = 0;
                startGame = false;
                time.t = 99;
              
                rr.reset();
                rnd.reset();
              }
            }, 1000);
            setInterval(()=>{
              if(sp <= 0)
                clearInterval(ti);
            },50);
          } catch(e) {}
        }
      }
      
      function youWinRound(ctx) {
        if(v == 1) {
          v = 0;
        
          time.t = 99;
          sp = 20;
          var ti = null;
          ef = 1;
          try {
            clearInterval(ti);
            ti = setInterval(()=>{
              if(sp >0) {
                ctx.fillStyle = "beige";
                ctx.fillRect(0,0,500,500);
                ctx.font = '50px Arial';
                ctx.fillStyle = "black";
                ctx.fillText('You Win the Round', 20, 80);
              
                sp--;
              }
              if(sp <= 0) {
              
                ef = 0;
                startGame = false;
                time.t = 99;
                 
                rr.reset();
                rnd.reset();
              }
            }, 1000);
            setInterval(()=>{
              if(sp <= 0)
                clearInterval(ti);
            },50);
          } catch(e) {}
        }
      }
      
      function youLose(ctx) {
        if(v == 1) {
          v = 0;
          time.t = 99;
          sp = 20;
          var ti = null;
          ef = 1;
          try {
            clearInterval(ti);
            ti = setInterval(()=>{
              if(sp >0) {
                ctx.fillStyle = "red";
                ctx.fillRect(0,0,500,500);
                ctx.font = '50px Arial';
                 ctx.fillStyle = "black";
                ctx.fillText('You Lose', 200, 80);
              
              sp--;
              }
              if(sp <= 0) {
                if(cursorLevel == level.length) {
                  cursorLevel = 0;
                }
                ef = 0;
                startGame = true;
                time.t = 99;
                sp = -10;
                rr.reset();
                rnd.reset();
              }
            }, 1000);
            setInterval(()=>{
              if(sp <= 0)
                clearInterval(ti);
            },50);
          } catch(e) {}
        }
      }
      
      class RoundMg {
        player1 = 0;
        player2 = 0;
        
        setPlayers(pl1, pl2) {
          this.player1 = pl1;
          this.player2 = pl2;
          // alert("*"+this.player1);
        }
        
        reset() {
          this.player1 = 99;
          this.player2 = 99;
          rnd.setRound = 0;
        }
        
        setRoundObj(rnd) {
          //alert(time.t);
          if(rnd.pl1 > rnd.pl2 && time.t <= 0) {
            //alert("__");
            rnd.inc1();
          
            //alert("+");
          } else if(rnd.pl2 > rnd.pl1 && time.t <= 0) {
            rnd.inc2();
          
            //alert("-");
          }
          //alert(rnd.setRound);
          this.setPlayers(rnd.pl1wins, rnd.pl2wins); 
        }
        
        checkWinner() {
          //alert("@"+this.player1);
          
          //alert("t@"+rnd.setRound);
          if(this.player1 >= 2)
            return 1;
          else if(this.player2 >= 2)
            return 2;
          return 0;
        }
        
        thenDraw(ctx) {
          //alert("#"+time.t);
          if(time.t <= 0) {
         
            let winner = this.checkWinner();
            //alert("()"+winner);
            if(winner == 1)
              youWin(ctx);
            else
              if(winner == 2)
                youLose(ctx);
         
           /* if(rnd.pl1 > rnd.pl2)
              youWinRound(ctx);
            else if(rnd.pl2 > rnd.pl1)
              youLoseRound(ctx);*/
          }
          
          this.reset();
        }
      }
      
      rr = new RoundMg();
      
      class Time {
        t = 99;
        c = null;
        
        runTime() {
          try {
            clearInterval(c);
            
          } catch(e) {}
          c = setInterval(() => {
            this.t--;
          }, 1000);
        }
        
        reset() {
          clearInterval(c);
          this.t = 99;
          runTime();
        }
        
        
        draw(ctx, en, en2) {
          ctx.fillStyle = "red";
          ctx.font = "55px Arial";
          if(this.t > 0)
            ctx.fillText(this.t, 210, 100);
          if(this.t <= 0) {
            rnd.setValues(en.point, en2.point);
            //alert(en2.point);
            rr.setRoundObj(rnd);
            rr.thenDraw(ctx);
            en.point = en2.point = this.t = 99;
            //en2.xx = 370;
            //startGame = true;
          }
        }
      }
      
      time = new Time();
      var a = true;   
      
      class Drawer {
          
        constructor(dr) {
          this.dr = dr;
          
          this.#sky();
          this.#myfield();
              
        }
        
        
        #sky() {
          this.dr.fillStyle = "blue";
          
          this.dr.fillRect(0, 0, 500, 350);
        }
        
        #myfield() {
          this.dr.fillStyle = "brown";
          
          this.dr.fillRect(0, 350, 500, 150);
        }
        
        #drawLevelName(en, en2) {
          this.dr.fillStyle = "yellow";
          
          this.dr.font = "50px Arial";
          
          this.dr.fillText("R.Y.U.", 20, 150);
          this.dr.fillText(level [cursorLevel], 360, 150);
        }
        
        #punch(en, en2) {
          if(en.isPunching) {
            en.armLeftX -= 50;
            if(en.armLeftX < en2.armRightX - 50) {
              en2.point-=5;
              en2.xx -= 10;
              en2.armLeftX -= 10;
              en2.armRightX -= 10;
            }
            en.isPunching = false;
          } else {
            if(en.armLeftX != en.xx - 50) {
              en.armLeftX += 50;
            }
          }
        }
        
        #punchByNeat(en, en2) {
          if(en.isPunching) {
            en.armRightX += 50;
            if(en.armRightX > en2.armLeftX + 50) {
              en2.point-=5;
              en2.xx += 10;
              en2.armLeftX += 10;
              en2.armRightX += 10;
            }
            en.isPunching = false;
          } else {
            if(en.armRightX != en.xx + 100) {
              en.armRightX -= 50;
              en.isPunching = true;
            }
          }
          this.dr.fillStyle = "black";
          
          this.dr.font = "40px Arial";
        
          this.dr.fillText(en.point, 20, 50);
          this.dr.fillText(en2.point, 360, 50);
        }
        
        #runChores(g) {
       
          this.#sky();
          this.#myfield();
              
              
          var i = Math.floor(Math.random()*20);
          
          var k = 0;
          var splash = 50;
          
          
          g.addEventListener('click', ()=>{
            const rect = g.getBoundingClientRect();
            const x = event.clientX - rect.left;
            const y = event.clientY - rect.top;
            if(y > 250) {
              if(x < 250) {
                neat.xx -= 15;
                neat.armLeftX -= 15;
                neat.armRightX -= 15;
              } else {
                neat.xx += 15;
                neat.armLeftX += 15;
                neat.armRightX += 15;
                if(enem.xx - 50 < neat.xx + 50) {
                  enem.xx += 15;
                  enem.armRightX += 15;
                  enem.armLeftX += 15;
                }
              }
            } else {
              if(x > 250) {
                var centerX = neat.armRightX;
                var centerY = 250;

                // Ellipse properties
                const radiusX = 15; // Horizontal radius
                const radiusY = 6;  // Vertical radius
                let rotationAngle = 0; // Starting angle in radians
      
                var j = 0;
                // Initialize animation
                var r = setInterval(() => {
                  j++;
                  centerX+=5;
                  animate1(this.dr,centerX,centerY,radiusX,radiusY,rotationAngle);
              },45);
              var hit=false;
              var s = setInterval(()=>{
                  if(j>60||centerX>enem.armLeftX)
                  clearInterval(r);
                  if(centerX>enem.armLeftX) { 
                    clearInterval(r);
                    if(!hit)enem.point -= 10;
                    enem.xx+=2;
                    enem.armLeftX+=2;
                    enem.armRightX+=2;
                    hit=true;
               }
              }, 50);
            } else {
                this.#punchByNeat(neat, enem);
            }
           }
          });
          
          
          setInterval(() => {
      
            
            if(startGame && sp == -10) {
              v = 1;
              
              this.dr.fillStyle = "green";
              this.dr.fillRect(0, 0, 500, 500);
              this.dr.font = "50px Arial";
              this.dr.fillStyle = "ivory";
              this.dr.fillText(level[cursorLevel], 120, 200);
              splash--;
              if(splash == 0) {
                startGame = false;
                splash = 50;
                if(a)
                  time.runTime();
                a = false;
                time.t = 99;
                neat.point = enem.point = 99;
              }
            } else {
              
              if(ef == 0) {
            
              this.#sky();
              this.#myfield();
              
              if(splash == 50) {
                splash = 52;
               // if(a)
                //  time.runTime();
              
                a = false;
              }
              
              if(sp == 0) {
                //alert(sp);
                //sp = 1;
              }
              
              time.draw(this.dr, neat, enem);
              
              
              
              i = Math.floor(Math.random()*5);
              if(i == 0)
                enem.isPunching = true;
              k = Math.floor(Math.random()*10);
              if(k == 5)
                k -= Math.floor(Math.random()*13);
              if(enem.xx > 350)
                k = -Math.floor(Math.random()*40);
              if(enem.xx < neat.armRightX)
                k = Math.floor(Math.random()*40);
              enem.xx += k;
              enem.armLeftX += k;
              enem.armRightX += k;
              if(enem.xx - 50 < neat.xx + 50)
              {
                neat.xx -= 15;
                neat.armRightX -= 15;
                neat.armLeftX -= 15;
              }
              this.#punch(enem, neat);
              this.#drawNeat(neat);
              
              if(!neat.isPunching) {
                if(neat.armRightX != neat.xx + 100) {
                  neat.armRightX -= 50;
                  neat.isPunching = true;
                }
              }
              this.#drawEnemy(enem);
              /*this.#drawPoints(neat, enem);*/
              this.#drawLevelName(neat, enem);
            }
            }
          }, 350);
          
          
          // this.#drawPoints(neat, enem);
           
           
        }
        
        skyField(g) {
          this.#runChores(g);
        }
        
        #drawEnemy(en) {
          fillOval(this.dr, en.xx, en.yy, 50, 75, levelColor[cursorLevel]);
          const img = new Image();
          img.src = './blanka.png';
          if(level[cursorLevel] == 'ryu')
            img.src = './ryu.png';
          if(level[cursorLevel] == 'm bison')
            img.src = './mbison.png';
          if(level[cursorLevel] == 'sagat')
            img.src = './sagat.png';
          this.dr.drawImage(img, en.xx + 5, en.yy + 10, 40, 55);
          drawLine(this.dr, en.armLeftX, en.armLeftY, en.xx, en.yy + 38, 'white', 4);
        }
        
        #drawNeat(en) {
          fillOval(this.dr, en.xx, en.yy, 50, 75, 'gray');
          drawLine(this.dr, en.armRightX, en.armRightY, en.xx+50, en.yy + 38, 'white', 5);
        }
        
      }
      
      
      class Graphics { 
        g = null;
        constructor() {}
        #getGCont() {
          this.g = document.getElementById("canv");
          return this.g;
        }
        
        getCanvas() {
          return this.g;
        }
        
        
        getDrawerInstance() {
          return new Drawer(this.#getGCont().getContext("2d"));
        }
      }
      
      var cv = new Canvas(null);
      var G = new Graphics();
      cv.setDrawer(G.getDrawerInstance());
      cv.getDrawer().skyField(G.getCanvas());
  
      <button style="font-size:50px" onclick="cv.getDrawer().left()"><</button> <button style="font-size:50px"  onclick="cv.getDrawer().right()">></button> <button style="font-size:50px" onclick="cv.getDrawer().jumpLeft()"><<</button> <button style="font-size:50px" onclick="cv.getDrawer().jumpRight()">>></button> <button style="font-size:50px" onclick="cv.getDrawer().punchPlayer()">punch</button>