< Return to Video

The Ultimate Game Boy Talk (33c3)

  • 0:14 - 0:18
    下一个演讲 我个人十分期待
  • 0:18 - 0:23
    我也知道你们很多人为此在这里等候
  • 0:24 - 0:26
    我也非常激动
  • 0:27 - 0:32
    我自己有台GameBoy 我也很荣幸能拥有一台
  • 0:32 - 0:36
    我一直放着 有时也拿出来玩玩
  • 0:36 - 0:39
    当然一般情况下还是玩模拟器多
  • 0:40 - 0:44
    而且我只在模拟器上玩我拥有实体卡带的游戏
  • 0:46 - 0:53
    本来就应该是这样的 对吧
  • 0:54 - 0:54
    嗯是的
  • 0:56 - 0:57
    非常期待
  • 0:58 - 1:02
    顺便 我个人在Gameboy平台上最喜欢的游戏
  • 1:02 - 1:07
    第一个 是Megaman 2
  • 1:08 - 1:14
    随后是Wario Land, Mystic Quest 如果你不同意的话
  • 1:14 - 1:17
    那说明你还不够了解我
  • 1:19 - 1:25
    好了讲讲演讲吧
  • 1:25 - 1:27
    非常期待
  • 1:27 - 1:32
    主讲是Michael Steil
  • 1:33 - 1:36
    他在25C3给过一个非常棒的演讲
  • 1:37 - 1:41
    “The Ultimate Commodore 64 Talk” 现在
  • 1:41 - 1:44
    为大家带来的是 “The Ultimate Gameboy Talk”
  • 1:44 - 1:45
    很期待
  • 1:45 - 1:49
    Michael Steil 白天他在工作研究操作系统相关技术
  • 1:49 - 1:52
    晚上回到家就研究这些古董系统
  • 1:52 - 1:55
    在之前 它是个游戏机破解工作者
  • 1:55 - 1:58
    请为他热烈的鼓掌
  • 1:58 - 2:00
    把讲台交给Michel
  • 2:08 - 2:09
    大家好
  • 2:10 - 2:11
    那 我的名字是Michael Steil
  • 2:12 - 2:13
    这次讲座是“The Ultimate Gameboy Talk” (一场讲座,关于Gameboy的一切)
  • 2:22 - 2:24
    这场讲座的主要想法就是
  • 2:24 - 2:28
    在60分钟内 尽可能多得谈谈Gameboy的各种硬件细节
  • 2:28 - 2:32
    60分钟,关于Gameboy的一切
  • 2:32 - 2:36
    我准备了大约200张幻灯片 800张不同的表
  • 2:36 - 2:39
    所以信息密度可能比一般稍微高了一点
  • 2:39 - 2:41
    所以赶紧开始吧
  • 2:41 - 2:43
    这次的GameBoy演讲
  • 2:43 - 2:46
    算是一个大系列之一
  • 2:46 - 2:48
    我在几年前讲了Commodore 64
  • 2:48 - 2:51
    后来有人就接上讲了Atari 2600
  • 2:51 - 2:54
    讲了Galaksija 还有Amiga 500
  • 2:54 - 2:55
    所以现在又轮到我了
  • 2:57 - 2:59
    我选择了GameBoy
  • 2:59 - 3:01
    为什么GameBoy那么有趣
  • 3:01 - 3:04
    因为他们销售了很多很多的GameBoy
  • 3:04 - 3:06
    GameBoy和GBC加起来就有1亿1800万台
  • 3:07 - 3:11
    如果再考虑上兼容GameBoy的GBA机型 不包括GBM
  • 3:12 - 3:14
    加起来这几乎是2亿台机器
  • 3:14 - 3:18
    大约有1600款游戏
  • 3:19 - 3:24
    从1989年开始生产 8-Bit型号一直生产到2003年
  • 3:24 - 3:27
    一样,如果考虑兼容的GBA型号
  • 3:27 - 3:31
    8-Bit兼容机一直生产到2009年
  • 3:31 - 3:33
    也就是20年 相当厉害
  • 3:34 - 3:36
    我们再来看看当时的竞争对手
  • 3:36 - 3:38
    就在当时 就在GameBoy发布后
  • 3:39 - 3:43
    Atari发布了Lynx SEGA发布了Game Gear NEC发布了Turbo Express
  • 3:43 - 3:46
    这些竞品有一个共同点 它们都有彩屏
  • 3:46 - 3:47
    很棒的彩屏
  • 3:47 - 3:52
    但是还有一个共同点 就是渣续航 大约3-5小时
  • 3:52 - 3:54
    然而GameBoy可以做到15-30小时
  • 3:54 - 3:57
    然而妥协就是,只有一个这样的屏幕
  • 3:57 - 4:00
    而且一旦开始卷动就很难看清楚东西
  • 4:02 - 4:05
    当然,并不是所有的GameBoy都是这个情况
  • 4:06 - 4:09
    最初的GameBoy 也是生产最长时间的型号
  • 4:10 - 4:14
    最初代号是DMG 代表的是Dot-Matrix Game(点阵游戏)
  • 4:14 - 4:21
    1996年他们发布了GBP 带有效果好得多的屏幕 体积也小了很多 代号MGB
  • 4:21 - 4:24
    GBL只在日本发售 带有屏幕背光
  • 4:24 - 4:29
    最后是GBC 2倍的CPU速度 2倍的内存 2倍的显存 以及支持彩色
  • 4:31 - 4:36
    接着是GBA系列 架构完全不同 基于ARM CPU
  • 4:36 - 4:41
    但是仍然和GB、GBC游戏100%兼容
  • 4:41 - 4:45
    至于GBA SP,存在两种型号
  • 4:45 - 4:49
    如果你要买的话,记得买AGS101
  • 4:49 - 4:51
    也就是带有背光而不是前光的型号
  • 4:52 - 4:55
    而且可以看见任天堂总是有一点超前
  • 4:55 - 4:59
    不单单是做了翻盖设计 而且还需要一个转接头才能接一般的耳机
  • 5:06 - 5:09
    如果你想在电视上玩GameBoy
  • 5:10 - 5:14
    有两种选择 要么是Super Nintendo插上Super Game Boy
  • 5:14 - 5:20
    有两个版本 SGB2是日本专有型号 有专门的计时系统 不会比正常的快3%
  • 5:20 - 5:24
    以及Game Boy Player 搭配NGC使用
  • 5:24 - 5:27
    这三个都是内置了完整的GameBoy硬件
  • 5:27 - 5:31
    基本就是一个GameBoy 只是把图形输出到主机而不是自己的屏幕
  • 5:32 - 5:34
    所以GameBoy具体的外观
  • 5:34 - 5:39
    一个2.6英寸的屏幕 按键 单声道喇叭 耳机是立体的
  • 5:39 - 5:42
    有一个联机口 通过串行总线连接两台GameBoy
  • 5:42 - 5:44
    对比度和音量调节旋钮
  • 5:44 - 5:47
    背面 这里是插游戏卡带的地方
  • 5:47 - 5:49
    这里则是安装电池的地方
  • 5:49 - 5:51
    一般的游戏卡带就长这个样子
  • 5:51 - 5:53
    一般的游戏卡带里面一般也就是一片ROM芯片
  • 5:53 - 5:54
    没有什么特殊的 (具体后面会讲)
  • 5:56 - 5:57
    参数
  • 5:57 - 5:59
    GameBoy的参数是怎么样的
  • 5:59 - 6:02
    拿来和一些其它可能根本不具备可比性的机型比一比吧
  • 6:02 - 6:05
    CPU是1MHz的8Bit处理器
  • 6:05 - 6:10
    有人可能会讲这里错了 应该是个4MHz的CPU 但是我一会会解释为什么这里称之为1MHz
  • 6:12 - 6:15
    8KB的内存 对于这类的游戏机其实算是充裕了
  • 6:15 - 6:17
    显存(VRAM)也是8KB 稍微有点紧张
  • 6:18 - 6:24
    分辨率160*144 非常糟糕 但是对于这个屏幕尺寸 其实效果也还可以
  • 6:25 - 6:29
    同屏最大4种颜色 就是4级灰度
  • 6:29 - 6:32
    每行最多10个精灵
  • 6:32 - 6:36
    所以如果和这里其它的一些系统比较的话
  • 6:36 - 6:43
    很明显 GameBoy比Atari2600要先进得多 但是却又比不上SNES
  • 6:44 - 6:48
    更接近于一般的NES(美版红白机)或者是Commodore 64
  • 6:49 - 6:54
    有趣的是 NES和C64是在80年代早期发布的
  • 6:54 - 6:55
    GameBoy是89年
  • 6:55 - 7:01
    而且如我前面所说 兼容机一直生产到了2009年
  • 7:01 - 7:03
    这也就非常有趣了
  • 7:03 - 7:09
    它是8-Bit机 但是是最晚一批大量使用的8-Bit游戏机
  • 7:11 - 7:12
    看看内部
  • 7:12 - 7:15
    右边的板没什么花头
  • 7:15 - 7:19
    从正面看 LCD就是连接在这块板上 以及扬声器和按键
  • 7:21 - 7:23
    背后这块板就有趣多了
  • 7:24 - 7:28
    可以看见3块芯片 这个是DMG 也就是最初的型号
  • 7:28 - 7:30
    2片一样的RAM芯片
  • 7:30 - 7:33
    一片工作内存(WRAM) 一片视频内存(VRAM)
  • 7:33 - 7:36
    中间这个叫DMG-CPU
  • 7:36 - 7:39
    然而其实更应该被称为SoC(System on a Chip)
  • 7:39 - 7:45
    正常这类的系统都应该有很多芯片
  • 7:45 - 7:48
    但是这里全部都集成进了一个芯片 也就这个DMG芯片
  • 7:48 - 7:52
    来对比一下其它的GameBoy机型
  • 7:52 - 7:54
    比如SGB 这些芯片看起来很接近
  • 7:54 - 7:57
    其实基本上就是一样的
  • 7:58 - 8:05
    GBP 稍微优化了一下 只带有一片RAM芯片
  • 8:05 - 8:11
    GBL看起来基本没有区别 只是MGB系列的另外一个小型号
  • 8:11 - 8:12
    带有背光而已
  • 8:13 - 8:16
    接着是SGB2 基于GBP设计
  • 8:17 - 8:19
    这是GBC内部的样子
  • 8:20 - 8:21
    都有一个巨大的集成片
  • 8:22 - 8:25
    这个呢 这个比较特殊
  • 8:25 - 8:27
    可能从标识上不容易认
  • 8:27 - 8:29
    这个是GB Boy
  • 8:29 - 8:32
    总是有公司山寨GameBoy
  • 8:32 - 8:35
    这个型号 是一个相当完美的克隆
  • 8:36 - 8:41
    基本上就是 完全抄了一个原版的芯片
  • 8:42 - 8:45
    来自中国的山寨GameBoy
  • 8:45 - 8:48
    而且至今都可以在eBay上花三四十刀买到
  • 8:49 - 8:53
    然而很遗憾晶振快了30% 游戏都玩不了了
  • 8:56 - 8:58
    回来讲DMG的板子
  • 8:58 - 9:01
    DMG CPU还是相当有趣的
  • 9:01 - 9:02
    他接管整个系统的一切
  • 9:03 - 9:05
    DMG CPU包括了什么
  • 9:05 - 9:10
    CPU 中断控制器 定时器 内存 启动ROM
  • 9:10 - 9:16
    还有所有的外设以及IO控制器 摇杆 用于联机的串行控制器
  • 9:16 - 9:18
    声音控制器 还有 图形控制器
  • 9:18 - 9:19
    也就是PPU (Pixel Processing Unit)
  • 9:20 - 9:21
    来讲讲CPU吧
  • 9:22 - 9:23
    历史角度来讲
  • 9:23 - 9:25
    最初的GameBoy,1989年
  • 9:25 - 9:30
    发布时间是在NES的和SNES的之间
  • 9:31 - 9:33
    NES搭载的是6502处理器
  • 9:33 - 9:36
    SNES搭载的是65816处理器
  • 9:36 - 9:38
    也就是相同CPU的16位版本
  • 9:39 - 9:43
    所以显然GameBoy搭载了SHARP LR35902 (强行显然2333)
  • 9:44 - 9:48
    SHARP LR35902是什么
  • 9:48 - 9:49
    这个和6502没啥关系
  • 9:50 - 9:54
    更接近于i8080和Z80
  • 9:54 - 9:54
    但是也不是其中任何一种
  • 9:55 - 9:57
    两种cpu都相当有趣
  • 9:57 - 10:00
    比如8080用于Altair
  • 10:00 - 10:03
    也就是Bill Gates最初写程序并销售的平台
  • 10:04 - 10:10
    Z80则是用于所有没有采用6502的8bit家用机
  • 10:10 - 10:11
    相当成功的架构
  • 10:13 - 10:16
    所以如果你想象 这是i8080的功能
  • 10:17 - 10:19
    这是Z80的功能
  • 10:19 - 10:21
    也就是一个超集 而且完全向下兼容
  • 10:24 - 10:28
    然后这个 是GameBoy CPU
  • 10:30 - 10:34
    核心架构是相同的 也就8080的那些
  • 10:34 - 10:39
    比如寄存器组 指令编码 这些都是一样的
  • 10:40 - 10:41
    当然也有一些不支持的功能
  • 10:42 - 10:45
    但是又支持一部分Z80的功能
  • 10:45 - 10:47
    然而大部分的Z80功能都不支持
  • 10:47 - 10:49
    接着又在这之上加了一点自己的功能
  • 10:50 - 10:52
    来看一遍吧
  • 10:52 - 10:56
    先来讲讲8080的架构
  • 10:56 - 10:58
    它拥有这些寄存器
  • 10:58 - 11:03
    一个累加器 可以用于进行算数运算 其它寄存器不行
  • 11:03 - 11:04
    一个状态寄存器
  • 11:04 - 11:09
    在GB内 只有两个有用的标志位 零 和 进位
  • 11:09 - 11:11
    剩下两个是用于十进制调整的
  • 11:11 - 11:15
    然后是BCDEHL 6个8位寄存器
  • 11:15 - 11:19
    但是你可以把B和C合起来 变成BC
  • 11:19 - 11:21
    DE HL同理
  • 11:21 - 11:25
    所以你实际上拥有可以作为指针的16位寄存器
  • 11:26 - 11:30
    所以加起来一共有4个16位计算器
  • 11:31 - 11:35
    7个8位寄存器 加上一个特殊的指针寄存器
  • 11:35 - 11:41
    指向hl寄存器指向的内存地址的数据
  • 11:41 - 11:45
    可以放到任何可以操作寄存器的指令中使用
  • 11:48 - 11:49
    然后来看指令
  • 11:49 - 11:55
    读取/存储指令 同一个指令可以直接或者间接寻址
  • 11:56 - 12:00
    堆栈是16位的 只能操作16位寄存器
  • 12:00 - 12:03
    这些是算数和逻辑指令
  • 12:03 - 12:05
    如之前所说 这些指令只能配合累加器使用
  • 12:05 - 12:08
    inc和dec(自加自减)指令是例外 可以配合任何寄存器使用
  • 12:08 - 12:11
    而且也可以配合16位寄存器使用
  • 12:11 - 12:18
    移位指令 还有控制指令 跳转 调用 返回 条件 间接操作 等等
  • 12:18 - 12:24
    还有一些杂类的指令 清除设置进位标志 空指令 停机 停用启用中断
  • 12:24 - 12:27
    中断模型
  • 12:28 - 12:32
    大部分当时的机器都有一个中断向量来控制中断
  • 12:32 - 12:35
    然而这个上面 并不是向量 也不止一个
  • 12:35 - 12:37
    他并不是跳转到一个中断向量
  • 12:37 - 12:40
    而是跳转到内存中开始部分一个固定的地址
  • 12:40 - 12:45
    不同的中断对应不同的地址 比如0x40 0x48这种
  • 12:46 - 12:49
    还有一些软件中断
  • 12:49 - 12:51
    你可以使用特殊指令跳转到这些地方
  • 12:52 - 12:55
    RST 0是一个特殊指令 因为就相当于RESET
  • 12:55 - 12:59
    当你启动8080 CPU 他就从0地址开始执行
  • 13:00 - 13:04
    来谈谈一些不被支持的8080功能
  • 13:04 - 13:08
    这个是GB的标志位 这个是8080的标志位
  • 13:08 - 13:15
    它有两个额外的标志 一个是符号位 还算有点用 一个奇偶校验 就不太有用
  • 13:15 - 13:16
    所以这些指令都是不支持的
  • 13:17 - 13:21
    还有一些其它指令 因为种种原因 他们决定不包括这些指令
  • 13:21 - 13:27
    端口IO 你可能在8086上听说过 有独立的端口空间
  • 13:27 - 13:29
    在8080上也是支持的 但是GameBoy上不支持
  • 13:29 - 13:31
    因为GB使用了MMIO(内存映射IO)
  • 13:33 - 13:41
    Z80支持大量额外的移位和位移位 设置位 清楚位指令
  • 13:41 - 13:42
    这些都是支持的
  • 13:42 - 13:47
    相对跳转 也就是更优化的跳转指令
  • 13:47 - 13:49
    从中断返回
  • 13:49 - 13:50
    这些都是支持的
  • 13:51 - 13:54
    而不支持的则是一些Z80有趣的功能
  • 13:54 - 13:59
    比如备份寄存器组 额外的寄存器 还有很多很多功能
  • 13:59 - 14:04
    还有适合复制内存的自加循环指令
  • 14:04 - 14:08
    不过他们也有一些自己的指令来代替这些
  • 14:08 - 14:13
    比如它具有访问预减后加指令
  • 14:13 - 14:20
    比如你要访问hl指针 可以使用预减指令或者后加指令
  • 14:21 - 14:23
    还有一个叫做 第0页 (Zero Page) 的概念
  • 14:23 - 14:26
    这个叫法有点晕 因为并不是真正的第0页
  • 14:26 - 14:28
    而是在内存的顶部
  • 14:28 - 14:32
    如果你了解6502就知道 这个是从6502借来的概念
  • 14:32 - 14:40
    含义只是对于在内存最上端的数据可以优化编码
  • 14:40 - 14:46
    比如原先这样载入需要3个字节 执行需要4个时钟机器周期
  • 14:46 - 14:49
    现在可以写成这样 也就是2个字节 执行需要3个机器周期
  • 14:50 - 14:53
    显然得在最高的位置放一些有用的东西
  • 14:53 - 14:55
    特别是对计时敏感的东西
  • 14:55 - 14:56
    还有一些额外的堆栈指令
  • 14:57 - 15:00
    存储SP的指令 一个用于交换一个字节高低4位的指令
  • 15:00 - 15:05
    这样8个指令 以及一个额外的电源指令
  • 15:06 - 15:08
    操作码表看起来是这样的
  • 15:08 - 15:10
    表明了颜色所以看起来更加直观一点
  • 15:13 - 15:16
    有几个操作码是无效的 或者说没有被用到
  • 15:16 - 15:18
    如果执行的话都会造成死机 应该算是个好设计
  • 15:19 - 15:22
    这个比较特殊 操作码CB
  • 15:23 - 15:26
    是个操作码前缀 以此为前缀又有256个操作码
  • 15:26 - 15:35
    这也就是从Z80借来的滚动、移位指令 以及自己新增加的指令的空间
  • 15:35 - 15:38
    再来看另外一个指令 只是作为一个例子
  • 15:39 - 15:43
    这是从一个固定地址载入到累加器
  • 15:43 - 15:47
    表示需要3个字节 在4MHz下需要16个时钟
  • 15:47 - 15:53
    虽然存在争议 就是应该是1MHz还是4MHz (实际4MHz 但是把4个周期当1个看)
  • 15:53 - 15:56
    因为所有的时钟周期数都是可以被4整除的
  • 15:57 - 16:01
    因为整个系统都是和内存挂钩的
  • 16:01 - 16:06
    CPU只能以RAM能够提供数据的速度来计算
  • 16:07 - 16:12
    所以你可以说这是一个1MHz的CPU
  • 16:12 - 16:14
    然后这个指令需要4个周期
  • 16:14 - 16:16
    这个数字就小得多
  • 16:16 - 16:18
    而且这个数字也才可以和类似的系统进行比较
  • 16:18 - 16:25
    比如说和同样拥有1MHz内存速度的6502机器比较
  • 16:25 - 16:28
    所以说 理论上 CPU确实频率是4MHz
  • 16:28 - 16:30
    RAM速度是1MHz
  • 16:30 - 16:34
    PPU以4MHz的速度绘图
  • 16:34 - 16:37
    连接到速度为2MHz的VRAM
  • 16:37 - 16:39
    所以这里就稍微有点复杂
  • 16:39 - 16:41
    但是大部分情况下
  • 16:41 - 16:46
    大部分的数据可以以1MHz为基准表示
  • 16:46 - 16:50
    但是要精确的话 并不是1MHz
  • 16:50 - 16:54
    而是1MiHz 1024*1024Hz
  • 16:54 - 16:59
    所以他们没有使用十进制 而是用了二进制
  • 16:59 - 17:00
    很有趣
  • 17:01 - 17:05
    所以以后我提到周期 我说的是1MHz的机器周期
  • 17:08 - 17:14
    所以这是一个拥有16位地址空间的8-Bit CPU
  • 17:14 - 17:19
    因为拥有16Bit的指针 所以一共也就是64KB的可见地址
  • 17:19 - 17:25
    32KB的是ROM 直接来自卡带 映射到卡带
  • 17:25 - 17:29
    然后在上方有一个Boot ROM 一会提
  • 17:29 - 17:36
    VRAM也映射在这里 可选的外部RAM 以及内部RAM
  • 17:36 - 17:40
    没有使用的部分 要么没有东西 要么就是镜像已有的
  • 17:41 - 17:42
    把最高地址的这些放大
  • 17:42 - 17:48
    可以看到另外一页的OAM内存 就像是一种特殊用途的VRAM
  • 17:48 - 17:51
    独立于VRAM 一会会具体讲
  • 17:51 - 17:55
    最后一页 也就是第0页 包括了IO部分
  • 17:55 - 17:58
    所有的寄存器 声音的视频的
  • 17:58 - 18:05
    还有127字节的HRAM 独立于其它的RAM
  • 18:05 - 18:08
    所以这代表游戏只能有32KB
  • 18:08 - 18:11
    有些游戏确实只需要32KB
  • 18:11 - 18:14
    比如说俄罗斯方块 就刚好挤进32KB 里面就一片芯片
  • 18:14 - 18:16
    生产也很方便
  • 18:17 - 18:18
    然后其它的卡带
  • 18:18 - 18:23
    容量没有理论上限 但是实际上最大是到2MB
  • 18:23 - 18:26
    这个是128KB
  • 18:26 - 18:30
    实现的办法是 增加一个MBC (内存分页控制器)
  • 18:30 - 18:33
    一个特殊的可以切换分页的芯片
  • 18:33 - 18:35
    这个在各种系统上都是很常见的做法
  • 18:36 - 18:41
    这些控制器可以很不一样 但是实际上 大部分的工作方式是这样的
  • 18:41 - 18:46
    最低16KB空间 永远映射到Bank0
  • 18:46 - 18:51
    而16KB-32KB这部分可以映射到Bank1 Bank2等等
  • 18:53 - 18:57
    切换分页的方法就是往一个地址空间内写入一些特定数值
  • 18:57 - 19:01
    这些就会被MBC读取到 然后切换分页
  • 19:02 - 19:04
    这点对于外部RAM也是一样的
  • 19:04 - 19:09
    游戏卡带如果含有外置内存 比如用于保存游戏
  • 19:09 - 19:12
    比如装有备份电池的内存 这也是保存游戏的唯一办法
  • 19:12 - 19:16
    可以把外部内存映射在这里 一样的模型
  • 19:16 - 19:18
    所以这个BootROM是什么
  • 19:18 - 19:22
    CPU从内存地址0开始执行
  • 19:23 - 19:27
    BootROM的作用就是显示这些东西 然后响一声
  • 19:27 - 19:29
    BootROM是内置在GameBoy里面的
  • 19:30 - 19:33
    花了一段时间这些代码才被提取出来 还是挺麻烦的
  • 19:33 - 19:34
    (不是我完成的)
  • 19:35 - 19:37
    这个就是完整的BootROM
  • 19:37 - 19:38
    首先初始化RAM
  • 19:38 - 19:40
    初始化声音
  • 19:40 - 19:42
    设置和解码显示在屏幕上的logo
  • 19:43 - 19:45
    卷动logo 播放声音
  • 19:45 - 19:49
    然后就是有趣的部分 它对比logo
  • 19:49 - 19:52
    游戏卡带内需要有一份logo副本
  • 19:52 - 19:56
    如果两者不一样 就不会继续开机
  • 19:56 - 20:00
    这样任天堂就能控制什么游戏是给这个平台发行的
  • 20:01 - 20:02
    游戏必须要内置这个logo
  • 20:02 - 20:08
    如果未经允许加入 那不单单是违反版权保护 而且还是违反商标保护
  • 20:10 - 20:13
    最后是计算校验和 算是再一次确认
  • 20:13 - 20:16
    否则你得拆出来吹吹卡带 吹吹机子 重新插一遍
  • 20:16 - 20:19
    接着它关闭BootROM 继续执行
  • 20:19 - 20:27
    这个logo 实际上是从卡带里面读取并且显示出来的
  • 20:27 - 20:30
    如果不插卡带开机会看见这个
  • 20:31 - 20:34
    但是这并不代表游戏开发商可以往里面装入任何logo
  • 20:34 - 20:36
    因为GameBoy会对比这个logo
  • 20:36 - 20:38
    如果logo错误就不会继续启动了
  • 20:39 - 20:42
    因为没有清理代码
  • 20:42 - 20:44
    没有重启系统或者其它事情
  • 20:44 - 20:47
    所以有些游戏就直接开始调戏这个logo
  • 20:47 - 20:48
    直接在此之上继续
  • 20:49 - 20:51
    demo也显然很喜欢调戏这个
  • 20:51 - 20:54
    任天堂logo已经在屏幕上了 就对它做点啥吧(阴险
  • 20:59 - 21:00
    很不错
  • 21:02 - 21:06
    BootROM一直运行 直到最后一条指令关闭BootROM
  • 21:06 - 21:12
    这是即使是最低地址显示的也是游戏卡带的内容了
  • 21:12 - 21:14
    它就继续从这里执行
  • 21:14 - 21:17
    运行来自游戏中的下一条指令
  • 21:17 - 21:19
    通常这里是一个跳转指令
  • 21:19 - 21:22
    因为这其实是所谓的ROM头 按照要求就应该是这样的
  • 21:23 - 21:28
    头部必须内置任天堂Logo 头部校验和 这是很重要的
  • 21:28 - 21:30
    剩下的元数据就不重要了
  • 21:30 - 21:32
    对于当时的游戏开发者来说什么很重要
  • 21:32 - 21:34
    但是没有软件会真正检查这些内容
  • 21:34 - 21:38
    在这之后 就可以放真正的游戏数据了
  • 21:39 - 21:43
    还没讲到过的东西就是IO部分和HRAM了
  • 21:43 - 21:52
    也就是在最高页 所谓的第0页 可以比较高效得操作
  • 21:52 - 21:56
    最高的127字节是额外的内存
  • 21:56 - 22:00
    剩下的 就是这些不同的设备
  • 22:00 - 22:03
    这些是所有系统内的寄存器
  • 22:03 - 22:07
    中断控制器 声音控制器 摇杆输入 串口传输 定时器 还有PPU
  • 22:07 - 22:10
    这些就是要讲的所有东西
  • 22:10 - 22:11
    摇杆输入
  • 22:12 - 22:15
    非常简单 这是所有GameBoy拥有的输入
  • 22:16 - 22:17
    4个按钮 4个方向
  • 22:17 - 22:21
    于是你会想 弄8个GPIO 这样就能实现了
  • 22:21 - 22:24
    但是也可以用6个GPIO
  • 22:24 - 22:26
    2列4行
  • 22:27 - 22:33
    你选择想要测试的行 然后知道这一行按下了什么按键
  • 22:33 - 22:35
    这样就能用6个而不是8个
  • 22:35 - 22:37
    按键就是这些 很简单
  • 22:37 - 22:39
    串行数据传输
  • 22:39 - 22:42
    你可以用一条联机线把两台GameBoy连在一起
  • 22:42 - 22:50
    联机线其实就是 1条单向数据线 1条另外一个方向的数据线 1条时钟线
  • 22:50 - 22:54
    两台GameBoy得确定谁发送时钟 谁接收时钟
  • 22:55 - 22:57
    这些就是控制这些东西的位
  • 22:57 - 22:59
    一个设置输出时钟 永远是8kHz
  • 23:00 - 23:04
    接收时钟范围很宽 可以从0一直到0.5MHz都能收到
  • 23:04 - 23:10
    一旦传输开始 就会一位位移出字节 而且永远是全双工的
  • 23:12 - 23:13
    定时器
  • 23:13 - 23:16
    任何系统都得有个时钟 这个系统只有一个时钟
  • 23:17 - 23:21
    TMA寄存器用来存放计数初值
  • 23:21 - 23:25
    然后可以选择四种速度之一
  • 23:25 - 23:28
    接着打开定时器 向上计时
  • 23:28 - 23:35
    直到溢出 就会载入初值 然后可选的产生一个中断
  • 23:35 - 23:37
    讲到中断
  • 23:37 - 23:40
    中断控制器支持5种不同的中断
  • 23:40 - 23:45
    V-Blank(场消隐) LCD状态 也就是和PPU相关 一会讲
  • 23:45 - 23:47
    已经讲过的定时器 可以产生中断
  • 23:47 - 23:50
    串口 可以在接受到数据的时候产生中断
  • 23:50 - 23:52
    摇杆 可以在有按键按下的时候产生中断
  • 23:52 - 23:54
    这个是中断启用寄存器
  • 23:55 - 23:56
    一个中断标志寄存器
  • 23:57 - 23:59
    可以看见有哪些中断还没有被处理
  • 23:59 - 24:03
    这些是中断发生时会跳转的地址
  • 24:03 - 24:05
    你不需要手动确定发生的是哪个中断
  • 24:06 - 24:07
    因为直接跳转的就是不同的地址
  • 24:07 - 24:10
    所以 声音控制器
  • 24:10 - 24:15
    声音控制器的寄存器数量是最多的
  • 24:15 - 24:20
    一共有四个声部 每个声部有自己的一组独立的寄存器
  • 24:20 - 24:22
    这样看更为合理
  • 24:22 - 24:24
    4个声部 每个声部5个寄存器
  • 24:26 - 24:30
    每个寄存器有特定的含义
  • 24:32 - 24:33
    但是含义只是大致的
  • 24:33 - 24:36
    因为四个声道并不完全一样
  • 24:36 - 24:39
    有两个很接近的 产生方波
  • 24:39 - 24:42
    剩下两个一个是PCM采样 一个是杂波
  • 24:43 - 24:46
    看位定义的话 有一定相似性 但是还是不一样
  • 24:47 - 24:50
    具体通道有具体的定义
  • 24:50 - 24:53
    先看看共通的一些参数
  • 24:53 - 24:56
    每个声部都有一个开关位 也就是控制这个通道的开关
  • 24:57 - 24:59
    你可以在某个时候关掉这个通道
  • 24:59 - 25:03
    但是还有一个长度开关 以及长度设置寄存器
  • 25:03 - 25:06
    所以比如你可以这么设置 在0.25秒后自动关闭
  • 25:07 - 25:10
    然后先来看PCM采样声部的寄存器 也是最简单的一个
  • 25:11 - 25:15
    这个声部的作用就是 可以播放任何的波形
  • 25:15 - 25:19
    它有额外的16字节寄存器
  • 25:19 - 25:21
    里面有32个位置 每个4位
  • 25:22 - 25:28
    你可以在里面放任何你想要的波形
  • 25:29 - 25:30
    这里是几个例子
  • 25:30 - 25:32
    比如你可以产生一个锯齿波
  • 25:36 - 25:37
    算是相当基本的波形
  • 25:37 - 25:39
    也可以有正弦波
  • 25:44 - 25:46
    或者是任何自定义的东西
  • 25:51 - 25:52
    相当灵活
  • 25:53 - 25:54
    然后有一个频率控制
  • 25:55 - 25:59
    也就是控制采样的播放速度
  • 25:59 - 26:01
    2位的音量
  • 26:01 - 26:04
    音量可以在100% 50% 25%和静音之间控制
  • 26:05 - 26:10
    另外两个 是很相似的两个方波声部
  • 26:10 - 26:13
    这些位都是一样的,功能也一样
  • 26:13 - 26:18
    你不能指定波形 波形是固定的 只能是方波
  • 26:18 - 26:20
    就是只能是高或者低
  • 26:21 - 26:22
    但是高低比例(占空比)可以不同
  • 26:22 - 26:26
    这两个位就是控制占空比的
  • 26:28 - 26:31
    可以设置12.5%高 剩下的低
  • 26:33 - 26:34
    25%
  • 26:37 - 26:37
    50%
  • 26:37 - 26:40
    75%听起来应该和25%一样,只是反相了
  • 26:43 - 26:47
    这个是两个声部都支持的功能
  • 26:47 - 26:49
    另外有一个功能叫音量扫频 (Volume Sweep,翻译不准确,暂时想不到更好的)
  • 26:50 - 26:52
    就是音量可以增高或者降低
  • 26:52 - 26:56
    降低就是模拟乐器的情况
  • 26:59 - 27:01
    或者也能增高 效果比较有趣
  • 27:05 - 27:10
    然后 只有第一个声部有扫频功能
  • 27:11 - 27:12
    可以升高
  • 27:15 - 27:16
    也可以降低
  • 27:19 - 27:21
    所以可以注意到主要是用于音效的
  • 27:21 - 27:23
    更多的音效例子
  • 27:25 - 27:27
    这就是可以实现的效果
  • 27:28 - 27:30
    然后还有第四个杂波通道
  • 27:31 - 27:36
    就是一个只能产生伪随机数的移位寄存器
  • 27:36 - 27:41
    根据你设置的15bit模式或者7bit模式
  • 27:41 - 27:45
    他能产生两种不同的波形
  • 27:48 - 27:49
    这是15bit模式
  • 27:52 - 27:53
    这是7bit模式
  • 27:54 - 27:56
    这些是所有的寄存器
  • 27:56 - 28:00
    4个声部的寄存器 3个通用寄存器
  • 28:00 - 28:04
    这个可以设置左声道和右声道的音量
  • 28:04 - 28:08
    有趣的是卡带可以有自己的音频控制器
  • 28:08 - 28:11
    可以产生接到这个上面的音频信号
  • 28:11 - 28:12
    但是没有游戏做过这种事情
  • 28:13 - 28:21
    然后还有一个寄存器 可以设置一个通道是接到左声道还是右声道 或者都接、都不接
  • 28:21 - 28:23
    然后有一个电源开关
  • 28:23 - 28:27
    关掉音频部分可以减少约30%的电力消耗
  • 28:29 - 28:33
    然后 GameBoy的声音系统不单单被用于游戏
  • 28:34 - 28:39
    人们现在还在GB上用Little Sound DJ一类的软件编曲
  • 28:39 - 28:41
    我展示一个简单的例子
  • 29:17 - 29:18
    音频就到此为止
  • 29:19 - 29:21
    我们来谈谈Pixel Processing Unit (像素处理单元/PPU)
  • 29:22 - 29:25
    PPU就是产生图形的部分 拥有12个寄存器
  • 29:26 - 29:27
    并不是很多
  • 29:27 - 29:29
    首先来看看规格
  • 29:29 - 29:32
    在之前讲过,160*144像素,不是很多
  • 29:33 - 29:36
    4级灰度 其实更接近于4级不同的绿色
  • 29:36 - 29:39
    当然后续的GameBoy要好得多
  • 29:39 - 29:41
    所有屏幕上的东西都是以8*8像素的方格为单位的
  • 29:42 - 29:44
    屏幕上有一定数量的方格 还有一些精灵
  • 29:45 - 29:46
    这些东西都得装进8KB的显存
  • 29:46 - 29:49
    具体解释下这个8*8像素方格
  • 29:50 - 29:51
    我们看一下俄罗斯方块的游戏画面
  • 29:52 - 29:54
    所有东西都是基于这些方块的
  • 29:55 - 30:01
    塞尔达也是一样 画上网格线就能看见重复的图案 而且都是和网格线对齐的
  • 30:01 - 30:06
    超级马里奥大陆也是很明显 因为没有很多不同的方格
  • 30:07 - 30:09
    甚至是像Donkey Kong Land这样的游戏
  • 30:10 - 30:12
    在画上网格后还是能看出来的
  • 30:12 - 30:14
    可以看见重复对齐的图案
  • 30:14 - 30:17
    尽管他们很好地隐藏了这一点
  • 30:18 - 30:21
    有些游戏干脆就利用这个特性来设计
  • 30:21 - 30:24
    在Turrican里面干脆就用方块做了个动画
  • 30:25 - 30:27
    我们来看看方格是什么样的
  • 30:27 - 30:30
    一个方格尺寸是8*8 可以有4种颜色
  • 30:32 - 30:35
    4种颜色的编码就是00 01 10和11
  • 30:36 - 30:40
    把这个叠加到像素上看看编码是如何完成的
  • 30:40 - 30:43
    看第一行 直接当成一个二进制数读
  • 30:43 - 30:47
    于是就是 02 FF 一行像素需要2个字节
  • 30:47 - 30:51
    整个下来一个方块就是16字节
  • 30:52 - 30:56
    你可能注意到了这个颜色的排序比较奇怪
  • 30:57 - 30:59
    这是因为调色板是可以自定的
  • 30:59 - 31:01
    我可以选择任何想要的调色板
  • 31:01 - 31:04
    系统内对于这些背景方块有个2位到2位的映射
  • 31:06 - 31:10
    原生的表示方法是 00表示白 11表示黑
  • 31:10 - 31:13
    我可以选择任意的这种的调色板
  • 31:13 - 31:16
    如果有需要 我也可以选择一样的颜色
  • 31:18 - 31:20
    系统内一共支持256个方块
  • 31:20 - 31:22
    看这个设置 你认出是什么游戏了吗
  • 31:22 - 31:24
    这是俄罗斯方块
  • 31:24 - 31:27
    如果你不认识底部那些跳舞的人
  • 31:27 - 31:28
    说明你没有通关过俄罗斯方块
  • 31:31 - 31:32
    这是塞尔达
  • 31:34 - 31:37
    这是超级马里奥大陆 只使用了128个方块
  • 31:39 - 31:41
    有人认识这个吗?
  • 31:43 - 31:45
    这个只是一个拼图
  • 31:46 - 31:47
    是网球
  • 31:50 - 31:55
    20*18个方块填满了整个屏幕
  • 31:56 - 31:57
    但是其实事情不完全是这样
  • 31:57 - 32:02
    在视频内存中 有32*32方块
  • 32:02 - 32:03
    这才是完整的背景映射
  • 32:03 - 32:06
    屏幕上能看见的只是一个区域(Viewport)
  • 32:07 - 32:12
    256*256个像素还是相当方便的数字
  • 32:13 - 32:17
    卷动很方便,只要移动这个区域就可以了
  • 32:18 - 32:23
    使用这个模拟器就能很清楚得看到背景中发生了什么事情
  • 32:23 - 32:25
    以及可视区域是如何移动的
  • 32:25 - 32:29
    其实就像是一个摄像机,在32*32的映射中移动
  • 32:30 - 32:34
    但是这种方法只适用于最大地图只有32*32的游戏
  • 32:34 - 32:36
    但是那种需要无限卷动的游戏怎么办
  • 32:36 - 32:38
    比如超级马里奥大陆
  • 32:38 - 32:40
    最多可以有这么多的列
  • 32:41 - 32:42
    可以把区域移动到这里
  • 32:43 - 32:45
    但是到最后怎么办
  • 32:45 - 32:48
    它会直接卷到左边
  • 32:48 - 32:52
    如果我们能在显示出来之前重绘这些画面
  • 32:52 - 32:53
    就可以拥有无限的世界大小
  • 32:54 - 32:56
    在模拟器里就看得很清楚了
  • 32:57 - 33:02
    在屏幕显示不到的地方会不断刷新新的地图
  • 33:02 - 33:04
    对于二维也是一个道理
  • 33:04 - 33:05
    这是Donkey Kong Land
  • 33:05 - 33:07
    这个看起来很奇怪
  • 33:07 - 33:11
    只在需要显示的地方绘制新的地图
  • 33:14 - 33:17
    这是我们已经谈论过的一个图层
  • 33:19 - 33:20
    背景图层
  • 33:20 - 33:23
    除了背景外 还能放一层图像
  • 33:23 - 33:24
    窗口
  • 33:24 - 33:25
    可以直接覆盖
  • 33:25 - 33:27
    也可以放在任意地方
  • 33:27 - 33:28
    有个XY坐标
  • 33:28 - 33:31
    他会从起始坐标开始向右下方绘制
  • 33:31 - 33:33
    然而没有透明支持
  • 33:33 - 33:36
    通常的用法就是放到右边
  • 33:36 - 33:38
    或者放到下面
  • 33:38 - 33:41
    因为这个是不受卷动影响的
  • 33:42 - 33:47
    显然这个功能对于屏幕下方的分数显示来说是很必要的
  • 33:47 - 33:49
    对于游戏来说非常简单好用的功能
  • 33:50 - 33:52
    当然也能放在右边
  • 33:52 - 33:56
    这些是GBC游戏 但是不影响 在GB上也能玩
  • 33:57 - 34:00
    然后在背景和窗口层之上还有一个图层
  • 34:00 - 34:01
    就是精灵层
  • 34:02 - 34:06
    精灵就是放在屏幕上的不用受限于8*8方格的物体
  • 34:06 - 34:08
    可以自由摆放
  • 34:08 - 34:10
    现在屏幕上有3个精灵
  • 34:10 - 34:12
    任天堂把它们叫做 对象,OBJ
  • 34:12 - 34:15
    但是我还是继续叫他们精灵 因为就是精灵
  • 34:15 - 34:17
    就直接拿这个蘑菇举例吧
  • 34:17 - 34:20
    每个精灵都有自己的属性
  • 34:20 - 34:24
    系统内有个 OAM 也就是对象属性映射表
  • 34:24 - 34:25
    这个就是一个OAM记录
  • 34:25 - 34:27
    含有以下值
  • 34:27 - 34:28
    第一个是X位置
  • 34:28 - 34:31
    把它放到屏幕的左边
  • 34:31 - 34:34
    你可能会以为应该横向坐标为0
  • 34:35 - 34:36
    但是不是 是8
  • 34:36 - 34:37
    为什么呢
  • 34:37 - 34:38
    因为如果你把它放在4
  • 34:38 - 34:39
    他就在这
  • 34:39 - 34:39
    如果设置成0
  • 34:39 - 34:41
    那就看不见了 因为宽度是8
  • 34:41 - 34:42
    需要有一种方法能让它进入屏幕
  • 34:43 - 34:46
    对于屏幕顶端的情况也是一样的
  • 34:46 - 34:49
    但是你看现在的Y坐标是16
  • 34:49 - 34:58
    因为一个精灵最高可以有16像素高
  • 34:59 - 35:02
    把它放到一个自然的位置
  • 35:02 - 35:06
    下一个问题就是应该长什么样
  • 35:06 - 35:08
    首先看见是一个8*8的方格
  • 35:08 - 35:09
    和之前的方格是一样的编码
  • 35:09 - 35:11
    只是这个还带有透明色
  • 35:11 - 35:14
    所以00 表示透明
  • 35:14 - 35:17
    因为是一样的编码 所以也是一样的方格
  • 35:17 - 35:21
    而且系统内也有256个方格位可供使用
  • 35:21 - 35:23
    你看现在是方块编号0x90
  • 35:24 - 35:27
    剩下一个是 X翻转 选项
  • 35:27 - 35:32
    所以你没有必要为 向左走 和 向右走 的蘑菇单独存两个方块
  • 35:32 - 35:35
    水平翻转一下 就有向右走的了
  • 35:36 - 35:38
    垂直翻转一下 就有死蘑菇了
  • 35:38 - 35:42
    同时垂直和水平翻转 就有向右走的死蘑菇啦~
  • 35:43 - 35:45
    调回来
  • 35:45 - 35:47
    下一个是调色板
  • 35:47 - 35:52
    因为其中一种的颜色表示的是透明
  • 35:52 - 35:55
    所以只剩下3种颜色可以选择
  • 35:55 - 36:01
    他们不想强制固定这三种颜色
  • 36:01 - 36:05
    所以你可以在四种颜色里面挑3种想要的
  • 36:05 - 36:08
    而且不同的精灵不需要使用同样的3种颜色
  • 36:08 - 36:10
    因为系统内可以有两个调色板
  • 36:11 - 36:15
    所以才有这个位 可以选择是调色板0还是调色板1
  • 36:15 - 36:18
    调色板1和0分别效果就是这样
  • 36:20 - 36:21
    剩下一个是优先级
  • 36:21 - 36:25
    就是精灵碰到背景时如何绘图
  • 36:26 - 36:28
    如果优先级是1就有趣了
  • 36:28 - 36:30
    它会画在这些白色像素之上
  • 36:30 - 36:34
    但是在所有不是白色的像素后面
  • 36:34 - 36:36
    当然白色并不是一个什么特殊颜色
  • 36:36 - 36:42
    只是指背景调色板里的0号颜色
  • 36:42 - 36:46
    所以改调色板 就能让蘑菇显示在任意颜色之上
  • 36:47 - 36:50
    优先级0的话就会绘制在任何东西之上
  • 36:50 - 36:52
    当然不包括透明像素
  • 36:53 - 36:55
    然后就是精灵之间的优先级问题
  • 36:55 - 36:57
    这个没有办法自己设置
  • 36:57 - 36:58
    这个是固定的
  • 36:58 - 37:01
    现在蘑菇在正方形之上
  • 37:01 - 37:05
    因为它的横向坐标比正方形小
  • 37:05 - 37:07
    一旦达到一样的坐标
  • 37:07 - 37:09
    精灵编号小的显示在上
  • 37:09 - 37:14
    因为精灵在内存中也是一个数组 存前面的画上面
  • 37:14 - 37:21
    然而一旦正方形的X坐标小于蘑菇的X坐标 就会画在上面
  • 37:21 - 37:24
    一部分游戏中穿透其它精灵的时候 就能看到这种现象
  • 37:26 - 37:30
    系统支持最多40个精灵 屏幕上最多也是能放40个
  • 37:30 - 37:32
    但是还有一个限制
  • 37:32 - 37:34
    每一行最多只能有10个
  • 37:34 - 37:35
    比如这里有11个
  • 37:36 - 37:37
    10个是按照一行像素计算的
  • 37:37 - 37:39
    所以这些像素就不会被显示出来
  • 37:40 - 37:42
    或者是下面两行
  • 37:42 - 37:45
    这个不是讲从左到右的第十个
  • 37:45 - 37:51
    而是按照精灵的编号来决定的
  • 37:52 - 37:54
    所以这是一个完整的OAM记录
  • 37:54 - 37:56
    一共4个字节
  • 37:56 - 37:58
    这是内存中的一个OAM记录
  • 37:58 - 38:01
    FE00就是存储这些记录的起始地址
  • 38:02 - 38:04
    一共有40个记录 里面能存40个精灵
  • 38:04 - 38:05
    整个这个叫做OAM内存
  • 38:05 - 38:09
    就是一个存在这个位置的专用内存
  • 38:09 - 38:10
    并不是显存的一部分
  • 38:12 - 38:13
    还有一件事情
  • 38:14 - 38:15
    就是即使是小马里奥
  • 38:16 - 38:18
    也超过了8*8
  • 38:18 - 38:21
    你可以用4个精灵来实现
  • 38:21 - 38:22
    这也是游戏里的做法
  • 38:22 - 38:23
    但是还有一个模式
  • 38:23 - 38:25
    可以拥有16像素高的精灵
  • 38:25 - 38:27
    但是这个设定是全局的
  • 38:27 - 38:30
    整个游戏都得使用16像素高的精灵
  • 38:31 - 38:33
    所以已经见过3层了
  • 38:33 - 38:38
    还有一件事情是 屏幕是可以被彻底关闭的
  • 38:38 - 38:40
    这样就有第五种颜色了(强行)
  • 38:40 - 38:42
    稍微比白色位再淡一点
  • 38:43 - 38:46
    没啥用 因为得把屏幕关掉
  • 38:46 - 38:49
    一旦打开屏幕但是不画任何东西
  • 38:49 - 38:51
    就是白色
  • 38:51 - 38:53
    然后打开背景层 比如说要显示个淡灰色
  • 38:53 - 38:56
    然后就完全代替了这个颜色
  • 38:56 - 38:57
    再画个窗口
  • 38:57 - 38:59
    注意没有透明
  • 38:59 - 39:01
    还能在上面画精灵
  • 39:01 - 39:05
    但是注意精灵和窗口的颜色就无法区分了
  • 39:05 - 39:07
    所以说窗口上没有裁剪一类的事情
  • 39:09 - 39:12
    所以内存映射是怎么样的
  • 39:12 - 39:14
    4KB的精灵方块
  • 39:14 - 39:16
    4KB的背景方块
  • 39:16 - 39:19
    1KB的背景映射表
  • 39:19 - 39:21
    32*32
  • 39:21 - 39:23
    1KB的窗口映射表
  • 39:23 - 39:24
    这不是最高效的表示方法
  • 39:24 - 39:27
    但是他们这么做了 因为方便
  • 39:27 - 39:30
    但是我们只有8KB的显存
  • 39:30 - 39:34
    放个精灵方块和背景方块 就用完了
  • 39:35 - 39:36
    换种方法
  • 39:36 - 39:40
    先放上精灵方块 然后在最后放上背景和窗口映射
  • 39:40 - 39:41
    背景方块怎么办
  • 39:41 - 39:43
    就让它们重合
  • 39:44 - 39:47
    有不同的配置 3个位
  • 39:47 - 39:48
    可以让它们完全重合
  • 39:48 - 39:49
    也可以只重合一部分
  • 39:50 - 39:52
    这些也可以交换或者重合
  • 39:53 - 39:55
    重合表示什么意思
  • 39:55 - 40:01
    这个情况就是精灵方块和背景方块完全重合
  • 40:01 - 40:03
    可以共享完全相同的方块
  • 40:03 - 40:05
    但是也可以这么放
  • 40:05 - 40:12
    前128个就是精灵专用 后128个就是背景专用
  • 40:12 - 40:15
    中间128个共享
  • 40:15 - 40:16
    比如这个超级马里奥大陆
  • 40:17 - 40:20
    前2/3都用于精灵了
  • 40:20 - 40:22
    剩下的1/3被用于背景
  • 40:24 - 40:27
    下一个部分是横向计时
  • 40:30 - 40:33
    在基于CRT的机器当中
  • 40:33 - 40:38
    这就是CRT显示图像的慢动作效果
  • 40:39 - 40:42
    从头到底 从左到右
  • 40:43 - 40:45
    对于GameBoy也是一样的
  • 40:45 - 40:47
    它以60Hz的速度不停地扫描
  • 40:47 - 40:49
    从上到下 一行一行
  • 40:49 - 40:50
    从左到右
  • 40:50 - 40:52
    这不是因为使用了一些旧的器件
  • 40:53 - 40:57
    他们完全重新实现了这一部分的内容
  • 40:57 - 41:00
    但是液晶本身就需要以60Hz的速度刷新
  • 41:00 - 41:01
    所以就这样了
  • 41:01 - 41:06
    如果要实现一些特效的话是很重要的
  • 41:06 - 41:07
    比如这个游戏中
  • 41:07 - 41:10
    屏幕不同的区域行为是不一样的
  • 41:10 - 41:14
    比如我们先只看这个滚动的城市图
  • 41:14 - 41:19
    直接全屏滚动肯定是不成问题的
  • 41:19 - 41:20
    但是我们只想让它在屏幕上的一部分滚动
  • 41:21 - 41:23
    就可以通过这些额外的寄存器完成
  • 41:23 - 41:28
    如果你之前接触过8位机的编程 比如C64什么的 那么应该会理解
  • 41:29 - 41:31
    你可以知道当前正在画哪一行
  • 41:31 - 41:34
    或者马上会画哪一行
  • 41:34 - 41:37
    除了一直等着 还可以设定一个中断
  • 41:38 - 41:40
    一旦到达某一行就会执行特定代码
  • 41:40 - 41:44
    我们先把SCX寄存器设定到0
  • 41:44 - 41:46
    然后在第8行触发
  • 41:46 - 41:48
    所以它就会以卷动为0的参数显示出这些
  • 41:48 - 41:57
    然后现在我把横向滚动 设置成比如23 然后下一帧设置成24 这样就能滚动了
  • 41:58 - 42:03
    把对比寄存器设置到42 就会一直继续绘图到42行
  • 42:03 - 42:10
    设置成其它的 再修改LYC 画完这个路面 一会具体讲路面的事情
  • 42:11 - 42:14
    最后再设置回0 因为仪表盘不需要卷动
  • 42:14 - 42:17
    下一帧也是同样这么处理
  • 42:17 - 42:23
    这个例子中就不需要修改X卷动寄存器了
  • 42:23 - 42:27
    这个例子中 右上角的马里奥其实是一个窗口
  • 42:28 - 42:33
    我们在之前讲过 窗口会从左到右从上到下绘图
  • 42:33 - 42:36
    本身并不能这样只停在右上角
  • 42:36 - 42:37
    但是可以做到
  • 42:37 - 42:40
    在第0行触发中断 启用窗口
  • 42:40 - 42:42
    在第40行的时候再触发中断 关闭窗口
  • 42:43 - 42:49
    于是在40行的时候 PPU的情况就是:“窗口?啥子窗口?没听过这个说法”
  • 42:49 - 42:51
    于是就不会继续画
  • 42:51 - 42:53
    这个方法在不同的游戏中都有应用
  • 42:54 - 42:58
    一些是关于窗口,一些则是和卷动有关
  • 42:59 - 43:02
    但是如果你不是在一个特定行触发
  • 43:03 - 43:05
    而是每一行都触发的话 就能实现一些比如这样的效果
  • 43:05 - 43:07
    左边是屏幕上的效果
  • 43:07 - 43:11
    右边是实际上存储在显存中的数据
  • 43:12 - 43:14
    如果你在每一行都改变卷动寄存器
  • 43:15 - 43:17
    比如按照这个曲线调整
  • 43:17 - 43:19
    那么就能实现对图像的变形
  • 43:19 - 43:21
    然后每一帧都改变这个曲线
  • 43:21 - 43:29
    程序要做的就是 在每一行都向SCX写入一个值
  • 43:29 - 43:33
    当然如果图片每行都显示那就每行都得修改
  • 43:33 - 43:38
    而这个赛车游戏的效果其实差不多也是一样的道理
  • 43:38 - 43:39
    这是视频内存中的情况
  • 43:40 - 43:41
    只是一条直的路
  • 43:41 - 43:45
    但是在绘图的时候被扭曲
  • 43:45 - 43:46
    放大这块
  • 43:46 - 43:48
    这是原始数据 这是效果
  • 43:49 - 43:51
    忽略这里的精灵
  • 43:51 - 43:54
    这是为了扭曲需要的曲线
  • 43:54 - 43:57
    这是需要的偏移 也就是SCX
  • 43:57 - 44:01
    如果你每行都调整SCX 就能扭曲成这样
  • 44:01 - 44:03
    另外一件事情就是
  • 44:03 - 44:08
    路中间的线变成了虚线 路外部也有一些横线的图案
  • 44:08 - 44:12
    这是通过每几行就调整调色板来实现的
  • 44:14 - 44:19
    如果看这个游戏的话 甚至可以实现弹跳的效果
  • 44:19 - 44:24
    这是通过在每行同时调整纵向和横向卷动寄存器实现的
  • 44:24 - 44:28
    所以就可以重复一行的内容或者跳过某些行
  • 44:28 - 44:31
    只要计算好 就可以实现这种效果
  • 44:31 - 44:36
    只要在行中修改垂直卷动寄存器
  • 44:36 - 44:39
    就能实现二维的扭曲效果
  • 44:39 - 44:44
    但是我们还得再仔细讲一讲 横向计时
  • 44:47 - 44:49
    在一行绘制的时候 发生了什么
  • 44:50 - 44:53
    这是PPU的像素传输模式
  • 44:53 - 44:55
    通常需要43个时钟的时间
  • 44:55 - 44:58
    一共144行
  • 44:58 - 45:01
    但是你不能直接认为
  • 45:01 - 45:05
    在第一行结束后 它会立即绘制下一行的第一个像素
  • 45:05 - 45:07
    现实不是这样的
  • 45:07 - 45:11
    因为在每一行的开始还有一个OAM搜索阶段 需要20时钟
  • 45:11 - 45:12
    我一会讲
  • 45:12 - 45:16
    每行的结尾还有一个51时钟的行消隐
  • 45:17 - 45:20
    在行消隐阶段,PPU就闲着,什么事情都不做。
  • 45:20 - 45:24
    还有一个场消隐阶段 就是在帧之间的空闲
  • 45:24 - 45:25
    来计算一下
  • 45:26 - 45:29
    一行有114时钟 频率是1MHz
  • 45:29 - 45:33
    154行 所以需要这么多个时钟周期完成1帧
  • 45:33 - 45:35
    如果以用基准频率除以这个
  • 45:35 - 45:38
    得到的就是59.7Hz的刷新率
  • 45:41 - 45:45
    PPU当前所在的状态是可以直接读出的
  • 45:45 - 45:49
    CPU可以知道 而且也可以基于这个设定中断
  • 45:49 - 45:52
    但是CPU为什么需要知道呢
  • 45:52 - 45:55
    我们来看看不同模式下都发生了什么
  • 45:55 - 45:59
    首先 每行开始20周期的OAM搜索是做什么的
  • 45:59 - 46:04
    每一行 PPU都需要确定这一行中哪些精灵是可见的
  • 46:04 - 46:06
    所以系统内一共有40个精灵
  • 46:07 - 46:12
    然后它得找出 这一行中可见的精灵
  • 46:13 - 46:16
    然后放进一个最多可以保存10个精灵的 可见精灵数组
  • 46:17 - 46:21
    逻辑是 x坐标不能为0 因为那样就不可见了
  • 46:21 - 46:27
    然后当前所绘制的行必须要在精灵的第一行和最后一行之间
  • 46:27 - 46:29
    符合要求就加入可见精灵数组
  • 46:30 - 46:32
    然后这需要20周期的时间
  • 46:32 - 46:36
    顺便在原版的GameBoy中这里有个有趣的bug
  • 46:36 - 46:44
    如果你在OAM搜索期间 进行了任何数字在FE00到FEFF之间的16位运算
  • 46:44 - 46:46
    也就是到OAM内存的指针
  • 46:46 - 46:47
    即使你没有访问内存
  • 46:48 - 46:52
    他也会破坏这一块的内存
  • 46:56 - 46:59
    还有什么需要注意的
  • 47:00 - 47:02
    CPU连接到内存
  • 47:02 - 47:04
    PPU连接到显存
  • 47:04 - 47:08
    OAM内存是特殊的 PPU也直接连接到OAM内存
  • 47:08 - 47:12
    CPU也可以连接到显存 这样就能写入到显存
  • 47:12 - 47:14
    但是并不是这样完成的
  • 47:14 - 47:16
    那样需要双倍速的显存
  • 47:16 - 47:20
    你看C64是那样做的 但是在GameBoy上就必须经过PPU
  • 47:21 - 47:23
    PPU内部有个开关 PPU可以决定CPU能不能访问
  • 47:23 - 47:25
    如果PPU不让CPU访问
  • 47:25 - 47:28
    那么CPU进行写入 什么都不会发生
  • 47:28 - 47:29
    CPU进行读取 读到的全部是FF
  • 47:29 - 47:31
    至少不会发生什么严重的问题
  • 47:31 - 47:32
    但是也没有什么意义
  • 47:32 - 47:37
    所以说CPU必须确保PPU在合适的模式下 这样才能顺利访问
  • 47:38 - 47:42
    在像素传输阶段 不能访问显存
  • 47:42 - 47:48
    但是在OAM搜索 行消隐和场消隐阶段都是可以访问的
  • 47:48 - 47:50
    如果你想要访问OAM内存
  • 47:51 - 47:54
    OAM搜索或者像素传输都不可以
  • 47:54 - 47:57
    像素传输时PPU要绘图 需要精灵数据
  • 47:57 - 48:00
    只能在这些时候才能访问
  • 48:00 - 48:03
    所以在屏幕绘图时就得十分小心
  • 48:04 - 48:07
    所以这些时间对于CPU来说都是不好的
  • 48:07 - 48:09
    不应该做任何重要的事情
  • 48:09 - 48:12
    比如说CPU想要把新的一行移动进背景映射
  • 48:12 - 48:14
    最好是在场消隐阶段完成
  • 48:14 - 48:16
    有最多的不被打断的时间
  • 48:17 - 48:21
    而所有的游戏逻辑和AI可以在屏幕绘图的时候完成
  • 48:21 - 48:27
    但是这个时候不能立即写入新的精灵位置
  • 48:27 - 48:28
    因为OAM也是不能访问的
  • 48:29 - 48:31
    所以游戏一般的做法都是
  • 48:31 - 48:36
    把新的精灵信息全部写入一个OAM内存的副本
  • 48:36 - 48:40
    然后在场消隐阶段复制进OAM
  • 48:40 - 48:44
    就是从任何这里其中一个 存放OAM副本的地方
  • 48:44 - 48:47
    复制进OAM 这个图不是按比例画的
  • 48:49 - 48:51
    而且这个过程不需要自己完成
  • 48:51 - 48:53
    有一个DMA功能
  • 48:53 - 48:56
    写入想要复制的块
  • 48:56 - 48:59
    然后等待160个时钟
  • 48:59 - 49:03
    在复制的过程中 CPU还是在运行的
  • 49:03 - 49:07
    但是不能访问任何的源地址空间
  • 49:07 - 49:08
    所以只能等着
  • 49:08 - 49:11
    但是因为这个代码也得有地方存放
  • 49:11 - 49:14
    所以可能的地方只有是HRAM
  • 49:14 - 49:16
    也算是个不错的用途
  • 49:17 - 49:19
    然后是像素流水线
  • 49:19 - 49:22
    我们继续深入来研究像素流水线
  • 49:22 - 49:29
    这个还算是非常新的研究 之前是没有公开的
  • 49:29 - 49:35
    像素FIFO(先入先出缓存)是GameBoy绘图的核心概念
  • 49:36 - 49:37
    我们直接跳到中间过程
  • 49:37 - 49:39
    屏幕上已经有一些像素了
  • 49:39 - 49:42
    比如这5个像素已经被送给LCD了
  • 49:43 - 49:45
    然后像素FIFO 里面有一些像素
  • 49:46 - 49:50
    然后每一个4MHz的步骤 它都会移出一个像素
  • 49:50 - 49:51
    送给LCD
  • 49:52 - 49:54
    移出一个像素 送给LCD
  • 49:54 - 49:56
    然后再移出下一个给LCD
  • 49:56 - 49:59
    你可能注意到那个绿色的指示灯变成红色了
  • 50:00 - 50:04
    因为像素FIFO必须要有至少8个像素才能移出像素
  • 50:04 - 50:06
    为什么 一会会讲到
  • 50:06 - 50:09
    现在需要产生新的数据来填充FIFO了
  • 50:10 - 50:13
    Fetch(获取)单元就是做这个的
  • 50:13 - 50:15
    它会读取背景方块单元
  • 50:15 - 50:19
    9802是目前在读取的映射位置
  • 50:19 - 50:22
    它从背景映射中读取方块的ID 需要1个周期
  • 50:22 - 50:28
    然后从方块数据内存 读取第一部分和第二部分的数据
  • 50:28 - 50:32
    因为每一行的方块是16位
  • 50:32 - 50:35
    这样它就能产生8个新的像素
  • 50:35 - 50:39
    然后就重新开始 进入下一个位置
  • 50:39 - 50:43
    就可以把这8个像素移入FIFO的上半部分
  • 50:43 - 50:46
    这样就可以继续移出新的像素
  • 50:46 - 50:48
    然而在执行过程中
  • 50:48 - 50:51
    并不是说等待有空了 然后开始Fetch填充 移出再这样
  • 50:51 - 50:54
    并不是交替进行的 而是同时进行的
  • 50:56 - 50:58
    FIFO是2倍速的
  • 50:58 - 51:02
    所以Fetch进行1个步骤 FIFO移出两个像素
  • 51:02 - 51:07
    移出 移出 读取第一字节的数据
  • 51:07 - 51:11
    移出 移出 读取第二字节的数据
  • 51:11 - 51:12
    然后到这个时候
  • 51:13 - 51:16
    现在还不能把数据存入FIFO
  • 51:16 - 51:18
    因为FIFO还放不下
  • 51:18 - 51:20
    所以Fetch先关闭
  • 51:20 - 51:22
    等待2个周期
  • 51:23 - 51:25
    也就是空闲一段时间
  • 51:25 - 51:27
    然后放入数据
  • 51:27 - 51:29
    所以如果你看内存访问的模式
  • 51:29 - 51:33
    就能看见3次读取 1次空闲 3次读取 1次空闲这样
  • 51:35 - 51:39
    所以 FIFO就是4MHz时钟下 每个周期移出一个像素
  • 51:39 - 51:41
    除非含有超过8个像素 否则暂停
  • 51:41 - 51:43
    Fetch单元 运行频率是2MHz
  • 51:43 - 51:45
    需要3个周期来获取8个像素
  • 51:45 - 51:48
    然后在第四周期停住 直到FIFO有空位
  • 51:49 - 51:51
    横向移动的实现方法非常简单
  • 51:51 - 51:53
    比如说我们移动3个像素
  • 51:53 - 51:55
    所以所有东西都向左移动了3个像素
  • 51:55 - 51:57
    最先的3个像素就直接无视掉了
  • 51:58 - 52:00
    然后下一个像素送往LCD
  • 52:00 - 52:02
    而在行的最后
  • 52:02 - 52:03
    事情变得有趣了
  • 52:03 - 52:06
    因为我们想在X=160的时候触发
  • 52:06 - 52:09
    FIFO可能还包含一些根本不会被画出来的像素
  • 52:09 - 52:14
    然后Fetch可能也已经在获取下8个像素的内容了 也不要了
  • 52:14 - 52:17
    然后就全部停止
  • 52:17 - 52:19
    就是干了太多活了 直接进入行消隐
  • 52:19 - 52:25
    这也是一行需要43周期 而不是40周期的原因
  • 52:27 - 52:28
    如果我们开启了窗口
  • 52:28 - 52:31
    比如说窗口坐标是26
  • 52:31 - 52:34
    我们现在就在26 然后FIFO已经缓存了一些像素了
  • 52:35 - 52:37
    它会完全清空FIFO
  • 52:37 - 52:38
    然后FIFO会被停止
  • 52:38 - 52:40
    因为这些像素已经不需要了
  • 52:41 - 52:45
    然后Fetch会被转到窗口映射
  • 52:45 - 52:47
    然后Fetch被重新开始
  • 52:47 - 52:50
    然后还是一样 读ID 读两个字节
  • 52:50 - 52:51
    就得到了窗口的数据
  • 52:52 - 52:53
    然后就可以放入像素FIFO
  • 52:53 - 52:57
    只要这些开始被移出了 窗口就绘制出来了
  • 52:57 - 53:00
    而精灵则是有10个比较器
  • 53:00 - 53:02
    也是根据X位置触发
  • 53:02 - 53:05
    比如说在这里X=26有一个精灵
  • 53:05 - 53:10
    一样 像素FIFO里面有很多像素 然后Fetch执行到一半
  • 53:10 - 53:13
    首先我们暂时暂停像素FIFO
  • 53:13 - 53:14
    就不能继续移出新的像素
  • 53:15 - 53:18
    然后暂时调整Fetch让它产生精灵数据
  • 53:18 - 53:21
    重新开始Fetch
  • 53:21 - 53:22
    然后就得到了精灵数据
  • 53:22 - 53:25
    然而这次不是放到最后
  • 53:25 - 53:27
    而是和前8个像素叠加
  • 53:27 - 53:29
    混合到已有的像素上
  • 53:29 - 53:32
    这也就解释了为什么FIFO中必须要有至少8个像素
  • 53:32 - 53:35
    因为精灵是用这种方法来混合的
  • 53:37 - 53:41
    然后和其它的系统有一个区别
  • 53:42 - 53:44
    在窗口开始前 都以恒定速度移出像素
  • 53:44 - 53:46
    当窗口开始的时候
  • 53:46 - 53:51
    FIFO被清空 很长一段时间都不能输出数据
  • 53:52 - 53:54
    直到FIFO内有了窗口数据
  • 53:54 - 53:57
    也就是等到恢复了
  • 53:58 - 54:00
    也就是需要至少43个周期
  • 54:00 - 54:04
    如果有精灵就需要更多
  • 54:04 - 54:06
    在基于液晶的系统上这么做是完全可行的
  • 54:06 - 54:08
    你可以暂停发送像素
  • 54:08 - 54:10
    而在基于CRT的系统上 不行
  • 54:10 - 54:12
    比如说在C64上
  • 54:12 - 54:14
    一行必须是正好的40时钟
  • 54:14 - 54:19
    因为任何晚出来的像素看起来都会被右移
  • 54:21 - 54:23
    所以这个图并不是完全准确
  • 54:24 - 54:27
    像素传输应该是至少43时钟
  • 54:27 - 54:30
    行消隐则是剩下的时间
  • 54:31 - 54:35
    然后实际过程中 取决于屏幕上的内容 更接近于这样
  • 54:37 - 54:41
    但是之前这个并不是像素FIFO真正的工作方式
  • 54:41 - 54:43
    它并不存储像素颜色
  • 54:43 - 54:49
    它存储的是原始的位组合
  • 54:49 - 54:50
    以及来源
  • 54:50 - 54:53
    比如说这里是9个背景像素
  • 54:54 - 54:55
    Fetch也是一样的
  • 54:55 - 54:57
    它并不产生像素颜色
  • 54:57 - 55:00
    它产生的是位组合
  • 55:00 - 55:05
    加上来源或者精灵调色板
  • 55:05 - 55:07
    我们来把这个混合一下
  • 55:08 - 55:10
    精灵的00表示在背景之上绘图
  • 55:11 - 55:12
    来过一遍
  • 55:13 - 55:17
    这里是精灵调色板1 数据00 表明是透明的 背景获胜
  • 55:17 - 55:20
    这个情况下精灵获胜 因为应该画在背景之上
  • 55:20 - 55:23
    大部分像素都是这个情况
  • 55:23 - 55:30
    而最后这个像素 是精灵调色板1 数据透明 所以背景获胜
  • 55:31 - 55:34
    再来和同一坐标下另外一个精灵混合一下
  • 55:37 - 55:42
    这里是精灵调色板0 在背景之上 精灵获胜
  • 55:42 - 55:46
    然后这个情况下 新的精灵不会覆盖旧的
  • 55:46 - 55:50
    所以旧的获胜 然后就一直这样
  • 55:50 - 55:53
    这也就是精灵会画在右边精灵的上面
  • 55:53 - 55:55
    但是不会画在已有精灵之上
  • 55:55 - 55:58
    高ID精灵输给低ID精灵的原因
  • 55:58 - 56:00
    最后这里新的精灵又获胜了
  • 56:01 - 56:04
    然后应用上调色板
  • 56:04 - 56:06
    只有在最后像素被移出的时候才进行
  • 56:06 - 56:09
    这里对应调色板 移出一个像素到液晶
  • 56:09 - 56:14
    查表 转换 LCD
  • 56:14 - 56:17
    另外一个 黑色
  • 56:18 - 56:22
    这也是在彩色机型上的做法
  • 56:22 - 56:24
    从SGB开始
  • 56:24 - 56:27
    现有的游戏不能处理颜色 但是可以上色
  • 56:27 - 56:33
    然后就是 已有的三种调色板现在变成了RGB调色板
  • 56:33 - 56:34
    其它所有的都是一致的
  • 56:36 - 56:39
    但是一旦移出像素
  • 56:39 - 56:42
    它就对应RGB颜色
  • 56:42 - 56:43
    把这个粉色的像素显示在屏幕上
  • 56:44 - 56:46
    S1 11是这里
  • 56:46 - 56:49
    黑色像素
  • 56:49 - 56:54
    再来一个例子 S1 01 精灵调色板1 显示在屏幕上
  • 56:55 - 56:57
    所有技术性内容到此为止
  • 57:09 - 57:10
    还有5分钟的时间
  • 57:12 - 57:13
    来讲讲开发
  • 57:14 - 57:16
    如果你对GameBoy开发感兴趣
  • 57:16 - 57:18
    有一些很不错的开发工具
  • 57:18 - 57:22
    Rednex Game Boy 开发系统是一套命令行工具
  • 57:22 - 57:25
    可以配合自己的编辑器和Makefile使用
  • 57:25 - 57:27
    如果想要Debug
  • 57:27 - 57:30
    BGB模拟器 就很不错
  • 57:30 - 57:35
    为Windows设计 但是配合Wine在OSX和Linux上也没问题
  • 57:36 - 57:39
    内置调试器 断点啊 单步啊 一类的
  • 57:39 - 57:43
    然后还有一个显存查看器 可以查看所有发生的事情
  • 57:43 - 57:47
    很适合在上面运行Demo然后观察发生了什么
  • 57:48 - 57:51
    如果你想要在真机上运行
  • 57:51 - 57:53
    也有像Everdrive一类的设备
  • 57:53 - 57:54
    可以插SD卡
  • 57:56 - 57:59
    因为还有4分钟时间
  • 57:59 - 58:03
    我们来谈谈我最喜欢的GameBoy外设
  • 58:03 - 58:04
    Game Boy Camera
  • 58:04 - 58:06
    但是不是技术层面
  • 58:06 - 58:08
    只是吹一波这个设备
  • 58:08 - 58:09
    这个就是Game Boy Camera
  • 58:09 - 58:12
    你把它插入GameBoy
  • 58:12 - 58:14
    能拍照片
  • 58:14 - 58:15
    然后可以用Game Boy Printer打印出来
  • 58:15 - 58:17
    用的热敏纸
  • 58:17 - 58:19
    如果还买得到的话
  • 58:20 - 58:24
    然后可以拍出像这样的照片
  • 58:24 - 58:26
    放大一点
  • 58:31 - 58:32
    非常棒的照片
  • 58:33 - 58:38
    每张照片 都是用这个14K像素的CCD拍出来的
  • 58:39 - 58:42
    位深2位 (译者注:硬件为3位,抖动为2位以匹配GameBoy屏幕)
  • 58:53 - 58:56
    所以下次去旅游的时候 记得带上GameBoy
  • 59:09 - 59:16
    然后还有Game Boy Camera 加上一台带并口的PC 还有已经买不到的联机线
  • 59:16 - 59:24
    所以感谢这些人 研究GameBoy 以及帮助我准备这场讲座
  • 59:25 - 59:28
    这些人也是以各种途径帮助了我
  • 59:30 - 59:31
    所以
  • 59:40 - 59:44
    在这个系列中 这已经是第五场讲座
  • 59:44 - 59:45
    下一个是什么
  • 59:45 - 59:48
    明年应该有个讲座吧
  • 59:48 - 59:51
    我建议两个讲座
  • 59:51 - 59:54
    我就先给34C3几个提名
  • 59:55 - 59:59
    Dominik Wagner来讲Acorn Archimedes
  • 60:04 - 60:16
    然后Jannis Harder来讲SNES
  • 60:16 - 60:19
    这是你们自己的选择 可以做这些讲座
  • 60:19 - 60:22
    或者也可以在自己头上倒冰水
  • 60:26 - 60:27
    感谢参加 明年见
  • 60:29 - 61:07
    subtitles created by c3subtitles.de
    in the year 2017. Join, and help us!
Title:
The Ultimate Game Boy Talk (33c3)
Description:

more » « less
Video Language:
English
Duration:
01:01:07

Chinese, Simplified subtitles

Revisions