加入收藏 | 设为首页 | 交流中心 | 我要投稿 | RSS
您当前的位置:首页 > 技术中心 > 高谈阔论

为什么魂斗罗只有128KB却可以实现那么长的剧情?

时间:2017-05-07 20:38:14  来源:  作者:

 436快充网络

 

 
关注者
1105
 
被浏览
147937
 

19 个回答

1.游戏大量复用图块,图块还使用调色板索引,好像每个像素才占用2bit。436快充网络
2.程序员精心优化各种数据结构,每一bit存储都不浪费。436快充网络
3.声音只存储发声通道的调制参数序列,能复用就复用。436快充网络
4.代码全是汇编写成,直接操作硬件,基本不存在浪费的指令。436快充网络

个人觉得fc最神奇的游戏还属超级玛丽,32个关卡,每关都不同,各种隐藏要素,好像代码区才10多k,数据区10多k。反汇编看完还是不敢相信这点东西能玩一个童年…现在helloworld的二进制都可能比这大多了。
你如果注意观察,会发现fc游戏背景画面是重复的,只需制作一个贴图块,程序运行时,随着玩家拖动卷轴,机器会调用这些重复图块,是一种实时渲染,这些2d主机游戏的设计理念很先进的。436快充网络
你可以录制一段游戏视频看看容量有多大,这些信息量都产生于玩家玩游戏的过程中,你玩魂斗罗游戏当然觉得很开心。

下文摘录自于春的《电脑游戏机硬件与编程特技》p.267-277,侵删。436快充网络

5.4.4 优化查表法436快充网络

《魂斗罗》游戏已为广大朋友所熟悉、所喜爱。该游戏的编程中有许多优化的方法可供我们学习和借鉴。兹特列两例供参考。436快充网络
①武器选项画面的绘制436快充网络
压缩版的《魂斗罗》游戏开始有一个武器选项画面(见图5-9)。在该画面,游戏者可通过选择键(SELECT)在四种武器中任选其一。该画面的绘制程序见 No.5-25。436快充网络
436快充网络
No.5-25《魂斗罗》武器选项画面的绘制程序436快充网络
F80D  A94E      LDA #$4E F80F  8500      STA $00 F811  A9F8      LDA #$F8 F813  8501      STA $01           ;置绘图数据区首址于 $00、$01 单元 F815  A000      LDY #$00 F817  B100      LDA ($00),Y F819  8D0620    STA $2006         ;置 PPU 地址高位 F81C  C8        INY F81D  B100      LDA ($00),Y F81F  8D0620    STA $2006         ;置 PPU 地址低位 F822  C8        INY F823  B100      LDA ($00),Y F825  AA        TAX F826  3011      BMI $F839         ;判断送数指南,若大于 H7F 则 F828  C8        INY               ;转 $F839 F829  B100      LDA ($00),Y       ;送数指南小于 H80 的送数处理, F82B  8D0720    STA $2007         ;将其后的 N 个数送入 PPU。 F82E  CA        DEX F82F  D0F7      BNE $F828 F831  C8        INY F832  B100      LDA ($00),Y F834  C980      CMP #$80 F836  D0DF      BNE $F817         ;不是 H80 则改变 PPU 地址,继续送数 F838  60        RTS               ;如是 H80 则结束送数 F839  8A        TXA F83A  297F      AND #$7F F83C  AA        TAX               ;以该数的 D6~D0 位为计数器,将其后 F83D  C8        INY               ;的一数连送 N 次。 F83E  B100      LDA ($00),Y F840  8D0720    STA $2007 F843  CA        DEX F844  D0FA      BNE $F840 F846  F0E9      BEQ $F831 
数据区如下:436快充网络
F84E                                            3F 00                                                 PPU 配 F850  08 0F 20 20 20 0F 27 27 27 3F 10 04 0F 05 0F 17       色,送 $3F00~$3F07。       送 PPU $3F10~$3F13 F860  23 d0 88 50 20 E4 17 20 20 20 20 20 20 20 20 20       背景零页配色,$23D0~$23D7 F870  20 20 20 20 20 20 20 20 20 20 20 20 20 20 21 2A F880  0B 47 41 4D 45 00 53 45 4C 45 43 54 21 66 93 3F          G  A  M  E     S  E  L  E  C  T F890  21 AA 0B 41 40 00 43 4F 4E 54 52 41 00 31 21 EA                A  .     C  O  N  T  R  A     1 F8A0  0B 42 40 00 43 4F 4E 54 52 41 00 32 22 2A 0B 43          B  .     C  O  N  T  R  A     2           C F8B0  40 00 43 4F 4E 54 52 41 00 33 22 6A 0B 44 40 00       .     C  O  N  T  R  A     3           D  . F8C0  43 4F 4E 54 52 41 00 34 00 00       C  O  N  T  R  A     4 
436快充网络

