public static Mesh2D Ball(float radius, P3 position, V3 velocity) { Mesh2D c = Mesh2D.Circle(radius, 16, position); c.Velocity = velocity; return(c); }
void cache() { dirty = true; buildVertices(); buildEdges(); centerOfGravity = P3.Average(vertices.ToArray()); boundingRadiusSquared = centerOfGravity.SquaredDistanceTo(P3.Farthest(vertices.ToArray(), centerOfGravity)); }
// Inputs: plane origin, plane normal, ray origin ray vector. // NOTE: both vectors are assumed to be normalized float intersect(P3 planeOrigin, V3 planeNormal, P3 rayOrigin, V3 rayVector) { float d = -(planeNormal * planeOrigin.ToV3()); float numer = (planeNormal * rayOrigin.ToV3()) + d; float denom = (planeNormal * rayVector); return(-(numer / denom)); }
public static Mesh2D Rectangle(P3 topLeft, float width, float height, P3 position) { P3[] vertices = new P3[4]; vertices[0] = topLeft; vertices[1] = new P3(topLeft.X + width, topLeft.Y, 0); //tr vertices[2] = new P3(topLeft.X + width, topLeft.Y + height, 0); //br vertices[3] = new P3(topLeft.X, topLeft.Y + height, 0); //bl return(new Mesh2D(vertices, position)); }
P3[] GenerateVertices() { P3[] pts = new P3[relativeVertices.Length]; for (int i = 0; i < pts.Length; i++) { pts[i] = relativeVertices[i] + Position; } return(pts); }
public Level(Game parent, string[][] data) { Game = parent; World = new World(this); buildHpColors(); this.data = data; float pwid, ph; int nrows, ncols; Width = 1.0F; Height = 0.625F; nrows = data.Length; ncols = data[0].Length; BrickWidth = Width / (float)ncols; //100% BrickHeight = Height / (float)nrows; //100% pwid = Width * 0.1F; ph = Height * 0.15F; Paddle = Mesh2D.Paddle(new P3(-pwid / 2F, -ph / 2.0F, 0), pwid, ph, new P3(Width / 2.0F, Height - ph / 2F, 0), 0.98f); Paddle.Color = Color.Blue; CreatePaddle(Paddle); World.AddMesh("paddles", Paddle); PaddleStop = BrickWidth + pwid / 2F; World.Meshes.Add("vectors", new List <Mesh2D>()); P3 ballStart = new P3(Width / 2F, Height - BrickHeight, 0); V3 vel = new V3(new P3((float)r.NextDouble() * Width, Height / 2F, 0), ballStart); //set random init direction vel.Magnitude = 1.0F; Ball = Mesh2D.Ball(Width / 200.0F, ballStart, vel); CreateBall(Ball); World.AddMesh("balls", Ball); string type; Mesh2D m; for (int i = 0; i < data.Length; i++) { for (int j = 0; j < data[i].Length; j++) { m = Mesh2D.Rectangle(P3.Zero, BrickWidth, BrickHeight, P3.New(BrickWidth * j, BrickHeight * i)); type = data[i][j]; if (type == "W") { CreateWall(m); World.AddMesh("walls", m); continue; } int hp = int.Parse(type); if (hp == 0) { continue; } CreateBrick(m, hp); BricksLeft++; World.AddMesh("bricks", m); } } }
public static Mesh2D Circle(float radius, int numPoints, P3 position) { float theta = 2.0F * (float)(Math.PI / (double)numPoints); //2*pi rad P3[] vertices = new P3[numPoints]; for (int i = 0; i < numPoints; i++) { vertices[i] = new P3((float)Math.Cos(i * theta) * radius, (float)Math.Sin(i * theta) * radius, 0); } return(new Mesh2D(vertices, position)); }
void Init(P3[] relativeVertices, P3 position) { if (relativeVertices.Length < 3) { throw new Exception("need at least 3 pts for a poly"); } relativeVertices = P3.Clone(relativeVertices); this.relativeVertices = relativeVertices; this.position = position; cache(); }
public bool Contains(P3 point) { int numverts = vertices.Count; float[] xp = new float[numverts]; float[] yp = new float[numverts]; for (int i = 0; i < numverts; i++) { xp[i] = vertices[i].X; yp[i] = vertices[i].Y; } return(pnpoly(numverts, xp, yp, point.X, point.Y)); }
public static Mesh2D Paddle(P3 topLeft, float width, float height, P3 position, float roofPct) { P3[] vertices = new P3[paddleVerts.Length + 2]; int i; float dx = width / (paddleVerts.Length - 1), dy = roofPct * height; for (i = 0; i < paddleVerts.Length; i++) { vertices[i] = V3.New(topLeft.X + dx * i, topLeft.Y + dy * (1 - (float)paddleVerts[i]), 0); } vertices[i] = new V3(topLeft.X + width, topLeft.Y + height, 0); //br vertices[i + 1] = new V3(topLeft.X, topLeft.Y + height, 0); //bl return(new Mesh2D(vertices, position)); }
//(the inputs are the ray’s origin and normalized direction vector, as well as the sphere’s origin and radius) float intersectSphere(P3 rO, V3 rV, P3 sO, float sR) { V3 Q = new V3(sO, rO); float c = Q.Magnitude; // length of Q; float v = Q * rV; float d = sR * sR - (c * c - v * v); // If there was no intersection, return -1 if (d < 0.0F) { return(-1.0F); } // Return the distance to the [first] intersecting point return(v - (float)Math.Sqrt(d)); }
public static Mesh2D Vector(V3 direction, P3 position, float width) { P3[] vertices = new P3[3]; V3 perp = direction.Perpendicular2DLeftHanded(); perp.Magnitude = width; V3 perp2 = perp.Clone().Flip(); vertices[0] = direction.ToPoint(); vertices[2] = perp.ToPoint(); vertices[1] = perp2.ToPoint(); Mesh2D c = new Mesh2D(vertices, position); c.Color = System.Drawing.Color.Magenta; return(c); }
public Result IntersectsWith(Edge other, out P3 intersectionPoint) { intersectionPoint = null; float denom = ((other.Tail.Y - other.Head.Y) * (Tail.X - Head.X)) - ((other.Tail.X - other.Head.X) * (Tail.Y - Head.Y)); float numeA = ((other.Tail.X - other.Head.X) * (Head.Y - other.Head.Y)) - ((other.Tail.Y - other.Head.Y) * (Head.X - other.Head.X)); float numeB = ((Tail.X - Head.X) * (Head.Y - other.Head.Y)) - ((Tail.Y - Head.Y) * (Head.X - other.Head.X)); if (denom == 0) { if (numeA == 0 && numeB == 0) //find out if coincident seg touches us { V3 n = other.ToVector().Perpendicular2DLeftHanded().UnitVector; Edge perp = new Edge(other.Head + n, other.Head); Edge perp2 = new Edge(other.Tail + n, other.Tail); P3 o; if (Edge.Result.Intersecting == perp.IntersectsWith(this, out o)) { intersectionPoint = o; return(Edge.Result.Intersecting); } if (Edge.Result.Intersecting == perp2.IntersectsWith(this, out o)) { intersectionPoint = o; return(Edge.Result.Intersecting); } return(Result.Coincident); } return(Result.Parallel); } float ua = numeA / denom; float ub = numeB / denom; if (ua >= 0 && ua <= 1.0 && ub >= 0 && ub <= 1.0) { // Get the intersection point. intersectionPoint = V3.New(Head.X + ua * (Tail.X - Head.X), Head.Y + ua * (Tail.Y - Head.Y), 0); return(Result.Intersecting); } return(Result.NotIntersecting); }
static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Edge e = new Edge(P3.New(0, 0), P3.New(0, -1)); Edge e2 = new Edge(P3.New(0, -1), P3.New(0, 0)); V3 v = new V3(1, 1, 0); V3 v2 = new V3(0.5F, 0, 0); V3 v3 = new V3(0, 1, 0); v3.RotateBy2D(-0.78f); v3.RotateBy2D(0.78f * 2); float d = v.ProjectionDistance(v2); Dictionary <Edge, int> dic = new Dictionary <Edge, int>(); //dic.Add(e, 0); //dic.Add(e2, 0); V3 n = e.GetNormal2DRightHanded(); V3 n2 = e2.GetNormal2DRightHanded(); P3 p; Application.Run(new Form1()); }
public Edge(P3 head, P3 tail, Mesh2D parent) { Head = head; Tail = tail; this.Parent = parent; }
//http://www.gamedev.net/reference/articles/article1026.asp void collideWithWorld(Mesh2D projectile, float deltaTimeInSec) { P3 sourcePoint = projectile.Position; V3 velocityVector = projectile.Velocity.Clone() * deltaTimeInSec; // How far do we need to go? float distanceToTravel = velocityVector.Magnitude; //length of velocityVector; // Do we need to bother? if (distanceToTravel < float.Epsilon) { return; } // What's our destination? P3 destinationPoint = sourcePoint + velocityVector; // Whom might we collide with? List <Mesh2D> potentialColliders = null; //= GetObstacles(projectile); // If there are none, we can safely move to the destination and bail if (potentialColliders.Count == 0) { projectile.MoveNext(deltaTimeInSec); return; } // Determine the nearest collider from the list potentialColliders bool firstTimeThrough = true; float nearestDistance = -1.0F; Mesh2D nearestCollider = null; P3 nearestIntersectionPoint = null; P3 nearestPolygonIntersectionPoint = null; for (int i = 0; i < potentialColliders.Count; i++) { // Plane origin/normal P3 pOrigin = potentialColliders[i].Vertices[0]; //any vertex from the current polygon; V3 pNormal = potentialColliders[i].Edges[0].GetNormal2DRightHanded().UnitVector; //surface normal from the current polygon; // Determine the distance from the plane to the source float pDist = intersect(sourcePoint, -pNormal, pOrigin, pNormal); //P3 sphereIntersectionPoint; P3 planeIntersectionPoint; // The radius of the ellipsoid (in the direction of pNormal) //V3 directionalRadius = -pNormal * new V3(projectile.BoundingRadius, projectile.BoundingRadius, 0); float radius = projectile.BoundingRadius; //directionalRadius.Magnitude; // Is the plane embedded? if (Math.Abs(pDist) <= radius) { // Calculate the plane intersection point V3 pN = -pNormal; pN.Magnitude = pDist; //-pNormal with length set to pDist planeIntersectionPoint = sourcePoint + pN; } else { // Calculate the ellipsoid intersection point V3 pN = -pNormal; pN.Magnitude = radius; //-pNormal with length set to radius P3 ellipsoidIntersectionPoint = sourcePoint + pN; // Calculate the plane intersection point //Ray ray(sphereIntersectionPoint, Velocity); float tt = intersect(ellipsoidIntersectionPoint, velocityVector, pOrigin, pNormal); // Calculate the plane intersection point V3 VV = velocityVector.Clone(); VV.Magnitude = tt; // velocityVector with length set to t; planeIntersectionPoint = ellipsoidIntersectionPoint + VV; } // Unless otherwise stated, our polygonIntersectionPoint is the // same point as planeIntersectionPoint P3 polygonIntersectionPoint = planeIntersectionPoint.Clone(); // So… are they the same? if (!potentialColliders[i].Contains(planeIntersectionPoint)) //planeIntersectionPoint is not within the current polygon) { polygonIntersectionPoint = P3.Closest(potentialColliders[i].Vertices, planeIntersectionPoint); //nearest point on polygon's perimeter to planeIntersectionPoint; } // Invert the velocity vector V3 negativeVelocityVector = -velocityVector; // Using the polygonIntersectionPoint, we need to reverse-intersect // with the ellipsoid float t = intersectSphere(polygonIntersectionPoint, negativeVelocityVector, sourcePoint, projectile.BoundingRadius); // Was there an intersection with the ellipsoid? if (t >= 0.0F && t <= distanceToTravel) { V3 VV = negativeVelocityVector.Clone(); //negativeVelocityVector with length set to t; VV.Magnitude = t; // Where did we intersect the ellipsoid? V3 intersectionPoint = (polygonIntersectionPoint + VV).ToV3(); // Closest intersection thus far? if (firstTimeThrough || t < nearestDistance) { nearestDistance = t; nearestCollider = potentialColliders[i]; nearestIntersectionPoint = intersectionPoint; nearestPolygonIntersectionPoint = polygonIntersectionPoint; firstTimeThrough = false; } } } // If we never found a collision, we can safely move to the destination // and bail if (firstTimeThrough) { projectile.MoveNext(deltaTimeInSec); return; } // Move to the nearest collision V3 V = velocityVector.Clone(); //velocityVector with length set to (nearestDistance - EPSILON); V.Magnitude = nearestDistance; sourcePoint = sourcePoint + V; // Determine the sliding plane (we do this now, because we're about to // change sourcePoint) P3 slidePlaneOrigin = nearestPolygonIntersectionPoint; V3 slidePlaneNormal = new V3(nearestPolygonIntersectionPoint, sourcePoint); // We now project the destination point onto the sliding plane float time = intersect(destinationPoint, slidePlaneNormal, slidePlaneOrigin, slidePlaneNormal); //Set length of slidePlaneNormal to time; V3 destinationProjectionNormal = slidePlaneNormal; P3 newDestinationPoint = destinationPoint + destinationProjectionNormal; // Generate the slide vector, which will become our new velocity vector // for the next iteration V3 newVelocityVector = new V3(newDestinationPoint, nearestPolygonIntersectionPoint); // Recursively slide (without adding gravity) projectile.Position = sourcePoint; projectile.Velocity = newVelocityVector; collideWithWorld(projectile, deltaTimeInSec); }
public Mesh2D(P3[] relativeVertices, P3 position) { Init(relativeVertices, position); }
public V3(P3 v) : base(v) { }
public Mesh2D Clone() { trash = new Mesh2D(P3.Clone(relativeVertices), position.Clone()); trash.velocity = this.velocity.Clone(); return(trash); }
public V3(P3 head, P3 tail) { Set(head.X - tail.X, head.Y - tail.Y, head.Z - tail.Z); }
public Edge(P3 head, P3 tail) { Head = head; Tail = tail; }
public static new V3 New(P3 p) { return new V3(p); }
//1w to 0.625h /// <returns>true if a collision occured</returns> public void ResolveCollisions2(float deltaTimeInSec, bool moveNext) { List <Mesh2D> obstacles = new List <Mesh2D>(); List <Mesh2D> collideable; obstacles.AddRange(Meshes["bricks"]); obstacles.AddRange(Meshes["walls"]); obstacles.AddRange(Meshes["paddles"]); Mesh2D next; Mesh2D projectile; for (int i = 0; i < Meshes["balls"].Count; i++) { projectile = Meshes["balls"][i]; next = projectile.Clone(); next.MoveNext(deltaTimeInSec); //AddVec(next.Trajectory(), Color.Blue); collideable = GetCollideable(next, obstacles); //find hittable meshes if (collideable.Count > 0) { List <Mesh2D> collided = GetCollidedMeshes(next, collideable); if (collided.Count > 0) { float d; Edge closest = GetCollisionEdge(next, projectile, collided, out d); if (closest != null) { projectile.DeflectAgainst(closest.GetNormal2DRightHanded().UnitVector); if (closest.Parent.Attributes.Get <string>("name") == "brick") { int hp = closest.Parent.Attributes.Get <int>("hitpoints"); Level.Game.Score += 100 * hp; hp--; if (hp == 0) { closest.Parent.Position = P3.New(2, 2); } closest.Parent.Attributes["hitpoints"] = hp; Level.Game.Sound.PlaySFX("brickhit"); Level.BricksLeft--; if (Level.BricksLeft == 0) { Level.Game.NextLevel(); } } else if (closest.Parent.Attributes.Get <string>("name") == "wall" || closest.Parent.Attributes.Get <string>("name") == "paddle") { Level.Game.Sound.PlaySFX("wallhit"); } } else { if (moveNext) { projectile.MoveNext(deltaTimeInSec); } } } else //collided.count==0 { if (moveNext) { projectile.MoveNext(deltaTimeInSec); } } } else //if collideable.count==0 { if (moveNext) { projectile.MoveNext(deltaTimeInSec); } } } }
CustomVertex.TransformedColored Make(P3 point, Color color) { return(new CustomVertex.TransformedColored(point.X, point.Y, point.Z, 1F, color.ToArgb())); }