Compare commits

...

2 Commits

Author SHA1 Message Date
Ian Burgmyer 046bbf4320 Added some basic collision properties to sprites. 5 years ago
Ian Burgmyer b8edb976f7 Unified the drawing routines. 5 years ago
  1. 2
      DotSDL/Graphics/Background.cs
  2. 11
      DotSDL/Graphics/Canvas.cs
  3. 147
      DotSDL/Graphics/SdlWindow.cs
  4. 52
      DotSDL/Graphics/Sprite.cs

2
DotSDL/Graphics/Background.cs

@ -30,7 +30,7 @@ namespace DotSDL.Graphics {
// TODO: Might be able to make this faster by leveraging memcpy(). Need to benchmark it.
unsafe {
var copySize = Width * Height * 4; // Width x Height at 4 bytes per pixel.
Render.LockTexture(Texture, IntPtr.Zero, out var pixels, out var _);
Render.LockTexture(Texture, IntPtr.Zero, out var pixels, out _);
Buffer.MemoryCopy(GetCanvasPointer().ToPointer(), pixels, copySize, copySize);
Render.UnlockTexture(Texture);
}

11
DotSDL/Graphics/Canvas.cs

@ -153,6 +153,17 @@ namespace DotSDL.Graphics {
}
}
/// <summary>
/// <c>true</c> if the <see cref="Canvas"/> should be drawn to the screen, otherwise <c>false</c>.
/// </summary>
public bool Shown { get; set; } = true;
/// <summary>
/// The order in which the canvas is drawn. Lower numbered <see cref="Canvas"/> instances are drawn first
/// and will appear on the bottom. This number can be negative.
/// </summary>
public int ZOrder { get; set; }
/// <summary>
/// Sets the section of the <see cref="Canvas"/> that should be drawn. If the size values are set to 0, the
/// <see cref="Canvas"/> will fill as much of its containing object as possible.

147
DotSDL/Graphics/SdlWindow.cs

@ -24,6 +24,8 @@ namespace DotSDL.Graphics {
private uint _nextVideoUpdate;
private uint _nextGameUpdate;
private List<Canvas> _drawList = new List<Canvas>();
private ScalingQuality _scalingQuality = ScalingQuality.Nearest;
/// <summary>Gets the background layer of this window. This is equivalent to accessing Layers[0].</summary>
@ -191,6 +193,7 @@ namespace DotSDL.Graphics {
BlendMode = BlendMode.None
}
};
Background.ZOrder = int.MinValue;
Background.CreateTexture();
CameraView = new Rectangle(
@ -240,20 +243,29 @@ namespace DotSDL.Graphics {
Render.SetRenderTarget(_renderer, _texture);
// Blit the background canvases to the target texture.
foreach(var canvas in Layers) {
canvas.Clipping.Position = CameraView.Position;
canvas.Clipping.Size = CameraView.Size;
canvas.UpdateTexture();
unsafe {
var canvasClippingRect = canvas.Clipping.SdlRect;
Render.RenderCopy(_renderer, canvas.Texture, new IntPtr(&canvasClippingRect), IntPtr.Zero);
// Sort all of the canvases, then draw them.
_drawList.Clear();
_drawList.AddRange(Layers.Where(l => l.Shown).ToArray());
_drawList.AddRange(Sprites.Where(s => s.Shown).ToArray());
foreach(var canvas in _drawList.OrderBy(layer => layer.ZOrder)) {
switch(canvas) {
case Sprite sprite:
DrawSprite(sprite);
break;
default:
canvas.Clipping.Position = CameraView.Position;
canvas.Clipping.Size = CameraView.Size;
canvas.UpdateTexture();
unsafe {
var canvasClippingRect = canvas.Clipping.SdlRect;
Render.RenderCopy(_renderer, canvas.Texture, new IntPtr(&canvasClippingRect), IntPtr.Zero);
}
break;
}
}
// Plot sprites on top of the background layer.
if(Sprites.Count > 0) DrawSprites();
Render.SetRenderTarget(_renderer, IntPtr.Zero);
Render.RenderCopy(_renderer, _texture, IntPtr.Zero, IntPtr.Zero);
@ -306,61 +318,58 @@ namespace DotSDL.Graphics {
}
/// <summary>
/// Plots the sprites stored in <see cref="Sprites"/> to the screen. Please note that this method is called by
/// DotSDL's drawing routines and does not need to be called manually. Additionally, this method will not be
/// called if there are no sprites defined. You usually do not need to override this method.
/// </summary>
public virtual void DrawSprites() {
Render.SetRenderTarget(_renderer, _texture);
foreach(var sprite in Sprites.Where(e => e.Shown).OrderBy(e => e.ZOrder)) {
var srcRect = sprite.Clipping.SdlRect;
var drawSize = sprite.DrawSize;
Rectangle dest;
Point rotationCenter;
if(sprite.CoordinateSystem == CoordinateSystem.ScreenSpace) {
dest = new Rectangle(sprite.Position, drawSize);
rotationCenter = sprite.RotationCenter;
} else {
// Create a set of world coordinates based on the position of the camera
// and this sprite.
var relPosition = new Point(sprite.Position - CameraView.Position);
var screenPosition = new Point(
(int)((float)relPosition.X / CameraView.Size.X * RenderWidth),
(int)((float)relPosition.Y / CameraView.Size.Y * RenderHeight)
);
var scaleFactorX = (float)RenderWidth / CameraView.Size.X;
var scaleFactorY = (float)RenderHeight / CameraView.Size.Y;
var size = new Point(
(int)(drawSize.X * scaleFactorX),
(int)(drawSize.Y * scaleFactorY)
);
dest = new Rectangle(screenPosition, size);
rotationCenter = new Point(
(int)(sprite.RotationCenter.X * scaleFactorX),
(int)(sprite.RotationCenter.Y * scaleFactorY)
);
}
/// Plots a sprite to the screen. Please note that this method is called by DotSDL's drawing
/// routines and does not need to be called manually. Additionally, this method will never be
/// called if there are no active sprites. You usually do not need to override this method.
/// </summary>
public virtual void DrawSprite(Sprite sprite) {
var srcRect = sprite.Clipping.SdlRect;
var drawSize = sprite.DrawSize;
Rectangle dest;
Point rotationCenter;
if(sprite.CoordinateSystem == CoordinateSystem.ScreenSpace) {
dest = new Rectangle(sprite.Position, drawSize);
rotationCenter = sprite.RotationCenter;
} else {
// Create a set of world coordinates based on the position of the camera
// and this sprite.
var relPosition = new Point(sprite.Position - CameraView.Position);
var screenPosition = new Point(
(int)((float)relPosition.X / CameraView.Size.X * RenderWidth),
(int)((float)relPosition.Y / CameraView.Size.Y * RenderHeight)
);
var scaleFactorX = (float)RenderWidth / CameraView.Size.X;
var scaleFactorY = (float)RenderHeight / CameraView.Size.Y;
var size = new Point(
(int)(drawSize.X * scaleFactorX),
(int)(drawSize.Y * scaleFactorY)
);
dest = new Rectangle(screenPosition, size);
rotationCenter = new Point(
(int)(sprite.RotationCenter.X * scaleFactorX),
(int)(sprite.RotationCenter.Y * scaleFactorY)
);
}
var destRect = dest.SdlRect;
var rotationCenterPoint = rotationCenter.SdlPoint;
unsafe {
var srcRectPtr = new IntPtr(&srcRect);
var destRectPtr = new IntPtr(&destRect);
var rotationCenterPtr = new IntPtr(&rotationCenterPoint);
Render.RenderCopyEx(
renderer: _renderer,
texture: sprite.Texture,
srcRect: srcRectPtr,
dstRect: destRectPtr,
angle: sprite.Rotation,
center: rotationCenterPtr,
flip: sprite.Flip
);
}
var destRect = dest.SdlRect;
var rotationCenterPoint = rotationCenter.SdlPoint;
unsafe {
var srcRectPtr = new IntPtr(&srcRect);
var destRectPtr = new IntPtr(&destRect);
var rotationCenterPtr = new IntPtr(&rotationCenterPoint);
Render.RenderCopyEx(
renderer: _renderer,
texture: sprite.Texture,
srcRect: srcRectPtr,
dstRect: destRectPtr,
angle: sprite.Rotation,
center: rotationCenterPtr,
flip: sprite.Flip
);
}
}
@ -486,17 +495,13 @@ namespace DotSDL.Graphics {
/// <summary>
/// Displays the window and begins executing code that's associated with it.
/// </summary>
public void Start() {
Start(0, 0);
}
public void Start() => Start(0, 0);
/// <summary>
/// Displays the window and begins executing code that's associated with it.
/// </summary>
/// <param name="updateRate">The desired number of milliseconds between frames and game logic updates. 0 causes the display and game to be continuously updated.</param>
public void Start(uint updateRate) {
Start(updateRate, updateRate);
}
public void Start(uint updateRate) => Start(updateRate, updateRate);
/// <summary>
/// Displays the window and begins executing code that's associated with it.

52
DotSDL/Graphics/Sprite.cs

@ -9,6 +9,8 @@ namespace DotSDL.Graphics {
public class Sprite : Canvas {
private readonly Point _effectiveSize = new Point();
private Vector2<float> _scale;
private bool _collisionBoxSet;
private Rectangle _collisionBox;
/// <summary>
/// The position on the screen where the <see cref="Sprite"/> should be drawn.
@ -41,6 +43,9 @@ namespace DotSDL.Graphics {
_scale = value;
_effectiveSize.X = (int)(Width * _scale.X);
_effectiveSize.Y = (int)(Height * _scale.Y);
if(!_collisionBoxSet)
_collisionBox = new Rectangle(new Point(0, 0), _effectiveSize);
}
}
@ -84,15 +89,20 @@ namespace DotSDL.Graphics {
public CoordinateSystem CoordinateSystem { get; set; } = CoordinateSystem.WorldSpace;
/// <summary>
/// <c>true</c> if the sprite should be drawn to the screen, otherwise <c>false</c>.
/// Gets or sets the size and position of the collision box for this <see cref="Sprite"/>.
/// </summary>
public bool Shown { get; set; }
public Rectangle CollisionBox {
get => _collisionBox;
set {
_collisionBox = value;
_collisionBoxSet = true;
}
}
/// <summary>
/// The order in which the sprite is drawn. Lower numbered <see cref="Sprite"/> instances are drawn first
/// and will appear on the bottom.
/// Gets or sets whether or not collision calculations are performed on this <see cref="Sprite"/>.
/// </summary>
public int ZOrder { get; set; }
public bool HasCollision { get; set; }
/// <summary>
/// Initializes a new <see cref="Sprite"/>.
@ -174,6 +184,35 @@ namespace DotSDL.Graphics {
(int)(Clipping.Size.Y * _scale.Y / 2)
);
/// <summary>
/// Determines whether or not a given point collides with this <see cref="Sprite"/>. By default
/// this will test the point against the sprite's <see cref="CollisionBox"/>, but this method
/// can be overridden.
/// </summary>
/// <param name="point">The <see cref="Point"/> to check.</param>
/// <returns><c>true</c> if this object's collision is enabled and this sprite's collision
/// routine determines that the given pixel collides with the sprite, otherwise <c>false</c>.</returns>
public virtual bool CheckCollision(Point point) {
if(!HasCollision) return false;
return point.X >= CollisionBox.Position.X + Position.X
&& point.X <= CollisionBox.Position.X + CollisionBox.Size.X + Position.X
&& point.Y >= CollisionBox.Position.Y + Position.Y
&& point.Y <= CollisionBox.Position.Y + CollisionBox.Size.Y + Position.Y;
}
/// <summary>
/// Determines whether or not a given point collides with this <see cref="Sprite"/>. By default
/// this will test the point against the sprite's <see cref="CollisionBox"/>. If you wish to
/// override this sprite's collision routine, override the <see cref="CheckCollision(DotSDL.Graphics.Point)"/>
/// method instead.
/// </summary>
/// <param name="x">The X coordinate of the point to check.</param>
/// <param name="y">The Y coordinate of the point to check.</param>
/// <returns><c>true</c> if this object's collision is enabled and this sprite's collision
/// routine determines that the given pixel collides with the sprite, otherwise <c>false</c>.</returns>
public bool CheckCollision(int x, int y) => CheckCollision(new Point(x, y));
/// <inheritdoc/>
internal override void CreateTexture() {
CreateTexture(Render.TextureAccess.Static);
@ -184,7 +223,8 @@ namespace DotSDL.Graphics {
/// <see cref="Canvas.Pixels"/> array is changed after adding this sprite to the sprite list associated
/// with the application's <see cref="SdlWindow"/>.
/// </summary>
/// <returns><c>true</c> if the texture was successfully updated, otherwise <c>false</c>. This will return <c>false</c> if this <see cref="Sprite"/> hasn't been added to the sprite list.</returns>
/// <returns><c>true</c> if the texture was successfully updated, otherwise <c>false</c>. This will return
/// <c>false</c> if this <see cref="Sprite"/> hasn't been added to the sprite list.</returns>
public new bool UpdateTexture() {
return base.UpdateTexture();
}

Loading…
Cancel
Save