注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

深夜是徘徊在潮湿睫毛上的我的梦以及他的梦

是直到最后都无法放手的一种气息,是我们生命中最后的思念……

 
 
 

日志

 
 

菜菜鸟自编FC(NES)游戏,初阶经历记录06  

2009-07-27 23:40:11|  分类: FC开发记录 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

今年3、4月重新写了贪吃蛇。这是最终代码了。再做就要换别的型式了。

今晚将之重新注释。

这个代码分成9个BAS文件。

header.bas  这个文件必须是排在首位。

main1.bas  这个文件必须是排在第二位。

footer.bas  这个文件必须是排在最后。

其余的可以乱排。

NES下载:http://www.uudisc.com/user/fogota/file/1209160

代码下载:http://www.uudisc.com/user/fogota/file/1209157

 

程序代码如下:(下面的注释比下载版的全)

//////////////////

//header.bas

/////////////////

//header for nesasm
//文件头,用嵌入式汇编码
asm
 .inesprg 1 ;//one PRG bank
 .ineschr 1 ;//one CHR bank
 .inesmir 0 ;//mirroring type 0
 .inesmap 0 ;//memory mapper 0 (none)
 .org $8000
 .bank 0
endasm

 

///////////////////

//main1.bas

///////////////////

//这里就进入程序部分了
//这是入口
goto start
//数据部分
//每行以0表示一串字符的结束。所有引号中的字符会按ASCII转换成数字。nbasic没有字符串概念
//在字符前面注释偏移量。用偏移量的方法记录字符串位置,这方法比较容易。但结束位只能在255以下。
data_str:
 //0
 data "YOU LOSE",0
 //9
 data "YOU WIN",0
 //17
 data "<< GREEDY SNAKE >>",0
 //36
 data "GAME LEVEL",0
 //47
 data "YOU PASS",0
 //56
 data "SNAKE      PASS",0
 //72
 data "press START.",0
 //85
 data "press A.",0
//开始执行程序
start:
 // some init code based on Duck Hunt
 // turn off the PPU
//先等一次vblank,不知为什么,是抄老外代码的。但有用。不闪屏。
 gosub vwait_start
//关十进制运算,CPU6502是提供10进制运算的,但FC是不用10进制的,要先关了,祥细不知
 asm
  cld
  sei
 endasm

 //now turn on the PPU 设定软开关$2000$2001,记录k0,k0_1,k1,k1_1是为了试验在中途更改$2000和$2001
 set k0 %00100000
 set k0_1 %00100100
 set k1 %00011100
 set k1_1 %00010100
//设成禁中断,背景地址,每次+1,即向右移光标.
 set $2000 k0
 set $2001 k1 //sprites and bg visible, no sprite clipping
 gosub load_palette //载入配色
 gosub init_vars  //载入初始变量

//过关的开始 清空背景 画版头
//注释了的语句是作废的语句。说不定以后会用上。
start_2:
 gosub vwait  //空等一转vblank,有什么用?本想是为了不闪屏,不知有没有作用。。
 //set $2001 k1_1

 gosub clear_background   //清屏
 gosub vwait  //又一次,同上
 //set $2001 k1
 gosub start_3  //打印开始图面
 goto start_4

//开始图面
start_3:
 gosub vwait_start  //打印前,等到vblank来临
 //"<< GREEDY SNAKE >>"  向我的打印函数,传数值
 set str_stay_h $20
 set str_stay_l $E7
 set str_n 17
 gosub draw_string
 //"GAME LEVEL "  向我的打印函数,传数值
 set str_stay_h $21
 set str_stay_l $4A
 set str_n 36
 gosub draw_string
 set $2007 0
 set $2007 + leve $30

//开始,待机
start_3_1:
 //"press START."   向我的打印函数,传数值
 set str_stay_h $21
 set str_stay_l $CA
 set str_n 72
 gosub draw_string
 gosub vwait_end   //打印完,等到vblank结束
start_3_2:
 gosub vwait  //再等一转vblank,为的是每次扫描手柄的间隔。
 gosub joystick1   //扫描手柄
 if joy1start=0 branchto start_3_2   //没按star就回去继续,按了就跳出
 return


//设定颜色  
load_palette:
 // set the PPU start address (background color 0)
//写入PPU的内存地址$3F00,这里只写背景部分的。因为只用到这些。
 set $2006 $3f
 set $2006 0
 set $2007 $0F  //($3F00)=$0F
 set $2007 $30  //($3F01)=$30
 set $2007 $2A  //($3F02)=$2A
 set $2007 $05  //($3F03)=$05

