」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 使用 JavaScript IV 建立俄羅斯方塊:canvas

使用 JavaScript IV 建立俄羅斯方塊:canvas

發佈於2024-08-01
瀏覽:408

介紹

在該系列的新部分中,我們將了解如何顯示棋盤和當前在螢幕上下降的棋子。為此,我們必須在瀏覽器中繪製它,我們必須執行的選項是 Canvas HTML 元素。

class Canvas {
    static SEPARATION = 2;
    #_painting = false;
    #_element = null;
    #_board = null;
    #_piece = null;

    constructor(element, board)
    {        
        element.width = 5   ( board.cols * Board.PIXEL_SIZE );
        element.height = 5   ( board.rows * Board.PIXEL_SIZE );

        this._board = board;
        this._element = element;
    }

    // más cosas...
}

這個類別Canvas表示同名的HTML元素,在建構子中作為參數傳遞。由於您要繪製棋盤,因此它也作為參數傳遞,以便訪問要繪製的點。

它所做的第一件事是根據板本身透過其屬性colsrowsCanvas 的大小以適應板]。棋盤也透過 PIXEL_SIZE 告訴我們有多少像素組成了棋盤的每個棋子或每個單元的一個點。

重新繪製遊戲

讓我們少走彎路。我們必須畫出木板和那一刻正在下降的棋子,對嗎?好吧,讓我們開始吧。


