It is currently Wed Jul 26, 2017 3:28 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Fri Jan 18, 2013 7:21 pm 
Offline

Joined: Sun Jan 06, 2013 7:08 am
Posts: 4
当我成功的完成了我的碰撞检测算法后,真心想跟大家分享一下,希望大家多给些意见,让这个算法更加完善。
首先解释一下代码中用到的变量:
$0D $0E $14 $15 $16 $17 $18 $19 (Sp_addr1~Sp_addr4)
这八个内存里面分别保存了4个ROM区的16位内存地址(低8为+高8位),用来记录player精灵当前所在的位置(最少占1格,最多占4格)。
思路就是将精灵的位置映射到地图中,地图数据保存在命名表,命名表的数据又是从ROM中提取出来的,所以直接将精灵的位置映射到ROM了。
$13 $0F (Xp,Yp)
分别保存了精灵的水平和垂直的偏移量(值都是在F9~07间变化)。当精灵在某个方向上移动时,每8像素后便完全进入了另一个tile,所以这两个偏移量将会区分精灵是从上下左右哪个方向进入tile。而从不同的方向进入将会有不同的方法改变精灵当前在ROM中映射的内存地址。
代码中用到的方法:
change_addr()
当精灵从不同的方向完全进入一个tile的时候(通过对Xp,Yp的值来进行判断),它在ROM中所映射的地址将会有所改变(用以对未来前进方向是否可以通行进行判断)。
xx_on()
对应四个按钮的触发事件。
get(Sp_addr)
获取精灵当前映射到的地址。
getID(Sp_addr)
获取精灵所映射的地址中保存的tile ID。
=========================
代码:
//==================
change_addr(){
if(Xp==0 && Yp!=0){
if(Yp>8){
Sp_addr2=Sp_addr1+$20
}
if(Yp<8){
Sp_addr2=Sp_addr1-$20
}
}
if(Xp!=0 && Yp==0){
if(Xp>8){
Sp_addr2=Sp_addr1+$1
}
if(Xp<8){
Sp_addr2=Sp_addr1-$1
}
}
}
//================
//===================
Up_on(){
change_addr();
if(Yp==$07){
Sp_addr1-=$20;
Yp=$00;
Sy--;
return;
}
if(Xp==0 && Yp==0){
get(Sp_addr1);
Sp_addr2=Spaddr_1-$20;
if((getID(Sp_addr2)-$82)<0){
Yp++;
Sy--;
return;
}else{
return;
}
}
if(Xp==0 && Yp!=0){
Yp++;
Sy--;
return;
}
if(Xp!=0 && Yp==0){
get(Sp_addr1);
Sp_addr3=Spaddr_1-$20;
if((getID(Sp_addr3)-$82)<0){
get(Sp_addr2);
Sp_addr4=Spaddr_2-$20;
if((getID(Sp_addr4)-$82)<0){
Yp++;
Sy--;
return;
}else{
return;
}
}else{
return;
}
}
if(Xp!=0 && Yp!=0){
Yp++;
Sy--;
return;
}
}
//===================
//====================
Down_on(){
change_addr();
if(Yp==$F9){
Sp_addr1+=$20;
Yp=$00;
Sy++;
return;
}
if(Xp==0 && Yp==0){
get(Sp_addr1);
Sp_addr2=Spaddr_1+$20;
if((getID(Sp_addr2)-$82)<0){
Yp--;
Sy++;
return;
}else{
return;
}
}
if(Xp==0 && Yp!=0){
Yp--;
Sy++;
return;
}
if(Xp!=0 && Yp==0){
get(Sp_addr1);
Sp_addr3=Spaddr_1+$20;
if((getID(Sp_addr3)-$82)<0){
get(Sp_addr2);
Sp_addr4=Spaddr_2+$20;
if((getID(Sp_addr4)-$82)<0){
Yp--;
Sy++;
return;
}else{
return;
}
}else{
return;
}
}
if(Xp!=0 && Yp!=0){
Yp--;
Sy++;
return;
}
}
//======================
//======================
Left_on(){
change_addr();
(Xp==$07){
Sp_addr1-=$01;
Xp=$00;
Sx--;
return;
}
if(Xp==0 && Yp==0){
get(Sp_addr1);
Sp_addr2=Spaddr_1-$01;
if((getID(Sp_addr2)-$82)<0){
Xp++;
Sx--;
return;
}else{
return;
}
}
if(Xp!=0 && Yp==0){
Xp++;
Sx--;
return;
}
if(Xp==0 && Yp!=0){
get(Sp_addr1);
Sp_addr3=Spaddr_1-$01;
if((getID(Sp_addr3)-$82)<0){
get(Sp_addr2);
Sp_addr4=Spaddr_2-$01;
if((getID(Sp_addr4)-$82)<0){
Xp++;
Sx--;
return;
}else{
return;
}
}else{
return;
}
}
if(Xp!=0 && Yp!=0){
Xp++;
Sx--;
return;
}
}
//======================
//======================
Right_on(){
change_addr();
(Xp==$F9){
Sp_addr1+=$01;
Xp=$00;
Sx++;
return;
}
if(Xp==0 && Yp==0){
get(Sp_addr1);
Sp_addr2=Spaddr_1+$01;
if((getID(Sp_addr2)-$82)<0){
Xp--;
Sx++;
return;
}else{
return;
}
}
if(Xp!=0 && Yp==0){
Xp--;
Sx++;
return;
}
if(Xp==0 && Yp!=0){
get(Sp_addr1);
Sp_addr3=Spaddr_1+$01;
if((getID(Sp_addr3)-$82)<0){
get(Sp_addr2);
Sp_addr4=Spaddr_2+$01;
if((getID(Sp_addr4)-$82)<0){
Xp--;
Sx++;
return;
}else{
return;
}
}else{
return;
}
}
if(Xp!=0 && Yp!=0){
Xp--;
Sx++;
return;
}
}
//======================