//镜像再写一次?这个也是抄老外的,可能为了兼容性,(个人理解)
 set $2006 $3f
 set $2006 $10
 set $2007 $0F
 set $2007 $30
 set $2007 $2A
 set $2007 $05
 return


//set default sprite location设置默认(初始)值
init_vars:
 set snake_maxlong 92 //最后一关的蛇的长度
 set snake_winlong 20 //过关的蛇的长度
 set snake_long 5 //蛇的长度

 set egg01 $AE //彩蛋的字符号
 set egg01_M 3 //彩蛋的分值
 set egg02 $AF
 set egg02_M 2
 set egg03 $B0
 set egg03_M 1
 set egg04 $B1
 set egg04_M 4
 set wall $B2 //墙的字符号
 set delayer_0 7 //初始的程序延迟

 set add1_nl 0 //加减法变量的初始
 set add1_nh 0
 set add2_nl $20
 set add2_nh 0
 set sub1_nl 0
 set sub1_nh 0
 set sub2_nl $20
 set sub2_nh 0

 array snake 200 //蛇身记录的空间
 set snake_logend 199 //200-1
 set leve 1 //版号
 set lose 0 //0=游戏中 1=失败 2=胜  过关记号
 set random_seed $AA //随机数种子

 array drawer 90 //以3个数为单位,分别是地址高位、地址低位、TlieID
 return

 

 

///////////////

//main2.bas

//////////////

//另一部分的初始值设置,这部分有关程序的运行
init_vars_1:
 set snake_facing 2 //蛇头方向 0=左 1=右 2=上 3=下
 set moving 0 //活动状态 0=暂停 1=活动
 set lose 0 //游戏状态 0=游戏中 1=失败 2=胜
 set delayer - delayer_0 leve
 
 set snake_headloc_h $21 //记录蛇头的地址高位
 set snake_headloc_l $0A //记录蛇头的地址低位
 set snake_endloc_h $21 //记录蛇尾的地址高位
 set snake_endloc_l + snake_headloc_l snake_long //记录蛇尾的地址低位

 set snake_headmark 0 //蛇头记录的指针(偏移量)
 set snake_endmark 0 //蛇尾记录的指针(偏移量)

 //记入蛇头位置
 set x snake_headmark
 set [snake x] snake_headloc_h
 inc x
 set [snake,x] snake_headloc_l
 set snake_headmark 2

 set markendlater snake_long //蛇尾读取延迟
 return

//游戏部分
start_4:
 gosub init_vars_1   //定义变量
 gosub clear_background   //清屏
 gosub draw_background    //画场景
 gosub draw_backsome     //画上一些圣诞树,圣诞礼物

//画顶行的字
 gosub vwait_start
 //"SNAKE      PASS"
 set str_stay_h $20
 set str_stay_l $23
 set str_n 56
 gosub draw_string
 gosub vwait_end

//输入参数,调用函数写个数字
 set sum_input snake_winlong
 set draw_sum000_h $20
 set draw_sum000_l $33
 gosub draw_sum000
//输入参数,调用函数写个数字
 set sum_input snake_long
 set draw_sum000_h $20
 set draw_sum000_l $29
 gosub draw_sum000
//进入游戏的循环
 goto mainloop

//画上一些圣诞树,圣诞礼物
draw_backsome:

 set drawer_mark 0
 set draw_adder_h $21
 set draw_adder_l $66
 set draw_tileid egg03
 gosub mark_drawer
 set draw_adder_h $20
 set draw_adder_l $B9
 set draw_tileid egg04
 gosub mark_drawer
 set draw_adder_h $22
 set draw_adder_l $91
 set draw_tileid egg03
 gosub mark_drawer

 set walls 0
draw_backsome_1:
 set egg_n wall
 gosub mark_egg
 inc walls
 if walls<9 branchto draw_backsome_1

 set egg_n egg01
 gosub mark_egg

 set draw_adder_h snake_headloc_h
 set draw_adder_l snake_headloc_l
 set draw_tileid $AC
 gosub mark_drawer

 gosub draw_something
 return

 

//////////////////////

//main3.bas

/////////////////////

//the main program loop
//游戏循环主体
mainloop:
 set $4015 0
 gosub vwait
 gosub joy_handler
 if moving=0 branchto mainloop_1
 gosub draw_snake
mainloop_1:
 if Boom1<>0 gosub Boom
 set temp02 delayer
mainloop_2:
 set temp02 - temp02 1
 gosub vwait
 if temp02 > 0 branchto mainloop_2
 goto mainloop_3

