/// <summary> /// Called when the surface becomes available. /// </summary> /// <param name="delayedRequest">A request that was delayed until surface becomes available.</param> protected override void OnSurfaceAvailable(PathfindingRequest delayedRequest) { if (currentFace == null || !AlchemyNavigationSystem.Current.ContainsFace(Layer, currentFace.source)) { var ray = new Ray(position, Vector3.down); if (AlchemyNavigationSystem.Current.Raycast(ray, Layer, AreaMask, out var result)) { currentFace = new CachedFace(result.face); position = result.position; ApplyPosition(); } else { Debug.LogWarning("Agent couldn't be placed on navigation surface."); gameObject.SetActive(false); return; } } if (delayedRequest != null) { CancelAllRequests(); RequestPath(position, delayedRequest.endPosition, PathType, currentFace.source); } else if (IsPathWalking) { Vector3 destination = progress.pointPath[progress.pointsCount - 1]; CancelAllRequests(); RequestPath(position, destination, PathType, currentFace.source); } }
private void Move(Vector3 move) { Vector3 displacement = Vector3.ProjectOnPlane(move, currentFace.plane.normal); Vector3 potentialPosition = position + displacement; if (currentFace.source.IsPointInsideFace(potentialPosition, EpsilonOffset)) { position = potentialPosition; } else { Vector3 clampedPosition = currentFace.SnapToFace(position, displacement); Vector3 clampedDisplacement = clampedPosition - position; position = clampedPosition; Vector3 cutDisplacement = displacement.normalized * (displacement.magnitude - clampedDisplacement.magnitude); // + 2 * EpsilonOffset if (progress != null && progress.HasNextFace && progress.NextFace.IsPointInsideFace(position, EpsilonOffset)) { progress.currentFace++; currentFace = new CachedFace(progress.CurrentFace); var ray = new Ray(position, Vector3.down); currentFace.plane.Raycast(ray, out float enter); position = ray.GetPoint(enter); while (progress.HasNextPoint && !progress.IsCurrentPointOnCurrentOrNextFaces()) { progress.currentPoint++; } Move(cutDisplacement); } else { position += currentFace.CastDisplacementOnClosestEdge(position, cutDisplacement); } } }
/// <summary> /// Called when the agent becomes enabled and active. /// </summary> protected override void OnAgentEnable() { currentFace = null; velocity = Vector3.zero; position = transform.position; ApplyPosition(); ReloadMovementModifiers(); }
/// <summary> /// Store the mesh and texture. /// </summary> public CachedPlanet CachePlanet() { CachedFace[] cachedFaces = new CachedFace[6]; for (int i = 0; i < 6; i++) { cachedFaces[i] = new CachedFace(terrainFaces[i].mesh, terrainFaces[i].texture); } return(new CachedPlanet(cachedFaces)); }
public void AppendText(char *text, int count, TextFormat format) { // look up the cache entry for the given font and size var font = format.Font; var size = FontFace.ComputePixelSize(format.Size, Dpi); var key = new CacheKey(font.Id, size); if (!cache.TryGetValue(key, out var cachedFace)) { cache.Add(key, cachedFace = new CachedFace(font, size)); } // process each character in the string var nextBreak = BreakCategory.None; var previous = new CodePoint(); var end = text + count; while (text != end) { // handle surrogate pairs properly CodePoint codePoint; var c = *text++; if (char.IsSurrogate(c) && text != end) { codePoint = new CodePoint(c, *text++); } else { codePoint = c; } // ignore linefeeds directly after a carriage return if (c == '\n' && (char)previous == '\r') { continue; } // get the glyph data if (!cachedFace.Glyphs.TryGetValue(codePoint, out var glyph) && !char.IsControl(c)) { var data = font.GetGlyph(codePoint, size); var width = data.RenderWidth; var height = data.RenderHeight; if (width > atlas.Width || height > atlas.Height) { throw new InvalidOperationException("Glyph is larger than the size of the provided atlas."); } var rect = new Rect(); if (width > 0 && height > 0) { // render the glyph var memSize = width * height; var mem = memoryBuffer; if (mem == null) { memoryBuffer = mem = new MemoryBuffer(memSize); } mem.Clear(memSize); data.RenderTo(new Surface { Bits = mem.Pointer, Width = width, Height = height, Pitch = width }); // save the rasterized glyph in the user's atlas rect = packer.Insert(width, height); if (rect.Height == 0) { // didn't fit in the atlas... start a new sheet currentPage++; packer.Clear(atlas.Width, atlas.Height); rect = packer.Insert(width, height); if (rect.Height == 0) { throw new InvalidOperationException("Failed to insert glyph into fresh page."); } } atlas.Insert(currentPage, rect.X, rect.Y, rect.Width, rect.Height, mem.Pointer); } glyph = new CachedGlyph(rect, data.HorizontalMetrics.Bearing, data.HorizontalMetrics.Advance); cachedFace.Glyphs.Add(codePoint, glyph); } // check for a kerning offset var kerning = font.GetKerning(previous, codePoint, size); previous = codePoint; // figure out whether this character can serve as a line break point // TODO: more robust character class handling var breakCategory = BreakCategory.None; if (char.IsWhiteSpace(c)) { if (c == '\r' || c == '\n') { breakCategory = BreakCategory.Mandatory; } else { breakCategory = BreakCategory.Opportunity; } } // the previous character might make us think that this one should be a break opportunity if (nextBreak > breakCategory) { breakCategory = nextBreak; } if (c == '-') { nextBreak = BreakCategory.Opportunity; } // alright, we have all the right glyph data cached and loaded // append relevant info to our buffer; we'll do the actual layout later buffer.Add(new BufferEntry { GlyphData = glyph, Kerning = kerning, Break = breakCategory }); } }