XNA 2D 鼠标拾取
我正在使用 XNA 开发一个简单的 2D 实时策略游戏。现在我已经达到了这样的程度:我需要能够单击单元或建筑物的精灵,并能够引用与该精灵关联的对象。 从我过去三天所做的研究中,我发现了许多关于如何在 3D 中进行“鼠标拾取”的参考,但这似乎不适用于我的情况。 我知道另一种方法是简单地拥有世界上所有“可选”对象的数组,当玩家单击精灵时,它会根据数组中所有对象的位置检查鼠标位置。我使用这种方法的问题是,如果单位和建筑物的数量增加到更多,它会变得相当慢。 (它看起来也不是很优雅)那么我还有什么其他方法可以做到这一点。 (请注意,我还研究了使用哈希表将对象与精灵位置关联起来,并使用二维数组的想法,其中数组中的每个位置代表世界上的一个像素。再次,它们看起来更像是笨拙的做事方式。)
I'm working on a simple 2D Real time strategy game using XNA. Right now I have reached the point where I need to be able to click on the sprite for a unit or building and be able to reference the object associated with that sprite.
From the research I have done over the last three days I have found many references on how to do "Mouse picking" in 3D which does not seem to apply to my situation.
I understand that another way to do this is to simply have an array of all "selectable" objects in the world and when the player clicks on a sprite it checks the mouse location against the locations of all the objects in the array. the problem I have with this approach is that it would become rather slow if the number of units and buildings grows to larger numbers. (it also does not seem very elegant) so what are some other ways I could do this. (Please note that I have also worked over the ideas of using a Hash table to associate the object with the sprite location, and using a 2 dimensional array where each location in the array represents one pixel in the world. once again they seem like rather clunky ways of doing things.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于多达数百个单位,如果点击区域是圆形或矩形,那么它应该足够快,可以简单地对世界上的所有单位进行线性搜索 O(n)。特别是每次点击一次,而不是每帧一次。
如果您的单位不是圆形或矩形,请首先检查边界圆或矩形,如果通过,则检查更复杂的边界形状。
有关更详细的答案,这是我对有关空间分区的类似问题的回答。在那里我提到了桶状网格和四叉树作为性能优化的潜在结构。
但是,在经过测试并且确实确实存在性能问题之前,永远不要进行性能优化!
For up to hundreds of units, it should be fast enough to simply do a linear search O(n) over all the units in the world if the click regions are circles or rectangles. Especially seeing as it will be once per click, not once per frame.
If your units are not circular or rectangular, check against a bounding circle or rectangle first, and if that passes check against the more complicated bounding shape.
For a more detailed answer, here's my answer to a similar question about space partitioning. There I mention bucketed grids and quadtrees as potential structures for performance optimisation.
But you should never do performance optimisation until you have tested and actually do have a performance problem!
如果您有一个管理 Drawabel 对象的类,则可以有一个静态 int,每次创建新对象时都会增加该静态 int,并将旧对象保存为 Drawabel 对象中 Color 的本地实例。然后,您可以使用 .Net 类型转换器将其转换为再见数组并返回,不记得它的名称,我在火车上使用手机,所以恐怕无法为您检查。
当您从字节数组构建颜色时,只需记住最大化 Alpha 通道,如果您碰巧获得太多对象,您可能会超出可以使用的索引.. 不知道该怎么办... 可能拥有所有对象再次从 0:0:0:255 开始重新获取新颜色,因为希望一些旧颜色不再使用:P
不确定我说得有多大意义,但因为我在火车上,这就是我能给你的一切,抱歉:)
If you have a class that manages drawabel objects you could have a static int that you increase every time you make a new object, and save the old one as a local instance of Color in the drawabel object. You can then use the .Net type converter to make its to bye arrays and back, dont remember its name and im on my phoneon a train so can't check for you im afraid.
When you build the color from the byte array just remember to max the alpha channel, and if you happen to get too many objects you might overrun the indexes you can use.. not sure what to do then... probably have all your objects reaquire new colors from 0:0:0:255 again since hopefully some old ones are no longer in use :P
Not sure i made alot of sense but since im on a train thats all i can give you, sorry :)
您可以使用像素完美拾取,它可以很好地扩展到大量对象(并且具有像素完美的优点)。
本质上,您使用每个对象的唯一颜色来渲染场景。然后将后备缓冲区解析为纹理并获取纹理数据,最后您可以简单地检查鼠标下方的像素并找出鼠标所在的对象。
您可以巧妙地处理返回的信息,您可以仅请求鼠标所在的单个像素。
您应该小心,不要通过执行此操作来停止管道(导致 CPU 等待 GPU 渲染内容)。做到这一点的最佳方法是在 2 个渲染目标之间交换,并且始终从上一帧使用的渲染目标获取数据,这意味着数据是过时的帧,但没有人有足够快的反应来注意到。
针对您的评论的附录。
要为每个对象分配唯一的颜色,只需为每个对象增加一个字节即可。当该字节溢出时,增加另一个字节,当该字节溢出时增加另一个字节;然后您可以将这三个字节用作红色、绿色和蓝色。请记住将 alpha 保持在最大值,您不希望看到任何物体!
为了解决后备缓冲区问题,XNA4 中略有更改。现在您必须渲染到渲染目标并解决该问题。要做到这一点非常简单,Shawn Hargreaves 概述了 此处
You could use pixel perfect picking, which scales very well to massive numbers of objects (and has the advantage of being pixel perfect).
Essentially you render your scene using a unique colour for each object. Then you resolve the backbuffer into a texture and get the texture data back, finally you can simply check the pixel underneath the mouse and find out which object the mouse is on.
You can be clever about the information you get back, you can request just the single pixel the mouse is on top of.
You should be careful not to stall the pipeline by doing this (causing the CPU to wait for the GPU to render things). The best way to do this is to swap between 2 render targets, and always GetData from the render target you used last frame, this means the data is a frame out of date, but no human has fast enough reactions to notice.
Addendum in response to your comment.
To assign a unique colour to each object, simply increment a byte for each object. When that byte overflows, increment another, and when that one overflows increment another; Then you can use those three bytes as Red, Green and Blue. Remeber to keep alpha at max value, you don't want any see through objects!
To resolve the backbuffer is slightly changed in XNA4. Now you must render to a rendertarget and resolve that. To do this is pretty simple, and outlined by Shawn Hargreaves here