师悠逸 发表于 2025-10-16 08:50:18

语音控制的太空射击游戏开发笔记

语音控制的太空射击游戏开发笔记

项目背景

最近在研究 Rokid AR 眼镜的开发,想做点有意思的东西。看了一圈案例,发现大家都在做一些比较"正经"的应用——导航、信息展示之类的。我就想,能不能整点不一样的?
游戏!而且是用语音控制的游戏。
这篇文章记录了我从零开始,用 JSAR 框架开发一款太空射击小游戏的全过程。代码不复杂,效果还挺酷的。

技术选型


[*]框架: JSAR (Rokid 官方的空间应用运行时)
[*]3D 引擎: Babylon.js
[*]目标设备: Rokid AR 智能眼镜
[*]开发环境: VSCode + JSAR 扩展
游戏设计

在写代码之前,先把游戏玩法想清楚:
元素
设计
玩家角色
三角形飞船,可左右移动
敌人
随机生成的陨石,从上往下掉
战斗方式
发射能量弹击毁陨石
得分规则
每击毁一个陨石+10分
失败条件
被陨石撞击3次游戏结束
难度曲线
分数越高,陨石速度越快
控制方式设计成双模式:

[*]键盘模式:电脑上调试用(方向键移动,空格射击)
[*]语音模式:Rokid 眼镜实际使用(说"左"、"右"、"发射")
核心技术实现

1. 3D 场景搭建

1.1 相机视角

采用 45 度俯视角,让玩家能同时看到自己的飞船和前方飞来的陨石:
const camera = new BABYLON.ArcRotateCamera(
'camera',
0,
Math.PI / 4,// 45度俯视角
80,         // 距离场景中心80单位
new BABYLON.Vector3(0, 0, 0),
scene
);1.2 网格地板

为了增强 3D 空间感,添加了蓝色网格地板:
// 用线条绘制网格
const gridSize = 150;
const gridDivisions = 15;
const lineColor = new BABYLON.Color3(0, 0.5, 1);

// 横向线
for (let i = 0; i <= gridDivisions; i++) {
const z = (i / gridDivisions) * 200;
const points = [
    new BABYLON.Vector3(-gridSize / 2, -20, z - 50),
    new BABYLON.Vector3(gridSize / 2, -20, z - 50)
];
const line = BABYLON.MeshBuilder.CreateLines('gridLineH' + i, { points }, scene);
line.color = lineColor;
line.alpha = 0.5;
}

// 纵向线(类似代码)
2. 飞船系统

2.1 飞船模型

飞船由三角形机身 + 机翼 + 引擎光效组成。为了在 AR 眼镜中看得清楚,所有尺寸都放大了 5 倍:
const starCount = 300;
const stars = new BABYLON.PointsCloudSystem('stars', 3, scene);

stars.addPoints(starCount, (particle, i) => {
particle.position = new BABYLON.Vector3(
    Math.random() * 200 - 100,
    Math.random() * 200 - 100,
    Math.random() * 100 + 30// Z轴分布增强深度
);
particle.color = new BABYLON.Color4(1, 1, 1, Math.random() * 0.8 + 0.2);
});

stars.buildMeshAsync();2.2 流畅移动控制

使用按键状态追踪实现流畅的连续移动:
// 三角形机身
const ship = BABYLON.MeshBuilder.CreateCylinder('player', {
height: 10,      // 放大5倍后的尺寸
diameterTop: 0,
diameterBottom: 7.5,
tessellation: 3    // 三条边形成三角形
}, scene);

ship.rotation.x = Math.PI / 2;// 旋转90度,让尖端朝上
ship.position.y = -15;

// 添加机翼增强3D效果
const wingLeft = BABYLON.MeshBuilder.CreateBox('wingLeft', {
width: 3,
height: 0.5,
depth: 4
}, scene);
wingLeft.position = new BABYLON.Vector3(-4, -2, 0);
wingLeft.parent = ship;

// 引擎光效
const engineGlow = BABYLON.MeshBuilder.CreateSphere('engineGlow', {
diameter: 2.5
}, scene);
engineGlow.position = new BABYLON.Vector3(0, -6, 0);
engineGlow.parent = ship;

