有两种方法。
一种是创建一个地图类Map,将其作为主要的JPanel,维护单位的集合,但保持Unit类为非Swing。当调用Map的paint()方法时,通过调用每个可见Unit中的一个方法来要求每个Unit重新绘制自身。在这种情况下,Unit类处理绘画和计算,而Map处理每个Unit的点击和事件。如果需要,它可以将消息传递给Unit;但是,如果单元本身不需要知道这些事情,那么这种方法就能很好地工作。Unit类轻巧而经济。您还可以决定Unit是否知道其在Map中的位置。
另一种方法是将每个单元作为一个JComponent,并单独处理其自己的事件。缺点是每个Unit实例都会为绘制占用大量数据。因此,如果有成百上千个单位,而只有几个被绘制出来,这样的效率并不高。优点是每个单元都可以处理自己的GUI事件,无需进行转换等操作。这也假设在游戏中实际单位与屏幕上的图形单位之间存在1:1的映射关系。如果一个Unit需要知道周围有哪些其他Units,某些事件处理程序在Unit中实现起来也比较棘手!
第三种方法是拥有一个纯数据的Unit类,包含有关单位的游戏信息,如(1)中所述,但该类具有在需要时创建JComponent的方法。例如,JComponent可以是Unit的内部类——它可以访问Unit的数据。如果一个单元需要在两个地方显示(例如,在2个屏幕或视图上),这种方法非常好。
补充以解决评论问题:
在第一种方法中,Map(主要的JPanel)实现了鼠标处理程序,并依次询问每个Unit是否被“点击”。这允许您执行更复杂的操作,例如,使两个单元重叠/位于顶部,并且两者都可以响应单击。
此外,例如,它们可能不是矩形的,或者可能用alpha通道绘制(如果Units是JComponents,则默认情况下会将其整个矩形上的任何鼠标事件捕获为自己的)。如果您的单元不重叠并且位于自己的矩形中,则JComponent自己的鼠标处理程序就足够了。
如果使用第一种方法,Map可以询问每个Unit是否包含一个被点击的点,然后Map可以处理“选择”过程。请记住,单独的单位将无法计算出其他单位是否被选择——选择可能涉及取消选择另一个单位。在这种情况下,选择操作实际上是Map操作,而不是Unit操作,尽管它也可能改变Unit的外观或功能。
如果您为单位使用单独的JComponents,您可以覆盖contains(Point)以确定鼠标是否命中该项,但这不会让其他单位也响应点击。但是每个单位都可以“选择自己”(设置在绘图时使用的标志),然后通知地图(它需要使用getParent或预设属性找到它)。
在决定此设计之前,您需要知道以下关键事项:
1. 每个游戏是否需要超过一个“地图”面板?
2. 是否需要显示的单位对象多于要显示的单位对象?
3. 是否需要多次显示单位?
如果答案是肯定的,建议按照3中所建议的将“数据”类与“视图”类分开。
接下来,一个单位需要“做什么”,以及为了做到这一点,它需要了解地图和其他单位的情况?例如,在这种情况下,移动通常由Map类完成,因为它取决于Map和其他单位;绘制最好由Unit完成,因为可能有许多具有不同数据结构的单位子类型需要绘制;正如您指出的那样,单位选择操作位于中间某处。如果您看看Swing如何实现这一点(例如ButtonGroup、ListSelectionModel),则“选择”本身可以被认为是一个单独的类。