AHKv1移植版

#NoEnv
#SingleInstance Force
; AHKVERSION: V1.1 U32/U64
; 原 v2 版来源:https://github.com/fuwt/AHKScript
; 本文件为 AutoHotkey v1 转写版。

ListLines, Off
SetBatchLines, -1
SendMode, Input
SetWorkingDir, %A_ScriptDir%

global t := new Tetris()
OnMessage(0x000F, "Tetris_WM_PAINT")
t.Startup()
OnExit, Tetris_OnExit
return

Up::
  t.transform_current_block()
return

Down::
  t.move_down()
return

Left::
  t.move_left()
return

Right::
  t.move_right()
return

TetrisGuiClose:
TetrisGuiEscape:
ExitApp
return

Tetris_OnExit:
  if (IsObject(t))
    t.Close()
ExitApp
return

Tetris_RedrawOnce:
  if (IsObject(t))
    t.RefreshBitmaps()
return

Tetris_WM_PAINT(wParam, lParam, msg, hwnd) {
  global t
  if (IsObject(t) && hwnd == t.hwnd)
    SetTimer, Tetris_RedrawOnce, -10
}

class Tetris
{
  __New() {
    this.current_block := []
    this.next_block := 0
    this.stop_blocks := []
    this.width := 10
    this.height := 20
    this.linewidth := 1
    this.blockwidth := 30
    this.width_px := this.width * this.blockwidth + (1 + this.width) * this.linewidth
    this.height_px := this.height * this.blockwidth + (1 + this.height) * this.linewidth
    this.score := 0
    this.closed := false
    this.blocks := this.CreateBlocks()
  }

  CreateBlocks() {
    blocks := []
    blocks.Push([[[0,1,1],[1,1,0],[0,0,0]], [[1,0,0],[1,1,0],[0,1,0]]])
    blocks.Push([[[1,1,0],[0,1,1],[0,0,0]], [[0,1,0],[1,1,0],[1,0,0]]])
    blocks.Push([[[1,0,0],[1,0,0],[1,0,0],[1,0,0]], [[0,0,0,0],[0,0,0,0],[1,1,1,1],[0,0,0,0]]])
    blocks.Push([[[0,1,1],[0,1,1]]])
    blocks.Push([[[1,0,0],[1,1,1],[0,0,0]], [[0,1,1],[0,1,0],[0,1,0]], [[0,0,0],[1,1,1],[0,0,1]], [[0,1,0],[0,1,0],[1,1,0]]])
    blocks.Push([[[0,0,1],[1,1,1],[0,0,0]], [[0,1,0],[0,1,0],[0,1,1]], [[0,0,0],[1,1,1],[1,0,0]], [[1,1,0],[0,1,0],[0,1,0]]])
    blocks.Push([[[0,1,0],[1,1,1],[0,0,0]], [[0,1,0],[0,1,1],[0,1,0]], [[0,0,0],[1,1,1],[0,1,0]], [[0,1,0],[1,1,0],[0,1,0]]])
    return blocks
  }

  ; 启动入口
  Startup() {
    this.hGdipModule := DllCall("LoadLibrary", "Str", "gdiplus", "Ptr")

    VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0)
    NumPut(1, si, 0, "UInt")
    DllCall("gdiplus\GdiplusStartup", "PtrP", pToken, "Ptr", &si, "Ptr", 0)
    this.pGdipToken := pToken

