public int Points; // how many points the block awards when destroyed #endregion Fields #region Constructors // class constructor. A block will not move, so I can set the edges at creation, assuming they will never move public Block(PictureBox picture, Vector position, Vector size) { PictureBox = picture; Position = position; Size = size; Edges[TopEdge] = new Ray(position, new Vector(Size.X, 0)); // top edge Edges[RightEdge] = new Ray(Vector.Add(position, new Vector(Size.X, 0)), new Vector(0, Size.Y)); // right edge Edges[BottomEdge] = new Ray(Vector.Add(position, new Vector(0, Size.Y)), new Vector(Size.X, 0)); // bottom edge Edges[LeftEdge] = new Ray(position, new Vector(0, Size.Y)); // left edge Game.Blocks.Add(this); }
/// <summary> /// calculates collisions between the ball and a paddle, and finds the paddle surface that was hit /// </summary> /// <param name="paddle">the paddle that is being hit</param> /// <param name="newPosition">the position the ball has</param> /// <param name="newVelocity">the velocity the ball is trying to move with</param> /// <returns>the position, length and surface of the collision</returns> public CollisionReturn CollidesWithPaddle(Paddle paddle, Vector newPosition, Vector newVelocity) { Ray[] Vectors = new Ray[4]; // vector rays of moving ball Vectors[TopEdge] = new Ray(newPosition, newVelocity); Vectors[RightEdge] = new Ray(Vector.Add(newPosition, new Vector(Size.X, 0)), newVelocity); Vectors[BottomEdge] = new Ray(Vector.Add(newPosition, new Vector(0, Size.Y)), newVelocity); Vectors[LeftEdge] = new Ray(Vector.Add(newPosition, new Vector(Size.X, Size.Y)), newVelocity); CollisionReturn collisionReturn = new CollisionReturn(false); foreach (Ray ray in Vectors) { int edgeID = 0; foreach (Ray edge in paddle.Edges) { RaycastReturn raycastReturn = Ray.Raycast(ray, edge); if (raycastReturn.Intersects) { if (collisionReturn.Intersects) { if (raycastReturn.length < collisionReturn.length) { collisionReturn = new CollisionReturn(raycastReturn); collisionReturn.Edge = edgeID; } } else { collisionReturn = new CollisionReturn(raycastReturn); collisionReturn.Edge = edgeID; } } edgeID++; } } return collisionReturn; }
/// <summary> /// will check for collisions between 2 rays and return the results /// </summary> /// <param name="ray1">the first ray in the collision</param> /// <param name="ray2">the second ray in the collision</param> /// <returns>the position and length of the raycast collision</returns> public static RaycastReturn Raycast(Ray ray1, Ray ray2) { // shorten the variable names float x1 = ray1.Position.X; float y1 = ray1.Position.Y; float a1 = ray1.Direction.X; float b1 = ray1.Direction.Y; float x2 = ray2.Position.X; float y2 = ray2.Position.Y; float a2 = ray2.Direction.X; float b2 = ray2.Direction.Y; if (a1 * b2 == a2 * b1) // parallel, so won't collide { return new RaycastReturn(false); // rays don't collide, so return false collision } else // they collide at some point, given their lengths are infinite { float i = (x2 * b2 + a2 * y1 - a2 * y2 - x1 * b2) / (a1 * b2 - a2 * b1); // distance between start and collision along ray1 Vector position = new Vector(x1 + i * a1, y1 + i * b1); // form coordinates of collision if (i > 1 || i < 0) // outside length of ray1 { return new RaycastReturn(false); // do not meet each other, so return false collision } else // they collide within their lengths { float length = i * ray1.Length; // length of ray1 up to collision return new RaycastReturn(true, position, length); // return true collision } } }
/// <summary> /// calculates collisions between the ball and a block, and finds the block surface tha was hit /// </summary> /// <param name="block">the block being hit</param> /// <param name="newPosition">the position the ball has</param> /// <param name="newVelocity">the velocity the ball is trying to move with</param> /// <param name="collidedRays">a list of rayIDs which have already collided with a surface</param> /// <returns>the position, length and surface of the collision</returns> public CollisionReturn CollidesWithBlock(Block block, Vector newPosition, Vector newVelocity, List<int> collidedRays) { // vector rays of moving ball Ray[] Vectors = new Ray[4]; Vectors[TopEdge] = new Ray(newPosition, newVelocity); Vectors[RightEdge] = new Ray(Vector.Add(newPosition, new Vector(Size.X, 0)), newVelocity); Vectors[BottomEdge] = new Ray(Vector.Add(newPosition, new Vector(0, Size.Y)), newVelocity); Vectors[LeftEdge] = new Ray(Vector.Add(newPosition, new Vector(Size.X, Size.Y)), newVelocity); CollisionReturn collisionReturn = new CollisionReturn(false); int rayID = 0; foreach (Ray ray in Vectors) { int edgeID = 0; if (!collidedRays.Contains(rayID)) // if the ray being used hasn't already collided with a box { // check every edge of the block foreach (Ray edge in block.Edges) { RaycastReturn raycastReturn = Ray.Raycast(ray, edge); // see if the ray meets the edge if (raycastReturn.Intersects) { // if there has already been a collision, check for a shorter one if (collisionReturn.Intersects) { if (raycastReturn.length < collisionReturn.length) // if the ball velocity ray hits this edge before any other ray hits an edge { collisionReturn = new CollisionReturn(raycastReturn); collisionReturn.Edge = edgeID; collisionReturn.Ray = rayID; } } // haven't had a ray collision yet, so use this collision by default else { collisionReturn = new CollisionReturn(raycastReturn); collisionReturn.Edge = edgeID; collisionReturn.Ray = rayID; } } edgeID++; // check next edge } } rayID++; // check next ray } return collisionReturn; // return results }
/// <summary> /// finds the rays for the edges at a specific moment /// </summary> private void CalculateEdges() { Vector position = Position; Vector size = Size; edges[TopEdge] = new Ray(position, new Vector(size.X, 0)); // top edge edges[RightEdge] = new Ray(Vector.Add(position, new Vector(size.X, 0)), new Vector(0, size.Y)); // right edge edges[BottomEdge] = new Ray(Vector.Add(position, new Vector(0, size.Y)), new Vector(size.X, 0)); // bottom edge edges[LeftEdge] = new Ray(position, new Vector(0, size.Y)); // left edge }