1using System.Collections.ObjectModel;
4using System.Runtime.Serialization;
18 private readonly List<Sprite> _children =
new();
39 foreach (var sprite
in sprites)
52 private void OnDeserialized(StreamingContext context)
54 foreach (var sprite
in _children)
55 sprite.Disposing += sprite_Disposing;
60 #region IMovable / IMovableOnSceneLayer
77 if (_children.Count == 0)
78 throw new InvalidOperationException(
"CompositeSprite has no children; SceneLayer is undefined.");
81 return _children[0].SceneLayer;
93 if (r == Rectangle.Empty)
100 r.Left + (r.Width / 2f),
101 r.Top + (r.Height / 2f)),
102 _ =>
new PointF(r.Left, r.Top)
105 PointF anchorGrid =
SceneLayer.WorldPxToGrid(anchorWorldPx);
106 return new Vector2(anchorGrid.X, anchorGrid.Y);
116 Vector2 delta = pos - oldAnchor;
118 if (delta == Vector2.Zero || _children.Count == 0)
123 foreach (var sprite
in _children)
125 Vector2 childPos = GetSpritePosition(sprite);
126 sprite.SetPosition(childPos + delta);
136 if (delta == Vector2.Zero)
142 #endregion IMovable / IMovableOnSceneLayer
154 if (sprite is
null)
throw new ArgumentNullException(nameof(sprite));
155 if (_children.Contains(sprite))
return;
157 EnforceSameSceneLayer(sprite);
159 sprite.Disposing += sprite_Disposing;
160 _children.Add(sprite);
172 if (sprite is
null)
throw new ArgumentNullException(nameof(sprite));
173 if (_children.Contains(sprite))
return;
175 EnforceSameSceneLayer(sprite);
177 sprite.Disposing += sprite_Disposing;
178 _children.Add(sprite);
193 if (sprite is
null)
throw new ArgumentNullException(nameof(sprite));
194 if (_children.Contains(sprite))
return;
196 EnforceSameSceneLayer(sprite);
201 if (_children.Count == 0)
203 sprite.Disposing += sprite_Disposing;
204 _children.Add(sprite);
206 Vector2 firstPos = GetSpritePosition(sprite);
207 Vector2 target = firstPos + offsetFromCompositeAnchor;
209 if (offsetFromCompositeAnchor != Vector2.Zero)
226 if (sprite is
null)
return;
227 if (!_children.Contains(sprite))
return;
229 sprite.Disposing -= sprite_Disposing;
230 _children.Remove(sprite);
233 private void sprite_Disposing(
Sprite sprite)
235 sprite.Disposing -= sprite_Disposing;
236 _children.Remove(sprite);
239 private void EnforceSameSceneLayer(Sprite sprite)
241 if (_children.Count == 0)
244 if (!ReferenceEquals(sprite.SceneLayer, _children[0].SceneLayer))
245 throw new InvalidOperationException(
"All sprites in a CompositeSprite must belong to the same SceneLayer.");
248 private static Vector2 GetSpritePosition(Sprite sprite)
252 PointF p = sprite.SceneLayerCoordinates;
253 return new Vector2(p.X, p.Y);
264 public ReadOnlyCollection<Sprite>
Children => _children.AsReadOnly();
275 if (_children.Count == 0)
276 return Rectangle.Empty;
278 int minX =
int.MaxValue;
279 int minY =
int.MaxValue;
280 int maxX =
int.MinValue;
281 int maxY =
int.MinValue;
283 foreach (var sprite
in _children)
285 var r = sprite.DrawLocationWorld;
287 if (r.Left < minX) minX = r.Left;
288 if (r.Top < minY) minY = r.Top;
289 if (r.Right > maxX) maxX = r.Right;
290 if (r.Bottom > maxY) maxY = r.Bottom;
293 return Rectangle.FromLTRB(minX, minY, maxX, maxY);
297 #endregion properties
Vector2 GetPosition()
Gets the current position of the composite sprite in scene-layer grid coordinates,...
void AddChildWithOffset(Sprite sprite, Vector2 offsetFromCompositeAnchor)
Add a sprite and place it by offset from the composite anchor. Offset is interpreted in grid coordina...
SceneLayer SceneLayer
Gets the scene layer that all child sprites belong to.
void Translate(Vector2 delta)
Translates the composite sprite by the specified delta vector.
void SetPosition(Vector2 pos)
Sets the position of the composite sprite by moving all child sprites to maintain their relative posi...
ReadOnlyCollection< Sprite > Children
Gets a read-only collection of all child sprites in this composite.
CompositeSprite(params Sprite[] sprites)
Initializes a new instance of the CompositeSprite class with the specified array of sprites.
CompositeSprite(List< Sprite > sprites)
Initializes a new instance of the CompositeSprite class with the specified list of sprites.
void AddChildAtPosition(Sprite sprite, Vector2 absolutePosition)
Add a sprite and place it at an absolute position (in the composite's PositionSpace).
Rectangle Range
Gets the bounding rectangle that encompasses all child sprites. Returns Rectangle....
void Remove(Sprite sprite)
Removes a sprite from this composite.
CompositeAnchorMode AnchorMode
Gets or sets the anchor mode that determines how the composite's position is calculated relative to i...
void Add(Sprite sprite)
Adds an existing sprite at its current position (no reposition).
MovementSpace PositionSpace
Gets the movement space used for positioning this composite sprite.
CompositeSprite()
Initializes a new instance of the CompositeSprite class.
Represents a movable visual element on a scene layer.
void SetPosition(Vector2 pos)
Sets the sprite position in scene-layer grid coordinates and invalidates its old and new bounds.
Implemented by grid-space IMovable objects that belong to a specific Scenes.SceneLayer.
CompositeAnchorMode
Defines the anchor mode for a composite sprite, determining how its position is calculated.
@ Center
The anchor is at the center of the bounding rectangle.
@ TopLeft
The anchor is at the top-left corner of the bounding rectangle.
MovementSpace
Specifies the coordinate system used for movement calculations and updates.