draw_snake:
 set drawer_mark 0
 set draw_adder_h snake_headloc_h
 set draw_adder_l snake_headloc_l
 set draw_tileid $80
 gosub mark_drawer

 if snake_facing=1 inc snake_headloc_l
 if snake_facing=0 dec snake_headloc_l
 if snake_facing=3 then
  set add1_nh snake_headloc_h
  set add1_nl snake_headloc_l
  set add2_nl $20
  set add2_nh 0
  gosub add16
  set snake_headloc_h add1_nh
  set snake_headloc_l add1_nl
  endif
 if snake_facing=2 then
  set sub1_nh snake_headloc_h
  set sub1_nl snake_headloc_l
  set sub2_nl $20
  set sub2_nh 0
  gosub sub16
  set snake_headloc_h sub1_nh
  set snake_headloc_l sub1_nl
  endif

 set draw_adder_h snake_headloc_h
 set draw_adder_l snake_headloc_l
 set draw_tileid + snake_facing $AA
 gosub mark_drawer
 gosub markhead

 if markendlater>0 branchto draw_snake_1
 gosub readendmark
 set draw_adder_h snake_endloc_h
 set draw_adder_l snake_endloc_l
 set draw_tileid 0
 gosub mark_drawer

 goto draw_snake_2
draw_snake_1:
 dec markendlater

draw_snake_2:
 gosub CheckBoom
 gosub draw_something
 return

//检测碰撞
CheckBoom:
 set Boom1 0
 gosub vwait_start
 set $2006 snake_headloc_h
 set $2006 snake_headloc_l
 set Boom1 [$2007]
 gosub vwait_end
 return

//处理碰撞
Boom:
 if Boom1=wall set lose 1
 if Boom1=$80 set lose 1
 if Boom1=egg01 branchto Boom_1
 if Boom1=egg02 branchto Boom_2
 if Boom1=egg03 branchto Boom_3
 if Boom1=egg04 branchto Boom_4
 goto Boom_z
Boom_1:
 set markendlater + markendlater egg01_M
 goto Boom_x
Boom_2:
 set markendlater + markendlater egg02_M
 goto Boom_x
Boom_3:
 set markendlater + markendlater egg03_M
 goto Boom_x
Boom_4:
 set markendlater + markendlater egg04_M
Boom_x:
 set snake_long + snake_long markendlater

 //
 set drawer_mark 0
 set egg_n wall
 gosub mark_egg
 gosub mark_egg
 //
 set egg_n egg01
 gosub mark_egg
 set sgg_n egg02
 gosub mark_egg

 set draw_adder_h snake_headloc_h
 set draw_adder_l snake_headloc_l
 set draw_tileid + snake_facing $AA
 gosub mark_drawer

 gosub draw_something

 set sum_input snake_long
 set draw_sum000_h $20
 set draw_sum000_l $29
 gosub draw_sum000
 if snake_long > snake_winlong set lose 2
Boom_z:
 set Boom1 0
 return

//记下蛇头位置,并指向下一记录点
markhead:
 set x snake_headmark
 set [snake,x] snake_headloc_h
 inc x
 set [snake,x] snake_headloc_l

 inc snake_headmark
 inc snake_headmark
 if snake_headmark < snake_logend goto markhead_1 
 set snake_headmark 0
markhead_1:
 return

//读出蛇尾位置,指向下一蛇尾位置
readendmark:
 set x snake_endmark
 set snake_endloc_h [snake,x]
 set [snake,x] 0
 inc x
 set snake_endloc_l [snake,x]
 set [snake,x] 0
 inc snake_endmark
 inc snake_endmark
 if snake_endmark < snake_logend branchto readendmark_1
 set snake_endmark 0
readendmark_1:
 return


//读取手柄,并判断合法移动,接收暂停和活动指令
joy_handler:
 gosub joystick1
 if joy1select=1 goto joy_handler_3
 if snake_facing=0 set joy1right 0
 if snake_facing=1 set joy1left 0
 if snake_facing=2 set joy1down 0
 if snake_facing=3 set joy1up 0
 if moving=1 branchto joy_handler_2

 set temp01 0
 asm
  lda #$0
  ora joy1left
  ora joy1right
  ora joy1up
  ora joy1down
  sta temp01
 endasm
 if temp01=0 goto joy_handler_2
 set moving 1
 set $4015 %00000001
 set $4000 $1F
 set $4001 $96
 set $4002 $EF
 set $4003 $08
joy_handler_2:
 if joy1left=1 set snake_facing 0
 if joy1right=1 set snake_facing 1
 if joy1up=1 set snake_facing 2
 if joy1down=1 set snake_facing 3
 goto joy_handler_4
