This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Canvas, as one of the features of HTML5, can be used in many scenarios, such as data visualization (Echart), small games, page effects, and even page screenshots (HTML2Canvas).

This article introduces some common Canvas apis and usage techniques.

123 Wooden head game

123 Wooden head game online experience address

The game features

The rules of the game is very simple, after clicking on the start, you can press the space bar to control the character forward, but to the right of the wooden man back body when it can advance, or it will be judged to lose, as long as the control character across the white line, even if win.

Function split:

  • Start button
  • The player and the dummy
  • background
  • Rules for implementation

The game to achieve

This small game is implemented using native Canvas. First of all, the code split out of three canvas canvas, the first background canvas, mainly draw the game background; The first is the game content canvas, which shows the player and the wood; The third is the foreground canvas, which is mainly used to display the start button. Once you’ve implemented the three canvases, you just need to implement the rules of the game.

Background rendering

The background of the game is relatively simple to draw, directly look at the code

const bgPaint = {
  ctx: bgCanvas.getContext("2d"),
  drawBg() {
    this.ctx.beginPath();
    this.ctx.rect(0.0, width, height);
    this.ctx.fillStyle = "#ce574f";
    this.ctx.fill();
    const perHeight = height / 4;
    const end = 650;
    this.ctx.beginPath();
    this.ctx.lineWidth = 5;
    this.ctx.strokeStyle = "#e6b322";
    this.ctx.moveTo(end, 0);
    this.ctx.lineTo(end, height);
    this.ctx.closePath();
    this.ctx.stroke(); }}Copy the code

A rectangle is drawn, filled with background colors, and then a white line is drawn as the finish line.

Player and dummy drawing

Resources for both players and golems are available online. For the player, use the drawImage method to draw each frame in the third row to realize the character’s movement. For wooden people, just use the two or three lines in the third column to achieve the head turn effect.

There’s a class implemented on the player side

class Character {
  constructor(context, options = {}) {
    const { src, width = 32, height = 48, top = 50, listener } = options;
    this.ctx = context;
    this.src = src;
    this.width = width;
    this.height = height;
    this.top = top;
    this.actionIndex = 0;
    this.moveX = 0;
    this.timer = null;
    this.isMove = false;
    this.listener = listener;
    this.init();
  }

  init() {
    this.image = new Image();
    this.image.onload = () = > {
      this.ctx.drawImage(
        this.image,
        this.actionIndex * this.width, this.height * 2.this.width, this.height,
        0.this.top, this.width * 1.5.this.height * 1.5
      );
    };
    this.image.src = this.src;
  }

  walk() {
    if (this.isMove) {
      return;
    }
    this.isMove = true;
    this.forward();
    this.timer = setInterval(() = > {
      this.forward();
    }, 150);
  }

  forward() {
    this.actionIndex = (this.actionIndex + 1) % 4;
    this.moveX += 4;
    this.ctx.clearRect(0.this.top, 800.this.height * 1.5);
    this.ctx.drawImage(
      this.image,
      this.actionIndex * this.width, this.height * 2.this.width, this.height,
      this.moveX, this.top, this.width * 1.5.this.height * 1.5
    );
    this.listener && this.listener(this.moveX);
  }

  stop() {
    this.isMove = false;
    clearInterval(this.timer); }}Copy the code

The code uses actionIndex to record the current animation frame and moveX to record the player’s progress. The figure’s width and height corresponds to Sprite’s width and height divided by 4.

The init method in the class draws the character at the starting point; The forward method is to increase the horizontal position of the character by 4 and switch the animation frame; The walk method calls the forward method and uses setInterval to repeat the forward method. The stop method is to cancel setInterval. There’s also a listener property on this side that passes out the forward distance argument.

The main one in this class is the drawImge API, which is covered in more detail later.

The drawing code of wooden people:

const judge = {
  image: new Image(),
  init() {
    this.image.onload = () = > {
      this.draw();
    };
    this.image.src = "https://s3.bmp.ovh/imgs/2021/10/727fc27ee8b9a6e7.png";
  },
  turn(isLeft) {
    ctx.clearRect(700, (height - 96) / 2.64.96);
    this.draw(isLeft);
  },
  draw(isLeft) {
    ctx.drawImage(
      this.image,
      64, isLeft ? 48 : 96.32.48.700, (height - 96) / 2.64.96); }}Copy the code

Wood drawing is to draw the image at the destination position, and then draw the appropriate frame according to the need.

Start drawing the function

const forePaint = {
  ctx: foreCanvas.getContext("2d"),
  drawButton(text) {
    const btnW = 120;
    const btnH = 48;
    this.ctx.beginPath();
    this.ctx.rect((width - btnW) / 2.250, btnW, btnH);
    this.ctx.strokeStyle = "#ccc";
    this.ctx.stroke();
    this.ctx.font = '20px "Microsoft Yahei";
    this.ctx.textBaseline = "middle";
    this.ctx.textAlign = "center";
    this.ctx.fillStyle = "#fff";
    this.ctx.fillText(text, width / 2.250 + btnH / 2);
  },
  drawStart() {
    this.drawButton("Start");
  },
  drawWin() {
    this.ctx.font = '32px "Microsoft Yahei";
    this.ctx.textBaseline = "middle";
    this.ctx.textAlign = "center";
    this.ctx.fillStyle = "#fff";
    this.ctx.fillText("Win", width / 2.150);
    this.drawButton("One more time.");
  },
  drawLose() {
    this.ctx.font = '32px "Microsoft Yahei";
    this.ctx.textBaseline = "middle";
    this.ctx.textAlign = "center";
    this.ctx.fillStyle = "#fff";
    this.ctx.fillText("Lose", width / 2.150);
    this.drawButton("Start over");
  },
  clear() {
    this.ctx.clearRect(0.0, width, height); }};Copy the code

The start function is drawn on the foreground canvas for easy click function. The code is also relatively simple, using the ability to draw rectangles and draw text

Implementation of rules

foreCanvas.addEventListener("click".(e) = > {
  const isClickBtn = forePaint.ctx.isPointInPath(e.offsetX, e.offsetY);
  if(! isClickBtn || isGaming) {return;
  }

  isGaming = true;
  forePaint.clear();
  gameCount++;
  isCat = gameCount > 5;
  initGame();
})

const initGame = () = > {
  let isAllowRun = true;
  let timer = null;

  ctx.clearRect(0.0, width, height);
  judge.init();
  const girl = new Character(ctx, {
    src: isCat
      ? "https://s3.bmp.ovh/imgs/2021/10/035e5eb7556f6cf3.png"
      : "https://s3.bmp.ovh/imgs/2021/10/70b59c5699cfbab5.png".width: 32.height: isCat ? 32 : 48.listener: (x) = > {
      if (x > 650) {
        girl.stop();
        forePaint.drawWin();
        isGaming = false;
        isAllowRun = false;
        clearTimeout(timer);
        document.removeEventListener("keypress", handleKeyPress);
        document.removeEventListener("keyup", handleKeyUp); }}});let isRobotEnd = false;
  const robot = new Character(ctx, {
    src: "https://s3.bmp.ovh/imgs/2021/10/56c68440f5c1a836.png".top: 300.listener: (x) = > {
      if (x > 650) {
        isRobotEnd = true; robot.stop(); }}}); robot.walk();const handleKeyUp = () = > {
    girl.stop();
  };
  const handleKeyPress = (e) = > {
    e.preventDefault();
    if(! isGaming) {return;
    }
    if(! isAllowRun && isGaming && ! isCat) { girl.walk(); girl.stop(); forePaint.drawLose(); isGaming =false;
      isAllowRun = false;
      clearTimeout(timer);
      document.removeEventListener("keypress", handleKeyPress);
      document.removeEventListener("keyup", handleKeyUp);
      return;
    }
    if(event.keyCode ! = =32 || girl.isMove) {
      return;
    }
    girl.walk();
  };

  const singAndLook = () = >{ isAllowRun = ! isAllowRun; judge.turn(! isAllowRun);if(isAllowRun) { ! isRobotEnd && robot.walk(); }else {
      robot.stop();
    }
    timer = setTimeout(
      () = > { singAndLook(); },
      isAllowRun ? 5000 : 3000
    );
  };
  timer = setTimeout(() = > {
    singAndLook();
  }, 5000);

  document.addEventListener("keypress", handleKeyPress);
  document.addEventListener("keyup", handleKeyUp);
};

