从零开始的8-bit迷宫探险【Level 256】恭喜全部破关!游戏完成 & 结语

为什麽铁人 30 天的最後一篇标题是 Level 256 呢?
主要是致敬小精灵 Pac-Man 在第 256 关的时候,发生了知名的 Bug,画面上的乱码造成游戏无法再继续游玩。因为 8-bit 的正整数范围是 0~255,在第 256 关的时候发生了溢位 (overflow),导致关卡最多就停留在 256 关。

游戏完成影片

让我们来看一下游戏完成品吧!


技术重点整理

在游戏实作的过程中,所使用到的技术及方法,整理在这边:

  • SpriteKit
    • 节点 (node) 相关
      • node 在父节点中的层级:zPosition
      • 搜寻子节点:childNode(withName:)
    • 动画相关
      • 图片序列动画:animate(with:timePerFrame:)
      • 依据 node 当前的所在位置移动 x 及 y 向量:moveBy(x:y:duration:)
      • 调整 Alpha 值:fadeAlpha(to:duration:)
      • 建立序列动作:sequence(_:)
      • 执行动作:run(_:)
      • 重复播放动作,可设定重复次数:repeat(_:count:)
      • 不断重复播放动作:repeatForever(_:)
    • 场景相关
      • 通知更新场景:update(_:)
      • 转场动画:SKTransition
    • 灯光效果相关
      • 可以照亮周围的灯光节点:SKLightNode
        • 灯光周围的颜色:ambientColor
        • 光源散射和反射的颜色:lightColor
        • 阴影的颜色,由节点 (sprite) 投射而成:shadowColor
        • 光源的衰减率指数:falloff
        • 灯光的类型:categoryBitMask
      • 定义 sprite 节点是如何被光源点亮:lightingBitMask
  • SafeArea
    • 侦测当 Safe Area 改变时:viewSafeAreaInsetsDidChange()
  • 数学计算相关
    • 计算开根号的值:sqrtf
    • 随机取整数:random(in:)
    • 取绝对值:abs(_:)
  • Timer
    • 建立计时器:scheduledTimer(timeInterval:target:selector:userInfo:repeats:)
  • 本机纪录(Property List) 与档案相关
    • 遵循 Decodable 与 Encodable 协定:Codable
    • 转成 property list 档案:encode(_:)
    • 取得档案的内容:contents(atPath:)
    • 解析 property list 的档案内容:decode(_:from:)
  • 音乐/音效 (AVFoundation Framework)
    • 播放音乐档案:AVAudioPlayer

回顾 30 天

整理了一下大纲,包含游戏实作各篇的成果,方便让大家能直接连结到想看的主题

前言与基础篇

前言

Xcode

Swift 基础语法

SpriteKit

游戏开发实作篇

【Level 10】游戏故事及架构设计

  • 游戏企划书

【Level 11】在 iPhone 里盖座迷宫,就。很。墙

  • 创建专案
  • 画面排版 (创建 SKSpriteNode 以及使用其属性)
  • Safe Area 的概念

https://imgur.com/aFf5rJm.png

【Level 12】把迷宫涂上喜欢的颜色

  • 绘制迷宫背景图片素材
  • 将迷宫套上图片

https://imgur.com/N4X8gd3.png

【Level 13】主角总是孤独的

  • 制作主角 (类别的概念)
  • 主角的动画

https://imgur.com/CyaguQ6.gif

【Level 14】让主角奔跑吧!Running Sam

  • 新增方向按钮,控制主角的移动
  • 在迷宫中的移动逻辑

https://imgur.com/buPSWd7.gif

【Level 15】迷人的反派角色-制作怪物

  • 制作怪物
  • 怪物的动画

https://imgur.com/uudL2ZW.gif

【Level 16】丞相,起风了!远方飘来乌云怪物了

  • 让怪物自动移动 (随机选方向移动)

https://imgur.com/0HJGD84.gif

【Level 17】稻草人也想要智慧大脑,给怪物一点灵魂跟一点点个性

  • 让怪物追踪主角的位置来移动
  • 让四种怪物各有不一样的追击方式

https://imgur.com/qmHnrf5.gif

【Level 18】为什麽他们开始乱跑?捉摸不定的怪物移动模式

  • 改变怪物的移动模式
  • 使用计时器 (Timer)

https://imgur.com/ut7WQf7.gif

【Level 19】这个相遇我等了一辈子了-侦测主角与怪物接触

  • 侦测主角与怪物的接触
  • 接触时的动画 (跌倒动画)

https://imgur.com/j7KUCtz.gif

【Level 20】搜集水晶可以召唤神龙吗?

  • 在迷宫中加入水晶 (收集物)
  • 侦测主角碰触到水晶後,水晶消失

https://imgur.com/N3kOpwy.gif

【Level 21】进击的主角!暴风雨来呐,你坐啊!

  • 新增魔幻水晶
  • 魔幻水晶的闪烁动画
  • 主角收集魔幻水晶後的效果:怪物变成逃逸模式,主角可以反击怪物

