如何实现Entity类中position与tile_position属性的联动更新?
双向联动position与tile_position的优雅实现方案
核心思路是给通用的Vector类添加可选的分量变化回调,让Entity类监听两个Vector的变化,在回调中完成双向同步,同时通过标志位避免循环更新。
1. 修改Vector类,添加变化回调
给Vector增加一个on_change可选参数,当x/y分量修改时触发该回调,确保Vector仍保持通用属性,无需持有Entity引用:
class Vector: def __init__(self, x=0, y=0, on_change=None): self._x = x self._y = y self.on_change = on_change # 分量变化时触发的回调 @property def x(self): return self._x @x.setter def x(self, value): if self._x != value: self._x = value if self.on_change: self.on_change(self) @property def y(self): return self._y @y.setter def y(self, value): if self._y != value: self._y = value if self.on_change: self.on_change(self) def __repr__(self): return f"Vector({self.x}, {self.y})"
2. 实现Entity类的双向同步逻辑
在Entity中维护两个Vector实例,分别绑定回调函数,通过_updating标志避免循环更新,同时覆盖直接赋值整个属性和修改分量两种场景:
def tile_to_position(entity, x, y): return (x + entity.tile_width / 2, y + entity.tile_height / 2) def position_to_tile(entity, x, y): return (round(x - entity.tile_width / 2), round(y - entity.tile_height / 2)) class Entity: def __init__(self, tile_width=1, tile_height=1): self.tile_width = tile_width self.tile_height = tile_height self._updating = False # 防止循环更新的锁标志 # 初始化两个Vector,绑定各自的变化回调 self._position = Vector(on_change=self._on_position_change) self._tile_position = Vector(on_change=self._on_tile_position_change) # 初始同步位置 self._sync_position_to_tile() def _on_position_change(self, _): if not self._updating: self._updating = True self._sync_position_to_tile() self._updating = False def _on_tile_position_change(self, _): if not self._updating: self._updating = True self._sync_tile_to_position() self._updating = False def _sync_position_to_tile(self): # 根据position计算并更新tile_position tile_x, tile_y = position_to_tile(self, self._position.x, self._position.y) self._tile_position.x = tile_x self._tile_position.y = tile_y def _sync_tile_to_position(self): # 根据tile_position计算并更新position pos_x, pos_y = tile_to_position(self, self._tile_position.x, self._tile_position.y) self._position.x = pos_x self._position.y = pos_y @property def position(self): return self._position @position.setter def position(self, value): if not self._updating: self._updating = True self._position.x = value.x self._position.y = value.y self._sync_position_to_tile() self._updating = False @property def tile_position(self): return self._tile_position @tile_position.setter def tile_position(self, value): if not self._updating: self._updating = True self._tile_position.x = value.x self._tile_position.y = value.y self._sync_tile_to_position() self._updating = False
3. 额外优化:支持tile_width/tile_height动态修改
如果需要在运行时修改tile尺寸后自动同步位置,可以给tile_width和tile_height添加setter:
class Entity: # ... 保留其他代码 ... def __init__(self, tile_width=1, tile_height=1): self._tile_width = tile_width self._tile_height = tile_height # ... 保留其他初始化代码 ... @property def tile_width(self): return self._tile_width @tile_width.setter def tile_width(self, value): if self._tile_width != value: self._tile_width = value if not self._updating: self._updating = True self._sync_position_to_tile() self._updating = False @property def tile_height(self): return self._tile_height @tile_height.setter def tile_height(self, value): if self._tile_height != value: self._tile_height = value if not self._updating: self._updating = True self._sync_position_to_tile() self._updating = False
方案优势
- Vector保持通用性:回调是可选参数,不影响
Vector在其他场景的使用,也不会产生循环引用。 - 全场景覆盖:无论是直接赋值整个
position/tile_position,还是修改它们的x/y分量,都能触发双向同步。 - 避免循环更新:通过
_updating标志阻断回调的循环触发,防止死循环。 - 扩展性强:可以轻松扩展支持tile尺寸动态修改等需求。
内容的提问来源于stack exchange,提问作者RedRuin
相关产品推荐
相关产品推荐

