I am participating in the nuggets Community game creative submission Contest. For details, please see: Game Creative Submission Contest

Vue3 + Vite + TypeScript + element-Plus Open source: github.com/wmuhua/vue3…

Welcome to experience, a star, thank you very much

The game is introduced

Let’s look at the interface

This is a jigsaw puzzle game – Huarong Road, it can choose the difficulty and choose the picture

After the start of the game according to different difficulty, generate and selected main map corresponding to different pieces of random order of the small map, and then as long as the disorderly small picture to restore the complete picture on the success of the pass

There is a blank position in the game area, which can be replaced by clicking the picture adjacent to the blank position with the mouse, that is, moving, or operating up and down with the keyboard

When you have nothing to do, or when you are not thinking clearly, ha ha ha.

Although the technique is very simple, it took me a while, especially with the images. Determine the overall style, look for background images, game frames. Also taking advantage of the holiday two days ago, I asked my girlfriend to help me find pictures, and also found a lot of pictures for her to help reference, after all, her aesthetic is stronger than me, I am a rough man

The core idea

  • The level of the game, such as beginner, is set at 3, the game interface is three rows and three columns, intermediate level is set at 4, the game interface is four rows and four columns, which is the square of the current level, is the total number of cells
  • After the start of the game with the total number of grid for the maximum, to generate random number arrayrandomDataPrimary as:,1,7,2,4,8,6,5,9 [3], traversal to generate a small picture, the maximum value is blank grid, that is 9
  • And according to the current level to generate the jigsaw completed datafinishDataPrimary as:123456789
  • Click or keyboard keys will be eligible,randomDataSwap the values of the target cell and the blank cell, and then automatically update the view to complete the move
  • At each step, count the steps and checkrandomData().join('') == finishDataEquality is the completion of the puzzle

The core code

Pay attention to the notes

html

Below is the complete HTML of the jigsaw area, controlled by state isStart

<div class="stage">
  <div class="game-name" v-show=! "" isStart">Game hua-rong-dao</div>
  <div class="content clearfix" v-show="isStart">
    <div
      v-for="item in randomData"
      :key="item"
      :class="`img${level}`"
      @click="handleMove(item)"
    >
      <el-image
        v-if="item ! = randomData.length"
        :src="getSmallImg(`${gameImg}/${level}/${item}.jpg`)"
      ></el-image>
    </div>
  </div>
</div>
Copy the code

The getSmallImg method is used to dynamically import images. After all, it is not webpack and is not as convenient as require

// Get a small picture of the current game
export const getSmallImg = (path: string) = > {
  return new URL(`.. /assets/images/${path}`.import.meta.url).href
}
Copy the code

Games class

The JS part mainly encapsulates a class to facilitate unified management operations

/ / puzzle
class Puzzle implements IPuzzle {
  isStart = false  // Game state
  randomData: Array<number> = [] // An out-of-order array corresponding to the number of small images in the current game
  finishData = "" // Complete the puzzle in order
  gameImg = ""  // Game master image
  level = 3 // Game level
  step = 0 // The number of game steps
  constructor() {}
  / / initialization
  init({ gameImg, level }: IMode) {
    this.step = 0
    this.level = level
    this.gameImg = gameImg
    // Generate a random number array for the current game
    this.randomData = this.getRandomData()
    this.isStart = !this.isStart
    // If the game is started, calculate the data when the puzzle is completed
    if (this.isStart) this.finishData = this.getFinishData()
  }
  // Move the image
  move(idx: number) {}
  // Keyboard events
  onKeyDown(code: number){}
  // Check to see if the puzzle is complete
  finish() {}
  // Generates a small array of images
  getRandomData(){}}Copy the code

Generate a random number of images

When clicked to start the game, getRandomData is executed to generate a random number array, and then the DOM section walks through the generated random number array and renders the minced image

// Generates a small array of images
getRandomData() {
    // Set of random numbers
    let randomArr = []
    // The maximum value is generated based on the level of the game, minus 1 because the maximum value is reserved as a blank bit at the end
    let max = Math.pow(this.level, 2) - 1
    while (randomArr.length < max) {
      // Generate a random number within the maximum range
      let random = Math.floor(Math.random() * max) + 1
      if (randomArr.indexOf(random) == -1) {
        // Add if there are no duplicates
        randomArr.push(random)
      }
    }
    randomArr.push(max + 1) // Add the largest number as the last blank bit
    return randomArr // For example: [3, 1, 7, 2, 4, 8, 6, 5, 9]
}
Copy the code

Moving pictures

Receive a parameter that corresponds to the value of each image while iterating through the random number array randomData, which is given when the mouse clicks

// Move the image
move(idx: number) {
    let level = this.level
    let target = this.randomData.indexOf(idx) // Current click position subscript
    let space = this.randomData.indexOf(Math.pow(level, 2)) // Blank position subscript

    // If the blank space is on the far left, click on a number on the right
    // And white space can also be swapped when the next number on the left is clicked on the far right
    let condition =
      (space % level == 0 && target % level == level - 1) ||
      (space % level == level - 1 && target % level == 0)
      
    // If you can swap
    if(! condition) {// And click the target, up or down or left or right is blank, to switch positions
      if (
        target == space - level ||
        target == space + level ||
        target == space - 1 ||
        target == space + 1
      ) {
          this.change(space, target)
      }
    }
}
/ / move
change(space: number, target: number) {
    // Replace the blank position with the target position
    this.randomData[space] = this.randomData[target]
    // The target position is the maximum value
    this.randomData[target] = Math.pow(this.level, 2)
    Steps / /
    this.step += 1
    // Check if it is complete
    this.finish()
}
Copy the code

Keyboard events

// Keyboard events
onKeydown(code: number) {
    let level = this.level
    // Target position subscript
    let target
    // Blank position subscript
    let space = this.randomData.indexOf(Math.pow(level, 2))
    // up, down, left and right
    switch (code) {
      case 37:
        target = space + 1
        if (space % level == level - 1) return
        this.change(space, target)
        break
      case 38:
        target = space + level
        if (target > this.randomData.length - 1) return
        this.change(space, target)
        break
      case 39:
        target = space - 1
        if (space % level == 0) return
        this.change(space, target)
        break
      case 40:
        target = space - level
        if (target < 0) return
        this.change(space, target)
        break}}Copy the code

The puzzle to complete

The idea is to convert the current out-of-order randomData into a string, and the positive order finishData for comparison, if the same, is completed

// Check to see if the puzzle is complete
finish() {
    // If '312' == '123'
    if (this.randomData.join("") = =this.finishData) {
      ElMessageBox.alert('Congratulations, pass successfully, only useThe ${this.step}Step `."Tip", {
        confirmButtonText: "OK".callback: (action: Action) = > {
          this.randomData = []
          this.step = 0
          this.isStart = false}})}}// According to different difficulty to generate the completion of the puzzle data for comparison, judge whether to complete
// For example: 123456789
getFinishData(): string {
    let str = ""
    for (let i = 1, len = Math.pow(this.level, 2); i <= len; i++) {
      str += i
    }
    return str
}
Copy the code

conclusion

  • If there is any mistake or better scheme, welcome to help me to correct the comments section
  • If you have any requirements, please leave a comment
  • XDM, please support me by clicking a “like”. Thank you very much