开维游戏引擎实例:五子棋

开维游戏引擎(Kaiwei Engine)是基于js设计的跨平台游戏引擎。内核c++编写,v8引擎封装游戏函数,Assembly实现htm跨平台高效运行。

下面以"五子棋"小游戏为例,演示实现过程。

开维游戏引擎js代码跨平台通用,一次编写,多端运行。支持导出exe和网页html,网页使用wasm运行,小游戏运行效率网页版和exe无太大差别,比原生javacript游戏引擎运行速度快数倍。

开维游戏引擎适合AI写小游戏、特效或功能模块。利用AI模型自动生成特效代码,代码短小精炼,函数简单易懂,200行左右即可完成独立功能。导出的html网页可以内嵌到各种网站、安卓苹果手机app中。

开维引擎的底层是C++编写的高性能内核,通过V8引擎封装JavaScript接口,再通过WASM实现网页端高效运行。这意味着,虽然你用的是JavaScript,但实际执行效率远高于普通HTML5游戏引擎(如Phaser),接近原生应用。这一架构决定了它特别适合AI生成代码------因为AI模型只需理解JavaScript API层,无需关心底层C++实现,即可生成可直接运行的高效代码。因此以API为标准,避免参考其他引擎(如Unity或Cocos)的思维模式,否则容易混淆概念。

开维游戏引擎-五子棋

代码如下:

javascript 复制代码
// 五子棋实例

// AI模型应用:此实例包含几乎所有基本控件函数,可以给AI模型,例如:DeepSeek,Gemini,豆包等
// AI游戏生成:以实例为基础自动生成AI游戏代码,例如贪吃蛇,飞机大战,俄罗斯方块等小游戏
// AI提示文本:"下面是开维游戏引擎的代码演示,根据这个代码,写一个sinx的函数演示代码。 代码如下:(实例代码,可以002游戏登录的代码)"

game.init()
game.setFPS(10);

var window = game.getWindow(); // 获取资源对象
var texture = game.getResource().getTexture("logo.png"); // 获取纹理数据对象
window.setIcon(texture); // 设置主游戏窗口图标
window.setTitle("开维游戏引擎-五子棋");// 设置主游戏窗口标题

new Gobang();
game.run();

// 工具类:生成对象
class Util{

    // 函数功能:创建背景场景,并返回场景和背景节点
    static bj=(options={})=>{

        let w = game.getWindow().getWidth();
        let h = game.getWindow().getHeight();
        let config = {
            x: 0,
            y: 0,
            width: w,
            height: h,
            picture: "bg.jpg",
            ...options
        };

        // 创建场景
        let scene = new Scene();
        GlobalVariable.scene = scene;
        game.pushScene(scene);

        // 添加游戏背景图
        const cache_res = game.getResource();
        let bg = cache_res.getTexture(config.picture);
        const node = new Sprite();
        node.setTexture(bg);
        node.setSize(config.width,config.height);
        node.setPosition(config.x,config.y);
        node.setColor(1,1,1,1);
        scene.addNode(node);

        // 返回场景对象
        return {scene:scene,backgroundNode:node};
    }

    // 函数功能:创建精灵节点,并返回精灵
    static newSprite(options={}){
        let config = {
            x: 0,
            y: 0,
            width: 50,
            height: 30,
            clickCb: undefined,
            texture: "",
            ...options
        };
        if(!GlobalVariable.scene){
            //   log("scene is not exist");
            return;
        }
        const cache_ = game.getResource();
        let bg = cache_.getTexture(config.texture);
        let sprite = new Sprite();
        sprite.setTexture(bg);
        sprite.setSize(config.width, config.height);
        sprite.setPosition(config.x, config.y);
        GlobalVariable.scene.addNode(sprite);

        sprite.click(()=>{
            if (config.clickCb !== undefined && config.clickCb instanceof Function){
                config.clickCb();
            }
        });
        return sprite;
    }


