百科问答小站 logo
百科问答小站 font logo



为何FC魂斗罗S枪长时间发射后子弹会变的稀疏不成扇形,停止发射一秒后再开始发射就又可以以扇形状态发射? 第1页

  

user avatar   pig_10 网友的相关建议: 
      

谢邀=w=

这个其实看它的behavior就很容易猜出程序是怎么写的了

S抢的发射逻辑是,一枪发射前方扇形5颗子弹,屏幕上最多不超过10颗子弹

两枪之间并没有最小发射间隔(连射键是我们“中华FC”后加的功能,那时候谁tm能想到玩家能连续每秒15次20次的速度输入啊)

如果超过10颗,无法发射,如果这枪发射后多于10颗,那么多出来的部分就无法发射

本来按照街机的逻辑,五颗五颗应该是分组的,前五颗彻底飞出屏幕之后才应该能再发射五颗,但是可能负责移植的程序员懒还是怎么地,并没有如此判断

其实L枪也一样,本应该是飞出屏幕之后才能射第二枪,结果并没有判断,而是第二枪覆盖第一枪的数据,于是你可以连射变成短棍……

扇形嘛,肯定有先飞出去的和后飞出去的,或者打倒敌人消失的,10个槽位(可以这么想象)有空出来了,就可以发射补上了,但是总体不能超过10个啊,于是就只能吞掉扇形上下两边的子弹了

于是就变成长条了

用C代码写大概他们是写成了这样:

       typedef struct _SPREADGUNBULLET {     unsigned char available;     unsigned char x;     unsigned char y;     unsigned char deltax;     unsigned char deltay; } SPREADGUNBULLET;  SPREADGUNBULLET sbullet[10];  char getSBullet() {     int i;      for (i = 0; i < 10; i++) {         if (sbullet[i].available)             return i;     }      return -1; }  void shotSpreadGun() {     int i;     const static char dListX = { 8, 6, 6, 4, 4 } ; // 这数字我瞎写的     const static char dListY = { 0, -2, 2, -4, 4 } ; // 总之是扇形……      for (i = 0; i < 5; i++) {         char slot = getSBullet();         if (slot == -1)             break;          sbullet[slot].available = 0;         sbullet[slot].x = player.x + (player.direction ? 8 : -8);          sbullet[slot].y = player.y;         sbullet[slot].deltax = player.direction ? dListX[i] : -dListX[i];         sbullet[slot].deltay = dListY[i];     } }     

准备给S枪子弹的位置一共10个,然后子弹或是飞出屏幕或是打倒敌人,某available变成1,我觉得接下来的东西都可以想象了……

评论区中出现了一位原教旨主义者(

@Applebloom

,现在又多了一位

@blue dark

),认为魂斗罗是用6502汇编写成的,所以我应该用6502汇编写出上面的程序,所以我决定现查6502指令集手册,写一个等同于上面C代码的6502汇编……没条件测试,我现在也很困,不确定100%正确,而且这个代码应该对理解本答案没有任何帮助……没兴趣的人可以无视,这是我第一次写6502汇编,如果有高手发现错误轻喷……

       ; typedef struct _SPREADGUNBULLET { ;     unsigned char available; ;     unsigned char x; ;     unsigned char y; ;     unsigned char deltax; ;     unsigned char deltay; ; } SPREADGUNBULLET;  ; typedef struct _PLAYER { ;     unsigned char status; ;     unsigned char x; ;     unsigned char y; ;     unsigned char direction; ;     unsigned char gun; ;     unsigned char life; ; } PLAYER; ; ; 假设已经定义S弹内存地址为SBULLET,对应SPREADGUNBULLET构造体 ; 假设已经定义1P数据为PLY1,对应PLAYER构造体 ; 直接访问PLY1构造体变量的各种宏也已定义 ; 发射S弹的子程序为SHOTSBUL  GETSBUL  LDX #45   ; X计数器45(5字节一组,对应SPREADGUNBULLET构造体,[9]~[0])  LOOPGETSBUL LDA (SBULLET),X  ; 读取SBULLET[X/5].available   BNE ENDSBUL  ; 如果非0,结束循环   TXA   ; X寄存器不能直接做数学运算……   SBC #05   ; 计数器-5   TAX   ; 存回去   BPL LOOPSBUL  ; 如果大于0(也就是还没到10组子弹的范围)则循环     ENDGETSBUL RTS   ; return  ;  DLISTX  .BYTE 4   .BYTE 4   .BYTE 6   .BYTE 6   .BYTE 8 DLISTY  .BYTE 4    .BYTE -4   .BYTE 2   .BYTE -2   .BYTE 0     SHOTSBUL LDY #4   ; Y计数器4,对应5发子弹[4]~[0]  SETSHOTSBUL JSR GETSBUL  ; 获取空余子弹槽位   BMI ENDSHOTSBUL  ; 如果结果小于0(也就是没有剩余)则结束       LDA #0   ; .available = 0   STA (SBULLET),X  ;       INX   ; X现在指向.x   LDA (PLY1DIR)  ; 发射方向向玩家面朝方向平移8像素,对准枪口   BEQ SHOTSRIGHT  ; 如果为0则朝右   LDA #-8   JMP SHOTSXSET SHOTSRIGHT LDA #8 SHOTSXSET ADC (PLY1X)   STA (SBULLET),X  ; .x = PLY1.x + (PLY1.direction ? 8 : -8)       INX   ; X现在指向.y   LDA (PLY1Y)   STA (SBULLET),X  ; .y = PLY1.y      INX   ; X现在指向.deltax   LDA (PLY1DIR)     BEQ SHOTSDRIGHT  ; 如果为0则朝右   LDA (DLISTX),Y   EOR #$FF  ; 因为朝左,所以取反   ADC #1   JMP SHOTSDXSET SHOTSDRIGHT LDA (DLISTX),Y SHOTSDXSET STA (SBULLET),X  ; .deltax = PLY1.direction ? dListX[Y] : -dListX[Y]       INX   ; X现在指向.deltaY   LDA (DLISTY),Y   STA (SBULLET),X  ; .deltay = dListY[Y]       DEY   BPL SETSHOTSBUL  ; 如果Y大于0(还没到5个一组),则继续循环     ENDSHOTSBUL RTS   ; return        



  

相关话题

  「没有《精灵宝可梦》就没有现在的任天堂」的说法是否正确? 
  2019 年 5 月 16 日任天堂举行的《超级马力欧创作家2》直面会有何看点? 
  为什么游戏《塞尔达传说·旷野之息》的大小只有 13 G? 
  如何看待《精灵宝可梦》(口袋妖怪)新作「太阳·月亮」加入中文语言? 
  有哪些至今仍旧值得体验的老游戏? 
  你们塞尔达全通都用了多久? 
  只玩《塞尔达传说:旷野之息》的话,买一台 Switch 亏吗? 
  如何看待任天堂发布Switch OLED? 
  八位机游戏中出现过哪些真实人物?活到今天的还有多少?比卡斯特罗/格瓦拉出名的还有吗? 
  FC/NES 游戏是怎么制作的? 

前一个讨论
狮子和老虎实力孰强孰弱,发生争斗谁厉害?
下一个讨论
一个演技很烂的演员和一个演技很好的演员,谁更能饰演好「演技很烂的演员」这个角色?





© 2024-11-21 - tinynew.org. All Rights Reserved.
© 2024-11-21 - tinynew.org. 保留所有权利