【问题标题】:C++ object not saving variable valuesC++ 对象不保存变量值
【发布时间】:2012-03-11 18:54:43
【问题描述】:

我是一名 C++ 初学者,自学成才。我正在开发一个简单的 roguelike 游戏作为学习项目。我遇到的问题在于用于确定玩家是否能够朝指定方向移动的代码。例如,当玩家想要向东移动一个方格时,运行以下代码,其中 int a 和 b 是 intended 方格的 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,或者装饰 Matched 正在被保存。因此,即使玩家撞到了阻碍他们移动的装饰物,逻辑也总是像 Blocked == false 一样。结果是,如果玩家被什么东西挡住了,它总是会说“你撞墙了”,即使是别的东西。

我唯一能做的假设是,由于某种原因,当在第一个函数中分配 Blocked = true 时,它​​不会因为任何原因而保留给下一个函数使用它。

谁能指出我哪里出错了?我一直认为,一旦在 canMove() 函数期间设置了 Location 的 Match、Matched 和 Blocked 值,它们应该保留相同的值供 blockMsg() 使用,但显然不是。

【问题讨论】:

  • 很遗憾,您没有完全发布足够的代码让我们能够找到问题。问题:Blocked 和 Matched 是 Location 类的实例变量吗? blockMsg 是在与 canMove 相同的 Location 实例上调用的吗?
  • 还有。您发布了太多代码。尝试将问题简化为少于 20 行的自包含示例。
  • 抱歉各位,我以后会尽量多关注代码。 Blocked、Matched 和 Match 都是 Location 类的实例变量。想法是它们将在 canMove() 函数期间设置,并保持这种状态,因此当调用 blockedMsg() 函数时,它可以解释为什么玩家无法移动。不幸的是,它似乎没有在这两个函数之间正确存储值。 player 类有自己的 Location 对象,称为“currentLocation”,所以 canMove() 和 blockedMsg() 都会在 player.currentLocation 对象上调用。
  • 我也不清楚你的 canMove 函数不能从最后返回一个随机值。
  • Mark B:我认为它旨在处理任何可能发生的情况,尽管我需要发布更多代码来确认这一点。同时,谁能解释为什么当blockedMsg() 函数运行时,它没有正确获取Location 的Matched 和Blocked 变量?

标签: c++


【解决方案1】:

我做了几个关键假设,比如原始代码中的“a”参数等同于“x”地图坐标,而“b”参数等于“y”地图坐标。我更改了参数名称,以便更清楚地了解代码的操作。

我还假设“Locations”类可以访问“Decorations”对象和“Map”二维数组。如果“Locations”类无法访问装饰对象或 Map 数组,则可能会导致一些问题。

此外,如果 Blocked、Matched 和 Match 是 Location 类的数据成员,它们的值应该在函数调用之后持续存在,但为了确保它不是一些奇怪的编译器错误,请尝试包含显式的 "this->" (" 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

【讨论】:

    猜你喜欢
    • 2011-06-14
    • 2022-11-17
    • 1970-01-01
    • 2021-09-12
    • 2017-08-23
    • 2022-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多