    // 函数功能:创建文本节点,并返回文本对象
    static newText(options){

        // 如果场景不存在,返回
        if(!GlobalVariable.scene){
            return;
        }

        // 文本节点参数
        let config = {
            x: 0,
            y: 0,
            width: 50,
            height: 30,
            text: "",
            fontSize: 20,
            textColor: [1,0,0],
            ...options
        };

        // 打印日志,调试用
        log(JSON.stringify(config));

        // 设置lab标签
        const lab = new Label();
        lab.setPosition(config.x, config.y);
        lab.setSize(config.width, config.height);
        lab.setFont("st.ttf", config.fontSize);
        lab.setText(config.text);

        // 设置颜色
        if(config.textColor !== undefined && config.textColor.length === 3){
            let configColor = config.textColor;
            lab.setTextColor(configColor[0],configColor[1],configColor[2],1);
        }else {
            lab.setTextColor(1,0,0,1);
        }
        lab.setColor(1,1,1,0);
        GlobalVariable.scene.addNode(lab);
        return lab;
    }

    // 函数功能:获取节点位置和大小
    static getPosition(node){
        if (!node){
            return;
        }
        let x = node.getPosition().x;
        let y = node.getPosition().y;

        let width = node.getSize().x;
        let height = node.getSize().y;

        return {x:x, y:y, width:width, height:height};
    }
}

/**
 * 五子棋核心逻辑类
 */
class Gobang {
    // 棋子精灵对象数组,用于后续悔棋或清空画布
    static chessPieces = [];
    // 15x15 棋盘状态数组 (0:无子, 1:玩家/黑子, 2:电脑/白子)
    static chessBoard = [];
    // 赢法三维数组 [x][y][winIndex]
    static wins = [];
    // 赢法统计数组
    static myWin = [];
    static computerWin = [];
    // 赢法总数
    static count = 0;
    // 游戏结束标志位
    static win = false;
    // 棋盘在屏幕上的偏移坐标
    static posX = 0;
    static posY = 0;
    // 当前活动场景引用
    static scene;
    static audio = new Audio();

    constructor() {
        Gobang.init();
    }

    /**
     * 初始化游戏环境、棋盘状态及赢法统计
     */
    static init() {
        // 重置全局与静态状态
        GlobalVariable.gameOver = false;
        this.win = false;
        this.chessBoard = [];
        this.chessPieces = [];
        this.wins = [];
        this.myWin = [];
        this.computerWin = [];

        // 初始化UI背景
        let { scene } = Util.bj({ picture: "mainbg.png" });
        this.scene = scene;
        let bg = Gobang.createChessBg();

        // 注册交互事件:0-下子,1-其他功能
        bg.click((type, x, y) => {
            if (GlobalVariable.gameOver) return;
            if (type === 0) {
                this.logic(x, y);
            }
        });

        // 获取棋盘物理坐标起始点
        let position = Util.getPosition(bg);
        this.posX = position.x;
        this.posY = position.y;


        // --- 预计算赢法统计 (空间换时间) ---
        // 初始化三维赢法空间
        for (let i = 0; i < 15; i++) {
            this.wins[i] = [];
            for (let j = 0; j < 15; j++) {
                this.wins[i][j] = [];
            }
        }

        let count = 0;
        // 1. 横线赢法
        for (let i = 0; i < 15; i++) {
            for (let j = 0; j < 11; j++) {
                for (let k = 0; k < 5; k++) {
                    this.wins[i][j + k][count] = true;
                }
                count++;
            }
        }
        // 2. 竖线赢法
        for (let i = 0; i < 15; i++) {
            for (let j = 0; j < 11; j++) {
                for (let k = 0; k < 5; k++) {
                    this.wins[j + k][i][count] = true;
                }
                count++;
            }
        }
        // 3. 正斜线赢法 (\)
        for (let i = 0; i < 11; i++) {
            for (let j = 0; j < 11; j++) {
                for (let k = 0; k < 5; k++) {
                    this.wins[i + k][j + k][count] = true;
                }
                count++;
            }
        }
        // 4. 反斜线赢法 (/)
        for (let i = 0; i < 11; i++) {
            for (let j = 14; j > 3; j--) {
                for (let k = 0; k < 5; k++) {
                    this.wins[i + k][j - k][count] = true;
                }
                count++;
            }
        }

        this.count = count;

        // 初始化每种赢法的达成进度
        for (let i = 0; i < count; i++) {
            this.myWin[i] = 0;
            this.computerWin[i] = 0;
        }

        // 初始化逻辑棋盘
        for (let i = 0; i < 15; i++) {
            this.chessBoard[i] = [];
            for (let j = 0; j < 15; j++) {
                this.chessBoard[i][j] = 0;
            }
        }
    }

