手把手教學h5小游戲 - 貪吃蛇

来源:https://www.cnblogs.com/jundong/archive/2019/11/30/11963501.html
-Advertisement-
Play Games

簡單的小游戲製作,代碼量只有兩三百行。游戲可自行擴展延申。 源碼已發佈至github,喜歡的點個小星星,源碼入口: "game snake" 游戲已發佈,游戲入口: "http://snake.game.yanjd.top" 第一步 製作想法 游戲如何實現是首要想的,這裡我的想法如下: 1. 利用c ...


簡單的小游戲製作,代碼量只有兩三百行。游戲可自行擴展延申。

源碼已發佈至github,喜歡的點個小星星,源碼入口:game-snake

游戲已發佈,游戲入口:http://snake.game.yanjd.top

第一步 - 製作想法

游戲如何實現是首要想的,這裡我的想法如下:

  1. 利用canvas進行繪製地圖(格子裝)。
  2. 利用canvas繪製蛇,就是占用地圖格子。讓蛇移動,即:更新蛇坐標,重新繪製。
  3. 創建四個方向按鈕,控制蛇接下來的方向。
  4. 隨機在地圖上繪製出果子,蛇移動時“吃”到果子,增加長度和“移速”。
  5. 開始鍵和結束鍵配置,分數顯示、歷史記錄

第二步 - 框架選型

從第一步可知,我想實現這個游戲,只需要用到canvas繪製就可以了,沒有物理引擎啥的,也沒有高級的UI特效。可以選個簡單點的,用來方便操作canvas繪製。精挑細選後選的是EaselJS,比較輕量,用於繪製canvas,以及canvas的動態效果。

第三步 - 開發

準備

目錄和文件準備:

| - index.html

| - js

| - | - main.js

| - css

| - | - stylesheet.css

index.html 導入相關的依賴,以及樣式文件和腳本文件。設計是屏幕80%高度為canvas繪製區域,20%高度是操作欄以及展示分數區域.

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible"
    content="ie=edge">
  <title>貪吃蛇</title>
  <link rel="stylesheet" href="css/stylesheet.css">
  <meta name="viewport"
    content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
</head>

<body>
  <div id="app">
    <div class="content-canvas">
      <canvas></canvas>
    </div>
    <div class="control">
    </div>
  </div>
  <script src="https://cdn.bootcss.com/EaselJS/1.0.2/easeljs.min.js"></script>
  <!-- 載入jquery 方便dom操作 -->
  <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  <!-- sweetalert 美化alert用的 -->
  <script src="https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js"></script>
  <script src="js/main.js"></script>
</body>

</html>

stylesheet.css

* {
  padding: 0;
  margin: 0;
}
body {
  position: fixed;
  width: 100%;
  height: 100%;
}
#app {
  max-width: 768px;
  margin-left: auto;
  margin-right: auto;
}
/* canvas繪製區域 */
.content-canvas {
  width: 100%;
  max-width: 768px;
  height: 80%;
  position: fixed;
  overflow: hidden;
}
.content-canvas canvas {
  position: absolute;
  width: 100%;
  height: 100%;
}
/* 操作區域 */
.control {
  position: fixed;
  width: 100%;
  max-width: 768px;
  height: 20%;
  bottom: 0;
  background-color: #aeff5d;
}

main.js

$(function() {
  // 主代碼編寫區域
})

1.繪製格子

註意的點(遇到的問題以及解決方案):

  1. canvas繪製的路線是無寬度的,但線條是有寬度的。比如:從(0, 0)到(0, 100)繪製一條寬度為10px的線,則線條一半是在區域外看不見的。處理方案是起點偏移,比如:從(0, 0)到(0, 100)繪製一條寬度為10px的線,改為從(5,0)到(5,100),偏移量為線條寬度的一半。
  2. 用樣式定義canvas的寬高坐標會被拉伸,處理方案是給canvas元素設置寬高屬性,值為它當前的實際寬高。