Top
 Profile  
 
PostPosted: Fri Jan 18, 2013 9:10 pm 
Offline

Joined: Sun Jan 06, 2013 7:08 am
Posts: 4
上游戏文件,仿作的“世界最难小游戏”,仅有第一关。player与地图之间的碰撞和player与CPU精灵之间的碰撞算法是不同的。不过对于多个精灵之间的碰撞检测还没有完善,目前的算法只适用于少数精灵之间的碰撞(通过对比精灵4个边角的坐标)。


Attachments:
d_20130118.nes [40.02 KiB]
Downloaded 590 times
Top
 Profile  
 
PostPosted: Sat Jan 19, 2013 11:42 pm 
Offline

Joined: Sun Jan 06, 2013 7:08 am
Posts: 4
我的这个碰撞检测方法仅适用于tile级别的碰撞检测。
精灵初始化后,映射在ROM中的内存地址会保存在Sp_addr1,水平和垂直偏移量会置0。
所以精灵所在的tile将会有3种状态:仅占1个tile位置,此时水平偏移量Xp,垂直偏移量Yp均为0;
占2个tile位置,此时会是Xp==0&&Yp!=0,或者Xp!=0&&Yp==0,对应垂直方向占2格,水平方向占2格;
占4个tile位置,Xp!=0&&Yp!=0。
但是精灵的移动是按像素来的,所以将会在精灵完全进入下一个tile中后,改变其在ROM中映射的内存地址,这由每个按键事件的第一个判断语句来实现。
精灵在移动的过程中将会在这3中情况中变换。每种情况有不同的检测方法,这取决于精灵所占的tile情况,和将要移动的方向。
我花费了大量的时间去演算所有在精灵移动中可能发生的情况,它是大量的,我在试图描述它们的过程中遇到了很多困扰。终于在第四天的时候想到了一个充分描述它们的办法。
算法的核心在于如何随着精灵的移动去改变其映射在ROM中的内存地址,这由change_addr方法进行实现。
当精灵处于占1个tile的状态时,如果成功向按键方向进行了移动,将会把前进方向在ROM中映射的内存地址写入Sp_addr2。
当精灵处于占2个tile的状态时,会有四种情况:
Xp==0&&Yp!=0{向垂直方向移动是向占1tile的状态变化,无需碰撞检测;向水平方向移动时将会触发碰撞检测}
Xp!=0&&Yp==0{向水平方向移动是向占1tile的状态变化,无需碰撞检测;向垂直方向移动时将会触发碰撞检测}
当精灵处于占4个tile的状态时,无需进行碰撞检测,因为检测发生在进入这种状态之前,所以已经进入后就可以随意移动了。
而在精灵从占4个tile的状态变化成占2个tile的状态时,将对它在ROM中映射的内存地址(Sp_addr1,Sp_addr2)进行改变。
以上就完成了对精灵移动的完整描述,如果您发现了Bug,希望及时联系我,在此表示感谢。


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group