    this.CreateBitmapCanvas(this.width_px, this.height_px, hbm, sdc, graphics)
    this.hbm := hbm
    this.sdc := sdc
    this.Graphics := graphics
    this.CreateBitmapCanvas(this.blockwidth * 4, this.blockwidth * 4, hbm2, sdc2, graphics2)
    this.hbm2 := hbm2
    this.sdc2 := sdc2
    this.Graphics2 := graphics2

    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFDDEDFF, "PtrP", pBrush1), this.pBrush1 := pBrush1
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFFFAAAA, "PtrP", pBrush2), this.pBrush2 := pBrush2
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFFF5555, "PtrP", pBrush3), this.pBrush3 := pBrush3
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFF0F0F0, "PtrP", pBrush4), this.pBrush4 := pBrush4
    DllCall("gdiplus\GdipCreatePen1", "UInt", 0xFFCCCCCC, "Float", this.linewidth, "Int", 2, "PtrP", pPen), this.pPen := pPen

    this.get_current_block()
    this.CreateMainWindow()
    this.Draw()

    this.blank_line := []
    Loop, % this.width
      this.blank_line.Push(0)
    this.Reset()

    timer := ObjBindMethod(this, "move_down")
    this.timer := timer
    SetTimer, % timer, 500
  }

  CreateBitmapCanvas(width, height, ByRef hbm, ByRef sdc, ByRef graphics) {
    VarSetCapacity(bi, 40, 0)
    NumPut(40, bi, 0, "UInt")
    NumPut(Round(width), bi, 4, "Int")
    NumPut(Round(height), bi, 8, "Int")
    NumPut(1, bi, 12, "UShort")
    NumPut(32, bi, 14, "UShort")
    NumPut(0, bi, 16, "UInt")
    hbm := DllCall("CreateDIBSection", "Ptr", 0, "Ptr", &bi, "UInt", 0, "PtrP", pBits, "Ptr", 0, "UInt", 0, "Ptr")
    sdc := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
    DllCall("SelectObject", "Ptr", sdc, "Ptr", hbm, "Ptr")
    DllCall("gdiplus\GdipCreateFromHDC", "Ptr", sdc, "PtrP", graphics)
  }

  Reset() {
    this.stop_blocks := []
    Loop, % this.height
      this.stop_blocks.Push(this.blank_line.Clone())
  }

  ; 绘制游戏主界面
  Draw() {
    DllCall("gdiplus\GdipFillRectangle", "Ptr", this.Graphics, "Ptr", this.pBrush1, "Float", 0, "Float", 0, "Float", this.width_px, "Float", this.height_px)

    Loop, 11 {
      x := (A_Index - 1) * (this.blockwidth + this.linewidth)
      DllCall("gdiplus\GdipDrawLine", "Ptr", this.Graphics, "Ptr", this.pPen, "Float", x, "Float", 0, "Float", x, "Float", this.height_px)
    }
    Loop, 21 {
      y := (A_Index - 1) * (this.blockwidth + this.linewidth)
      DllCall("gdiplus\GdipDrawLine", "Ptr", this.Graphics, "Ptr", this.pPen, "Float", 0, "Float", y, "Float", this.width_px, "Float", y)
    }

    for rowIndex, line in this.current_block {
      line_num := rowIndex - 1
      for colIndex, c in line {
        if (!c)
          continue
        x := (this.linewidth + this.blockwidth) * (colIndex - 1 + this.current_block_start_col) + this.linewidth
        y := (this.linewidth + this.blockwidth) * (line_num + this.current_block_start_row) + this.linewidth
        DllCall("gdiplus\GdipFillRectangle", "Ptr", this.Graphics, "Ptr", this.pBrush2, "Float", x, "Float", y, "Float", this.blockwidth, "Float", this.blockwidth)
      }
    }

    for rowIndex, line in this.stop_blocks {
      line_num := rowIndex - 1
      for colIndex, c in line {
        if (!c)
          continue
        x := (this.linewidth + this.blockwidth) * (colIndex - 1) + this.linewidth
        y := (this.linewidth + this.blockwidth) * line_num + this.linewidth
        DllCall("gdiplus\GdipFillRectangle", "Ptr", this.Graphics, "Ptr", this.pBrush3, "Float", x, "Float", y, "Float", this.blockwidth, "Float", this.blockwidth)
      }
    }

    DllCall("gdiplus\GdipFillRectangle", "Ptr", this.Graphics2, "Ptr", this.pBrush4, "Float", 0, "Float", 0, "Float", this.blockwidth * 4, "Float", this.blockwidth * 4)
    for rowIndex, line in this.next_block {
      for colIndex, c in line {
        if (!c)
          continue
        x := (colIndex - 1) * (this.blockwidth + 1)
        y := (rowIndex - 1) * (this.blockwidth + 1)
        DllCall("gdiplus\GdipFillRectangle", "Ptr", this.Graphics2, "Ptr", this.pBrush3, "Float", x, "Float", y, "Float", this.blockwidth, "Float", this.blockwidth)
      }
    }

    this.RefreshBitmaps()
  }

  RefreshBitmaps() {
    if (!this.hwnd)
      return
    DllCall("gdiplus\GdipFlush", "Ptr", this.Graphics, "Int", 1)
    DllCall("gdiplus\GdipFlush", "Ptr", this.Graphics2, "Int", 1)
    ddc := DllCall("GetDC", "Ptr", this.hwnd, "Ptr")
    DllCall("gdi32\BitBlt", "Ptr", ddc, "Int", 5, "Int", 5, "Int", this.width_px, "Int", this.height_px, "Ptr", this.sdc, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
    DllCall("gdi32\BitBlt", "Ptr", ddc, "Int", this.width_px + 10, "Int", 150, "Int", this.blockwidth * 4, "Int", this.blockwidth * 4, "Ptr", this.sdc2, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
    DllCall("ReleaseDC", "Ptr", this.hwnd, "Ptr", ddc)
  }

  ; 创建窗口
  CreateMainWindow() {
    global
    w := Round(this.width_px * 1.5)
    h := Round(this.height_px + 10)
    Gui, New, +HwndhWnd +LabelTetrisGui, 俄罗斯方块
    this.hwnd := hWnd
    Gui, Font, S17
    Gui, Add, Text, % "x" (this.width_px + 20) " y60 vTetrisScore", 0
    Gui, Show, % "w" w " h" h
  }

  ; 从定义好的形状中随机抽取
  get_block() {
    Random, x, 1, % this.blocks.MaxIndex()
    Random, y, 1, % this.blocks[x].MaxIndex()
    return this.blocks[x][y]
  }

  ; 获取新砖块或者下一个砖块
  get_current_block() {
    if (!this.next_block)
      this.current_block := this.get_block()
    else
      this.current_block := this.next_block
    this.next_block := this.get_block()
    this.current_block_start_row := -2
    this.current_block_start_col := 3
  }

  move_left() {
    if (!this.judge_move_left())
      return
    this.current_block_start_col -= 1
    this.Draw()
  }

  move_right() {
    if (!this.judge_move_right())
      return
    this.current_block_start_col += 1
    this.Draw()
  }

  move_down() {
    if (this.judge_move_down()) {
      this.current_block_start_row += 1
    } else {
      this.update_stop_blocks()
      this.get_current_block()
      this.judge_lines()
    }
    this.Draw()
  }

  transform_current_block() {
    block_style_list := ""
    i := 0
    for _, line in this.blocks {
      for styleIndex, c in line {
        if (c == this.current_block) {
          block_style_list := line
          i := styleIndex
          break, 2
        }
      }
    }
    if (!IsObject(block_style_list))
      return
    i++
    i := i > block_style_list.MaxIndex() ? 1 : i
    if (!this.judge_new_block(block_style_list[i]))
      return
    this.current_block := block_style_list[i]
    this.Draw()
  }

  update_stop_blocks() {
    if (this.current_block_start_row < 0) {
      timer := this.timer
      SetTimer, % timer, Off
      MsgBox, 64, 俄罗斯方块, % "哈哈你挂了! 分数:" this.score
      this.score := 0
      GuiControl,, TetrisScore, % this.score
      this.Reset()
      timer := this.timer
      SetTimer, % timer, 500
      return
    }

    for rowIndex, line in this.current_block {
      for colIndex, c in line {
        if (!c)
          continue
        this.stop_blocks[this.current_block_start_row + rowIndex][this.current_block_start_col + colIndex] := 1
      }
    }
  }

  judge_move_down() {
    for rowIndex, line in this.current_block {
      for colIndex, c in line {
        if (!c)
          continue
        x := colIndex + this.current_block_start_col
        y := rowIndex + this.current_block_start_row + 1
        if (y > this.height)
          return false
        if (y >= 1 && this.stop_blocks[y][x] == 1)
          return false
      }
    }
    return true
  }

  judge_move_left() {
    for rowIndex, line in this.current_block {
      for colIndex, c in line {
        if (!c)
          continue
        x := colIndex + this.current_block_start_col - 1
        y := rowIndex + this.current_block_start_row
        if (x < 1 || (y >= 1 && this.stop_blocks[y][x] == 1))
          return false
      }
    }
    return true
  }

  judge_move_right() {
    for rowIndex, line in this.current_block {
      for colIndex, c in line {
        if (!c)
          continue
        x := colIndex + this.current_block_start_col + 1
        y := rowIndex + this.current_block_start_row
        if (x > this.width || (y >= 1 && this.stop_blocks[y][x] == 1))
          return false
      }
    }
    return true
  }

  judge_new_block(block) {
    for rowIndex, line in block {
      for colIndex, c in line {
        if (!c)
          continue
        x := colIndex + this.current_block_start_col
        y := rowIndex + this.current_block_start_row
        if (x < 1 || x > this.width || y > this.height || (y >= 1 && this.stop_blocks[y][x] == 1))
          return false
      }
    }
    return true
  }

  judge_lines() {
    i := 1
    for rowIndex, line in this.stop_blocks {
      for _, c in line {
        if (!c)
          continue, 2
      }
      this.stop_blocks.RemoveAt(rowIndex)
      this.stop_blocks.InsertAt(1, this.blank_line.Clone())
      this.score += i
      GuiControl,, TetrisScore, % this.score
      i++
    }
  }

  Close() {
    if (this.closed)
      return
    this.closed := true
    if (this.timer) {
      timer := this.timer
      SetTimer, % timer, Off
    }
    if (this.pPen)
      DllCall("gdiplus\GdipDeletePen", "Ptr", this.pPen)
    if (this.pBrush1)
      DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush1)
    if (this.pBrush2)
      DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush2)
    if (this.pBrush3)
      DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush3)
    if (this.pBrush4)
      DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush4)
    if (this.Graphics)
      DllCall("gdiplus\GdipDeleteGraphics", "Ptr", this.Graphics)
    if (this.Graphics2)
      DllCall("gdiplus\GdipDeleteGraphics", "Ptr", this.Graphics2)
    if (this.hbm)
      DllCall("DeleteObject", "Ptr", this.hbm)
    if (this.hbm2)
      DllCall("DeleteObject", "Ptr", this.hbm2)
    if (this.sdc)
      DllCall("DeleteDC", "Ptr", this.sdc)
    if (this.sdc2)
      DllCall("DeleteDC", "Ptr", this.sdc2)
    if (this.pGdipToken)
      DllCall("gdiplus\GdiplusShutdown", "Ptr", this.pGdipToken)
    if (this.hGdipModule)
      DllCall("FreeLibrary", "Ptr", this.hGdipModule)
  }
}

