我是一名初学C ++程序员,自学成才。我正在开发一个简单的roguelike游戏作为学习项目。我遇到的问题是用于确定玩家是否能够在指定方向上移动的代码。当玩家想要向东移动一个方格时,运行以下代码,其中int a和b是预期方形的X和Y坐标:
bool Location::canMove(int a, int b)
{
for (int i = 0; i < Decorations.size(); i++)
{
if (Decorations[i].getPosX() == b && Decorations[i].getPosY() == a)
{
Match = true;
Matched = Decorations[i];
break;
} else
{
Match = false;
}
}
if (Match == true)
{
if (Matched.Clips() == true)
{
Blocked = true;
return false;
} else
{
Blocked = false;
return true;
}
} else
{
switch(Map[a][b])
{
case TILE_VOID:
case TILE_FLOOR:
Blocked = false;
return true;
break;
case TILE_WALL:
Blocked = true;
return false;
break;
}
}
}
它的作用基本上是看玩家的当前位置是否在X和Y坐标处有任何装饰对象,如桌子,柱子等。如果它发现它有一个,则它会运行检查以查看该对象是否允许玩家使用Clips()函数传递或不传递,并返回true或false以确定玩家是否可以移动到那里。如果没有找到装饰物,那么它会检查该位置的基础砖,如果它是空的或地板,那么玩家可以移动,如果它是墙,那么他们就不能。
这条代码尽我所知(播放器无法穿过墙壁或固体物体)。但是,在主循环中,如果玩家被告知他们无法移动,则会调用另一个函数,这会告诉玩家原因:
string Location::blockMsg()
{
blockmsg = "You bump into the ";
if (Blocked == false)
{
blockmsg = blockmsg + "wall";
} else
{
blockmsg = blockmsg + Matched.getName();
}
return blockmsg;
}
这用于告知玩家他们为什么不能向这个方向移动。如果他们碰到一张桌子,就应该说“你撞到桌子上”,例如。
我遇到的问题是它看起来不像bool Matched或Blocked,或者匹配的装饰在第一段代码完成后被保存。因此,逻辑总是表现为Blocked == false,即使玩家碰到阻挡他们移动的装饰。结果是,如果一个玩家被某些东西阻挡,它总会说“你撞到墙上”,即使它是别的东西。
我能做的唯一假设是,由于某种原因,当在第一个函数中分配Blocked = true时,不会因为下一个函数使用它而保留它。
有谁可以指出我哪里出错了?我一直认为,一旦在canMove()函数中设置了Location的Match,Matched和Blocked值,它们应该保留blockMsg()使用的相同值,但显然不是。
答案 0 :(得分:1)
我做了几个关键的假设,比如原始代码中的“a”参数等同于“x”地图坐标,而“b”param是=“y”地图坐标。我更改了参数名称,以便更清楚地了解代码的操作。
我还假设“Locations”类可以访问“Decorations”对象和“Map”2d数组。如果“Locations”类无法访问Decorations对象或Map数组,那么这可能会导致一些问题。
此外,如果Blocked,Matched和Match是Location类的数据成员,它们的值应该超出函数调用的范围,但只是为了确保它不是一些奇怪的编译器错误,请尝试包含显式的“this-&gt;” (“this”是指向父对象或进程的指针)对所有实例变量的引用。这样做可以确保代码的操作将数据保存在某种持久变量中,而不是仅在执行后消失。请注意,我在下面的代码示例中进行了更改:
bool Location::canMove(int x, int y) //change param names for clarity sake
{
//I recommend turning the "bool Location::Match" into a "int Location::Match"
// I also recommend this for the "bool Location::Blocked" variable
// This way you can have a flag that says, yes, no, error, etc.
// For illustration purposes I commented out old and inserted new with that integer assumption
// Key for the new "Location::Match" and "Location::Blocked" values:
// -1 = error
// 0 = false
// 1 = true
//Initialize Match to an error state, that way if the for loop below fails to
// execute, your application will flag that failure
this->Match = -1;
for (int i = 0; i < Decorations.size(); i++)
{
// did you mean to have your values criss-crossed in the "if" statement below?
if (Decorations[i].getPosX() == y && Decorations[i].getPosY() == x)
{
this->Match = 1;
this->Matched = Decorations[i];
break;
} else
{
this->Match = 0;
}
}
if (this->Match == 1) //Match found!
{
if (this->Matched.Clips() == true)
{
this->Blocked = 1;
return false;
} else
{
this->Blocked = 0;
return true;
}
} else if (this->Match == 0) // no match found
{
switch(Map[x][y]) //changed to reflect new parameter names
{
case TILE_VOID:
case TILE_FLOOR:
this->Blocked = 0; //false
return true;
//break; // break is unreachable, due to the return above, therefore not needed
case TILE_WALL:
this->Blocked = 1; //true
return false;
//break; //see case above
default:
//Always include a default case
// log it, report it, write it to file, print to screen, debug, etc.
this->Blocked = -1; //error
break;
}
} else if (this->Match == -1) // error case
{
//Yet another error case...
// By adding separate, discrete error cases you can track down the
// source of your errors more efficiently
this->Blocked = -1; // error
return false;
}
}
进行这些小改动以允许Blocked和Match拥有比布尔标志更多的选项后,必须更改输出消息功能以使用新值。 (是的,我意识到,如果您在其他地方使用Match或Blocked,则必须进行更新。)
以下是输出消息的样子:
string Location::blockMsg()
{
blockmsg = "You bump into the ";
if (this->Blocked == 0)
{
blockmsg += "wall";
} else if(this->Blocked == 1)
{
blockmsg += Matched.getName();
}else if(this->Blocked == -1)
{
blockmsg += "ERROR!";
}
return blockmsg;
}
通过进行这些更改,您应该能够更有效地调试代码,并能够弄清楚发生了什么以及出错的地方。此外,如果你能够,使用你的调试器并标记“canMove()”方法,这样当它被调用时你可以看到执行步骤。
祝你好运,玩得开心!
〜HV6 ^ 3