代码之家  ›  专栏  ›  技术社区  ›  Sneakyness

用播放器移动nsview边界的更好方法?

  •  0
  • Sneakyness  · 技术社区  · 15 年前

    目前正在编写一个roguelike来了解更多关于objective-c/cocoa的信息。到目前为止我真的很享受,而且我学到了很多。

    此代码移动 origin 视野中的 bounds 使它跟随玩家移动。代码工作得很好,我只是在问是否有比使用四个更好的方法 for s。

    我也看到在某些情况下,最好是分开做,而不是一个整体做,尤其是在绘图和 nsbezierpath 担心,为什么?

    编辑 人们很难确切地知道我在做什么,所以我会尽可能地把它分解。

    这个 view 是一个30x30网格(0-29,0-29)的瓷砖,每个20x20。地图可以根据需要大小。

    首先,你得到 [player_ location] 以及 起源 界限 对于 看法 . 它被划分为 20 因为瓷砖的尺寸是 20, 所以当它在 (1,2) ,实际上是在 (20,40) . 我这样做的唯一原因是更容易操作(以1为单位而不是20为单位计数更容易)。四 对于 我们检查一下 [玩家位置] 在里面 15 中心的瓷砖( bounds + 15 看法 . 如果玩家正在向屏幕的某个边缘移动,并且 bounds.x/y + 30 小于当前地图的高度/宽度,它移动 起源 这样,玩家仍然在地图上居中显示。

    代码运行良好,我移动了 setbounds 对于 发生了,只有一个。它不会被留在里面的 drawRect 我只是想弄清楚我需要做什么。它现在在自己的地方,只有当玩家真正移动时才会被调用。

    这是新的代码:

    - (void)keepViewCentered
    {
        NSPoint pl = [player_ location];
        NSPoint ll;
        NSPoint location = [self bounds].origin;
        ll.x = location.x / 20;
        ll.y = location.y / 20;
        for ( pl.y = [player_ location].y; pl.y >= ll.y + 15 && ll.y + 30 < [currentMap_ height]; ll.y++ )
        {
            location.y = ll.y * 20;
        }
        for ( pl.x = [player_ location].x; pl.x >= ll.x + 15 && ll.x + 30 < [currentMap_ width]; ll.x++ )
        {
            location.x = ll.x * 20;
        }
        for ( pl.y = [player_ location].y; pl.y <= ll.y + 15 && ll.y >= 0; ll.y-- )
        {
            location.y = ll.y * 20;
        }
        for ( pl.x = [player_ location].x; pl.x <= ll.x + 15 && ll.x >= 0; ll.x-- )
        {
            location.x = ll.x * 20;
        }
        [self setBoundsOrigin: location];
    }
    

    这是它的照片!

    图1:这是1,1的玩家。没什么特别的。 http://sneakyness.com/stackoverflow/SRLbounds1.png

    图2:这3块黄金代表玩家在视图边界前可以移动的距离。原点将移动到玩家的中心。尽管无关紧要,但请注意,玩家实际上看不到黄金。事实证明,编程视野是一个充满争议的领域,你可以使用几种不同的算法,它们都没有缺点,也没有移植到Objective-C。目前它只是一个正方形。看穿墙壁和一切。 http://sneakyness.com/stackoverflow/SRLbounds2.png

    图3:具有不同边界的视图。原点,以播放器为中心。 http://sneakyness.com/stackoverflow/SRLbounds3.png

    3 回复  |  直到 15 年前
        1
  •  1
  •   Peter Hosey    15 年前

    它现在在自己的地方,只有当玩家真正移动时才会被调用。

    哎呀!

    我只是问是否有比使用四个更好的方法 for s。

    我的建议是:

    1. 将左下角设置为玩家位置减15。
      ll.x = [player_ location].x - 15.0;
      ll.y = [player_ location].y - 15.0;
    2. 确保它不超过视图的边界。
      if (ll.x < 0.0)
          ll.x = 0.0;
      if (ll.y < 0.0)
          ll.y = 0.0;
      if (ll.x > [currentMap_ width] - 30.0)
          ll.x = [currentMap_ width] - 30.0;
      if (ll.y > [currentMap_ height] - 30.0)
          ll.y = [currentMap_ height] - 30.0;
    3. 乘以图块大小并设置为新边界原点。 位置.x=ll.x*20.0; 位置Y=ll.Y*20.0; [自我设置边界原点:位置];

    我也建议你不要硬编码瓷砖的大小和玩家的视线范围。

    对于图块大小,您可能希望为视图提供一些表示图块宽度和高度的属性,然后使用CTM缩放到 (widthInPoints / widthInTiles), (heightInPoints / heightInTiles) . 然后,您可以让用户调整窗口大小以更改平铺大小。

    对于玩家的视距(目前为30个方砖),你可能想让它成为玩家的一个属性,这样它可以随着技能数据、装备的物品以及药剂、怪物攻击和众神之怒的效果而改变。一个警告:如果玩家的视距超过游戏窗口的长度(尤其是垂直距离),你需要在上面的代码中添加一个检查,并通过放置玩家的死点并可能缩小来处理它。

        2
  •  1
  •   Rob Napier    15 年前

    我不清楚你想在这里做什么,但是效率非常非常低。你在打电话 setBoundsOrigin: 重复,这意味着只有最后一个调用实际上在做任何事情。将原点设置在 drawRect: 不会导致任何东西移动。一整段 牵引器: 如果您将此视为动画,则绘制单个“帧”。

    记住,你不负责绘制循环。 牵引器: 当框架决定需要绘制时由框架调用。您可以为框架提供各种提示(例如 setNeedsDisplay: 但最终是框架在需要时给你打电话。

    如果你的意图是动画,你将要阅读 Core Animation Programming Guide .它将讨论管理动画的非常简单和有效的方法。在屏幕上设置动画是可可的一大优势,非常复杂的事情可以很容易地完成。

        3
  •  0
  •   Peter Hosey    15 年前

    在某些情况下,最好是分开来做,而不是一劳永逸。

    对。有一个 drawBackgroundTile: 方法,也许是 drawItem: 方法与A drawPlayer: 方法,并在 drawRect: _“,它应该为级别绘制整个董事会。这是非基于层的解决方案。

    另一个,正如我在对Rob答案的评论中提到的,是使用核心动画。然后你就要砍了 牵引器: 总之,让视图宿主一个根层,其中包含平铺层,其中一些包含项目和演员(玩家/怪物/宠物)层。

    为什么会这样?

    因为它是一个合适的,高效的,可读的解决方案。