    /**
     * AI 决策逻辑 - 基于分值的启发式算法
     * 算法逻辑:遍历棋盘所有空位,计算拦截分(myScore)和进攻分(computerScore),选出最优点。
     */
    static computerAI() {
        if (GlobalVariable.gameOver) return;

        let myScore = [];
        let computerScore = [];
        let iMax = 0; // 最高评分
        let u = 0, v = 0; // 选中的坐标

        // 初始化当次评分表
        for (let i = 0; i < 15; i++) {
            myScore[i] = [];
            computerScore[i] = [];
            for (let j = 0; j < 15; j++) {
                myScore[i][j] = 0;
                computerScore[i][j] = 0;
            }
        }

        for (let i = 0; i < 15; i++) {
            for (let j = 0; j < 15; j++) {
                if (this.chessBoard[i][j] === 0) {
                    for (let k = 0; k < this.count; k++) {
                        if (this.wins[i][j][k]) {
                            // 评估玩家威胁程度 (拦截逻辑)
                            const playerP = this.myWin[k];
                            const scoresP = [0, 200, 400, 2000, 10000];
                            if (playerP < 5) myScore[i][j] += scoresP[playerP] || 0;

                            // 评估电脑优势程度 (攻击逻辑)
                            const aiP = this.computerWin[k];
                            const scoresAI = [0, 400, 800, 2200, 20000];
                            if (aiP < 5) computerScore[i][j] += scoresAI[aiP] || 0;
                        }
                    }

                    // 择优录取:比较玩家得分,决定是否围堵
                    if (myScore[i][j] > iMax) {
                        iMax = myScore[i][j];
                        u = i; v = j;
                    } else if (myScore[i][j] === iMax) {
                        if (computerScore[i][j] > computerScore[u][v]) {
                            u = i; v = j;
                        }
                    }

                    // 择优录取:比较电脑得分,决定是否进攻
                    if (computerScore[i][j] > iMax) {
                        iMax = computerScore[i][j];
                        u = i; v = j;
                    } else if (computerScore[i][j] === iMax) {
                        if (myScore[i][j] > myScore[u][v]) {
                            u = i; v = j;
                        }
                    }
                }
            }
        }

        // 执行AI落子
        this.createChessPiece(u + 1, v + 1, true);
        this.chessBoard[u][v] = 2;

        // 更新赢法权重统计
        for (let k = 0; k < this.count; k++) {
            if (this.wins[u][v][k]) {
                this.computerWin[k]++;
                this.myWin[k] = 6; // 该赢法路径已被阻塞,设为无效值
                if (this.computerWin[k] === 5) {
                    GlobalVariable.gameOver = true;
                    this.win = false;
                }
            }
        }
    }

    /**
     * 创建棋盘背景精灵
     * @returns {Sprite} 背景精灵对象
     */
    static createChessBg() {
        let w = game.getWindow().getWidth();
        return Util.newSprite({
            x: Math.abs(300 - w / 2) + 5,
            y: 5,
            width: 600,
            height: 600,
            texture: "gobang.png"
        });
    }

    /**
     * 实例化并渲染棋子
     * @param {number} row 行号 (1-15)
     * @param {number} col 列号 (1-15)
     * @param {boolean} isWhite 是否为白棋
     */
    static createChessPiece(row, col, isWhite) {
        const cache = game.getResource();
        let texture = cache.getTexture(isWhite ? "chess_white.png" : "chess_black.png");

        let chessPiece = new Sprite();
        chessPiece.setTexture(texture);
        chessPiece.setSize(25, 25);

        // 核心渲染计算:坐标偏移量 + (行列间隔 * 单位长度)
        let x = this.posX + 3 + 40.5 * (col - 1);
        let y = this.posY + 3 + 40.5 * (row - 1);

        chessPiece.setPosition(x, y);
        this.scene.addNode(chessPiece);
        this.chessPieces.push(chessPiece);
    }