類別畫布 { // 更多的東西... 畫() { if (this._painting) { 返回; } const ctx = this.element.getContext( "2d" ); const SEP = Canvas.SEPARATION; this._painting = true; this.clear(); this.paintBoard( ctx, SEP ); this.paintPiece( ctx, SEP ); this._painting = false; } 清除() { const ctx = this.element.getContext( "2d" ); ctx.clearRect( 0, 0, this.element.width, this.element.height ); } }
class Canvas {
    // más cosas...

    paint()
    {
        if ( this._painting ) {
            return;
        }

        const ctx = this.element.getContext( "2d" );
        const SEP = Canvas.SEPARATION;

        this._painting = true;
        this.clear();

        this.paintBoard( ctx, SEP );
        this.paintPiece( ctx, SEP );

        this._painting = false;
    }

    clear()
    {
        const ctx = this.element.getContext( "2d" );

        ctx.clearRect( 0, 0, this.element.width, this.element.height );
    }
}
首先,我們取得 2D 上下文,這將允許我們在畫布上繪圖。出於好奇,還有一個 3D 上下文,它是基於 WebGL。

我們有一些守衛(

_painting),它們可以防止多個執行緒在給定時間同時(在不同點)執行該方法。如果該方法的執行時間長於重繪之間的時間,則可能會發生這種情況。雖然好吧,那樣的話我們還會遇到很多其他問題...

下一步是刪除先前重繪中螢幕上的內容(

)。我們使用 clear() 方法來執行此操作,該方法使用 clearRect() 刪除畫布上的映像。

然後我們畫木板,然後畫那一刻掉下來的那塊。嗯,就這樣了。麥芽酒,交付完成。

我說不。讓我們看看棋盤和棋子是如何繪製的。首先是給木板上漆。 SEP 是我們在棋子和棋盤方塊之間留下的間隔。這個框是我們在標題為

繪製框架的程式碼段中繪製的第一個東西。 它是一個簡單的矩形,可以使用 StrokeRect() 繪製,它接受四個參數,其中包括左上角頂點的位置,然後是其寬度和高度。

畫板

類別畫布 { // 更多的東西... 畫板(ctx,SEP) { //畫框 ctx.筆畫寬度 = 1; ctx. StrokeStyle = this.board.color; ctx. 筆劃矩形( 1, 1, this.element.width - 1, this.element.height -1 ); //畫板 for(令 numRow = 0; numRow class Canvas { // más cosas... paint() { if ( this._painting ) { return; } const ctx = this.element.getContext( "2d" ); const SEP = Canvas.SEPARATION; this._painting = true; this.clear(); this.paintBoard( ctx, SEP ); this.paintPiece( ctx, SEP ); this._painting = false; } clear() { const ctx = this.element.getContext( "2d" ); ctx.clearRect( 0, 0, this.element.width, this.element.height ); } } 接下來是一個巢狀循環(行和列),因此我們將查看板上的哪些單元格有內容(整數 1,與整數 0),然後繪製一個邊長為 PIXEL_SIZE 的小正方形。

因此,第一個循環循環遍歷行,直到

Board.rows。然後我們使用 getRow() 方法來取得完整的行,並用內循環遍歷它,直到 Board.cols.

因此,給定行/列中的一個單元格

f/cBoard.getCell(f, c),並且考慮到JavaScript 有一個Boolean 構造函數,它接受除0 之外的任何值的整數,表示true,我們繪製一個邊長為PIXEL_SIZE 的正方形。因此,要知道在哪裡繪製行 f,我們必須乘以 PIXEL_SIZE 並添加板框和第一個單元格之間的間距。由於它們是正方形,我們將以相同的方式找到列 c:SEP (c * PIXEL_SIZE).

畫出這件作品

我們對這些作品做了類似的事。透過擁有一個形狀 (

shape)(它只不過是一個矩陣),我們將再次擁有兩個循環,外部循環用於行,內部循環用於列。

類別畫布 { // 更多的東西... 油漆片(ctx,SEP) { const SHAPE = this.piece.shape; for(令 numRow = 0; numRow class Canvas { // más cosas... paint() { if ( this._painting ) { return; } const ctx = this.element.getContext( "2d" ); const SEP = Canvas.SEPARATION; this._painting = true; this.clear(); this.paintBoard( ctx, SEP ); this.paintPiece( ctx, SEP ); this._painting = false; } clear() { const ctx = this.element.getContext( "2d" ); ctx.clearRect( 0, 0, this.element.width, this.element.height ); } } 同樣,如果我們找到 1,我們將繪製一個邊長為 PIXEL_SIZE 的正方形。繪製構成該塊的每個方塊的位置由該塊本身的行/列位置給出(

Piece.row/Piece. 捲心菜)。您必須將其乘以 PIXEL_SIZE 並添加與框的分隔。

El juego Insertrix en su estado actual

現在,我們將能夠看到的非常......平淡。棋盤是空的,我們沒有遊戲循環,所以棋子甚至不會落下。我們將在下一部分中討論該主題,以便我們可以開始看到與上圖類似的內容。

版本聲明 本文轉載於:https://dev.to/baltasarq/creando-un-tetris-con-javascript-iv-canvas-1h7k?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 版本5.6.5之前,使用current_timestamp與時間戳列的current_timestamp與時間戳列有什麼限制?
    版本5.6.5之前,使用current_timestamp與時間戳列的current_timestamp與時間戳列有什麼限制?
    在時間戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源於遺留實現的關注,這些限制需要對當前的_timestamp功能進行特定的實現。 創建表`foo`( `Productid` int(10)unsigned not ...
    程式設計 發佈於2025-07-14
  • 可以在純CS中將多個粘性元素彼此堆疊在一起嗎?
    可以在純CS中將多個粘性元素彼此堆疊在一起嗎?
    [2这里: https://webthemez.com/demo/sticky-multi-header-scroll/index.html </main> <section> { display:grid; grid-template-...
    程式設計 發佈於2025-07-14
  • Java字符串非空且非null的有效檢查方法
    Java字符串非空且非null的有效檢查方法
    檢查字符串是否不是null而不是空的 if(str!= null && str.isementy())二手: if(str!= null && str.length()== 0) option 3:trim()。 isement(Isement() trim whitespace whites...
    程式設計 發佈於2025-07-14
  • 如何使用不同數量列的聯合數據庫表?
    如何使用不同數量列的聯合數據庫表?
    合併列數不同的表 當嘗試合併列數不同的數據庫表時,可能會遇到挑戰。一種直接的方法是在列數較少的表中,為缺失的列追加空值。 例如,考慮兩個表,表 A 和表 B,其中表 A 的列數多於表 B。為了合併這些表,同時處理表 B 中缺失的列,請按照以下步驟操作: 確定表 B 中缺失的列,並將它們添加到表的...
    程式設計 發佈於2025-07-14
  • PHP未來:適應與創新
    PHP未來:適應與創新
    PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。 引言在編程世界中,PHP一直是網頁開發的中流砥柱。作為一個從1994年就開始發展...
    程式設計 發佈於2025-07-14
  • 如何限制動態大小的父元素中元素的滾動範圍?
    如何限制動態大小的父元素中元素的滾動範圍?
    在交互式接口中實現垂直滾動元素的CSS高度限制問題:考慮一個佈局,其中我們具有與用戶垂直滾動一起移動的可滾動地圖div,同時與固定的固定sidebar保持一致。但是,地圖的滾動無限期擴展,超過了視口的高度,阻止用戶訪問頁面頁腳。 $("#map").css({ margin...
    程式設計 發佈於2025-07-14
  • 在Java中使用for-to-loop和迭代器進行收集遍歷之間是否存在性能差異?
    在Java中使用for-to-loop和迭代器進行收集遍歷之間是否存在性能差異?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    程式設計 發佈於2025-07-14
  • 表單刷新後如何防止重複提交?
    表單刷新後如何防止重複提交?
    在Web開發中預防重複提交 在表格提交後刷新頁面時,遇到重複提交的問題是常見的。要解決這個問題,請考慮以下方法: 想像一下具有這樣的代碼段,看起來像這樣的代碼段:)){ //數據庫操作... 迴聲“操作完成”; 死(); } ? > ...
    程式設計 發佈於2025-07-14
  • Python高效去除文本中HTML標籤方法
    Python高效去除文本中HTML標籤方法
    在Python中剝離HTML標籤,以獲取原始的文本表示Achieving Text-Only Extraction with Python's MLStripperTo streamline the stripping process, the Python standard librar...
    程式設計 發佈於2025-07-14
  • Python中何時用"try"而非"if"檢測變量值?
    Python中何時用"try"而非"if"檢測變量值?
    使用“ try“ vs.” if”來測試python 在python中的變量值,在某些情況下,您可能需要在處理之前檢查變量是否具有值。在使用“如果”或“ try”構建體之間決定。 “ if” constructs result = function() 如果結果: 對於結果: ...
    程式設計 發佈於2025-07-14
  • CSS強類型語言解析
    CSS強類型語言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    程式設計 發佈於2025-07-14
  • 反射動態實現Go接口用於RPC方法探索
    反射動態實現Go接口用於RPC方法探索
    在GO 使用反射來實現定義RPC式方法的界面。例如,考慮一個接口,例如:鍵入myService接口{ 登錄(用戶名,密碼字符串)(sessionId int,錯誤錯誤) helloworld(sessionid int)(hi String,錯誤錯誤) } 替代方案而不是依靠反射...
    程式設計 發佈於2025-07-14
  • 如何使用Python的請求和假用戶代理繞過網站塊?
    如何使用Python的請求和假用戶代理繞過網站塊?
    如何使用Python的請求模擬瀏覽器行為,以及偽造的用戶代理提供了一個用戶 - 代理標頭一個有效方法是提供有效的用戶式header,以提供有效的用戶 - 設置,該標題可以通過browser和Acterner Systems the equestersystermery和操作系統。通過模仿像Chro...
    程式設計 發佈於2025-07-14
  • MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    在兩個條件下插入或更新或更新 solution:的答案在於mysql的插入中...在重複鍵更新語法上。如果不存在匹配行或更新現有行,則此功能強大的功能可以通過插入新行來進行有效的數據操作。如果違反了唯一的密鑰約束。 實現所需的行為,該表必須具有唯一的鍵定義(在這種情況下為'名稱'...
    程式設計 發佈於2025-07-14

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3