图 5-9 的数据区仅仅使用了 124 个单元就完成了 PPU 配色、背景页配色和画面显示,虽然四行都是相同的内容(CONTRA),但数据区中已留出了相应的空间,即使送显其它内容,数据区也不会增加。436快充网络
程序 No.5-25 的结构比较简单,读者可自己完成程序的转换,不多赘述。436快充网络

②《魂斗罗》标题画面的绘制436快充网络
我们知道,《魂斗罗》的标题画面是由画写的“CONTRA”和两个主人翁的上身组成的。画面既简单又富有力的感召,是正义和美的有机结合与升华。《魂斗罗》仅凭一幅标题画面就勾起了人们的无限遐思与向往,这怎能不令人钦佩和惊叹呢!现在让我们看看这一标题画面是如何绘制的。436快充网络
标题画面的绘制程序在 $C9CF~$CA60,其数据区在第二体的 $9097~$9251,现抄录如下,见程序 No.5-26436快充网络

N0.5-26《魂斗罗》标题画面绘制程序436快充网络
C9CF  A001      LDY #$01          ;该子程序调用前已向 $00、$01 单元 C9D1  B100      LDA ($00),Y       ;置入数据区首址 $9097 C9D3  8D0620    STA $2006         ;置 PPU 地址高位 C9D6  88        DEY C9D7  B100      LDA ($00),Y C9D9  8D0620    STA $2006         ;置 PPU 地址低位 C9DC  A902      LDA #$02 C9DE  A604      LDX $04 C9E0  1001      BPL $C9E3 C9E2  0A        ASL               ;若 $04>H7F 则 A=4 C9E3  A200      LDX #$00 C9E5  2092C8    JSR $C892         ;调整取数地址。 C9E8  A000      LDY #$00 C9EA  B100      LDA ($00),Y C9EC  C9FF      CMP #$FF          ;若 A==HFF 则结束送数 C9EE  F06B      BEQ $CA5B C9F0  C97F      CMP #$7F          ;若 A==H7F 则改变 PPU 地址 C9F2  F05D      BEQ $CA51 C9F4  A8        TAY C9F5  1026      BPL $CA1D C9F7  297F      AND #$7F C9F9  8502      STA $02           ;若取数指南小于 H7F 则以 $02 为计数器, C9FB  A001      LDY #$01          ;送后面的 N 个数。 C9FD  B100      LDA ($00),Y C9FF  A604      LDX $04 CA01  1003      BPL $CA06 CA03  2036CA    JSR $CA36         ;若 $04>H7F 则延时送数 CA06  8D0720    STA $2007 CA09  C402      CPY $02 CA0B  F003      BEQ $CA10         ;送到送数数量则转 $CA10 调整地址 CA0D  C8        INY CA0E  D0ED      BNE $C9FD         ;未达到送数数量则转 $C9FD 继续送数 CA10  A901      LDA #$01 CA12  18        CLC CA13  6502      ADC $02 CA15  A200      LDX #$00 CA17  2092C8    JSR $C892         ;调整取数地址 CA1A  4CE8C9    JMP $C9E8 CA1D  A001      LDY #$01          ;当取数指南 >H7F 时,把后面的一个数据 CA1F  8502      STA $02           ;连送 N 次的处理。 CA21  B100      LDA ($00),Y CA23  A402      LDY $02 CA25  A604      LDX $04 CA27  1003      BPL $CA2C CA29  2036CA    JSR $CA36 CA2C  8D0720    STA $2007 CA2F  88        DEY CA30  D0FA      BNE $CA2C CA32  A902      LDA #$02 CA34  DODF      BNE $CA15         ;一次送数结束后,调整取数地址 CA36  8503      STA $03           ;以下是延时子程序 CA38  0603      ASL $03 CA3A  6A        ROR CA3B  0603      ASL $03 CA3D  6A        ROR CA3E  0603      ASL $03 CA40  6A        ROR CA41  0603      ASL $03 CA43  6A        ROR CA44  0603      ASL $03 CA46  6A        ROR CA47  0603      ASL $03 CA49  6A        ROR CA4A  0603      ASL $03 CA4C  6A        ROR CA4D  0603      ASL $03 CA4F  6A        ROR CA50  60        RTS CA51  A901      LDA #$01 CA53  A200      LDX #$00 CA55  2092C8    JSR $C892         ;调整取数地址 CA58  4CCFC9    JMP $C9CF CA5B  60        RTS               ;结束送数 
调整取数地址子程序436快充网络
C892  18        CLC C893  7500      ADC $00,X C895  9500      STA $00,X C897  9002      BCC $C89B C899  F601      INC $01,X C89B  60        RTS 
绘图数据
9097                       00 20 4B 00 8B 00 00 00 00                            PPU $2000 先送 H4B 个 00、又送 H0B 个 00 90A0  00 00 00 00 00 00 00 14 00 8C 00 00 00 00 00 00                            送 H14 个 00,送 H0C 个 00(下同,不再注释) 90B0  00 00 00 00 00 00 14 00 82 00 00 3A 00 86 02 03 90C0  04 05 06 07 19 00 89 11 12 13 14 15 16 17 18 19 90D0  16 00 8A 20 21 22 23 24 25 26 27 28 29 16 00 83 90E0  60 61 62 04 00 82 08 09 17 00 96 70 71 72 00 00 90F0  63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 0A 0B 0C 9100  0D 0A 00 97 80 81 82 00 00 73 74 75 76 77 78 79 9110  7A 7B 7C 7D 7E 7F 1A 1B 1C 1D 1E 09 00 98 90 91 9120  92 00 00 83 84 85 86 87 88 89 8A 00 8C 8D 8E 8F 9130  2A 2B 2C 2D 2E 2F 08 00 98 A0 A1 A2 A3 00 93 94 9140  95 96 97 98 99 9A 00 9C 9D 9E 9F 3A 3B 3C 3D 3E 9150  3F 09 00 8B B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB 17 9160  00 86 A4 A5 A6 A7 A8 A9 27 00 85 C4 00 D0 D1 D2 9170  1A 00 87 D3 D4 D5 E0 E1 E2 E3 0B 00 8B 50 4C 41                                              P  L  A 9180  59 00 53 45 4C 45 43 54 04 00 85 E4 E5 F0 F1 F2       Y     S  E  L  E  C  T 9190  1A 00 88 F3 F4 F5 C5 C6 C7 C8 C9 0C 00 88 31 00 91A0  50 4C 41 59 45 52 03 00 85 CA CB CC CD CE 03 00       P  L  A  Y  E  R 91B0  82 EF D6 15 00 86 D9 DA DB DC DD DE 04 00 81 E6 91C0  0B 00 90 32 00 50 4C 41 59 45 52 53 00 E9 EA EB                2     P  L  A  Y  E  R  S 91D0  EC ED EE 01 00 81 F6 17 00 84 D7 D8 E7 E8 13 00 91EO  8D 00 00 00 00 00 00 00 00 00 00 00 00 00 0E 00 91F0  97 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9200  00 00 00 00 00 00 00 00 10 00 8B 00 00 00 00 00 9210  00 00 00 00 00 00 0E 00 97 00 00 00 00 00 00 00 9220  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (以下为配色数据) 9230  4D 00 83 A0 A0 20 06 00 82 58 52 03 50 83 00 00 9240  20 05 05 05 00 83 CC FF F3 05 00 83 FF FF CC 11 9250  00 FF 