代碼

main.js

$(function () {
  var LINE_WIDTH = 1 // 線條寬度
  var LINE_MAX_NUM = 32 // 一行格子數量
  var canvasHeight = $('canvas').height() // 獲取canvas的高度
  var canvasWidth = $('canvas').width() // 獲取canvas的寬度
  var gridWidth = (canvasWidth - LINE_WIDTH) / LINE_MAX_NUM // 格子寬度,按一行32個格子計算
  var num = { w: LINE_MAX_NUM, h: Math.floor((canvasHeight - LINE_WIDTH) / gridWidth) } // 計算橫向和縱向多少個格子,即:橫坐標的最大值和縱坐標的最大值

  /**
 * 繪製格子地圖
 * @param graphics
 */
  function drawGrid(graphics) {
    var wNum = num.w
    var hNum = num.h
    graphics.setStrokeStyle(LINE_WIDTH).beginStroke('#ffac52')
    // 畫橫向的線條
    for (var i = 0; i <= hNum; i++) {
      if (i === hNum || i === 0) graphics.setStrokeStyle(LINE_WIDTH)
      if (i === 1) graphics.setStrokeStyle(0.1)
      graphics.moveTo(LINE_WIDTH / 2, i * gridWidth + LINE_WIDTH / 2)
        .lineTo(gridWidth * wNum + LINE_WIDTH / 2, i * gridWidth + LINE_WIDTH / 2)
    }
    graphics.setStrokeStyle(LINE_WIDTH)
    // 畫縱向的線條
    for (i = 0; i <= wNum; i++) {
      if (i === wNum || i === 0) graphics.setStrokeStyle(LINE_WIDTH)
      if (i === 1) graphics.setStrokeStyle(.1)
      graphics.moveTo(i * gridWidth + LINE_WIDTH / 2, LINE_WIDTH / 2)
        .lineTo(i * gridWidth + LINE_WIDTH / 2, gridWidth * hNum + LINE_WIDTH / 2)
    }
  }

  function init() {
    $('canvas').attr('width', canvasWidth) // 給canvas設置寬高屬性賦值上當前canvas的寬度和高度(單用樣式配置寬高會被拉伸)
    $('canvas').attr('height', canvasHeight)
    var stage = new createjs.Stage($('canvas')[0])
    var grid = new createjs.Shape()
    drawGrid(grid.graphics)
    stage.addChild(grid)
    stage.update()
  }

  init()
})

效果圖

瀏覽器打開index.html,可以看到效果:

2.繪製蛇

蛇可以想象成一串坐標點(數組),“移動時”在數組頭部添加新的坐標,去除尾部的坐標。類似隊列,先進先出。

代碼

main.js

