使用播放器移动NSView边界的更好方法是什么?

时间:2009-07-23 22:03:53

标签: objective-c cocoa refactoring nsview

目前正在编写roguelike以了解有关Objective-C / Cocoa的更多信息。到目前为止,我真的非常喜欢它,而且我已经学到了很多东西。

此代码会移动视图origin的{​​{1}},以便在移动时跟随玩家。代码工作得很完美,我只是问是否有比使用四个bounds更好的方法。

在某些情况下,我也看到最好单独做事而不是一体做事,特别是在绘图和for时,为什么会这样?

编辑:人们无法弄清楚我到底在做什么,所以我会尽可能地将其分解。

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

首先,您获得view以及[player_ location] origin的{​​{1}}。它除以bounds,因为图块大小为view,因此当它位于20时,它实际上位于20,。我这样做的唯一原因是使操作更容易(以1为单位而不是以20为单位计算更容易)。这四个(1,2)会检查(20,40)是否在for中心[player_ location]的{​​{1}}个区块内。如果玩家正朝着屏幕的一个边缘移动,并且15小于当前地图/宽度的高度,则移动bounds + 15以使玩家仍然居中并显示在地图。

代码工作得很完美,我在view发生后将bounds.x/y + 30移动到了,而且只有一个。它没有留在origin,我只是在这里尝试找出我需要做的事情。它现在位于它自己的位置,只有在玩家实际移动时才会被调用。

这是新代码:

setbounds

以下是行动中的照片!

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

图2:3个金币表示玩家在视图绑定之前可以移动多远.sigin将移动以保持在玩家中心。虽然无关紧要,但请注意,玩家实际上无法看到黄金。结果编程视野是一个备受争议的领域,你可以使用几种不同的算法,没有一种没有缺点,或者已经移植到Objective-C。目前它只是一个广场。透过墙壁和一切看到。 http://sneakyness.com/stackoverflow/SRLbounds2.png

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

3 个答案:

答案 0 :(得分:1)

我不清楚你在这里要做什么,但这非常非常低效。你反复调用setBoundsOrigin:,这意味着只有最后一次调用实际上正在做任何事情。在drawRect:中间设置原点不会导致任何移动。如果您将此视为动画,整个drawRect:会绘制一个“框架”。

请记住,您不负责绘图循环。框架在确定需要绘图时会调用drawRect:。您可以为框架提供各种提示(例如setNeedsDisplay:),但最终它是在需要时调用您的框架。

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

答案 1 :(得分:1)

  

它现在位于它自己的位置,仅在玩家实际移动时被调用。

耶!

  

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

这是我的建议:

  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. 乘以您的图块大小并设置为新边界原点。 location.x = ll.x * 20.0; location.y = ll.y * 20.0; [self setBoundsOrigin:location];
  4. 我还建议您不要硬编码磁贴大小和播放器视距。

    对于图块大小,您可能更喜欢为视图提供表示图块中宽度和高度的几个属性,然后使用CTM缩放到(widthInPoints / widthInTiles), (heightInPoints / heightInTiles)。然后,您可以让用户调整窗口大小以更改切片大小。

    对于玩家的视线范围(目前30平方米),你可能想让它成为玩家的属性,这样它就可以随着技能统计,配备物品以及魔药,怪物攻击和愤怒的效果而改变众神之物。需要注意的一点是:如果玩家的视线范围可以比游戏窗口更适合(特别是垂直方向),你需要在上面的代码中添加一个检查,并通过将玩家设置为死中心并可能进行缩放来处理它进行。

答案 2 :(得分:0)

  

在某些情况下......最好单独进行,而不是一次性...

是。使用drawBackgroundTile:方法,可能是drawItem:方法和drawPlayer:方法,并在drawRect:中的循环中调用它们 - 这应该绘制整个电路板。这是非基于层的解决方案。

正如我在Rob的回答评论中所指出的那样,另一个是使用Core Animation。然后,您将完全取消drawRect:,并让您的视图托管一个根图层,其中包含图块图层,其中一些图层将包含项目和演员(玩家/怪物/宠物)图层。

  

为什么?

因为它是一种适当,高效且易读的解决方案。