图5-10《魂斗罗》标题画面的图形代码坐标图436快充网络

注——数据区中,凡下面划双线的数据为取数指南【注:输入的时候省略掉了】。436快充网络
程序 No.5-26 使用了 442 个数据完成了标题画面的绘制。实际上单对标题画面而言,数据量还可以压缩。如在清屏以后绘图时,数据区中的 $9097~$90BC 和 $91E0~$922F 这 118 个置零(清屏)的数据可以删除【注:这 118 个 00 其实是厂商 LOGO 显示的数据,被盗版厂商直接置零不显示】,那么数据区将减少到 326 个单元。可见,程序 No.5-26 是较优化的绘图程序。436快充网络
标题画面的图形代码排列见图 5-10。436快充网络

【注:省略一段于春修改的程序代码】436快充网络

5.4.5 间接分段绘图法(《魂斗罗》游戏画面的基本绘制方法)436快充网络

《魂斗罗》中的游戏画面都是采取间接分段绘图法绘制的。这种绘图方法的特点是:整幅画面分散绘制,一般一次中断或隔几次中断绘制一列或一行,横向卷动的画面每次绘一列,纵向滚动的画面每次绘一行;以七页为间接绘图数据缓冲区,由当前中断把绘图数据送入七页,在下一次中断再把七页的数据送入 PPU。这种绘图方法可保证多幅画面连续绘制,产生连绵不绝的效果。如第一关开始时的游戏画面犹如幕布从左向右拉开,而第二关又如幕布由下向上提起。随着游戏的进程,画面一幕幕的位移,使人丝毫感觉不到画面的间断,整关游戏画面好像是一幅长卷图画,左卷右放,尽头方休。下面仅列出源绘图程序并加以简要说明,以供学习、参考。源程序见 No.5-28。436快充网络
程序 No.5-28 共分两段:第一段为 $CB60~$CBC5,完成把 PPU 地址、绘图数据从数据区读出,按照一定的格式送入七页;第二段为 $CC3F~$CC7E,完成把七页的绘图数据送入 PPU,绘制游戏画面。436快充网络