$(function () {
  var LINE_WIDTH = 1 // 線條寬度
  var LINE_MAX_NUM = 32 // 一行格子數量
  var SNAKE_START_POINT = [[0, 3], [1, 3], [2, 3], [3, 3]] // 初始蛇坐標
  var DIR_ENUM = { UP: 1, DOWN: -1, LEFT: 2, RIGHT: -2 }    // 移動的四個方向枚舉值,兩個對立方向相加等於0
  var GAME_STATE_ENUM = { END: 1, READY: 2 } // 游戲狀態枚舉
  var canvasHeight = $('canvas').height() // 獲取canvas的高度
  var canvasWidth = $('canvas').width() // 獲取canvas的寬度
  var gridWidth = (canvasWidth - LINE_WIDTH) / LINE_MAX_NUM // 格子寬度,按一行32個格子計算
  var num = { w: LINE_MAX_NUM, h: Math.floor((canvasHeight - LINE_WIDTH) / gridWidth) } // 計算橫向和縱向多少個格子,即:橫坐標的最大值和縱坐標的最大值
  var directionNow = null // 當前移動移動方向
  var directionNext = null // 下一步移動方向
  var gameState = null // 游戲狀態

  /**
 * 繪製格子地圖
 * @param graphics
 */
  function drawGrid(graphics) {
    var wNum = num.w
    var hNum = num.h
    graphics.setStrokeStyle(LINE_WIDTH).beginStroke('#ffac52')
    // 畫橫向的線條
    for (var i = 0; i <= hNum; i++) {
      if (i === hNum || i === 0) graphics.setStrokeStyle(LINE_WIDTH)
      if (i === 1) graphics.setStrokeStyle(0.1)
      graphics.moveTo(LINE_WIDTH / 2, i * gridWidth + LINE_WIDTH / 2)
        .lineTo(gridWidth * wNum + LINE_WIDTH / 2, i * gridWidth + LINE_WIDTH / 2)
    }
    graphics.setStrokeStyle(LINE_WIDTH)
    // 畫縱向的線條
    for (i = 0; i <= wNum; i++) {
      if (i === wNum || i === 0) graphics.setStrokeStyle(LINE_WIDTH)
      if (i === 1) graphics.setStrokeStyle(.1)
      graphics.moveTo(i * gridWidth + LINE_WIDTH / 2, LINE_WIDTH / 2)
        .lineTo(i * gridWidth + LINE_WIDTH / 2, gridWidth * hNum + LINE_WIDTH / 2)
    }
  }

  /** 
   * 坐標類
   */
  function Point(x, y) {
    this.x = x
    this.y = y
  }

  /**
   * 根據移動的方向,獲取當前坐標的下一個坐標
   * @param direction 移動的方向
   */
  Point.prototype.nextPoint = function nextPoint(direction) {
    debugger
    var point = new Point(this.x, this.y)
    switch (direction) {
      case DIR_ENUM.UP:
        point.y -= 1
        break
      case DIR_ENUM.DOWN:
        point.y += 1
        break
      case DIR_ENUM.LEFT:
        point.x -= 1
        break
      case DIR_ENUM.RIGHT:
        point.x += 1
        break
    }
    return point
  }

  /**
 * 初始化蛇的坐標
 * @returns {[Point,Point,Point,Point,Point ...]}
 * @private
 */
  function initSnake() {
    return SNAKE_START_POINT.map(function (item) {
      return new Point(item[0], item[1])
    })
  }

  /**
   * 繪製蛇
   * @param graphics
   * @param snakes // 蛇坐標
   */
  function drawSnake(graphics, snakes) {
    graphics.clear()
    graphics.beginFill("#a088ff")
    var len = snakes.length
    for (var i = 0; i < len; i++) {
      if (i === len - 1) graphics.beginFill("#ff6ff9")
      graphics.drawRect(
        snakes[i].x * gridWidth + LINE_WIDTH / 2,
        snakes[i].y * gridWidth + LINE_WIDTH / 2,
        gridWidth, gridWidth)
    }
  }

  /**
 * 改變蛇身坐標
 * @param snakes 蛇坐標集
 * @param direction 方向
 */
  function updateSnake(snakes, direction) {
    var oldHead = snakes[snakes.length - 1]
    var newHead = oldHead.nextPoint(direction)
    // 超出邊界 游戲結束
    if (newHead.x < 0 || newHead.x >= num.w || newHead.y < 0 || newHead.y >= num.h) {
      gameState = GAME_STATE_ENUM.END
    } else if (snakes.some(function (p) { // ‘吃’到自己 游戲結束
      return newHead.x === p.x && newHead.y === p.y
    })) {
      gameState = GAME_STATE_ENUM.END
    } else {
      snakes.push(newHead)
      snakes.shift()
    }
  }

  /**
   * 引擎
   * @param graphics
   * @param snakes
   */
  function move(graphics, snakes, stage) {
    clearTimeout(window._engine) // 重啟時關停之前的引擎
    run()
    function run() {
      directionNow = directionNext
      updateSnake(snakes, directionNow) // 更新蛇坐標
      if (gameState === GAME_STATE_ENUM.END) {
        end()
      } else {
        drawSnake(graphics, snakes)
        stage.update()
        window._engine = setTimeout(run, 500)
      }
    }
  }

  /**
   * 游戲結束回調
   */
  function end() {
    console.log('游戲結束')
  }

  function init() {
    $('canvas').attr('width', canvasWidth) // 給canvas設置寬高屬性賦值上當前canvas的寬度和高度(單用樣式配置寬高會被拉伸)
    $('canvas').attr('height', canvasHeight)
    directionNow = directionNext = DIR_ENUM.DOWN // 初始化蛇的移動方向
    var snakes = initSnake()
    var stage = new createjs.Stage($('canvas')[0])
    var grid = new createjs.Shape()
    var snake = new createjs.Shape()
    drawGrid(grid.graphics) // 繪製格子
    drawSnake(snake.graphics, snakes)
    stage.addChild(grid)
    stage.addChild(snake)
    stage.update()
    move(snake.graphics, snakes, stage)
  }

  init()
})

