开维游戏引擎(Kaiwei Engine)是基于js设计的跨平台游戏引擎。内核c++编写,v8引擎封装游戏函数,Assembly实现htm跨平台高效运行。下面以“飞机大战”小游戏为实例,实现AI自动生成游戏代码。
AI模型应用:下面实例代码包含几乎所有基本控件函数,可以给AI 模型,例如:DeepSeek,Gemini,豆包等
AI游戏生成:以实例为基础自动生成AI游戏代码,例如贪吃蛇,飞机大战等小游戏
AI提示文本:“下面是开维游戏引擎的代码演示,根据这个代码,写一个飞机大战游戏。代码如下:(拷贝以下代码)”
AI平台:Gemini、DeepSeek。Gemini的代码效果比DeepSeek要好,例如增加星空背景,碰撞等,并且代码效率极高。
运行结果:Gemini生成的游戏代码
运行结果:DeepSeek生成的游戏代码
AI提问内容:“下面是开维游戏引擎的代码演示,根据这个代码,写一个飞机大战游戏。代码如下:(js代码)”
下面是开维游戏引擎的代码演示,根据这个代码,写一个飞机大战游戏。 代码如下:// 基础控件实例
// 初始化游戏引擎
game.init(); // 默认窗口大小为800*600
game.setFPS(30); // 设置帧率
// 游戏主窗口设置图标和标题
// ----------------------------------------------------------------------------------------------
var window = game.getWindow(); // 获取资源对象
var texture = game.getResource().getTexture("img/logo.png"); // 获取纹理数据对象
window.setIcon(texture); // 设置主游戏窗口图标
window.setTitle("开维游戏引擎"); // 设置主游戏窗口标题
// Scence场景设置
// ----------------------------------------------------------------------------------------------
var resBg = game.getResource().getTexture("img/bg.png"); // 获取背景图资源
var scene = new Scene(); // 新建场景
scene.setBg(resBg); // 设置场景背景图
scene.upDate((time)=>{ // 界面刷新回调函数,根据fps帧率的值回调,fps设置60就是一秒60次回调
// log("fps callback"); // 编写游戏地图、子弹移动等
var nodes = scene.getChilds(); // 读取所有场景节点,返回数组
var labDebug = nodes[0]; // 读取数据第一个对象
const timeStr = new Date().toTimeString().split(' ')[0]; // 返回当前时间
var str = "调试信息\n"+"时间:"+timeStr;
labDebug.setText(str); // 设置对象时间,每帧刷新一下时间
});
game.pushScene(scene);
// Audio音乐类,设置背景音乐
var audio = new Audio();
audio.playMusic("sound/bg.ogg"); // 播放背景音乐,循环播放
//audio.stopMusic(); // 停止当前背景音乐
//audio.playMusicOne("sound/bg.ogg"); // 播放音乐,仅播放一次
//audio.playMusic("sound/1.wav");
//audio.playMusic("sound/Normal2.mp3");
audio.playSound("sound/1.wav"); // 循环音效,例如按钮点击声、脚步声、爆炸声、技能音效
// Label标签设置,调试窗口信息
// ----------------------------------------------------------------------------------------------
var labDebug = new Label(); // 新建标签类
labDebug.setPosition(20, 20); // 标签位置横坐标,纵坐标。
labDebug.setSize(150, 150); // 标签宽,高
labDebug.setColor(0,0,0,0.1); // 标签背景颜色为黑色并透明
labDebug.setTextColor(0,1,0,0.5); // 标签字体颜色
labDebug.setFont("font/st.ttf",15); // 标签汉字字库,字体大小,必须指定
scene.addNode(labDebug); // 把标签增加到场景中
// Label标签设置,显示游戏名称
// ----------------------------------------------------------------------------------------------
var resName = game.getResource().getTexture("img/name.png"); // 获取背景图资源
var labLog = new Label(); // 新建标签类
labLog.setPosition(270, 5); // 标签位置横坐标,纵坐标。
labLog.setSize(400, 150); // 标签宽,高
labLog.setTexture(resName);
labLog.setFont("font/st.ttf",15); // 标签汉字字库,字体大小,必须指定
//labLog.setText("标签上的测试文字\n换行123");
//lab.setColor(0,0,0,1); // 标签背景颜色为黑色并透明
//labLog.setRotate(180); // 标签旋转180度
labLog.upDate((time)=>{ // 设置帧率回调,如果不需要可以注释
//log("Lab callback");
});
scene.addNode(labLog); // 把标签增加到场景中
// Node节点控件,这个是很多控件的基类。左上角显示一个绿色小方块,中间有个蓝色小方块
// ----------------------------------------------------------------------------------------------
log("\nNode节点控件 -------------------------------------------------------------------------");
var node = new Node(); // 新建节点
node.setPosition(1, 1); // 节点位置横坐标,纵坐标
var pos = node.getPosition(); // 获取节点坐标
log("节点横坐标x:" + pos.x + "节点纵坐标y:" + pos.y);
node.setSize(20,20); // 设置节点宽,高
var size = node.getSize(); // 获取节点大小
log("节点宽度:" + size.x + "节点宽度:" + size.y);
node.setName("Hello world"); // 设置节点文字
var name = node.getName(); // 获取节点文字
log("节点文字:"+name);
node.setColor(1,2,3,0.5); // 设置节点颜色
var color = node.getColor(); // 获取节点颜色
log("获取节点颜色值为:r:" + color.x + " g:" + color.y + " b:" + color.z+ " a:" + color.w);
node.setRotate(90); // 设置节点选择角度0~360
var routate = node.getRotate(); // 获取节点选择角度
log("旋转角度为:"+routate);
node.setHide(false); // 设置节点是否隐藏
var hide = node.isHide(); // 获取节点是否隐藏
log("node节点是否隐藏:" + hide);
scene.addNode(node); // 把节点增加到场景中
node.upDate((time)=>{ // 设置帧率回调,如果不需要可以注释
//log("Node callback");
});
// 增加节点:在绿色小方块上,添加子节点,红色小方块,然后改为蓝色小方块
var node1 = new Node(); // 新建子节点
node1.setPosition(2, 2); // 节点位置横坐标,纵坐标
node1.setSize(10,10); // 设置节点宽,高
node1.setColor(255,0,0,1); // 设置节点颜色,红色
node.addNode(node1); // 把子节点添加到父节点中
var nodeArray = node.getNodes(); // 获取node节点数组对象数据,从0开始
var nodeTemp = nodeArray[0]; // 获取第一个node对象
nodeTemp.setColor(0,0,255,1); // 设置子节点颜色,蓝色
// Edit编辑框设置,输入用户名称
// ----------------------------------------------------------------------------------------------
var resEditBg = game.getResource().getTexture("img/edit.png"); // 获取纹理数据对象
var editName = new Edit(); // 新建编辑框
editName.setTexture(resEditBg); // 设置底图
editName.setPosition(290, 340); // 编辑框的位置,横坐标和纵坐标
editName.setPadding(10); // 编辑框中开始输入的地方
editName.setSize(180, 60); // 编辑框的大小,宽度和高度
editName.setFont("font/st.ttf", 20); // 编辑框的汉字字库,字体大小,必不可少
//editName.setColor(255, 255, 255, 0.1); // 编辑框背景颜色为白色并透明
//editName.setPubText("编辑框内容"); // 编辑框字体颜色为黑色不透明
scene.addNode(editName); // 加入到场景中
// Sprite精灵设置,登录按钮,点击登录后替换背景音乐
// ----------------------------------------------------------------------------------------------
var resBtnBg = game.getResource().getTexture("img/button.png"); // 获取纹理数据对象
var sprLogin = new Sprite(); // 新建精灵
sprLogin.setTexture(resBtnBg); // 设置精灵背景
sprLogin.setSize(200,60); // 设置精灵大小
sprLogin.setPosition(275, 420); // 标签位置横坐标,纵坐标。
sprLogin.click(()=>{ // 点击回调函数,更换图片
var edittext = editName.getText(); // 点击时,读取edit框内容
log("Edit框内容:"+edittext);
audio.stopMusic(); // 停止当前背景音乐
audio.playMusic("sound/Normal2.mp3"); // 循环播放音乐
audio.playSound("sound/1.wav"); // 播放音效
aWebSocket.emitMsg("SIO_MESSAGE_UP","SIO_MESSAGE_UP"); // 发送长链接数据
});
sprLogin.longClick(()=>{ // 长按回调函数,更换图片
log("长按");
});
scene.addNode(sprLogin); // 加入到场景中
//var nodes = scene.getChilds();
// ProgressBar进度条设置
// ----------------------------------------------------------------------------------------------
var resLoad = game.getResource().getTexture("img/load.png"); // 获取纹理数据对象
var progLoad = new ProgressBar(); // 新建进度条
progLoad.setBgTexture(resLoad); // 设置进度条图片
progLoad.setTexture(resLoad); // 设置进度条图片
progLoad.setPosition(200, 550); // 进度条显示位置
progLoad.setSize(380, 20); // 进度条区域大小,宽和高
progLoad.setBgColor(1.0,0.5,0.2,1); // 进度条背景颜色,透明
progLoad.setMax(100); // 进度条最大值
progLoad.setValue(0); // 设置初始进度为0
var i = 0;
progLoad.upDate((time)=>{ // 设置帧率回调
if (i++>100) i = 0;
progLoad.setValue(i); // 设置当前进度
var max = progLoad.getMax(); // 获取最大进度值
var val = progLoad.getValue(); // 获取当前进度值
//log("进度条最大值:"+max+"进度条当前值:"+val);
});
scene.addNode(progLoad); // 加入到场景中
// Slide滑动控件,音量调节
// ----------------------------------------------------------------------------------------------
var resSlide = game.getResource().getTexture("img/slide.png"); // 获取纹理数据对象
var slideLoad = new Slide(); // 新建滑块条
slideLoad.setBarTexture(resSlide); // 设置滑块指针显示的图片
slideLoad.setPosition(300, 500); // 滑块显示位置,横坐标,纵坐标
slideLoad.setSize(150, 15); // 滑块区域大小,宽和高
//slideLoad.setBarColor(0,1,0,1); // 滑块颜色绿色,不透明
slideLoad.setColor(128,128,128,0.2); // 滑块背景颜色,透明
slideLoad.setMax(100); // 滑块最大值
slideLoad.setValue(audio.getMusicVolume()*100); // 设置初始值
var i = 0;
slideLoad.upDate((time)=>{ // 设置帧率回调
var max = slideLoad.getMax(); // 获取最大进度值
var val = slideLoad.getValue(); // 获取当前进度值
audio.setMusicVolume(val*1.0/max); // 设置背景音乐音量大小
audio.setSoundVolume(0.5); // 设置音效音量大小
var MusicVal = audio.getMusicVolume(); // 获取背景音乐音量大小
var SoundVal = audio.getSoundVolume();// 获取音效音量大小
//log("滑块最大值:"+max+"进度条当前值:"+val +"背景音乐音量大小:"+MusicVal +"音效音量大小:"+SoundVal );
});
scene.addNode(slideLoad); // 加入到场景中
// ScrollView滚动视图
// ----------------------------------------------------------------------------------------------
log("\nScrollView滚动视图 --------------------------------------------------------------------");
// 设置滚动视图大小,位置,背景等。半透明背景图中有白色的底图
var resScrollViewBg = game.getResource().getTexture("img/ScrollViewBg.png"); // 获取纹理数据对象
var scrollview = new ScrollView(); // 新建滚动视图
scrollview.setTexture(resScrollViewBg); //设置滚动视图背景图
scrollview.setColor(0.2, 0.5, 0.8, 0.5); // 设置滚动视图颜色
scrollview.setPosition(10,400);// 滚动视图的位置,横坐标和纵坐标
scrollview.setSize(100,100);// 滚动视图的大小,宽度和高度
scrollview.setContentSize(400,400); // 设置滚动视图中内容大小
// 是否隐藏滚动试图中,水平和垂直滑块
//scrollview.setShowHBar(false); // flase隐藏;ture显示;默认显示水平滚动条
//scrollview.setShowVBar(false); // flase隐藏;ture显示;默认显示垂直滚动条
// 获取滚动视图位置
scrollview.setScrollOffsetX(10); // 水平滚动滑块的初始位置,横坐标从10开始
scrollview.setScrollOffsetY(20); // 垂直滚动滑块的初始位置,纵坐标从20开始
var sx = scrollview.getOffsetX(); // 获取水平滚动滑块的位置
var sy = scrollview.getOffsetY(); // 获取垂直滚动滑块的位置
log("scrollview滚动窗口水平滑块初始位置:"+sx);
log("scrollview滚动窗口垂直滑块初始位置:"+sy);
// 设置滚动试图中,水平和垂直滑道的宽窄,如果不调用此函数,默认为20
scrollview.setHBarHeight(10); // 设置水平滚动条滑道的高度
scrollview.setVBarWidth(10); // 设置垂直滚动条滑道的宽度
// 滚动视图中加入一张图片
var resSpr1 = game.getResource().getTexture("img/resSpr1.png"); // 获取纹理数据对象
var spr1 = new Sprite(); // 新建精灵
spr1.setTexture(resSpr1); // 设置精灵为白色背景图
spr1.setSize(160,160); // 设置精灵大小
spr1.setPosition(10, 50); // 标签位置横坐标,纵坐标。
scrollview.addNode(spr1); // 向滚动动窗口中增加精灵,效果为:黑色的滚动窗口中有一个白色的图
// 设置滚动视图垂直滚动条
var vscrollBar =scrollview.getVScrollBar(); // 获取滚动窗口中的垂直滚动条
var resVScrollBarBg = game.getResource().getTexture("img/resVScrollBarBg.png"); // 获取纹理数据对象,灰色背景图
vscrollBar.setColor(0,255,0,1); // 设置垂直滚动条背景颜色为绿色
vscrollBar.setTexture(resVScrollBarBg); // 设置滚动条里面滑块背景图为灰色
vscrollBar.setBarColor(0,0,255,1); // 设置滚动条中滑块颜色为蓝色
vscrollBar.setBarTexture(resVScrollBarBg);// 设置滚动条中滑块背景图
// 设置滚动视图水平滚动条
var hscrollBar =scrollview.getHScrollBar(); // 获取滚动窗口中的水平滚动条
var resHScrollBarBg = game.getResource().getTexture("img/resVScrollBarBg.png"); // 获取纹理数据对象,灰色背景图
hscrollBar.setColor(0,255,255,1); // 设置水平滚动条背景颜色为青色
hscrollBar.setTexture(resHScrollBarBg); // 设置水平滚动条里面滑块背景图为灰色
hscrollBar.setBarColor(255,0,255,1); // 设置水平滚动条中滑块颜色为红色
hscrollBar.setBarTexture(resHScrollBarBg);// 设置水平滚动条中滑块背景图
scene.addNode(scrollview); // // 加入到场景中
// Http网络类
// ----------------------------------------------------------------------------------------------
log("\nHttp网络类 -----------------------------------------------------------------------------");
var http = new Http();
http.get("https://ctrljs.ikaiwei.com/api/test/request_logs.do?sf=sf",(str)=>{
log(str);
});
http.post("https://ctrljs.ikaiwei.com/api/test/request_logs.do?","sff=sf111&se=1",(str)=>{
});
// websocket类
// ----------------------------------------------------------------------------------------------
log("\nwebsocket长链接类 --------------------------------------------------------------------");
var aWebSocket = new SocketIO(); // 创建长连接类
var appid= "h11do3gq";
aWebSocket.initIO(appid); // 初始化长链接中的appid,区分项目用,也可以为空
// 设置长连接
aWebSocket.connectIO("https://imtest.linchixuan.com/"+appid,"appId="+appid+"&uid=68661f92a88ebd78856482bc&deviceId=132441241244"); // 建立长链接
aWebSocket.on("SIO_INFO",function(str){ // 监听长链接数据,设置回调函数
log(JSON.stringify(str));
});
aWebSocket.on("connect",function(){
aWebSocket.emitMsg("SIO_MESSAGE_UP","SIO_MESSAGE_UP"); // 发送长链接数据
//aWebSocket.disConnect(); // 关闭长链接
});
// 获取场景里面对象数据,从0开始
var nodeArray = scene.getChilds();
var labTest = nodeArray[0]; // 获取第一个场景对象
//labTest.setText("世界,你好!"); // lab对象重写设置内容
// ----------------------------------------------------------------------------------
// 键盘回调方法,键值参考帮助文档中的键值表
// ----------------------------------------------------------------------------------
// 全局类,全局变量和参数
class GlobalVariable
{
// 键盘键值
static KEY_W = 87;
static KEY_S = 83;
static KEY_A = 65;
static KEY_D = 68;
static KEY_BOTTOM = 40;
static KEY_UP = 38;
static KEY_LEFT = 37;
static KEY_RIGHT = 39;
}
// 函数功能:键盘回调函数,定义wasd或上下左右健
// 函数参数:key-键值;action-动作;
game.setKeyCallBack((key,action)=>{
let type = "";
if (key == GlobalVariable.KEY_W || key == GlobalVariable.KEY_UP)
type = "up";
else if (key == GlobalVariable.KEY_S || key == GlobalVariable.KEY_BOTTOM)
type = "down";
else if (key == GlobalVariable.KEY_A || key == GlobalVariable.KEY_LEFT)
type = "left";
else if (key == GlobalVariable.KEY_D || key == GlobalVariable.KEY_RIGHT)
type = "right";
// 控制台中显示调试信息
log("key "+key+" action "+action+" type "+type);
logic(type) // 调用操控函数
});
// 函数功能:游戏中的键盘操作
// 函数参数:direction,方向 up down left right
function logic(direction)
{
// 处理玩家输入的方向,移动所有格子并合并相同数字
if(direction == "up")
log("上");
else if (direction == "down")
log("下");
else if (direction == "left")
log("左");
else if (direction == "right")
log("右");
}
// 运行游戏
game.run();
生成代码:
- Gemini自动生成的游戏代码:
// ==============================================================================================
// 飞机大战:音效增强版 (纯黑背景 + 星空拉伸 + 音效)
// ==============================================================================================
game.init();
game.setFPS(60);
// 获取资源纹理
var resPlayer = game.getResource().getTexture("img/logo.png");
var resEnemy = game.getResource().getTexture("img/resSpr1.png");
var resBullet = game.getResource().getTexture("img/button.png");
var scene = new Scene();
scene.setColor(0, 0, 0, 1); // 纯黑背景
// --- [新增] 背景音乐初始化 ---
var audio = new Audio();
audio.playMusic("sound/bg.ogg");
// --- 1. 星空系统 ---
var stars = [];
const STAR_COUNT = 100;
var isWarpSpeed = false;
function initStarfield() {
for (let i = 0; i < STAR_COUNT; i++) {
let star = new Node();
let size = 1 + Math.random() * 2;
star.setSize(size, size);
star.setPosition(Math.random() * 800, Math.random() * 600);
star.setColor(1, 1, 1, 0.5);
star.setName((0.5 + Math.random() * 3.5).toString());
scene.addNode(star);
stars.push(star);
}
}
function updateStarfield() {
for (let i = 0; i < stars.length; i++) {
let star = stars[i];
let pos = star.getPosition();
let baseSpeed = parseFloat(star.getName());
let currentSpeed = isWarpSpeed ? baseSpeed * 15 : baseSpeed;
pos.y += currentSpeed;
if (isWarpSpeed) {
star.setSize(1, currentSpeed * 1.5);
star.setColor(0.6, 0.8, 1.0, 0.7);
} else {
star.setSize(baseSpeed, baseSpeed);
star.setColor(1, 1, 1, 0.5);
}
if (pos.y > 600) {
pos.y = -50;
pos.x = Math.random() * 800;
}
star.setPosition(pos.x, pos.y);
}
}
// --- 2. 游戏逻辑变量 ---
var bullets = [];
var enemies = [];
var score = 0;
var isGameOver = false;
// 创建玩家
var player = new Sprite();
player.setTexture(resPlayer);
player.setSize(50, 50);
player.setPosition(375, 500);
scene.addNode(player);
// 得分显示 (修正白色区域问题)
var labScore = new Label();
labScore.setPosition(20, 20);
labScore.setSize(400, 100);
labScore.setColor(0, 0, 0, 0); // 彻底透明背景,防止白色方块
labScore.setTextColor(0, 1, 0, 1); // 鲜绿色字体
labScore.setFont("font/st.ttf", 20);
labScore.setText("SCORE: 0\n[WASD]移动 [SPACE]射击\n[SHIFT]光速跳跃");
scene.addNode(labScore);
// --- 3. 交互系统 ---
game.setKeyCallBack((key, action) => {
if (key === 16) { isWarpSpeed = (action === 1); }
if (action !== 1) return;
var pos = player.getPosition();
var step = 30;
if (key === 87 || key === 38) player.setPosition(pos.x, pos.y - step);
if (key === 83 || key === 40) player.setPosition(pos.x, pos.y + step);
if (key === 65 || key === 37) player.setPosition(pos.x - step, pos.y);
if (key === 68 || key === 39) player.setPosition(pos.x + step, pos.y);
if (key === 32) shoot();
});
function shoot() {
if (isGameOver) return;
var b = new Sprite();
b.setTexture(resBullet);
b.setSize(6, 18);
b.setColor(0, 1, 1, 1);
var pPos = player.getPosition();
b.setPosition(pPos.x + 22, pPos.y - 10);
scene.addNode(b);
bullets.push(b);
}
function spawnEnemy() {
if (isGameOver || isWarpSpeed) return;
var e = new Sprite();
e.setTexture(resEnemy);
e.setSize(40, 40);
e.setColor(1, 0.4, 0.4, 1);
e.setPosition(Math.random() * 760, -50);
scene.addNode(e);
enemies.push(e);
}
// --- 4. 核心刷新循环 ---
var frameCount = 0;
initStarfield();
scene.upDate((time) => {
updateStarfield();
if (isGameOver) return;
frameCount++;
if (frameCount % 30 === 0) spawnEnemy();
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
var bPos = b.getPosition();
b.setPosition(bPos.x, bPos.y - 15);
if (bPos.y < -20) {
b.setHide(true);
bullets.splice(i, 1);
}
}
var pPos = player.getPosition();
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
var ePos = e.getPosition();
var eSpeed = isWarpSpeed ? 25 : 5;
e.setPosition(ePos.x, ePos.y + eSpeed);
// --- 判定逻辑:子弹碰撞 ---
for (var k = bullets.length - 1; k >= 0; k--) {
var b = bullets[k];
var bPos = b.getPosition();
var dist = Math.sqrt(Math.pow(ePos.x - bPos.x, 2) + Math.pow(ePos.y - bPos.y, 2));
if (dist < 30) {
score += 100;
labScore.setText("SCORE: " + score + "\n[WASD]移动 [SPACE]射击\n[SHIFT]光速跳跃");
// [新增] 碰撞音效
audio.playSound("sound/1.wav");
e.setHide(true);
b.setHide(true);
enemies.splice(j, 1);
bullets.splice(k, 1);
break;
}
}
// --- 判定逻辑:玩家碰撞 ---
var playerDist = Math.sqrt(Math.pow(ePos.x - pPos.x, 2) + Math.pow(ePos.y - pPos.y, 2));
if (playerDist < 35 && !isWarpSpeed) {
isGameOver = true;
// [新增] 玩家被撞音效
audio.playSound("sound/1.wav");
// 停止背景音乐
audio.stopMusic();
labScore.setText("GAME OVER!\nFINAL SCORE: " + score);
player.setColor(1, 0, 0, 0.5);
}
if (ePos.y > 600) {
e.setHide(true);
enemies.splice(j, 1);
}
}
});
game.pushScene(scene);
game.run();
- DeepSeek自动生成的游戏代码:
// 打飞机小游戏 - 基于开维游戏引擎
// 初始化游戏引擎
game.init(); // 默认窗口大小800*600
game.setFPS(30); // 设置帧率
// 游戏主窗口设置图标和标题
var window = game.getWindow();
var texture = game.getResource().getTexture("img/logo.png");
window.setIcon(texture);
window.setTitle("打飞机小游戏 - 开维游戏引擎");
// 创建游戏场景
var scene = new Scene();
game.pushScene(scene);
// 背景音乐(可选,确保文件存在)
var audio = new Audio();
audio.playMusic("sound/bg.ogg"); // 播放背景音乐
audio.setMusicVolume(0.5); // 设置音量
// ==================== 游戏全局变量 ====================
var player; // 玩家飞机
var enemies = []; // 敌机数组
var bullets = []; // 子弹数组
var score = 0; // 得分
var scoreLabel; // 得分显示标签
var gameOver = false; // 游戏结束标志
var gameOverLabel; // 游戏结束标签
// 按键状态记录
var keyState = {
left: false,
right: false,
up: false,
down: false,
space: false
};
// 子弹冷却时间(帧数)
var bulletCooldown = 0;
const BULLET_COOLDOWN_MAX = 10; // 每10帧可发射一颗子弹
// 敌机生成计时器
var enemySpawnTimer = 0;
const ENEMY_SPAWN_INTERVAL = 30; // 每30帧生成一个敌机
// ==================== 初始化游戏 ====================
function initGame() {
// 设置背景色(深蓝色,模拟夜空)
var bg = new Node();
bg.setSize(800, 600);
bg.setPosition(0, 0);
bg.setColor(0.1, 0.1, 0.3, 1.0);
scene.addNode(bg);
// 创建玩家飞机(使用绿色方块代替,可用纹理替换)
player = new Node();
player.setSize(30, 30);
player.setColor(0, 1, 0, 1); // 绿色
player.setPosition(400, 500); // 底部居中
scene.addNode(player);
// 创建得分标签
scoreLabel = new Label();
scoreLabel.setPosition(20, 20);
scoreLabel.setSize(150, 30);
scoreLabel.setFont("font/st.ttf", 20);
scoreLabel.setTextColor(1, 1, 1, 1);
scoreLabel.setColor(0, 0, 0, 0.5);
scoreLabel.setText("得分: 0");
scene.addNode(scoreLabel);
// 创建游戏结束标签(初始隐藏)
gameOverLabel = new Label();
gameOverLabel.setPosition(250, 250);
gameOverLabel.setSize(300, 100);
gameOverLabel.setFont("font/st.ttf", 40);
gameOverLabel.setTextColor(1, 0, 0, 1);
gameOverLabel.setColor(0, 0, 0, 0.8);
gameOverLabel.setText("GAME OVER");
gameOverLabel.setHide(true);
scene.addNode(gameOverLabel);
}
// ==================== 游戏更新循环 ====================
scene.upDate((time) => {
if (gameOver) {
return; // 游戏结束,停止更新
}
// 1. 根据按键移动玩家
var playerSpeed = 5;
var pos = player.getPosition();
if (keyState.left && pos.x > 0) {
player.setPosition(pos.x - playerSpeed, pos.y);
}
if (keyState.right && pos.x < 800 - 30) {
player.setPosition(pos.x + playerSpeed, pos.y);
}
if (keyState.up && pos.y > 0) {
player.setPosition(pos.x, pos.y - playerSpeed);
}
if (keyState.down && pos.y < 600 - 30) {
player.setPosition(pos.x, pos.y + playerSpeed);
}
// 2. 发射子弹(空格键,带冷却)
if (keyState.space && bulletCooldown <= 0) {
// 创建子弹(黄色小方块)
var bullet = new Node();
bullet.setSize(5, 10);
bullet.setColor(1, 1, 0, 1); // 黄色
bullet.setPosition(pos.x + 12, pos.y - 5); // 从玩家中心偏上发射
scene.addNode(bullet);
bullets.push(bullet);
bulletCooldown = BULLET_COOLDOWN_MAX;
audio.playSound("sound/1.wav"); // 发射音效
}
if (bulletCooldown > 0) {
bulletCooldown--;
}
// 3. 移动子弹并移除超出屏幕的
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
var bulletPos = bullet.getPosition();
bullet.setPosition(bulletPos.x, bulletPos.y - 8); // 向上移动
if (bulletPos.y < 0) { // 超出屏幕上边界
scene.removeNode(bullet);
bullets.splice(i, 1);
}
}
// 4. 生成敌机
enemySpawnTimer--;
if (enemySpawnTimer <= 0) {
var enemyX = Math.random() * (800 - 30);
var enemy = new Node();
enemy.setSize(30, 30);
enemy.setColor(1, 0, 0, 1); // 红色
enemy.setPosition(enemyX, 0);
scene.addNode(enemy);
enemies.push(enemy);
enemySpawnTimer = ENEMY_SPAWN_INTERVAL + Math.floor(Math.random() * 20); // 随机间隔
}
// 5. 移动敌机并移除超出屏幕的
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var enemyPos = enemy.getPosition();
enemy.setPosition(enemyPos.x, enemyPos.y + 3); // 向下移动
if (enemyPos.y > 600) { // 超出屏幕下边界
scene.removeNode(enemy);
enemies.splice(i, 1);
}
}
// 6. 碰撞检测(子弹 vs 敌机)
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
var bulletPos = bullet.getPosition();
var bulletRect = {
x: bulletPos.x,
y: bulletPos.y,
width: 5,
height: 10
};
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
var enemyPos = enemy.getPosition();
var enemyRect = {
x: enemyPos.x,
y: enemyPos.y,
width: 30,
height: 30
};
// 矩形碰撞检测
if (rectCollide(bulletRect, enemyRect)) {
// 击中敌机
scene.removeNode(bullet);
bullets.splice(i, 1);
scene.removeNode(enemy);
enemies.splice(j, 1);
score += 10;
scoreLabel.setText("得分: " + score);
audio.playSound("sound/1.wav"); // 击中音效
break; // 子弹消失,跳出内层循环
}
}
}
// 7. 碰撞检测(玩家 vs 敌机)
var playerPos = player.getPosition();
var playerRect = {
x: playerPos.x,
y: playerPos.y,
width: 30,
height: 30
};
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var enemyPos = enemy.getPosition();
var enemyRect = {
x: enemyPos.x,
y: enemyPos.y,
width: 30,
height: 30
};
if (rectCollide(playerRect, enemyRect)) {
// 游戏结束
gameOver = true;
gameOverLabel.setHide(false);
audio.stopMusic(); // 停止背景音乐
audio.playSound("sound/1.wav"); // 播放结束音效
break;
}
}
});
// 矩形碰撞检测辅助函数
function rectCollide(rect1, rect2) {
return rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y;
}
// ==================== 键盘回调 ====================
game.setKeyCallBack((key, action) => {
// action: 1 按下, 0 释放
var pressed = (action == 1);
// 方向键和WASD
if (key == 37 || key == 65) { // LEFT 或 A
keyState.left = pressed;
} else if (key == 39 || key == 68) { // RIGHT 或 D
keyState.right = pressed;
} else if (key == 38 || key == 87) { // UP 或 W
keyState.up = pressed;
} else if (key == 40 || key == 83) { // DOWN 或 S
keyState.down = pressed;
} else if (key == 32) { // 空格键
keyState.space = pressed;
}
// 调试输出(可选)
// log("key: " + key + " action: " + action);
});
// ==================== 启动游戏 ====================
initGame();
// 运行游戏
game.run();
开维游戏引擎代码简单,函数精简,尽量用极少的js脚本实现游戏功能。代码跨平台通用,一次编写,多端运行,可以直接导出生成exe或者html目录直接运行:
开维游戏引擎下载: www.ikaiwei.com/download/ga…
飞机大战Gemini生成代码页面演示: www.ikaiwei.com/gamejs/exam…
源码下载: github.com/ctrljshaha/…