百科问答小站 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        



  

相关话题

  FC 魂斗罗的背景为何都是黑色的、夜晚的感觉,是为了省内存么? 
  《太阁立志传 5 DX》发布宣传预告,5.19 发售,支持中文,登陆 PC 和 NS,你都有哪些期待? 
  为什么当年 FC 的硬件那么容易就被山寨? 
  有哪些至今仍旧值得体验的老游戏? 
  神游科技(iQue)是一个怎样的公司? 
  为何FC魂斗罗S枪长时间发射后子弹会变的稀疏不成扇形,停止发射一秒后再开始发射就又可以以扇形状态发射? 
  如何看待任天堂 Labo 在中文地区首发,在中文广告中特地标注不含中文? 
  如何评价任天堂新主机 Nintendo Switch? 
  数码宝贝这个ip交给任天堂经营的话会怎么样? 
  为什么在玩次时代画面的PS4时,却还没有小时候玩8位的红白机时快乐? 

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





© 2024-12-22 - tinynew.org. All Rights Reserved.
© 2024-12-22 - tinynew.org. 保留所有权利