https://imgur.com/YJuyNYT.gif

【Level 22】奥义隐身术 & 时间静止术

  • 新增香菇,主角吃到後可以让怪物停止移动一段时间
  • 位於隐身的树,可以逃避怪物的攻击

https://imgur.com/JWdyaph.gif
https://imgur.com/EJYTik2.gif

【Level 23】长老,这个水晶值多少钱?

  • 将主角收集到水晶、魔幻水晶、香菇、击退怪物後的得分,显示在画面上

https://imgur.com/dey7rz5.gif

【Level 24】谁才是高玩?纪录本机最高得分

  • 将最高得分存到本机中,下次开启游戏时可以显示最高得分纪录

https://imgur.com/e3xKXHi.gif

【Level 25】今天又是崭新的一天,回到原点

  • 新增主角生命值机制
  • 游戏重新开始流程

https://imgur.com/hqjtipx.gif

【Level 26】这游戏没有华佗,不能补血啊!Game Over 场景切换

  • 生命值用尽时,切换至游戏结束场景
  • 点击重新开始按钮,可重新回到游戏场景

https://imgur.com/hjcFHht.gif

【Level 27】神助攻-老弟帮我配个音效

  • 帮游戏配上音乐及音效

【Level 28】看我把关卡难度提升-在场景加上聚光灯效果

  • 主角收集完全部水晶後,游戏进入下一关
  • 增加关卡难度:加上 SKLightNode

https://imgur.com/j27ACRy.gif

【Level 29】让你的 App 与众不同!设计 Icon 及 LaunchScreen

  • 加上 App icon
  • 将萤幕锁定为直屏
  • 调整启动画面

https://imgur.com/opp8CSk.png
https://imgur.com/2rf6orI.gif
https://imgur.com/pKGmYKy.gif


关於游戏主角的原型

https://imgur.com/1EXU02K.png
你问说,主角有没有原型,当然有啊!而且原型的名字就叫做 Sam,是个爬过 30 座百岳的男人。
他刚刚才和我说最近想安排一日单攻的百岳,还好铁人赛完赛了,是时候该切换成户外模式了!
他爬山会自带水壶、对讲机、封箱胶带 (鞋子开口笑的时候可以补救),是个有如百宝袋一般的登山夥伴。
当初跟他说主角叫做山姆时,他就回了这麽一句:『不能画太丑』。殊不知,我把他画成了像素图 ^_^


结语

最後,来聊一下 it 铁人 30 天的感想
人们常把人生比喻成爬山,我想,铁人赛也是类似爬山的一种感受吧!

『在 99% 的时间里痛苦挣扎,用 1% 的时间去享受登顶的喜悦』

出自:youtuber 刘大白《最狂野的梦想:征服珠峰》

这些成果是自己一点一滴累积起来,而最终完赛的喜悦也是属於自己的深刻感受吧!
最後的最後,谢谢大家的阅读及陪伴/images/emoticon/emoticon29.gif


参考来源:
Pac-Man
小精灵游戏中的幽灵是怎麽追踪人的? 鲜为人知的bug和最快全破世界纪录! | 啾啾鞋
zPosition
childNode(withName:)
animate(with:timePerFrame:)
moveBy(x:y:duration:)
fadeAlpha(to:duration:)
sequence(_:)
run(_:)
repeat(_:count:)
repeatForever(_:)
update(_:)
SKTransition
SKLightNode
ambientColor
lightColor
shadowColor
falloff
categoryBitMask
lightingBitMask
viewSafeAreaInsetsDidChange()
sqrtf
random(in:)
abs(_:)
scheduledTimer(timeInterval:target:selector:userInfo:repeats:)
Codable
encode(_:)
contents(atPath:)
decode(_:from:)
AVAudioPlayer


<<:  电子工作日志纪录的重要性

>>:  [Day23]Vue3 E2E Testing: Cypress 基本介绍

Day12-记得要戴安全帽(二)

前言 昨天介绍了 Content Security Policy 跟 HTTP Strict Tra...

30天学习笔记 -day 30 -感言

LAST Day 终於到了铁人赛的最後一天,过程中复习了不少的东西,对某些用法有了更加的认识,过程中...

Day-11 其名为超级、於新电视再起的二代霸主超级任天堂

任天堂在红白机之後的这台後继机种超级任天堂、以下简称 SFC、是我家当年的第三台主机、也是我曾经拥有...

前端工程师也能开发全端网页:挑战 30 天用 React 加上 Firebase 打造社群网站|Day6 注册登入功能

连续 30 天不中断每天上传一支教学影片,教你如何用 React 加上 Firebase 打造社群...

[Angular] Day28. Control Value Accessor (CVA)

前几篇介绍了 Form 的基本操作与概念,也介绍了如何在表单中加入验证,最後要来介绍 Angular...