N0.5-28《魂斗罗》游戏画面绘制源程序436快充网络

从数据区取数送入七页子程序436快充网络
CB60  48        PHA               ;保存调该程序时的 A 值, CB61  A902      LDA #$02          ;该值决定绘图的种类 CB63  8503      STA $03 CB65  A901      LDA #$01 CB67  20BDCB    JSR $CBBD         ;令 $700=1、$21=1 CB6A  68        PLA               ;弹出绘图类型数据 CB6B  8502      STA $02 CB6D  0A        ASL CB6E  AA        TAX               ;以绘图类型数据为地址偏移量 CB6F  BD62B2    LDA $B262,X CB72  8500      STA $00 CB74  BD63B2    LDA $B263,X CB77  8501      STA $01           ;读出绘图数据区首址存入 CB79  A621      LDX $21           ;$00、$01 单元 CB7B  A000      LDY #$00 CB7D  B100      LDA ($00),Y       ;读第一个数据 CB7F  C8        INY CB80  C9FF      CMP #$FF CB82  F03F      BEQ $CBC3         ;若 A==HFF 则结束读数 CB84  C9FE      CMP #$FE CB86  F019      BEQ $CBA1         ;若 A==HFE 则令 $700+X==HFF、 CB88  C9FD      CMP #$FD          ;x+1→$21,结束取数 CB8A  F019      BEQ $CBA5         ;若 A=HFD 则令 $700+X=HFF, CB8C  9D0007    STA $0700,X       ;进行第二次送数,把数据送入七页 CB8F  A502      LDA $02 CB91  100B      BPL $CB9E CB93  A503      LDA $03           ;七页的数据格式为: CB95  D005      BNE $CB9C         ;$700 表示送数方式; CB97  9D0007    STA $0700,X       ;$701 表示一组送入 PPU 的数据个数 CB9A  F002      BEQ $CB9E         ;$702 表示送入 PPU 数据的组数 CB9C  C603      DEC $03           ;$703 表示 PPU 地址高位 CB9E  E8        INX               ;$704 表示 PPU 地址低位 CB9F  D0DC      BNE $CB7D         ;$705……为绘图数据 CBA1  A9FF      LDA #$FF          ;当一次送多组数据时,每一组数据 CBA3  D01A      BNE $CBBF         ;传送完毕后的下两个数据,即为下一组 CBA5  A9FF      LDA #$FF          ;绘图数据的 PPU 地址。 CBA7  20BFCB    JSR $CBBF CBAA  A902      LDA #$02 CBAC  8503      STA $03 CBAE  A901      LDA #$01 CBB0  20BFCB    JSR $CBBF CBB3  D0C8      BNE $CB7D CBB5  A9FF      LDA #$FF CBB7  D004      BNE $CBBD CBB9  A900      LDA #$00 CBBB  F000      BEQ $CBBD CBBD  A621      LDX $21 CBBF  9D0007    STA $0700,X CBC2  E8        INX CBC3  8621      STX $21 CBC5  60        RTS 
取七页数据送入 PPU 子程序436快充网络
CC3F  A200     LDX #$00 CC41  A5FF     LDA $FF CC43  2918     AND #$18 CC45  8502     STA $02 CC47  BC0007   LDY $0700,X CC4A  F0D0     BEQ $CC1C          ;$700==0 不送数 CC4C  A502     LDA $02 CC4E  19C5CB   ORA $CBC5,Y CC51  8D0020   STA $2000          ;设置送数方式 CC54  E8       INX CC55  BD0007   LDA $0700,X CC58  8500     STA $00            ;以 $00 为一组送数的个数计数器 CC5A  E8       INX CC5B  BD0007   LDA $0700,X CC5E  8501     STA $01            ;以 $01 为本次送数的组数计数器 CC60  A400     LDY $00 CC62  E8       INX CC63  BD0007   LDA $0700,X CC66  8D0620   STA $2006          ;置 PPU 地址高位 CC69  E8       INX CC6A  BD0007   LDA $0700,X CC6D  8D0620   STA $2006          ;置 PPU 地址低位 CC70  E8       INX CC71  BD0007   LDA $0700,X CC74  8D0720   STA $2007          ;取数送入 PPU CC77  88       DEY CC78  D0F6     BNE $CC70          ;若本组未送完则转 $CC70 继续 CC7A  C601     DEC $01            ;若本组已送完则令组数计数器减一 CC7C  D0E2     BNE $CC60          ;若还有数据组则转 $CC60 继续送数 CC7E  60       RTS                ;若数据组计数器为零则结束送数 
程序 No.5-28 通俗易懂,留给读者练习编写用于电脑游戏机的实用程序。