const glowMaterial = new BABYLON.StandardMaterial('glowMat', scene);
glowMaterial.emissiveColor = new BABYLON.Color3(1, 0.5, 0);// 橙色发光
engineGlow.material = glowMaterial;这样按住方向键就能持续移动,没有系统按键延迟的顿挫感。

3. 武器系统

3.1 子弹设计

子弹采用圆柱体造型,带有尾迹效果:
this.keys = {};

window.addEventListener('keydown', (event) => {
this.keys = true;
if (event.key === ' ' || event.key === 'Enter') {
    this.shoot();
}
});

window.addEventListener('keyup', (event) => {
this.keys = false;
});

// 在渲染循环中处理移动
scene.registerBeforeRender(() => {
if (this.keys['ArrowLeft'] || this.keys['a'] || this.keys['A']) {
    this.movePlayer(-1);
}
if (this.keys['ArrowRight'] || this.keys['d'] || this.keys['D']) {
    this.movePlayer(1);
}
});
3.2 子弹更新逻辑

shoot() {
const bullet = BABYLON.MeshBuilder.CreateCylinder('bullet', {
    height: 3,
    diameter: 1
}, this.scene);

bullet.position = this.player.position.clone();
bullet.position.y += 5;
bullet.rotation.x = Math.PI / 2;

// 黄色发光材质
const material = new BABYLON.StandardMaterial('bulletMat', this.scene);
material.emissiveColor = new BABYLON.Color3(1, 1, 0);
bullet.material = material;

// 添加尾迹
const trail = BABYLON.MeshBuilder.CreateCylinder('trail', {
    height: 2,
    diameter: 0.5
}, this.scene);
trail.position = new BABYLON.Vector3(0, -2.5, 0);
trail.parent = bullet;
const trailMat = new BABYLON.StandardMaterial('trailMat', this.scene);
trailMat.emissiveColor = new BABYLON.Color3(1, 0.8, 0);
trailMat.alpha = 0.6;
trail.material = trailMat;

this.bullets.push(bullet);
}4. 敌人系统

4.1 陨石生成

陨石使用 Babylon.js 的多面体,有 3 种不同形状:
scene.registerBeforeRender(() => {
for (let i = this.bullets.length - 1; i >= 0; i--) {
    this.bullets.position.y += 8;// 速度也放大了

    // 飞出屏幕后销毁
    if (this.bullets.position.y > 50) {
      this.bullets.dispose();
      this.bullets.splice(i, 1);
    }
}
});
4.2 定时生成

spawnAsteroid() {
const asteroid = BABYLON.MeshBuilder.CreatePolyhedron('asteroid', {
    type: Math.floor(Math.random() * 3),// 0-2随机形状
    size: Math.random() * 4 + 3         // 放大5倍
}, this.scene);

asteroid.position = new BABYLON.Vector3(
    Math.random() * 80 - 40,// X: -40到40随机位置
    50,                     // Y: 从顶部出现
    Math.random() * 10 - 5    // Z: -5到5增加深度变化
);

// 岩石材质
const material = new BABYLON.StandardMaterial('asteroidMat', this.scene);
material.diffuseColor = new BABYLON.Color3(0.6, 0.4, 0.3);
material.emissiveColor = new BABYLON.Color3(0.2, 0.1, 0.05);
asteroid.material = material;

// 随机旋转速度
asteroid.rotationSpeed = new BABYLON.Vector3(
    Math.random() * 0.05,
    Math.random() * 0.05,
    Math.random() * 0.05
);

this.asteroids.push(asteroid);
}5. 碰撞检测与爆炸效果

5.1 碰撞检测

使用 Babylon.js 内置的 intersectsMesh 方法:
startAsteroidSpawner() {
this.asteroidSpawnTimer = setInterval(() => {
    this.spawnAsteroid();
}, 2000);// 每2秒生成一个
}6. UI 系统

6.1 得分和生命值显示

