我把chrome恐龙小游戏改造成了3D版本

科技一点鑫得 2024-03-08 03:20:52

看完《WebGL编程指南》也有一段时间了,一直不知道该拿什么练手,受youtube大神SimonDev视频的启发我也试着将chrome恐龙小游戏改造成3D版本,这款小游戏是绝佳的开始,因为它真的足够简单。

整个游戏的逻辑非常简单,一只小恐龙在前进的过程中通过跳跃躲避仙人掌障碍物(其实恐龙并没有向前移动,只是上下跳跃,通过反向移动仙人掌和地面实现了恐龙前进的效果),一旦碰到仙人掌游戏就结束了,游戏进行过程中根据坚持的时间或距离展示分数,并记录最高分。

这里选择threejs进行3D游戏的实现,从简单的情形开始容易让人树立信心,最开始我们就拿立方体当作角色恐龙,通过官方文档入门指引很容易就能在场景中加一个立方体、一个平面作为地面。

接下来我们让立方体这个角色跳跃起来,通过document.addEventListener监听keydown事件,当按下空格键时给角色一个瞬时向上的速度,为了使跳跃动作显得自然,再为角色添加模拟重力加速度,通过在动画循环中不断改变角色的y轴坐标实现跳跃,注意这里重力加速度不一定必须和真实物理值一样,可以逐步调节模拟加速度的值使跳跃效果达到满意为止。

// 监听keydown事件document.addEventListener("keydown", this.handleKeydown(this), false);handleKeydown(self) { return (event) => { switch(event.code) { case "Space": if (state.gameover == true) { // 游戏结束情况下按空格先重新开始游戏 self.init(); } else if (state.space) { // 按键空格键将角色设定一个瞬时向上的速率 speed_y = 16; // 防止在空中二次跳跃 state.space = false; } break; default: break; } } }// 动画循环,更新角色的y轴坐标,delta为每次进入的时间间隔tick(delta) { if (state.gameover == false) { // 角色的y轴坐标为速率乘以时间 dinosaur.position.y += delta * speed_y; // g为加速度,速度在逐渐减小 speed_y -= delta * g; if (dinosaur.position.y <= 0) { // 落到地面处理 speed_y = 0; dinosaur.position.y = 0; state.space = true; } }}

接着我们在场景中添加绿色立方体代表仙人掌,这里使用threejs中的group容纳立方体,立方体源源不断地生成并加入到group中,并以一定的速率沿z轴正向移动即向着角色方向,为了避免生成越来越多的立方体,删除超过视野范围之外的立方体。

//以下代码写在动画循环中state.elapsed += delta;// 间隔一定的随机时间来生成绿色立方体if (state.elapsed > Math.random() * 20 + 1) { // 克隆一个事先创建的绿色立方体 let plant_new = random(this.cactus).clone(); // 设置生成的初始位置 plant_new.position.set(this.origin.x, this.origin.y, this.origin.z) // 加入到group中 plants.add(plant_new) // 清空经历时间,重新计时 state.elapsed = 0;}// 遍历group中的绿色立方体for (let i = 0; i < plants.children.length; i++) { let p = plants.children[i]; // 沿z轴正向移动 p.position.z += state.speed_running; // 已经移到角色身后的进行删除 if (p.position.z > 15) { plants.remove(p); }}

到目前为止,只要再添加碰撞检测功能整个游戏的业务逻辑就算完成了,查看threejs官方文档可以找到关于Box3类的说明(https://threejs.org/docs/index.html?q=Box3#api/en/math/Box3),setFromObject方法计算3D物体的包围盒、intersect方法计算两个Box3对象是否相交。

// 碰撞检测checkCollisions() { this.player_box.setFromObject(dinosaur); for (let p of plants.children) { this.plant_box.setFromObject(p); if (this.plant_box.intersectsBox(this.player_box)) { console.log("碰撞到了一起"); state.gameover = true; this.handleGameOver(state.gameover); } }}

最后为游戏添加分数和最高分,这里使用了下载的像素字体,整个游戏的主体就此完成了,足够简单吧。

// 以下代码写在动画循环中// 计算恐龙的得分,即跑步的距离state.score += (delta * state.speed_running) * 10;// 记录最高分if (state.score > state.hight_score) { state.hight_score = state.score;}if (state.elapsed >= 0.5) { this.showScore();}

剩下的工作就是为游戏增色,使其更具可玩性,主要做了如下几点改进,threejs官方文档针对这些主题都有简单的案例可供参考,没有什么特别交代之处。

立方体角色替换为了加载的gltf恐龙和仙人掌模型;地面添加了沙漠贴图效果;场景背景添加了天空贴图和雾化效果;地面随机添加了树木、石头、小草等,并同样沿z轴正向移动。

游戏的最终效果如下,很明显还有很多不足,移动的物体没有阴影,色彩也不对,测试发现有的模型可以产生阴影,暂时还没有找到解决的手段,解决了这个问题再单独写一篇来讲讲吧。

参考文献

[1]. https://www.youtube.com/watch?v=KJ38qCwFdy8&t=196s

0 阅读:0

科技一点鑫得

简介:感谢大家的关注