Copy the code

After clicking the start button, we initialized the player and the dummy, and started the timer to control the dummy’s back and front. The rules of the game are not very complicated, and the code just needs to follow the rules of the game.

Common apis and usage tips

Canvas is drawn mainly through the above objects. You can get the context object by using getContext.

Basic API

Drawing graphics

context.rect(x, y, width, height)
Copy the code

X,y is the position from the top left corner of the canvas, width, height is the width and height. Once the rectangular path is drawn, use the conetxt.stroke or context.fill methods to draw the border or fill

context.fillRect(x, y, width, height)
context.strokeRect(x, y, width, height)
Copy the code

These two methods, as their names suggest, are a combination of rect and the fill (or stroke) method

Draw the path

The following two apis are used to draw paths

moveTo(x, y) // Define the starting coordinates of a line
lineTo(x, y) // Define line end coordinates
Copy the code

The beginPath is called at the beginning of the drawing, which means that a new drawing is started and will not be mixed with the previous drawing.

Rendering text

fillText(text, x, y) // Draw solid text on canvas
strokeText(text, x, y) // Draw hollow text on canvas
Copy the code

Text is drawn through the above two apis. You can also set the font, textAlign, and textBaseLine of the context to control the font and display mode of the text.

Draw pictures

// Position the image on the canvas
context.drawImage(img, x, y)
// Position the image on the canvas and specify the width and height of the image
context.drawImage(img, x, y, width, height)
// Clip the image and position the clipped part on the canvas
context.drawImage(img, sx, sy, swidth, sheight, x, y, width, height)
Copy the code

There are three syntax methods for drawing pictures. The first two are easier to understand, and the third parameter has more meanings, each parameter has the following meanings:

  • The img parameter supports images, canvases, or videos.
  • Sx is the x-coordinate position where the shear starts
  • Sy is the y position where the shear starts
  • Swidth The width of the image to be clipped
  • Sheight Indicates the height of the clipped image
  • X Places the x coordinate position of the image on the canvas
  • Y The y-coordinate position of the image placed on the canvas
  • Width Specifies the width of the image to use. (Stretch or zoom out image)
  • Height Height of the image to use. (Stretch or zoom out image)

Use skills

Draw the animation

The main thing about drawing an animation is to use the drawImage method.

  • If each frame of your animation is an image, you can simply switch images, using either the first or second syntax of drawImage

  • If your animation is Sprite, you will need to crop the image using the third syntax of drawImage. Every frame has the right position

Support for click events

Unlike SVG, canvas click events can directly monitor the corresponding elements, which requires code implementation on canvas side. The above code type is determined using isPointInPath.

context.isPointInPath(x, y)
Copy the code

The isPointInPath() method returns true if the specified point is in the current path; Otherwise return false.

We start drawing a path using beginPath, and when we’re done drawing, we can use isPointInPath to tell if we clicked on the element.

However, this method only determines the final drawing path, and all of the above game code draws the button last on the foreground canvas. To support multiple path clicks, redraw the entire canvas using isPointInPath for each path.

conclusion

There are many advanced uses of Canvas, if you are interested, you can learn them in depth. There are also many Canvas libraries, such as pixi.js, fabric.js, paper.js, etc

123 Wooden head game code online address: 123 wooden head game

There is an Easter egg at the end of the game. Try to find it.