C ++对象不保存变量值

时间:2012-03-11 18:54:44

标签: c++

我是一名初学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()使用的相同值,但显然不是。

1 个答案:

答案 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