效果圖

效果圖(gif):

3.移動蛇

製作4個按鈕,控制移動方向

代碼

index.html

...
<div class="control">
  <div class="row">
    <div class="btn">
      <button id="UpBtn">上</button>
    </div>
  </div>
  <div class="row clearfix">
    <div class="btn half-width left">
      <button id="LeftBtn">左</button>
    </div>
    <div class="btn half-width right">
      <button id="RightBtn">右</button>
    </div>
  </div>
  <div class="row">
    <div class="btn">
      <button id="DownBtn">下</button>
    </div>
  </div>
  </div>
</div>
...

stylesheet.css

...
.control .row {
  position: relative;
  height: 33%;
  text-align: center;
}

.control .btn {
  box-sizing: border-box;
  height: 100%;
  padding: 4px;
}

.control button {
  display: inline-block;
  height: 100%;
  background-color: white;
  border: none;
  padding: 3px 20px;
  border-radius: 3px;
}

.half-width {
  width: 50%;
}

.btn.left {
  padding-right: 20px;
  float: left;
  text-align: right;
}

.btn.right {
  padding-left: 20px;
  float: right;
  text-align: left;
}

.clearfix:after {
  content: '';
  display: block;
  clear: both;
}

mian.js

...
/**
 * 改變蛇行進方向
 * @param dir
 */
function changeDirection(dir) {
  /* 逆向及同向則不改變 */
  if (directionNow + dir === 0 || directionNow === dir) return
  directionNext = dir
}

/**
 * 綁定相關元素點擊事件
 */
function bindEvent() {
  $('#UpBtn').click(function () { changeDirection(DIR_ENUM.UP) })
  $('#LeftBtn').click(function () { changeDirection(DIR_ENUM.LEFT) })
  $('#RightBtn').click(function () { changeDirection(DIR_ENUM.RIGHT) })
  $('#DownBtn').click(function () { changeDirection(DIR_ENUM.DOWN) })
}

function init() {
  bindEvent()
  ...
}

效果圖

效果圖(gif):

4. 繪製果子

隨機取兩個坐標點繪製果子,判定如果“吃到”,則不刪除尾巴。縮短定時器的時間間隔增加難度。

註意的點(遇到的問題以及解決方案):新增一個果子不能占用蛇的坐標,一開始考慮的是隨機生成一個坐標,如果坐標已被占用,那就繼續生成隨機坐標。然後發現這樣做有個問題就是整個界面剩餘兩個坐標可用時(極端情況,蛇占了整個屏幕就差兩個格子了),那這樣的話,不停隨機取坐標,要取到這最後兩個坐標要耗不少時間。後面改了方法,先統計所有坐標,然後迴圈蛇身坐標,一一排除不可用坐標,然後再隨機抽取可用坐標的其中一個。

