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

开维游戏引擎(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

相关推荐
紫_龙1 小时前
最新版vue3+TypeScript开发入门到实战教程之重要详解readonly/shallowReadOnly
前端·javascript·typescript
智算菩萨2 小时前
【Pygame】第10章 游戏状态管理与场景切换机制
python·游戏·pygame
SCLchuck3 小时前
Godot 4 2D 物理引擎位置初始化踩坑:add_child() 和 position 到底谁先? (错误位置触发物理事件)
游戏引擎·godot·游戏开发·物理引擎
蓝莓味的口香糖3 小时前
【vue】初始化 Vue 项目
前端·javascript·vue.js
aikongmeng3 小时前
【Ai】Claude Code 初始化引导
javascript
智算菩萨4 小时前
【Pygame】第15章 游戏人工智能基础、行为控制与寻路算法实现
人工智能·游戏·pygame
光影少年4 小时前
数组去重方法
开发语言·前端·javascript
我命由我123454 小时前
浏览器的 JS 模块化支持观察记录
开发语言·前端·javascript·css·html·ecmascript·html5
智算菩萨4 小时前
【Pygame】第17章 游戏用户界面系统与菜单交互设计实现
游戏·ui·pygame
weixin_443478514 小时前
Flutter第三方常用组件包之路由管理
前端·javascript·flutter