我想当我第一次开始设计我的游戏时我犯了一个巨大的错误,我会给你我的部分甚至全部代码,但它太复杂了。所以请多多包涵。
现在我进入了更高级的设计阶段,我在线程方面遇到了很大的麻烦。
在更新期间,我同时运行 3 个任务。更新、HitTesting 和 AI 甚至被拆分为更多线程。
- 更新需要对我的所有对象进行移动(包括物理)和动画。
- HitTesting 在数千个对象之间进行所有 Hit 测试,但仍需要大量优化……。诸如分而治之之类的事情是正确的。
- AI 向更新周期执行的对象发出命令。像左转或右转,火灾等。
当然我们有
- 绘制……或者在我的情况下,绘制期间的 GetSprites。除了更新过程之外,它必须具有所有优先级。
- 还有尚未实现的声音和信息系统。
正如您所看到的,这不是多任务处理的最佳过程,因为它们都在相同的对象上运行,但它必须如此。
所以……我想实现 System.Threading.ReaderWriterLockSlim
这是我真正的问题:我该怎么做?
- 因为更新是我绘制数据的唯一作者。
- 绘图是一个纯粹的阅读器
- HitTesting 可能需要重新计算 boundingRectangle 和 Matrix 但这不会影响绘图
- AI 只需要读取位置数据并发出命令,在下一个周期由 Update 读取并被分隔在一组单独的类中(我称之为 master/puppet,但可能有一个官方/更好的名称)
实现不同的 ReaderWriterLockSlim 对象来锁定线程可能需要的不同属性是否有意义?
我想在更新期间进行控制以绕过锁定的对象(通过 AI 或 HitTesting)并获取下一个对象,以便稍后在解锁时进行操作(或者如果更新花费的时间太长,甚至可以跳过它,但要这样做在下一个周期)
你们中有人知道有关高级线程的书籍或网站吗?不是我到处都能找到的常见小例子,所以我可以弄清楚吗?
我已经被困了一个多星期了,我想继续。
任何帮助表示赞赏。
这是我用于对象之间的碰撞检测的代码。我从很久以前找到的 c++ 示例转换它,但不记得在哪里。
public abstract class HitTestInfo : Object
{
static protected Random RND = new Random();
static protected Dictionary<String, Color[]> m_TextureDataDictionary;
public static Matrix GetMatrix(iSpriteInfo vDrawObject)
{
Matrix Transform =
Matrix.CreateTranslation(new Vector3(-vDrawObject.Origin, 0.0f)) *
Matrix.CreateScale(vDrawObject.Scale) *
Matrix.CreateRotationZ(vDrawObject.Angle) *
Matrix.CreateTranslation(new Vector3(vDrawObject.X, vDrawObject.Y, 0.0f));
return Transform;
}
/// <summary>
/// Calculates an axis aligned rectangle which fully contains an arbitrarily
/// transformed axis aligned rectangle.
/// </summary>
/// <param name="rectangle">Original bounding rectangle.</param>
/// <param name="transform">World transform of the rectangle.</param>
/// <returns>A new rectangle which contains the trasnformed rectangle.</returns>
public static Rectangle CalculateBoundingRectangle(Rectangle vrectangle,
Matrix transform)
{
Rectangle rectangle = vrectangle;
rectangle.X = 0;
rectangle.Y = 0;
// Get all four corners in local space
Vector2 leftTop = new Vector2(rectangle.Left, rectangle.Top);
Vector2 rightTop = new Vector2(rectangle.Right, rectangle.Top);
Vector2 leftBottom = new Vector2(rectangle.Left, rectangle.Bottom);
Vector2 rightBottom = new Vector2(rectangle.Right, rectangle.Bottom);
// Transform all four corners into work space
Vector2.Transform(ref leftTop, ref transform, out leftTop);
Vector2.Transform(ref rightTop, ref transform, out rightTop);
Vector2.Transform(ref leftBottom, ref transform, out leftBottom);
Vector2.Transform(ref rightBottom, ref transform, out rightBottom);
// Find the minimum and maximum extents of the rectangle in world space
Vector2 min = Vector2.Min(Vector2.Min(leftTop, rightTop),
Vector2.Min(leftBottom, rightBottom));
Vector2 max = Vector2.Max(Vector2.Max(leftTop, rightTop),
Vector2.Max(leftBottom, rightBottom));
// Return that as a rectangle
return new Rectangle((int)min.X, (int)min.Y,
(int)(max.X - min.X), (int)(max.Y - min.Y));
}
/// <summary>
/// Determines if there is overlap of the non-transparent pixels between two
/// sprites.
/// </summary>
/// <param name="transformA">World transform of the first sprite.</param>
/// <param name="widthA">Width of the first sprite's texture.</param>
/// <param name="heightA">Height of the first sprite's texture.</param>
/// <param name="dataA">Pixel color data of the first sprite.</param>
/// <param name="transformB">World transform of the second sprite.</param>
/// <param name="widthB">Width of the second sprite's texture.</param>
/// <param name="heightB">Height of the second sprite's texture.</param>
/// <param name="dataB">Pixel color data of the second sprite.</param>
/// <returns>True if non-transparent pixels overlap; false otherwise</returns>
public static bool IntersectPixels(
Matrix transformA, int widthA, int heightA, Color[] dataA,
Matrix transformB, int widthB, int heightB, Color[] dataB)
{
// Calculate a matrix which transforms from A's local space into
// world space and then into B's local space
Matrix transformAToB = transformA * Matrix.Invert(transformB);
// When a point moves in A's local space, it moves in B's local space with a
// fixed direction and distance proportional to the movement in A.
// This algorithm steps through A one pixel at a time along A's X and Y axes
// Calculate the analogous steps in B:
Vector2 stepX = Vector2.TransformNormal(Vector2.UnitX, transformAToB);
Vector2 stepY = Vector2.TransformNormal(Vector2.UnitY, transformAToB);
// Calculate the top left corner of A in B's local space
// This variable will be reused to keep track of the start of each row
Vector2 yPosInB = Vector2.Transform(Vector2.Zero, transformAToB);
// For each row of pixels in A
for (int yA = 0; yA < heightA; yA++)
{
// Start at the beginning of the row
Vector2 posInB = yPosInB;
// For each pixel in this row
for (int xA = 0; xA < widthA; xA++)
{
// Round to the nearest pixel
int xB = (int)Math.Round(posInB.X);
int yB = (int)Math.Round(posInB.Y);
// If the pixel lies within the bounds of B
if (0 <= xB && xB < widthB &&
0 <= yB && yB < heightB)
{
// Get the colors of the overlapping pixels
Color colorA = dataA[xA + yA * widthA];
Color colorB = dataB[xB + yB * widthB];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
// Move to the next pixel in the row
posInB += stepX;
}
// Move to the next row
yPosInB += stepY;
}
// No intersection found
return false;
}
public static List<CollisionData> CollisionCheck<T1, T2>(List<T1> List1, List<T2> List2)
{
List<CollisionData> RetList = new List<CollisionData>();
foreach (T1 obj1 in List1)
{
iSpriteInfo SI1 = obj1 as iSpriteInfo;
if (SI1 != null)
{
Matrix Matrix1 = SI1.Matrix;
Rectangle Rect1 = SI1.BoundingRectangle;
Color[] TextureData1 = SI1.TextureData;
foreach (T2 obj2 in List2)
{
iSpriteInfo SI2 = obj2 as iSpriteInfo;
if (SI1 != null)
{
Matrix Matrix2 = SI2.Matrix;
Rectangle Rect2 = SI2.BoundingRectangle;
Color[] TextureData2 = SI2.TextureData;
// The per-pixel check is expensive, so check the bounding rectangles
// first to prevent testing pixels when collisions are impossible.
if (Rect1.Intersects(Rect2))
{
// Check collision with Player and planets
if (IntersectPixels(Matrix1, (int)SI1.DestinationRectangle.Width,
(int)SI1.DestinationRectangle.Height, TextureData1,
Matrix2, (int)SI2.DestinationRectangle.Width,
(int)SI2.DestinationRectangle.Height, TextureData2))
{
RetList.Add(new CollisionData(SI1, SI2));
}
}
}
}
}
}
return RetList;
}
public static List<CollisionData> CollisionCheck<T1, T2>(T1 Obj1, List<T2> List2)
{
List<CollisionData> RetList = new List<CollisionData>();
lock (Obj1)
{
lock (List2)
{
iSpriteInfo SI1 = Obj1 as iSpriteInfo;
if (SI1 != null)
{
Matrix Matrix1 = SI1.Matrix;
Rectangle Rect1 = SI1.BoundingRectangle;
Color[] TextureData1 = SI1.TextureData;
foreach (T2 obj2 in List2)
{
iSpriteInfo SI2 = obj2 as iSpriteInfo;
if (SI1 != null)
{
Matrix Matrix2 = SI2.Matrix;
Rectangle Rect2 = SI2.BoundingRectangle;
Color[] TextureData2 = SI2.TextureData;
// The per-pixel check is expensive, so check the bounding rectangles
// first to prevent testing pixels when collisions are impossible.
if (Rect1.Intersects(Rect2))
{
// Check collision with Player and planets
if (IntersectPixels(Matrix1, (int)SI1.DestinationRectangle.Width,
(int)SI1.DestinationRectangle.Height, TextureData1,
Matrix2, (int)SI2.DestinationRectangle.Width,
(int)SI2.DestinationRectangle.Height, TextureData2))
{
RetList.Add(new CollisionData(SI1, SI2));
}
}
}
}
}
}
}
return RetList;
}
public static bool CollisionCheck<T1, T2>(T1 Obj1, T2 Obj2)
{
Matrix Matrix1;
Rectangle Rect1;
Color[] TextureData1;
Matrix Matrix2;
Rectangle Rect2;
Color[] TextureData2;
iSpriteInfo SI1 = Obj1 as iSpriteInfo;
if (SI1 != null)
{
lock (SI1)
{
Matrix1 = SI1.Matrix;
Rect1 = SI1.BoundingRectangle;
TextureData1 = SI1.TextureData;
}
iSpriteInfo SI2 = Obj2 as iSpriteInfo;
if (SI1 != null)
{
lock (SI2)
{
Matrix2 = SI2.Matrix;
Rect2 = SI2.BoundingRectangle;
TextureData2 = SI2.TextureData;
}
// The per-pixel check is expensive, so check the bounding rectangles
// first to prevent testing pixels when collisions are impossible.
if (Rect1.Intersects(Rect2))
{
// Check collision with Player and planets
if (IntersectPixels(Matrix1, (int)SI1.DestinationRectangle.Width,
(int)SI1.DestinationRectangle.Height, TextureData1,
Matrix2, (int)SI2.DestinationRectangle.Width,
(int)SI2.DestinationRectangle.Height, TextureData2))
{
return true;
}
}
}
}
return false;
}
}
iSpriteInfo 是这样定义的
public interface iSpriteInfo
{
float X { get; set; }
float Y { get; set; }
float Angle { get; set; }
Vector2 Origin { get; set; }
float Scale { get; set; }
float Depth { get; set; }
Color Color { get; set; }
Boolean Visible { get; set; }
Rectangle SourceRectangle { get; set; }
Rectangle DestinationRectangle { get; set; }
Rectangle BoundingRectangle { get; }
Matrix Matrix { get; }
SpriteSheet SpriteSheet { get; set; }
int SpriteSheetNum { get;}
Color[] TextureData { get; set; }
Vector2 GetVector2 { get; }
Vector3 GetVector3 { get; }
}