代碼

main.js

$(function () {
  var LINE_WIDTH = 1 // 線條寬度
  var LINE_MAX_NUM = 32 // 一行格子數量
  var SNAKE_START_POINT = [[0, 3], [1, 3], [2, 3], [3, 3]] // 初始蛇坐標
  var DIR_ENUM = { UP: 1, DOWN: -1, LEFT: 2, RIGHT: -2 }    // 移動的四個方向枚舉值,兩個對立方向相加等於0
  var GAME_STATE_ENUM = { END: 1, READY: 2 } // 游戲狀態枚舉
  var canvasHeight = $('canvas').height() // 獲取canvas的高度
  var canvasWidth = $('canvas').width() // 獲取canvas的寬度
  var gridWidth = (canvasWidth - LINE_WIDTH) / LINE_MAX_NUM // 格子寬度,按一行32個格子計算
  var num = { w: LINE_MAX_NUM, h: Math.floor((canvasHeight - LINE_WIDTH) / gridWidth) } // 計算橫向和縱向多少個格子,即:橫坐標的最大值和縱坐標的最大值
  var directionNow = null // 當前移動移動方向
  var directionNext = null // 下一步移動方向
  var gameState = null // 游戲狀態
  var scope = 0 // 分數

  /**
 * 繪製格子地圖
 * @param graphics
 */
  function drawGrid(graphics) {
    var wNum = num.w
    var hNum = num.h
    graphics.setStrokeStyle(LINE_WIDTH).beginStroke('#ffac52')
    // 畫橫向的線條
    for (var i = 0; i <= hNum; i++) {
      if (i === hNum || i === 0) graphics.setStrokeStyle(LINE_WIDTH)
      if (i === 1) graphics.setStrokeStyle(0.1)
      graphics.moveTo(LINE_WIDTH / 2, i * gridWidth + LINE_WIDTH / 2)
        .lineTo(gridWidth * wNum + LINE_WIDTH / 2, i * gridWidth + LINE_WIDTH / 2)
    }
    graphics.setStrokeStyle(LINE_WIDTH)
    // 畫縱向的線條
    for (i = 0; i <= wNum; i++) {
      if (i === wNum || i === 0) graphics.setStrokeStyle(LINE_WIDTH)
      if (i === 1) graphics.setStrokeStyle(.1)
      graphics.moveTo(i * gridWidth + LINE_WIDTH / 2, LINE_WIDTH / 2)
        .lineTo(i * gridWidth + LINE_WIDTH / 2, gridWidth * hNum + LINE_WIDTH / 2)
    }
  }

  /** 
   * 坐標類
   */
  function Point(x, y) {
    this.x = x
    this.y = y
  }

  /**
   * 根據移動的方向,獲取當前坐標的下一個坐標
   * @param direction 移動的方向
   */
  Point.prototype.nextPoint = function nextPoint(direction) {
    var point = new Point(this.x, this.y)
    switch (direction) {
      case DIR_ENUM.UP:
        point.y -= 1
        break
      case DIR_ENUM.DOWN:
        point.y += 1
        break
      case DIR_ENUM.LEFT:
        point.x -= 1
        break
      case DIR_ENUM.RIGHT:
        point.x += 1
        break
    }
    return point
  }

  /**
 * 初始化蛇的坐標
 * @returns {[Point,Point,Point,Point,Point ...]}
 * @private
 */
  function initSnake() {
    return SNAKE_START_POINT.map(function (item) {
      return new Point(item[0], item[1])
    })
  }

  /**
   * 繪製蛇
   * @param graphics
   * @param snakes // 蛇坐標
   */
  function drawSnake(graphics, snakes) {
    graphics.clear()
    graphics.beginFill("#a088ff")
    var len = snakes.length
    for (var i = 0; i < len; i++) {
      if (i === len - 1) graphics.beginFill("#ff6ff9")
      graphics.drawRect(
        snakes[i].x * gridWidth + LINE_WIDTH / 2,
        snakes[i].y * gridWidth + LINE_WIDTH / 2,
        gridWidth, gridWidth)
    }
  }

  /**
 * 改變蛇身坐標
 * @param snakes 蛇坐標集
 * @param direction 方向
 */
  function updateSnake(snakes, fruits, direction, fruitGraphics) {
    var oldHead = snakes[snakes.length - 1]
    var newHead = oldHead.nextPoint(direction)
    // 超出邊界 游戲結束
    if (newHead.x < 0 || newHead.x >= num.w || newHead.y < 0 || newHead.y >= num.h) {
      gameState = GAME_STATE_ENUM.END
    } else if (snakes.some(function (p) { // ‘吃’到自己 游戲結束
      return newHead.x === p.x && newHead.y === p.y
    })) {
      gameState = GAME_STATE_ENUM.END
    } else if (fruits.some(function (p) { // ‘吃’到水果
      return newHead.x === p.x && newHead.y === p.y
    })) {
      scope++
      snakes.push(newHead)
      var temp = 0
      fruits.forEach(function (p, i) {
        if (newHead.x === p.x && newHead.y === p.y) {
          temp = i
        }
      })
      fruits.splice(temp, 1)
      var newFruit = createFruit(snakes, fruits)
      if (newFruit) {
        fruits.push(newFruit)
        drawFruit(fruitGraphics, fruits)
      }
    } else {
      snakes.push(newHead)
      snakes.shift()
    }
  }

  /**
   * 引擎
   * @param graphics
   * @param snakes
   */
  function move(snakeGraphics, fruitGraphics, snakes, fruits, stage) {
    clearTimeout(window._engine) // 重啟時關停之前的引擎
    run()
    function run() {
      directionNow = directionNext
      updateSnake(snakes, fruits, directionNow, fruitGraphics) // 更新蛇坐標
      if (gameState === GAME_STATE_ENUM.END) {
        end()
      } else {
        drawSnake(snakeGraphics, snakes)
        stage.update()
        window._engine = setTimeout(run, 500 * Math.pow(0.9, scope))
      }
    }
  }

  /**
   * 游戲結束回調
   */
  function end() {
    console.log('游戲結束')
  }

  /**
   * 改變蛇行進方向
   * @param dir
   */
  function changeDirection(dir) {
    /* 逆向及同向則不改變 */
    if (directionNow + dir === 0 || directionNow === dir) return
    directionNext = dir
  }

  /**
   * 綁定相關元素點擊事件
   */
  function bindEvent() {
    $('#UpBtn').click(function () { changeDirection(DIR_ENUM.UP) })
    $('#LeftBtn').click(function () { changeDirection(DIR_ENUM.LEFT) })
    $('#RightBtn').click(function () { changeDirection(DIR_ENUM.RIGHT) })
    $('#DownBtn').click(function () { changeDirection(DIR_ENUM.DOWN) })
  }

  /**
 * 創建水果坐標
 * @returns Point
 * @param snakes
 * @param fruits
 */
  function createFruit(snakes, fruits) {
    var totals = {}
    for (var x = 0; x < num.w; x++) {
      for (var y = 0; y < num.h; y++) {
        totals[x + '-' + y] = true
      }
    }
    snakes.forEach(function (item) {
      delete totals[item.x + '-' + item.y]
    })
    fruits.forEach(function (item) {
      delete totals[item.x + '-' + item.y]
    })
    var keys = Object.keys(totals)
    if (keys.length) {
      var temp = Math.floor(keys.length * Math.random())
      var key = keys[temp].split('-')
      return new Point(Number(key[0]), Number(key[1]))
    } else {
      return null
    }
  }

  /**
 * 繪製水果
 * @param graphics
 * @param fruits 水果坐標集
 */
  function drawFruit(graphics, fruits) {
    graphics.clear()
    graphics.beginFill("#16ff16")
    for (var i = 0; i < fruits.length; i++) {
      graphics.drawRect(
        fruits[i].x * gridWidth + LINE_WIDTH / 2,
        fruits[i].y * gridWidth + LINE_WIDTH / 2,
        gridWidth, gridWidth)
    }
  }

  function init() {
    bindEvent()
    $('canvas').attr('width', canvasWidth) // 給canvas設置寬高屬性賦值上當前canvas的寬度和高度(單用樣式配置寬高會被拉伸)
    $('canvas').attr('height', canvasHeight)
    directionNow = directionNext = DIR_ENUM.DOWN // 初始化蛇的移動方向
    var snakes = initSnake()
    var fruits = []
    fruits.push(createFruit(snakes, fruits))
    fruits.push(createFruit(snakes, fruits))
    var stage = new createjs.Stage($('canvas')[0])
    var grid = new createjs.Shape()
    var snake = new createjs.Shape()
    var fruit = new createjs.Shape()
    drawGrid(grid.graphics) // 繪製格子
    drawSnake(snake.graphics, snakes)
    drawFruit(fruit.graphics, fruits)
    stage.addChild(grid)
    stage.addChild(snake)
    stage.addChild(fruit)
    stage.update()
    move(snake.graphics, fruit.graphics, snakes, fruits, stage)
  }

  init()
})