我做过电视游戏,虽然不知道魂斗罗为什么那么小,估计原理都是相同的。436快充网络
1 代码,用汇编写,不会先用很多东西的,而且电视游戏机的编译器会把一些const属性的东西放到norflash中,不用放ram,实际游戏机里面的ram更小436快充网络
2 游戏的rom大头是图片和声音。电视的游戏的图片都是由小图片叠加出来的,而且以前的crt对于颜色的分辨率不高,小图片很多都是单一颜色,这种小图片存储的时候占的空间很小,比如一个8*8的黑色方块,好像数据里面存的是很小,用几个bit存大小和图片属性,然后存个颜色值就行了,游戏就是靠把这些小图片拼接成一个大图片,利用几个图层叠加就是游戏的画面。436快充网络
3 声音,声音数据存的都是midi 占空间很小的。436快充网络

实际上游戏rom小,很大程度是靠游戏芯片对于图片和声音的处理换来的,当时维护的游戏芯片,也是号称三核。一个逻辑CPU 一个处理图片输出,一个处理声音输出

1998年上下接触“学习机(游戏机)”,小霸王学习机上还有Q-BASIC,F-BASIC,买机器时说明书上有比较详细的教程和实例,那时还在能上面写些小程序。后来在一个书店里看到passcal,有很多游戏实例代码,后来做的职业与这些无关,就没再深入了。436快充网络

亲自经历过从大规模集成电器到cob掩膜集成电路的卡带时代。那时的学习机CPU估计只有几十MHz吧,比较贵的游戏卡容量才几百K到2M不到。后者已经是天价的游戏卡了。436快充网络

2009年网上看到一代4K大小的明文汇编代码,实现了3D动画,还配有声音,有兴趣的可以试试,把代码存为a.txt,在cmd下运行debug < a.txt436快充网络
代码详见:97年Mekka 4K汇编3D作品436快充网络