UI 使用 DynamicTexture 在 3D 平面上绘制文字:
for (let i = this.asteroids.length - 1; i >= 0; i--) {
const asteroid = this.asteroids;

// 检测子弹碰撞
let hit = false;
for (let j = this.bullets.length - 1; j >= 0; j--) {
    const bullet = this.bullets;
    if (asteroid.intersectsMesh(bullet, false)) {
      this.createExplosion(asteroid.position);
      asteroid.dispose();
      bullet.dispose();
      this.asteroids.splice(i, 1);
      this.bullets.splice(j, 1);
      this.score += 10;
      this.updateUI();
      hit = true;
      break;
    }
}

// 检测飞船碰撞
if (!hit && asteroid.intersectsMesh(this.player, false)) {
    this.createExplosion(asteroid.position);
    asteroid.dispose();
    this.asteroids.splice(i, 1);
    this.lives--;
    this.updateUI();
    if (this.lives <= 0) {
      this.endGame();
    }
}
}canvas 尺寸是 1024x256,而 plane 是 60x12,这样宽高比一致,文字不会变形。

6.2 游戏结束界面

createExplosion(position) {
const particleSystem = new BABYLON.ParticleSystem('explosion', 100, this.scene);

particleSystem.particleTexture = new BABYLON.Texture('', this.scene);
particleSystem.emitter = position;

particleSystem.minSize = 0.5;
particleSystem.maxSize = 1.5;
particleSystem.minLifeTime = 0.3;
particleSystem.maxLifeTime = 0.6;
particleSystem.emitRate = 200;

particleSystem.createSphereEmitter(1);

particleSystem.color1 = new BABYLON.Color4(1, 0.5, 0, 1);
particleSystem.color2 = new BABYLON.Color4(1, 0.8, 0, 1);
particleSystem.colorDead = new BABYLON.Color4(0.5, 0.5, 0.5, 0);

particleSystem.minEmitPower = 1;
particleSystem.maxEmitPower = 3;

particleSystem.start();

setTimeout(() => {
    particleSystem.stop();
    setTimeout(() => particleSystem.dispose(), 1000);
}, 200);
}https://www.33rz.com/static/RNIJb3uTCo8oOaxw9kkcDcsRnOc.png
7. 语音控制

7.1 Rokid 语音 API

JSAR 提供了 rokid.voice API 用于语音识别:
createUI() {
// 得分显示
this.scoreText = BABYLON.MeshBuilder.CreatePlane('scoreText', {
    width: 60,
    height: 12
}, this.scene);
this.scoreText.position = new BABYLON.Vector3(-50, 40, 0);

const scoreTexture = new BABYLON.DynamicTexture('scoreTexture',
    { width: 1024, height: 256 }, this.scene, true);

const scoreMaterial = new BABYLON.StandardMaterial('scoreMat', this.scene);
scoreMaterial.diffuseTexture = scoreTexture;
scoreMaterial.emissiveColor = new BABYLON.Color3(1, 1, 1);
this.scoreText.material = scoreMaterial;
this.scoreText.renderingGroupId = 1;// 确保UI在最上层

this.scoreTexture = scoreTexture;

// 生命值显示(类似代码)
}

updateUI() {
// 更新得分
const ctx = this.scoreTexture.getContext();
ctx.clearRect(0, 0, 1024, 256);
ctx.fillStyle = '#FFD700';
ctx.font = 'bold 120px Arial';
ctx.textAlign = 'left';
ctx.fillText('得分: ' + this.score, 50, 160);
this.scoreTexture.update();

// 更新生命值(类似代码)
}7.2 键盘模拟语音(调试用)

在电脑上调试时,用 J/K/L 键模拟语音命令:
window.addEventListener('keydown', (event) => {// 语音模拟if (event.key === 'j' || event.key === 'J') {    console.log('
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

虾氲叱 发表于 2025-10-23 07:06:15

喜欢鼓捣这些软件,现在用得少,谢谢分享!

毡轩 发表于 2025-11-1 01:47:04

谢谢分享,辛苦了

揿纰潦 发表于 2025-11-19 00:53:13

谢谢分享,辛苦了

明思义 发表于 2025-12-6 01:26:09

感谢分享,学习下。
页: [1]
查看完整版本: 语音控制的太空射击游戏开发笔记