    /**
     * 处理玩家点击落子逻辑
     * @param {number} x 点击点绝对横坐标
     * @param {number} y 点击点绝对纵坐标
     */
    static logic(x, y) {
        if (GlobalVariable.gameOver) return;

        // 坐标反算:将屏幕坐标转为网格坐标
        let col = Math.floor((x - this.posX - 3) / 40.5) + 1;
        let row = Math.floor((y - this.posY - 3) / 40.5) + 1;

        // 边界防御检查
        if (row < 1 || row > 15 || col < 1 || col > 15) return;
        if (this.chessBoard[row - 1][col - 1] !== 0) return;

        // 玩家落子逻辑
        this.createChessPiece(row, col, false);
        this.chessBoard[row - 1][col - 1] = 1;
        this.audio.playSound("1.wav"); // 播放音效

        // 更新赢法权重并检测玩家是否获胜
        for (let k = 0; k < this.count; k++) {
            if (this.wins[row - 1][col - 1][k]) {
                this.myWin[k]++;
                this.computerWin[k] = 6; // 阻塞AI在该赢法上的可能性
                if (this.myWin[k] === 5) {
                    GlobalVariable.gameOver = true;
                    this.win = true;
                    break;
                }
            }
        }

        // 若玩家未胜,触发AI响应
        if (!GlobalVariable.gameOver) {
            this.computerAI();
        }

        this.gameEnd();
    }

    /**
     * 结算处理与UI反馈
     */
    static gameEnd() {
        if (!GlobalVariable.gameOver) return;

        let w = game.getWindow().getWidth();
        let h = game.getWindow().getHeight();
        let msg = this.win ? "游戏结束,胜利!" : "游戏结束,失败!";

        Util.newText({
            text: msg,
            x: w / 3 + 70,
            y: 10,
            width: 150,
        });

        // 显示重试按钮
        Util.newSprite({
            x: w / 2 - 73,
            y: h / 2 - 26,
            width: 147,
            height: 53,
            texture: 'restart.png',
            clickCb: () => {
                new Gobang(); // 重新实例化
            }
        });
    }
}
// 全局类,全局变量和参数
class GlobalVariable{

    // 场景
    static scene;

    // 游戏结束
    static gameOver = false;
}

代码功能:

  1. main.js:游戏初始化,设置背景音乐等
  2. util.js:公共类,设置文字等
  3. Gobang.js:五子棋算法
  4. GlobalVariable.js:全局类,例如键盘码值等

开维游戏引擎代码简单,函数精简,尽量用极少的js脚本实现游戏功能。代码跨平台通用,一次编写,多端运行,可以直接导出生成exe或者html目录直接运行:

开维游戏引擎-五子棋网页版运行

开维游戏引擎下载:
https://www.ikaiwei.com/download/gamejs/kaiwei_gameide_setup.exe

五子棋页面演示:
https://www.ikaiwei.com/gamejs/example/010_Gobang_html/index.html

源码下载:
https://github.com/ctrljshaha/KaiweiEngine

https://gamejs.ikaiwei.com/#/Market

开发文档:
https://www.ikaiwei.com/gamejs/api/index.html

相关推荐
FL16238631291 小时前
使用html实现超炫登录界面和diango实现同样登录界面
前端·html
简单不容易1 小时前
【vue hooks】useScreenOrientation-获取屏幕方向并支持低版本系统
javascript·vue.js
Swift社区1 小时前
为什么游戏公司不愿意开源经典游戏
游戏·开源
橘哥哥1 小时前
vue中读取静态配置文件中内容
前端·javascript·vue.js
wanhengidc2 小时前
什么是高性能计算服务器?
大数据·运维·服务器·游戏·智能手机
yuguo.im2 小时前
91 行代码实现一个打飞机游戏(HTML5 Canvas 版)
前端·游戏·html5·打飞机
怪侠_岭南一只猿2 小时前
爬虫工程师学习路径 · 阶段四:反爬虫对抗(完整学习文档)
css·爬虫·python·学习·html
前端小D2 小时前
面向对象编程
开发语言·javascript
进击的尘埃2 小时前
GPU 合成层炸了,页面白屏——从 will-change 滥用聊到层爆炸的治理
javascript