Yet Another Space Game (In 13kb of JavaScript)
今年我参加了JS13K 2020游戏开发比赛,要求用不超过13KB的JavaScript开发游戏。我在去年开发的Doom类游戏引擎基础上,构建了一个第三人称太空射击游戏。
开发起点
从去年完成的游戏引擎中剥离出仅保留基础渲染功能的核心代码,为开发太空射击游戏奠定基础。初始设计融合了《Descent》和《小行星》的游戏元素,重点实现三维空间飞行和射击机制。
核心系统实现
玩家与摄像机控制
- 采用指数移动平均算法实现摄像机跟随延迟效果
-
- 通过重复渲染10x10x3的"以太粒子"立方体营造空间运动感
-
- 关键代码片段:
-
- var base = NewVectorFromList(camera_position._xyz().map(x=>(x>>5)<<5));
- range(888).map(z => {
-
var v = NewVector((z&7)-3,((z>>=3)&7)-3,(z>>3)-3);
-
if (v.vector_length() < 3) {
-
glitter.position = base.add(v.scalar_multiply(32));
-
glitter.render();
-
}
- });
-
粒子系统优化
- 使用时间戳替代逐帧更新粒子状态
-
- 顶点着色器实现粒子生命周期管理:
-
- gl_Position = projection_matrix * object_position;
- transparency *= smoothstep(1., 0., (u_time-a_settings.x)/(a_settings.y-a_settings.x));
- gl_PointSize = (2000./gl_Position.w) * (2.+transparency) * size;
- v_normal = a_normal;
-
射击系统
- 利用WebGL内置矩阵求逆功能实现屏幕到世界坐标转换
-
- 射线-三角形精确碰撞检测算法:
-
- function does_hit(position, direction, filter) {
-
objects.map(other => {
-
other.sprites.map((sprite, sid) => {
-
sprite.b_positions.map((tri,idx) => {
-
tri = tri.map(x=>mat_vector_product(sprite.rotation, x).add(sprite.position))
-
var distance = ray_triangle_intersect(position, direction, ...tri);
-
if (distance > 0) {
-
return true;
-
}
-
})
-
})
-
})
-
return false;
- }
-
敌人AI
- 有限状态机实现追击/逃跑行为
-
- 弹道预测算法:
-
- var predicted_location = me.position;
- var vel = lazerspeed(this.damage);
- range(10).map(x=> {
-
var time_to_hit = predicted_location.distance_to(start_pos)/vel;
-
predicted_location = me.position.add(me.velocity.scalar_multiply(time_to_hit))
- });
-
性能优化
- 开发自定义.obj模型压缩格式(相比原始格式实现100:1压缩比)
-
- 使用Transform Feedback机制优化粒子系统
-
- 基于距离的碰撞检测提前终止策略
游戏设计
最终实现生存模式玩法,敌人会随时间增加而增多。游戏包含完整的失败动画效果,当玩家飞船被摧毁时,镜头会缓慢拉远并展示爆炸特效。