效果圖

效果圖(gif):

5. 分數顯示、游戲結束提示、排行榜

這一部分就比較簡單了,處理下數據的展示即可。這部分代碼就不展示出來了。

效果圖

結語

界面比較粗糙,主要是學習邏輯操作。中間出現一些小問題,但都一一的解決了。createjs這個游戲引擎還是比較簡單易學的,整體只用了繪製圖形的api。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • https://www.jianshu.com/p/faa5e852b76b https://bbs.csdn.net/topics/70039385 https://www.runoob.com/sqlite/sqlite-insert.html http://c.biancheng.net/vi ...
  • 基本語法如下 sqlite> select * from tb_user; sqlite> select userid,username from tb_user; 格式化的查詢輸出 sqlite> .header on sqlite> .mode column sqlite> select * f ...
  • 概述&背景 MySQL一直被人詬病沒有實現HashJoin,最新發佈的8.0.18已經帶上了這個功能,令人欣喜。有時候在想,MySQL為什麼一直不支持HashJoin呢?我想可能是因為MySQL多用於簡單的OLTP場景,並且在互聯網應用居多,需求沒那麼緊急。另一方面可能是因為以前完全靠社區,這種演進 ...
  • SQL:Structured Quety Language SQL SERVER是一個以客戶/伺服器(c/s)模式訪問、使用Transact-SQL語言的關係型資料庫管理子系統(RDBMS) DBMS :Database Management System資料庫管理系統 資料庫:程式用來存取數據的 ...
  • Responding to the Launch of Your App Initialize your app’s data structures, prepare your app to run, and respond to any launch-time requests from the ...
  • 一、完成了內容中的右邊的一部分。練習了三點:小盒子在大盒子中的位置,最好用大盒子的內邊距完成佈局,而不是用小盒子的外邊距來進行佈局;複習了ul,li的用法。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>D ...
  • css背景樣式屬性介紹 背景樣式就是自定義 標簽的背景顏色或背景圖像。 背景屬性說明表 屬性名 | 屬性值|描述 | | background color | f00、red、rgb(255,0,0)|設置背景顏色。 background image |url(背景圖片路徑)|設置背景圖像。 bac ...
  • jQuery中的事件 在JavaScript中,常用的基礎事件有滑鼠事件、鍵盤事件、window事件、表單事件、事件綁定和處理函數的語法格式如下 語法q 事件名 = "函數名()"; 或者 DOM對象.事件名 = 函數; 1、載入事件 $(function () {}); //推薦使用 $(docu ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...