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

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

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

 
 
 

日志

 
 

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

2009-07-28 00:04:32|  分类: FC开发记录 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

原文http://nicotine.knight.blog.163.com/blog/static/269261122009627114011404/

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

今晚将之重新注释。

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

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

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

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

其余的可以乱排。

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

代码下载:http://www.uushare.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
////////////////////////////结束

  评论这张
 
阅读(456)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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