2010年无聊时找了当年玩的游戏,这个算比较大的了,共有十关左右,每关都非常长,画质很好,故事情节不重复,画面每关里有少量重复,场景和变化真的让我无比惊叹,到现在也是,我想以后可能不会遇到有如此好的程序了。见图:436快充网络
436快充网络
想想早期的诺基亚QD手机,16M RAM可以运行10多M左右的皇拳97,早期的QQ2007,飞信,UC浏览器,视频播放器这些程序才几百KB,后来升级到1M多些,现在安桌上动不动就是几十M,电脑版的QQ装完都差不多几百M了,不得不说硬件逼着人精进编程技术!现在的硬件太便宜,各种游戏动耴上G,完全感受不到以前那种精益求精的味道。由此延生出来的驱动,在Linux下一个驱动小则几K,大的几M,超过10M的驱动是比较少的,但在windows下一个显卡驱动可以超过300M甚至更大,真不懂设计者的用意,是编程水平低下还是另有意图?
时之笛和马64的容量小更的让人害怕,总觉得光bgm加起来都不止那么点。。
只有我想起了当年用诺基亚2610的时候一个99kb的游戏能玩一个星期吗,而且画质什么的并不输FC……

从前,写程序是一项神圣的工作,程序员上知设计模式,下懂电路原理。436快充网络

后来随着生产力发展,码农阶层出现,写程序沦为烂大街的技能,程序质量不可同日而语。
虽然不是业内人士,但也玩了近20年,算是可以叨叨两句。436快充网络
个人认为其实是因为游戏的高难度造成所谓的“流程长”的假象。436快充网络
其实魂斗罗的剧情并不长,每个关卡有一个自己的背景,主线就是消灭外星心脏拯救地球,比起现在很多动作游戏来说,或者就拿《阿卡姆》系列来说,光是一条支线就要比这个剧情线要长了。436快充网络
而当时游戏的开发周期也并不比现在的游戏开发周期短,所以当时普遍的思路就是增加游戏难度以增加玩家在游戏中的游戏时间从而延长游戏的寿命。所以从玩家的角度来看这款游戏就显得好漫长。436快充网络
关于技术方面的别的答主都回答的很详尽了,就不赘言了。436快充网络
同理《超期马里奥》的流程原则上比魂斗罗初代还要长,3代同样也只有128k。436快充网络
不过随着技术发展,而且运行游戏的媒介也在发展(卡带-光盘-互联网)可以装载的内容也越来越多,但玩家群的游戏时间随着生活节奏的变快也在减少,所以降低游戏难度是一个必然的过程。现如今的大部分游戏的流程大约都在8小时左右(虽然有很多号称可以晚上几十上百小时的游戏,但实际上大部分都是世界探索和刷刷刷的成分,实际上比较充实的内容还是8小时左右)。但也不是没有例如《血缘》《黑魂》这种剑走偏锋的游戏,但比起魂斗罗来说还是要简单了,《魂系列》你打不过去可以刷刷等级,总会能过去,但是魂斗罗你技术不够,是根本过不去的...
你可以去玩玩kkrieger
128k的rar解压出来的小说够看上一整天的,游戏能玩个三十分钟也不奇怪了
说一个我知道的技巧,两张图通过一个颜色算法放到一张图里,要不同的图就用不同的颜色异或。我也不懂这叫什么,请懂的补充。
128K已经是相当大的容量了,而且使用的是低级语言更有体积优势。对于图形游戏而言,剧情脚本其实占用空间很小的,占用空间的大部分是图像、音频等多媒体资源,魂斗罗在图形音频方面的表现是正常的。
640K足够了,是盖茨说的,当时的指挥官64系统还是什么系统确实有这个压缩能力的,美国最早出的是阿塔里电视游戏机系统,和PC那样随意开发,他崩溃才轮到任天堂日本控制游戏平台制度的兴起
以前有一种64K的动画,很长,还有较壮观的立体动画,还有声音。我估计进行了压缩,并调用了大量系统里的内容。虽然文件小,但运行起来很占内存。
为什么无人深空才几个G就有永远探索不完的宇宙?
因为剧情不占什么时间, 俄罗斯方块剧情也很长
现在一张图片几mb 时代不一样了以前没那么大的内存
更多是资源复用解决问题
来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
推荐资讯
相关文章
    无相关信息
栏目更新
栏目热门