printarr(a) {
  s := ""
  for _, line in a {
    for _, c in line
      s .= c
    s .= "`r"
  }
  MsgBox, %s%
}

 

AHKv2原版

#Requires AutoHotkey v2.0
; AHKVERSION: V2.0 beat3 U64
; https://github.com/fuwt/AHKScript
t := Tetris()
t.Startup()

Hotkey("UP", (*) => t.transform_current_block())
Hotkey("Down", (*) => t.move_down())
Hotkey("Left", (*) => t.move_left())
Hotkey("Right", (*) => t.move_right())
OnExit((*) => t.Close())


Class Tetris
{
  current_block := []                                                                 ; 当前形状
  next_block    := 0                                                                  ; 下一个形状
  stop_blocks   := []                                                                 ; 停止运动的砖块
  width         := 10                                                                 ; 游戏界面宽度(格子数)
  height        := 20                                                                 ; 游戏界面高度(格子数)
  linewidth     := 1                                                                  ; 网格线宽度
  blockwidth    := 30                                                                 ; 方框大小
  width_px      := this.width * this.blockwidth + (1 + this.width) * this.linewidth   ; 游戏区域宽度
  height_px     := this.height * this.blockwidth + (1 + this.height) * this.linewidth ; 游戏区域高度
  blocks        := [[[[0,1,1],[1,1,0],[0,0,0]],[[1,0,0],[1,1,0],[0,1,0]]],[[[1,1,0],[0,1,1],[0,0,0]],[[0,1,0],[1,1,0],[1,0,0]]],[[[1,0,0],[1,0,0],[1,0,0],[1,0,0]],[[0,0,0,0],[0,0,0,0],[1,1,1,1],[0,0,0,0]]],[[[0,1,1],[0,1,1]]],[[[1,0,0],[1,1,1],[0,0,0]],[[0,1,1],[0,1,0],[0,1,0]],[[0,0,0],[1,1,1],[0,0,1]],[[0,1,0],[0,1,0],[1,1,0]]],[[[0,0,1],[1,1,1],[0,0,0]],[[0,1,0],[0,1,0],[0,1,1]],[[0,0,0],[1,1,1],[1,0,0]],[[1,1,0],[0,1,0],[0,1,0]]],[[[0,1,0],[1,1,1],[0,0,0]],[[0,1,0],[0,1,1],[0,1,0]],[[0,0,0],[1,1,1],[0,1,0]],[[0,1,0],[1,1,0],[0,1,0]]]]
  
  ; 启动入口
  Startup() {
    ; 装载gdiplus.ll提高性能
    this.hGdipModule := DllCall("LoadLibrary", "Str", "gdiplus")
    ; 启动gdip
    si := Buffer(A_PtrSize = 8 ? 24 : 16, 0), NumPut("UInt", 1, si, 0)
    DllCall("gdiplus\GdiplusStartup", "Ptr*", &pToken := 0, "Ptr", si, "Ptr", 0), this.pGdipToken := pToken
    ; 创建需要用到的画布和笔刷
    bi := Buffer(40, 0)
    NumPut("Uint", 40, "Uint", Integer(this.width_px), "Uint", Integer(this.height_px), "ushort", 1, "ushort", 32, "uInt", 0, bi, 0)
    this.hbm := DllCall("CreateDIBSection", "Ptr", 0, "Ptr", bi, "Uint", 0, "Ptr*", 0, "Ptr", 0, "Uint", 0, "Ptr")
    this.sdc := DllCall("CreateCompatibleDC", "Ptr", 0, "ptr")
    DllCall("SelectObject", "Ptr", this.sdc, "Ptr", this.hbm, "ptr")
    DllCall("gdiplus\GdipCreateFromHDC", "Ptr", this.sdc, "Ptr*", &G := 0), this.Graphics := G

    NumPut("Uint", 40, "Uint", Integer(this.blockwidth * 4), "Uint", Integer(this.blockwidth * 4), "ushort", 1, "ushort", 32, "uInt", 0, bi, 0)
    this.hbm2 := DllCall("CreateDIBSection", "Ptr", 0, "Ptr", bi, "Uint", 0, "Ptr*", 0, "Ptr", 0, "Uint", 0, "Ptr")
    this.sdc2 := DllCall("CreateCompatibleDC", "Ptr", 0, "ptr")
    DllCall("SelectObject", "Ptr", this.sdc2, "Ptr", this.hbm2, "ptr")
    DllCall("gdiplus\GdipCreateFromHDC", "Ptr", this.sdc2, "Ptr*", &G2 := 0), this.Graphics2 := G2

    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFDDEDFF, "Ptr*", &pBrush1 := 0), this.pBrush1 := pBrush1
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFFFAAAA, "Ptr*", &pBrush2 := 0), this.pBrush2 := pBrush2 
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFFF5555, "Ptr*", &pBrush3 := 0), this.pBrush3 := pBrush3 
    DllCall("gdiplus\GdipCreateSolidFill", "UInt", 0xFFF0F0F0, "Ptr*", &pBrush4 := 0), this.pBrush4 := pBrush4 
    DllCall("gdiplus\GdipCreatePen1", "UInt", 0xFFCCCCCC, "float", this.linewidth, "int", 2, "Ptr*", &pPen := 0), this.pPen := pPen
    ; 获取第一个砖块
    this.get_current_block()
    ; 创建GUi
    this.CreateMainWindow()
    ; 绘制游戏界面
    this.Draw()
    ; 将网格保存到数组,便于游戏中各种判断
    this.blank_line := []
    loop(this.width)
      this.blank_line.push(0)
    this.Reset()
    ; 开始游戏
    this.timer := ObjBindMethod(this, "move_down")
    SetTimer(this.timer, 500)
  }

  Reset(){
    this.stop_blocks := []
    loop(this.height)
      this.stop_blocks.push(this.blank_line.clone())
  }


  ; 绘制游戏主界面
  Draw(){
    ; 画底色和网格
    DllCall("gdiplus\GdipFillRectangle" , "Ptr", this.Graphics, "Ptr", this.pBrush1 , "float", 0, "float", 0, "float", this.width_px, "float", this.height_px)
    loop(11){
      x := (A_Index - 1) * (this.blockwidth + this.linewidth)
      DllCall("gdiplus\GdipDrawLine" , "Ptr", this.Graphics, "Ptr", this.pPen , "float", x, "float", 0, "float", x, "float", this.height_px)
    }
    loop(21){
      y := (A_Index - 1) * (this.blockwidth + this.linewidth)
      DllCall("gdiplus\GdipDrawLine" , "Ptr", this.Graphics, "Ptr", this.pPen , "float", 0, "float", y, "float", this.width_px, "float", y)
    }
    ; 绘制当前砖块
    for(line in this.current_block){
      line_num := A_Index - 1
      for(c in line){
        if(!c)
          continue  
        x := (this.linewidth + this.blockwidth) * (A_Index - 1 + this.current_block_start_col) + this.linewidth
        y := (this.linewidth + this.blockwidth) * (line_num  + this.current_block_start_row) + this.linewidth
        w := this.blockwidth
        DllCall("gdiplus\GdipFillRectangle" , "Ptr", this.Graphics, "Ptr", this.pBrush2 , "float", x, "float", y, "float", w, "float", w)
    }}
    ; 绘制已经停止的砖块
    for(line in this.stop_blocks){
      line_num := A_Index - 1
      for(c in line){
        if(!c)
          continue
        x := (this.linewidth + this.blockwidth) * (A_Index - 1) + this.linewidth
        y := (this.linewidth + this.blockwidth) * (line_num) + this.linewidth
        w := this.blockwidth
        DllCall("gdiplus\GdipFillRectangle" , "Ptr", this.Graphics, "Ptr", this.pBrush3 , "float", x, "float", y, "float", w, "float", w)
    }}

    ; 绘制下一个砖块(提示)
    DllCall("gdiplus\GdipFillRectangle" , "Ptr", this.Graphics2, "Ptr", this.pBrush4 , "float", 0, "float", 0, "float", this.width_px, "float", this.height_px)
    for(line in this.next_block){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue
          x := (A_Index - 1) * (this.blockwidth+1)
          y := (line_num - 1) * (this.blockwidth + 1)
          DllCall("gdiplus\GdipFillRectangle" , "Ptr", this.Graphics2, "Ptr", this.pBrush3 , "float", x, "float", y, "float", this.blockwidth, "float", this.blockwidth)
      }
    }
    ; 更新,上面只是在内存中绘制,现在更新到屏幕上
    this.ddc := DllCall("GetDC", "Ptr", this.win.Hwnd, "ptr")
    DllCall("gdi32\BitBlt", "Ptr", this.ddc, "int", 5, "int", 5, "int", this.width_px, "int", this.height_px , "Ptr", this.sdc, "int", 0, "int", 0, "Uint", 0x00CC0020)
    DllCall("gdi32\BitBlt", "Ptr", this.ddc, "int", this.width_px + 10, "int", 150, "int", this.blockwidth * 4, "int", this.blockwidth * 4 , "Ptr", this.sdc2, "int", 0, "int", 0, "Uint", 0x00CC0020)
  }
 
  ; 创建窗口
  CreateMainWindow(){
    this.win := Gui("", title := "俄罗斯方块")
    this.win.Show(format("w{} h{}", this.width_px * 1.5, this.height_px + 10))
    this.win.SetFont("S17")
    this.score_control := this.win.Add("Text", format("x{} y60", this.width_px + 20), "0")
    this.win.OnEvent("Close", ExitAPP)
  } 

  ; 从定义好的形状中随机抽取
  get_block(){
    x := random(1, this.blocks.length)
    y := random(1, this.blocks[x].length)
    return this.blocks[x][y]
  }

  ; 获取新砖块或者下一个砖块
  get_current_block(){
    if(!this.next_block)
      this.current_block := this.get_block()
    else 
      this.current_block := this.next_block
    this.next_block := this.get_block()
    this.current_block_start_row := -2
    this.current_block_start_col := 3
  }

  ; 砖块向左移动
  move_left(){
    if(!this.judge_move_left())
      return
    this.current_block_start_col -= 1
    this.Draw()
  }

  ; 砖块向右移动
  move_right(){
    if(!this.judge_move_right())
      return
    this.current_block_start_col += 1
    this.Draw()
  }

  ; 砖块向下移动
  move_down(){
    if(this.judge_move_down()){
      this.current_block_start_row += 1
    } else {
      this.update_stop_blocks()
      this.get_current_block()
      this.judge_lines()
    }
    this.Draw()
  }

  ; 变换(旋转)砖块
  transform_current_block(){
    for(line in this.blocks){
      for(c  in line){
        ; 因为cur_block是blocks里面抽取的一个元素,所以可以用等号判断,如果是自己重新构造的数组,哪怕一模一样也不相等
        if(c == this.current_block){ 
          block_style_list := line
          i := A_Index
          break 2
    }}}
    i++
    i := i > block_style_list.length ? 1 : i
    if(!this.judge_new_block(block_style_list[i]))
      return
    this.current_block := block_style_list[i]
    this.Draw()
  }

  ; 更新已停止的砖块列表
  update_stop_blocks(){
    ; 判断游戏是否失败,并重新开始
    if(this.current_block_start_row < 0){
      SetTimer(this.timer, 0)
      MsgBox("哈哈你挂了! 分数:" .  this.score_control.Text)
    this.score_control.Text := 0
      this.Reset()
      SetTimer(this.timer, 500)
      return 
    }
    for(line in this.current_block){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue
        this.stop_blocks[this.current_block_start_row + line_num][this.current_block_start_col + A_Index] := 1
  }}}

  ; 判断是否继续下落
  judge_move_down(){
    for(line in this.current_block){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue
        x := A_Index + this.current_block_start_col
        y := line_num + this.current_block_start_row + 1
        if(y > this.height)
          return False
        if( y >= 1 && this.stop_blocks[y][x] == 1)
          return False
    }}
    return True
  }

  ; 判断是否可以向左移动
  judge_move_left(){
    for(line in this.current_block){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue
        x := A_Index + this.current_block_start_col - 1
        y := line_num + this.current_block_start_row
        if(x < 1 || (y >= 1 && this.stop_blocks[y][x] == 1))
          return False
    }}
    return True
  }

  ; 判断是否可以向右移动
  judge_move_right(){
    for(line in this.current_block){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue
        x := A_Index + this.current_block_start_col + 1
        y := line_num + this.current_block_start_row
        if(x > this.width || (y >= 1 && this.stop_blocks[y][x] == 1))
          return False
    }}
    return True
  }

  ; 判断新砖块是否与边框或已经停止的砖块冲突
  judge_new_block(block){
    for(line in block){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue
        x := A_Index + this.current_block_start_col
        y := line_num + this.current_block_start_row
        if(x < 1 || x > this.width || y > this.height || (y >= 1 && this.stop_blocks[y][x] == 1))
          return False
    }}
    return True
  }

 ; 判断是否可消除
  judge_lines(){
    i := 1
    for(line in this.stop_blocks){
      line_num := A_Index
      for(c in line){
        if(c == 0)
          continue 2
      }
    this.stop_blocks.RemoveAt(line_num)  
    this.stop_blocks.InsertAt(1, this.blank_line.Clone())
    this.score_control.text += i
    i++
  }}

  Close() {
    DllCall("gdiplus\GdipDeletePen", "Ptr", this.pPen)
    DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush1)
    DllCall("gdiplus\GdipDeleteBrush", "Ptr", this.pBrush2)
    DllCall("DeleteObject", "Ptr", this.hbm)
    DllCall("DeleteObject", "Ptr", this.sdc)
    DllCall("DeleteObject", "Ptr", this.Graphics)
    DllCall("DeleteObject", "Ptr", this.hbm2)
    DllCall("DeleteObject", "Ptr", this.sdc2)
    DllCall("DeleteObject", "Ptr", this.Graphics2)
    DllCall("ReleaseDC", "Ptr", 0, "Ptr", this.ddc)
    DllCall("FreeLibrary", "Ptr", this.hGdipModule)
    DllCall("gdiplus\GdiplusShutdown", "Ptr", this.pGdipToken)
  }
}

printarr(a){
  s := ""
  for(line in a){
    for(c in line){
      s .= c
    }
    s .= '`r'
  }
  msgbox s
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。