首頁  >  文章  >  web前端  >  開發日誌 - 我正在創建一個遊戲引擎!

開發日誌 - 我正在創建一個遊戲引擎!

PHPz
PHPz原創
2024-09-12 18:15:38400瀏覽

Devlog - Je créé un moteur de jeu !

我正在創建一個遊戲引擎!

這場偉大的冒險簡介

幾週以來,我一直在定期從事一個我認為可能很有趣的項目,即基於 canvas 使用 JavaScript 和 HTML5 創建我的視頻遊戲引擎。

您可能想知道為什麼選擇 HTML5 和 JavaScript 來創建視訊遊戲?答案沒有問題那麼酷,是我的學校(Zone01 Normandie)所需的項目的競爭以及這些語言擁有執行該項目所需的一切的事實,促使我選擇了這些技術

但實際上這些並不是我會選擇作為基礎的語言,在完成這個任務後我一定會用不同的語言開始其他類似的冒險。

建築學

所以我開始設計我的電玩引擎,它將由幾個類別組成,包括至少兩個主要類別:Game 類別將管理整個遊戲區域,而GameObject 類別允許您生成物件我們的遊戲並讓它們互相互動。

對於這些類,我將添加 CollideBox 類,它將允許我管理所有物件的碰撞框。

Game 類別有一個 GameLoop 方法,將在遊戲的每個畫面(圖片)執行,還有一個 Draw 方法,將在每個遊戲循環期間呼叫。

對於GameObject類,它有一個Step方法和一個Draw方法。
第一個執行每輪遊戲循環,第二個每次呼叫 GameLoop 類別的 Draw 方法時執行。

理論上,您可以透過將引擎模組匯入到專案中來創建遊戲。
為了顯示精靈,我選擇使用 HTML5 內建的canva API(內建意味著它預設附帶)
它將允許我顯示所有精靈並重新剪切圖像以創建對我來說非常有用的動畫!

幾天后,我能夠以給定的速度顯示動畫,並透過我的 CollideBox 偵測碰撞。
還有很多其他好東西,我會讓你在下面看到:

GameObject 類別

class GameObject{
    constructor(game) { // Initialize the GameObject
        this.x = 0
        this.y = 0 
        this.sprite_img = {file: undefined, col: 1, row: 1, fw: 1, fh: 1, step: 0, anim_speed: 0, scale: 1}
        this.loaded = false
        this.game = game
        this.kill = false
        this.collision = new CollideBox()

        game.gObjects.push(this)

    };
    setSprite(img_path, row=1, col=1, speed=12, scale=1) {
        var img = new Image();
        img.onload = () => {
            console.log("image loaded")
            this.sprite_img = {file: img, col: col, row: row, fw: img.width / col, fh: img.height / row, step: 0, anim_speed: speed, scale: scale}
            this.onSpriteLoaded()
        };
        img.src = img_path


    }
    onSpriteLoaded() {}
    draw(context, frame) { // Draw function of game object
        if (this.sprite_img.file != undefined) {


            let column = this.sprite_img.step % this.sprite_img.col;
            let row = Math.floor(this.sprite_img.step / this.sprite_img.col);

           // context.clearRect(this.x, this.y, this.sprite_img.fw, this.sprite_img.fh);
            context.drawImage(
                this.sprite_img.file,
                this.sprite_img.fw * column,
                this.sprite_img.fh * row,
                this.sprite_img.fw,
                this.sprite_img.fh,
                this.x,
                this.y,
                this.sprite_img.fw * this.sprite_img.scale,
                this.sprite_img.fh * this.sprite_img.scale
            );

            if (frame % Math.floor(60 / this.sprite_img.anim_speed) === 0) {
                // Mise à jour de step seulement à 12 fps
                if (this.sprite_img.step < this.sprite_img.row * this.sprite_img.col - 1) {
                    this.sprite_img.step += 1;
                } else {
                    this.sprite_img.step = 0;
                }
            }
        }
    }
    distance_to(pos) {
        return Math.sqrt((pos.x - this.x) ** 2 + (pos.y - this.y) ** 2)
    }

    collide_with(box) {
        if (box instanceof GameObject) {
            box = box.collision
        }
        return (
            this.collision.x < box.x + box.w &&
            this.collision.x + this.collision.w > box.x &&
            this.collision.y < box.y + box.h &&
            this.collision.y + this.collision.h > box.y
          )
    }
    onStep()   {};
}   

遊戲類

