//returns the water block which contains the point (or null if it isn't inside any) public static Hull FindHull(Vector2 position, Hull guess = null, bool useWorldCoordinates = true) { if (entityGrids == null) { return(null); } if (guess != null) { if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position)) { return(guess); } } var entities = EntityGrid.GetEntities(entityGrids, position, useWorldCoordinates); foreach (Hull hull in entities) { if (Submarine.RectContains(useWorldCoordinates ? hull.WorldRect : hull.rect, position)) { return(hull); } } return(null); }
public static EntityGrid GenerateEntityGrid(Rectangle worldRect) { var newGrid = new EntityGrid(worldRect, 200.0f); EntityGrids.Add(newGrid); return(newGrid); }
public static EntityGrid GenerateEntityGrid(Submarine submarine) { var newGrid = new EntityGrid(submarine, 200.0f); EntityGrids.Add(newGrid); foreach (Hull hull in hullList) { if (hull.Submarine == submarine) { newGrid.InsertEntity(hull); } } return(newGrid); }
private void UpdateVertices(Camera cam, EntityGrid entityGrid, WaterRenderer renderer) { Vector2 submarinePos = Submarine == null ? Vector2.Zero : Submarine.DrawPosition; //if there's no more space in the buffer, don't render the water in the hull //not an ideal solution, but this seems to only happen in cases where the missing //water is not very noticeable (e.g. zoomed very far out so that multiple subs and ruins are visible) if (renderer.PositionInBuffer > renderer.vertices.Length - 6) { return; } if (!renderer.IndoorsVertices.ContainsKey(entityGrid)) { renderer.IndoorsVertices[entityGrid] = new VertexPositionColorTexture[WaterRenderer.DefaultIndoorsBufferSize]; renderer.PositionInIndoorsBuffer[entityGrid] = 0; } //calculate where the surface should be based on the water volume float top = rect.Y + submarinePos.Y; float bottom = top - rect.Height; float renderSurface = drawSurface + submarinePos.Y; if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) { return; } Matrix transform = cam.Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; if (!update) { // create the four corners of our triangle. Vector3[] corners = new Vector3[4]; corners[0] = new Vector3(rect.X, rect.Y, 0.0f); corners[1] = new Vector3(rect.X + rect.Width, rect.Y, 0.0f); corners[2] = new Vector3(corners[1].X, rect.Y - rect.Height, 0.0f); corners[3] = new Vector3(corners[0].X, corners[2].Y, 0.0f); Vector2[] uvCoords = new Vector2[4]; for (int i = 0; i < 4; i++) { corners[i] += new Vector3(submarinePos, 0.0f); uvCoords[i] = Vector2.Transform(new Vector2(corners[i].X, -corners[i].Y), transform); } renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(corners[0], uvCoords[0]); renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]); renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(corners[0], uvCoords[0]); renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(corners[3], uvCoords[3]); renderer.PositionInBuffer += 6; return; } float x = rect.X; if (Submarine != null) { x += Submarine.DrawPosition.X; } int start = (int)Math.Floor((cam.WorldView.X - x) / WaveWidth); start = Math.Max(start, 0); int end = (waveY.Length - 1) - (int)Math.Floor(((x + rect.Width) - (cam.WorldView.Right)) / WaveWidth); end = Math.Min(end, waveY.Length - 1); x += start * WaveWidth; Vector3[] prevCorners = new Vector3[2]; Vector2[] prevUVs = new Vector2[2]; int width = WaveWidth; for (int i = start; i < end; i++) { Vector3[] corners = new Vector3[6]; //top left corners[0] = new Vector3(x, top, 0.0f); //watersurface left corners[3] = new Vector3(corners[0].X, renderSurface + waveY[i], 0.0f); //top right corners[1] = new Vector3(x + width, top, 0.0f); //watersurface right corners[2] = new Vector3(corners[1].X, renderSurface + waveY[i + 1], 0.0f); //bottom left corners[4] = new Vector3(x, bottom, 0.0f); //bottom right corners[5] = new Vector3(x + width, bottom, 0.0f); Vector2[] uvCoords = new Vector2[4]; for (int n = 0; n < 4; n++) { uvCoords[n] = Vector2.Transform(new Vector2(corners[n].X, -corners[n].Y), transform); } if (renderer.PositionInBuffer <= renderer.vertices.Length - 6) { if (i == start) { prevCorners[0] = corners[0]; prevCorners[1] = corners[3]; prevUVs[0] = uvCoords[0]; prevUVs[1] = uvCoords[3]; } //we only create a new quad if this is the first or the last one, of if there's a wave large enough that we need more geometry if (i == end - 1 || i == start || Math.Abs(prevCorners[1].Y - corners[2].Y) > 0.01f) { renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(prevCorners[0], prevUVs[0]); renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]); renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(prevCorners[0], prevUVs[0]); renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(prevCorners[1], prevUVs[1]); prevCorners[0] = corners[1]; prevCorners[1] = corners[2]; prevUVs[0] = uvCoords[1]; prevUVs[1] = uvCoords[2]; renderer.PositionInBuffer += 6; } } if (renderer.PositionInIndoorsBuffer[entityGrid] <= renderer.IndoorsVertices[entityGrid].Length - 12 && cam.Zoom > 0.6f) { const float SurfaceSize = 10.0f; const float SineFrequency1 = 0.01f; const float SineFrequency2 = 0.05f; //surface shrinks and finally disappears when the water level starts to reach the top of the hull float surfaceScale = 1.0f - MathHelper.Clamp(corners[3].Y - (top - SurfaceSize), 0.0f, 1.0f); Vector3 surfaceOffset = new Vector3(0.0f, -SurfaceSize, 0.0f); surfaceOffset.Y += (float)Math.Sin((rect.X + i * WaveWidth) * SineFrequency1 + renderer.WavePos.X * 0.25f) * 2; surfaceOffset.Y += (float)Math.Sin((rect.X + i * WaveWidth) * SineFrequency2 - renderer.WavePos.X) * 2; surfaceOffset *= surfaceScale; Vector3 surfaceOffset2 = new Vector3(0.0f, -SurfaceSize, 0.0f); surfaceOffset2.Y += (float)Math.Sin((rect.X + i * WaveWidth + width) * SineFrequency1 + renderer.WavePos.X * 0.25f) * 2; surfaceOffset2.Y += (float)Math.Sin((rect.X + i * WaveWidth + width) * SineFrequency2 - renderer.WavePos.X) * 2; surfaceOffset2 *= surfaceScale; int posInBuffer = renderer.PositionInIndoorsBuffer[entityGrid]; renderer.IndoorsVertices[entityGrid][posInBuffer + 0] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 1] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 2] = new VertexPositionColorTexture(corners[5], renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 3] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 4] = new VertexPositionColorTexture(corners[5], renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 5] = new VertexPositionColorTexture(corners[4], renderer.IndoorsWaterColor, Vector2.Zero); posInBuffer += 6; renderer.PositionInIndoorsBuffer[entityGrid] = posInBuffer; if (surfaceScale > 0) { renderer.IndoorsVertices[entityGrid][posInBuffer + 0] = new VertexPositionColorTexture(corners[3], renderer.IndoorsSurfaceTopColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 1] = new VertexPositionColorTexture(corners[2], renderer.IndoorsSurfaceTopColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 2] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsSurfaceBottomColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 3] = new VertexPositionColorTexture(corners[3], renderer.IndoorsSurfaceTopColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 4] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsSurfaceBottomColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 5] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsSurfaceBottomColor, Vector2.Zero); renderer.PositionInIndoorsBuffer[entityGrid] += 6; } } x += WaveWidth; //clamp the last segment to the right edge of the hull if (i == end - 2) { width -= (int)Math.Max((x + WaveWidth) - (Submarine == null ? rect.Right : (rect.Right + Submarine.DrawPosition.X)), 0); } } }
public void FlipX(List <Submarine> parents = null) { if (parents == null) { parents = new List <Submarine>(); } parents.Add(this); flippedX = !flippedX; Item.UpdateHulls(); List <Item> bodyItems = Item.ItemList.FindAll(it => it.Submarine == this && it.body != null); List <MapEntity> subEntities = MapEntity.mapEntityList.FindAll(me => me.Submarine == this); foreach (MapEntity e in subEntities) { if (e.MoveWithLevel || e is Item) { continue; } if (e is LinkedSubmarine) { Submarine sub = ((LinkedSubmarine)e).Sub; if (!parents.Contains(sub)) { Vector2 relative1 = sub.SubBody.Position - SubBody.Position; relative1.X = -relative1.X; sub.SetPosition(relative1 + SubBody.Position); sub.FlipX(parents); } } else { e.FlipX(); } } foreach (MapEntity mapEntity in subEntities) { mapEntity.Move(-HiddenSubPosition); } Vector2 pos = new Vector2(subBody.Position.X, subBody.Position.Y); subBody.Body.Remove(); subBody = new SubmarineBody(this); SetPosition(pos); if (entityGrid != null) { Hull.EntityGrids.Remove(entityGrid); entityGrid = null; } entityGrid = Hull.GenerateEntityGrid(this); foreach (MapEntity mapEntity in subEntities) { mapEntity.Move(HiddenSubPosition); } foreach (Item item in Item.ItemList) { if (bodyItems.Contains(item)) { item.Submarine = this; if (Position == Vector2.Zero) { item.Move(-HiddenSubPosition); } } else if (item.Submarine != this) { continue; } item.FlipX(); } Item.UpdateHulls(); Gap.UpdateHulls(); }
public void Load(bool unloadPrevious, XElement submarineElement = null) { if (unloadPrevious) { Unload(); } Loading = true; if (submarineElement == null) { XDocument doc = OpenFile(filePath); if (doc == null || doc.Root == null) { return; } submarineElement = doc.Root; } Description = submarineElement.GetAttributeString("description", ""); Enum.TryParse(submarineElement.GetAttributeString("tags", ""), out tags); //place the sub above the top of the level HiddenSubPosition = HiddenSubStartPosition; if (GameMain.GameSession != null && GameMain.GameSession.Level != null) { HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.Level.Size.Y; } foreach (Submarine sub in Submarine.loaded) { HiddenSubPosition += Vector2.UnitY * (sub.Borders.Height + 5000.0f); } IdOffset = 0; foreach (MapEntity me in MapEntity.mapEntityList) { IdOffset = Math.Max(IdOffset, me.ID); } foreach (XElement element in submarineElement.Elements()) { string typeName = element.Name.ToString(); Type t; try { t = Type.GetType("Barotrauma." + typeName, true, true); if (t == null) { DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type \"" + typeName + "\"."); continue; } } catch (Exception e) { DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type \"" + typeName + "\".", e); continue; } try { MethodInfo loadMethod = t.GetMethod("Load"); loadMethod.Invoke(t, new object[] { element, this }); } catch (Exception e) { DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".", e); } } Vector2 center = Vector2.Zero; var matchingHulls = Hull.hullList.FindAll(h => h.Submarine == this); if (matchingHulls.Any()) { Vector2 topLeft = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y); Vector2 bottomRight = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y); foreach (Hull hull in matchingHulls) { if (hull.Rect.X < topLeft.X) { topLeft.X = hull.Rect.X; } if (hull.Rect.Y > topLeft.Y) { topLeft.Y = hull.Rect.Y; } if (hull.Rect.Right > bottomRight.X) { bottomRight.X = hull.Rect.Right; } if (hull.Rect.Y - hull.Rect.Height < bottomRight.Y) { bottomRight.Y = hull.Rect.Y - hull.Rect.Height; } } center = (topLeft + bottomRight) / 2.0f; center.X -= center.X % GridSize.X; center.Y -= center.Y % GridSize.Y; if (center != Vector2.Zero) { foreach (Item item in Item.ItemList) { if (item.Submarine != this) { continue; } var wire = item.GetComponent <Items.Components.Wire>(); if (wire != null) { wire.MoveNodes(-center); } } for (int i = 0; i < MapEntity.mapEntityList.Count; i++) { if (MapEntity.mapEntityList[i].Submarine != this) { continue; } MapEntity.mapEntityList[i].Move(-center); } } } subBody = new SubmarineBody(this); subBody.SetPosition(HiddenSubPosition); loaded.Add(this); if (entityGrid != null) { Hull.EntityGrids.Remove(entityGrid); entityGrid = null; } entityGrid = Hull.GenerateEntityGrid(this); for (int i = 0; i < MapEntity.mapEntityList.Count; i++) { if (MapEntity.mapEntityList[i].Submarine != this) { continue; } MapEntity.mapEntityList[i].Move(HiddenSubPosition); } Loading = false; MapEntity.MapLoaded(this); //WayPoint.GenerateSubWaypoints(); #if CLIENT GameMain.LightManager.OnMapLoaded(); #endif ID = (ushort)(ushort.MaxValue - Submarine.loaded.IndexOf(this)); }