joy_handler_3:
 set moving 0
joy_handler_4:
 return

 

////////////////////////

//main4.bas

//////////////////////

mainloop_3:
 if lose=1 branchto mainloop_4
 if lose=2 branchto mainloop_7
 goto mainloop

//失败,连关
mainloop_4:
 set moving 0
 set snake_long + leve 5
 gosub vwait_start
 //"YOU LOSE"
 set str_stay_h $21
 set str_stay_l $8A
 set str_n 0
 gosub draw_string
 goto mainloop_6

//胜利
mainloop_5:
 set moving 0
 gosub vwait_start
 //"YOU WIN"
 set str_stay_h $21
 set str_stay_l $8A
 set str_n 9
 gosub draw_string
 gosub vwait_end
mainloop_5_1:
 goto mainloop_5_1

//过关待机
mainloop_6:
 //"press A."
 set str_stay_h $21
 set str_stay_l $CA
 set str_n 85
 gosub draw_string
 gosub vwait_end 
mainloop_6_1:
 gosub vwait
 gosub joystick1
 if joy1a=0 branchto mainloop_6_1
 goto start_2

//过关,或胜利
mainloop_7:
 if snake_long > snake_maxlong branchto mainloop_5
 //过关,增加难度
 inc leve
 set snake_winlong + snake_winlong 12
 set snake_long + leve 5
 set moving 0
 gosub vwait_start
 //"YOU PASS"
 set str_stay_h $21
 set str_stay_l $8A
 set str_n 47
 gosub draw_string
 goto mainloop_6

 

 

///////////////////////////

//common1.bas

/////////////////////////

//函数库
//显示一行字
draw_string:
 set $2006 str_stay_h
 set $2006 str_stay_l
 set x str_n //定义偏移量 
 draw_string_1:
  set $2007 [data_str x]
  inc x
  set a [data_str x]
  if a <> 0 branchto draw_string_1
 return

//update joystick button status 扫描手柄
joystick1:
 set $4016 1 //first strobe byte
 set $4016 0 //second strobe byte
 set joy1a & [$4016] 1
 set joy1b & [$4016] 1
 set joy1select & [$4016] 1
 set joy1start & [$4016] 1
 set joy1up & [$4016] 1
 set joy1down & [$4016] 1
 set joy1left & [$4016] 1
 set joy1right & [$4016] 1
 return
//wait for the start of the vertical blanking interval
//等到vblank开始
vwait_start:
 asm
  bit $2002
  bpl vwait_start
 endasm
 return

//wait for the end of the vertical blanking interval
//等到vblank结束
vwait_end:
 asm
  bit $2002
  bmi vwait_end
 endasm
 set a 0
 set $2005 a
 set $2005 a
 set $2006 a
 set $2006 a
set $fff9 $ff
 return

//wait until screen refresh
//等一次擦屏
vwait:
 gosub vwait_start
 gosub vwait_end
 return

//清屏
clear_background:
 gosub vwait
 gosub clear_background_one
 gosub vwait
 gosub clear_background_two
 return

//擦上半屏
clear_background_one:
 set clear_background_temp $20
 gosub clear_background_helper
 set clear_background_temp $21
 gosub clear_background_helper
 set clear_background_temp $22
 gosub clear_background_helper
 set clear_background_temp $23
 gosub clear_background_helper
 gosub vwait
 return

//擦下半屏
clear_background_two:
 set clear_background_temp $24
 gosub clear_background_helper
 set clear_background_temp $25
 gosub clear_background_helper
 set clear_background_temp $26
 gosub clear_background_helper
 set clear_background_temp $27
 gosub clear_background_helper
 gosub vwait
 return

//擦屏子函数
clear_background_helper:
 gosub vwait
 set $2006 clear_background_temp
 set $2006 0
 set a 0
 set x 0
 clear_ppu_256_1:
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  set $2007 a
  inc x
  if x <> 16 branchto clear_ppu_256_1
 return

//清除配色
clear_palette:
 gosub vwait_start
 set $2006 $3f
 set $2006 0
 set x 0
 clear_palette_1:
  set $2007 $0e
  inc x
  if x <> 32 branchto clear_palette_1
 gosub vwait_end
 return

 

////////////////////

//common2.bas

//////////////////

//函数库
//绘画背景
draw_background:
 set pointer wall
 gosub vwait_start
 set point_h $20
 set point_l $41
 set linelong 30
 gosub draw_aline
 set point_h $23
 set point_l $81
 set linelong 30
 gosub draw_aline
 set point_h $20
 set point_l $61
 set linelong 25
 gosub draw_aVerticalLine
 set point_h $20
 set point_l $7E
 set linelong 25
 gosub draw_aVerticalLine
 gosub vwait_end

 return

//画横线 point_h,point_l起点地址 linelong线长
draw_aline:
 set $2006 point_h
 set $2006 point_l
 set x 0
draw_aline_1:
 set $2007 pointer
 inc x
 if x < linelong branchto draw_aline_1
 return

//画竖线 point_h,point_l起点地址 linelong线长
draw_aVerticalLine:
 set $2000 k0_1
 gosub draw_aline
 set $2000 k0
 return

//记下要画的背景
mark_drawer:
 set x drawer_mark
mark_drawer_1:
 set [drawer x] draw_adder_h
 inc x
 set [drawer x] draw_adder_l
 inc x
 set [drawer x] draw_tileid
 inc x
 set drawer_mark x
 return

draw_something:
 set x 0
 gosub vwait_start
draw_something_1:
 set $2006 [drawer x]
 inc x
 set $2006 [drawer x]
 inc x
 set $2007 [drawer x]
 inc x
 if x<>drawer_mark branchto draw_something_1
 gosub vwait_end
 set drawer_mark 0
 return

//显示数
draw_sum000:
 set mod1 sum_input
 set mod2 10
 gosub mod_div
 set sum3 mod1
 set mod1 div
 gosub mod_div
 set sum2 mod1
 set sum1 div
 gosub vwait_start
 set $2006 draw_sum000_h
 set $2006 draw_sum000_l
 set $2007 + sum1 $30
 set $2007 + sum2 $30
 set $2007 + sum3 $30
 gosub vwait_end
 return

//求余  mod(mod1,mod2)=mod1  例mod(13,10)=3
mod_div:
 set div 0
mod_1:
 if mod1 = mod2 branchto mod_2
 if mod1 < mod2 branchto mod_3
mod_2:
 set mod1 - mod1 mod2
 inc div
 goto mod_1
mod_3:
 return

mark_egg:
 gosub random_number
 set temp02 random_seed
 set random_seed + random_seed snake_endloc_l
 set random_seed << random_seed 2
 gosub random_number
 set temp03 random_seed
 //temp02=mod(temp02,$1A)
 set mod1 temp02
 set mod2 $1A
 gosub mod_div
 //----------
 set temp02 + mod1 3
 //temp03=mod(temp03,$14)
 set mod1 temp03
 set mod2 $14
 gosub mod_div
 //----------
 set temp03 + mod1 4
 set temp03 << temp03 1
 //高位
 set temp01 & temp03 $F0
 set temp01 >> temp01 4
 set temp01 + temp01 $20
 //低位
 set temp04 & temp03 $F
 set temp04 << temp04 4
 set temp02 + temp02 temp04

 set draw_adder_h temp01
 set draw_adder_l temp02
 set draw_tileid egg_n
 gosub mark_drawer
 return

//生成随机数
// You must set random_seed to a non-zero value to initialize
array random_seed 1

// The function returns the random number in the A register
random_number:
 asm
 lda random_seed
 and #$b8
 ldx #$05
 ldx #$00
 random_number_floop:
  asl a
  bcc random_number_bitclr
  iny
 random_number_bitclr:
  dex
  bne random_number_floop
 random_number_noclr:
  tya
  lsr a
  lda random_seed
  rol a
  sta random_seed
  rts
 endasm

 

////////////////////////

//common3.bas

//////////////////////

//进位加法
add16:
 asm
  lda add1_nl ;//mov a,add1_number_l
  clc
  adc add2_nl ;//add a,add2_number_l
  sta add1_nl ;//mov add1_number_l,a
  lda add1_nh ;//mov a,add1_number_h
  adc add2_nh ;//addc a,add2_number_h
  sta add1_nh ;//mov add1_number_h,a
 endasm
 return

//退位减法
sub16:
 asm
  lda sub1_nl
  sec
  sbc sub2_nl
  sta sub1_nl
  lda sub1_nh
  sbc sub2_nh
  sta sub1_nh
 endasm
 return

 

 

////////////////////////////////

//footer.bas

///////////////////////////////


//file footer
//文件尾
asm
;//jump table points to NMI, Reset, and IRQ start points
 .bank 1
 .org $fffa
 .dw start, start, start
;//include CHR ROM
//定义字模  这里我只用了一个chr,另一个是填空位的。
 .bank 2
 .org $0000
 .incbin "ascii_2.chr"
 .incbin "ascii_2.chr"
endasm
////////////////////////////结束

  评论这张
 
阅读(935)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017