class Game {
    constructor(width = 1400, height = 700) {
        this.gObjects = [];
        this.toLoad = [];
        this.timers = [];
        this.layers = [];
        this.canvas = document.getElementsByTagName("canvas")[0]

        this.canvas.width = width
        this.canvas.height = height
        this.context =  this.canvas.getContext("2d")
        this.context.globalCompositeOperation = 'source-over';
        this.inputs = {};
        this.mouse = {x: 0, y: 0}
        document.addEventListener('keydown', (e) => {
            this.inputs[e.key] = true;
        }, false);
        document.addEventListener('keyup', (e) => {
            this.inputs[e.key] = false;
        }, false);
        document.addEventListener('mousemove', (e) => {
            this.mouse.x = e.x;
            this.mouse.y = e.y;
        })
        document.addEventListener('mouseevent', (e) => {
            switch (e.button) {

            }
        })

    }
    draw(frame) {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        console.log( this.canvas.width, this.canvas.heigh)
        for(let i = 0; i < this.gObjects.length; i ++) {
            this.gObjects[i].draw(this.context, frame)
        }

    }
    gLoop() {
        let fps = Math.floor(1000 / 60)
        console.log(fps)
        let clock = 0
        setInterval(() => {
            clock += 1
            for(let i = 0; i < this.gObjects.length; i ++) {

                if (this.gObjects[i] != undefined) {
                    if (this.gObjects[i].kill) {
                        this.gObjects.splice(i, 1);
                        continue;
                    }
                    this.gObjects[i].onStep();
                }


            }
            this.draw(Math.floor(clock))
               // context.l();

           //     console.log(clock)

           if (fps <= clock) {
            clock = 0
           } 

        }, fps)
    }
    keyboard_check(key) {
        return this.inputs[key] == true
    }
}

當然有很多最佳化或其他錯誤,但一切都正常,
「完美的!」你能告訴我嗎?
那就太簡單了。

憂慮

完成此任務並開始嘗試使用此引擎創建遊戲後,我在與同事的談話中得知了一些可怕的消息。

我想您還記得所做的技術選擇是為了符合我的 Zone01 學校的要求......
確實,選擇的語言很好,但我不知道有一條指令會嚴重阻礙該項目......
我們被禁止使用 Canva 函式庫!

提醒一下,這是我們用來顯示圖像的函式庫。

接下來是什麼?

當我寫這篇文章時,我也開始完全重新設計這個遊戲引擎,而不使用canva。

本開發日誌已經完成,您很快就會看到這個故事的其餘部分,別擔心。
對於下一個開發日誌,我一定會嘗試新的格式。

希望這些內容對您有所幫助,給您帶來樂趣,或至少在一些主題上對您進行了教育。祝您一天愉快,程式設計愉快。

DevLogs 1.1:引擎完成了,它是如何運作的?

之前

幾個月前,我開始創建我的電玩引擎,我完成了它......不久前,在Zone01 的幾位同事的幫助下,我們甚至成功地創建了一款受《超級瑪利歐兄弟》啟發的遊戲,可以在我的網站上找到Itch.io 頁面。

決定申請這個開發日誌的格式花了很多時間,我承認我稍微推遲了甚至完全推遲了寫這篇文章的截止日期。
透過耐心地以我猶豫不決為藉口不從事這個主題,我現在發現自己在計劃發布日期兩個月後在魯昂汽車站的休息區寫作,而取消的火車迫使我多等一個小時。

因此,讓我們忽略架構的所有細節,自我的開發日誌的第一部分以來,這個架構的變化很小(除了透過避免使用畫布進行的調整之外)。
因此,我們將討論所進行的專案、我們作為團隊的工作方式以及我們遇到的問題。
將此視為對該專案的反饋,我希望您能夠從本文中吸取一些教訓,這將對您的專案之一有所幫助。

專案

這個專案是用 JavaScript 重新創建一個超級瑪利歐兄弟,並從頭開始,至少在程式碼方面是如此。

規格很簡單,我們必須有一個具有多個等級的馬裡奧遊戲,這是一種簡單地創建新等級的方法。
此外,我們還必須建立一個記分板和一個選單來調整選項。

這個項目的困難是:

  • 螢幕上元素的水平捲動
  • 優化螢幕上不存在的元素

捲動,因為它要求所有元素在背景中相對於玩家的位置滾動。
並且優化螢幕上未顯示的元素可以減少運行遊戲所需的資源,而不會損失效能。

解決了這些困難後,我們在我的 itch.io 頁面上發布了這個遊戲,您甚至可以去測試它。

本開發日誌就這樣結束了,現在完成了,我將能夠撰寫有關其他項目和/或其他主題的內容。

如果你對我告訴你的內容有一點興趣,你可以在 github 上查看我的不同項目(包括本開發日誌中的項目)。

祝你今天休息愉快!

以上是開發日誌 - 我正在創建一個遊戲引擎!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn