public override void Draw(IDrawDevice device) { if (gameobj == null) { return; } float timeMult = Time.TimeMult; for (int j = 0; j < circleEffectData.Length; j++) { ref CircleEffect circle = ref circleEffectData[j]; if (circle.Alpha <= 0f) { continue; } int segmentNum = MathF.Clamp(MathF.RoundToInt(MathF.Pow(circle.Radius, 0.65f) * 2.5f), 4, 32); float angle = 0.0f; for (int i = 0; i < segmentNum; i++) { vertices[i].Pos.X = circle.Pos.X + (float)Math.Sin(angle) * circle.Radius; vertices[i].Pos.Y = circle.Pos.Y - (float)Math.Cos(angle) * circle.Radius; vertices[i].Pos.Z = circle.Pos.Z - 10f; vertices[i].Color = new ColorRgba(1f, circle.Alpha); angle += (MathF.TwoPi / segmentNum); } device.AddVertices(material, VertexMode.LineLoop, vertices, 0, segmentNum); circle.Radius -= timeMult * 0.8f; circle.Alpha -= timeMult * 0.03f; }
public override void OnPaint(Canvas canvas, Rect view) { IDrawDevice device = canvas.DrawDevice; Vector2 center = device.TargetSize * 0.5f; const float topLine = 96f; float bottomLine = device.TargetSize.Y - 42; api.DrawMaterial("MenuDim", center.X, (topLine + bottomLine) * 0.5f, Alignment.Center, ColorRgba.White, 55f, (bottomLine - topLine) * 0.063f, new Rect(0f, 0.3f, 1f, 0.4f)); int charOffset = 0; if (levelList.Count > 0) { const float itemSpacing = 17f; float topItem = topLine - 4f; float bottomItem = bottomLine - 10f; float contentHeight = bottomItem - topItem; float maxVisibleItemsFloat = (contentHeight / itemSpacing); maxVisibleItems = (int)maxVisibleItemsFloat; float currentItem = topItem + itemSpacing + (maxVisibleItemsFloat - maxVisibleItems) * 0.5f * itemSpacing; // ToDo: ... float column2 = device.TargetSize.X * 0.55f; float sx = column2 * 1.52f; float column1 = column2 * 0.36f + view.X; column2 *= 1.1f; for (int i = 0; i < maxVisibleItems; i++) { int idx = i + scrollOffset; if (idx >= levelList.Count) { break; } if (selectedIndex == idx) { charOffset = 0; float xMultiplier = levelList[idx].DisplayName.Length * 0.5f; float easing = Ease.OutElastic(animation); float x = column1 + xMultiplier - easing * xMultiplier; float size = 0.7f + easing * 0.12f; // Column 2 api.DrawStringShadow(ref charOffset, levelList[idx].LevelName, column2, currentItem, Alignment.Left, new ColorRgba(0.48f, 0.5f), 0.8f, 0.4f, 1f, 1f, 8f, charSpacing: 0.88f); // Column 1 api.DrawStringShadow(ref charOffset, levelList[idx].DisplayName, x, currentItem, Alignment.Left, null, size, 0.4f, 1f, 1f, 8f, charSpacing: 0.88f); // Column 0 api.DrawStringShadow(ref charOffset, levelList[idx].Icon, column1 - 16f, currentItem, Alignment.Right, new ColorRgba(0.48f, 0.5f), size, 0.4f, 1f, 1f, 8f, charSpacing: 0.68f); } else { // Column 2 api.DrawString(ref charOffset, levelList[idx].LevelName, column2, currentItem, Alignment.Left, ColorRgba.TransparentBlack, 0.7f); // Column 1 api.DrawString(ref charOffset, levelList[idx].DisplayName, column1, currentItem, Alignment.Left, ColorRgba.TransparentBlack, 0.7f); // Column 0 api.DrawString(ref charOffset, levelList[idx].Icon, column1 - 16f, currentItem, Alignment.Right, ColorRgba.TransparentBlack, 0.7f, charSpacing: 0.7f); } currentItem += itemSpacing; } // Scrollbar if (levelList.Count > maxVisibleItems) { const float sw = 3f; float sy = ((float)scrollOffset / levelList.Count) * 18f * maxVisibleItems + topLine; float sh = ((float)maxVisibleItems / levelList.Count) * 16f * maxVisibleItems; BatchInfo mat1 = device.RentMaterial(); mat1.Technique = DrawTechnique.Alpha; mat1.MainColor = new ColorRgba(0f, 0f, 0f, 0.28f); canvas.State.SetMaterial(mat1); canvas.FillRect(sx + 1f, sy + 1f, sw, sh); BatchInfo mat2 = device.RentMaterial(); mat2.Technique = DrawTechnique.Alpha; mat2.MainColor = new ColorRgba(0.8f, 0.8f, 0.8f, 0.5f); canvas.State.SetMaterial(mat2); canvas.FillRect(sx, sy, sw, sh); } // Loading if (isLoadingAnimation > 0f) { if (!isLoading) { isLoadingAnimation -= Time.TimeMult * 0.03f; } else { isLoadingAnimation = 1f; } float loadingX = center.X - 50f; float loadingY = center.Y; float startAngle = (float)(Time.GameTimer.TotalSeconds * 6.0f); float time = (float)(Time.GameTimer.TotalSeconds * 1.3f) % 2f; bool reverse = (time >= 1f); if (reverse) { time -= 1f; } float timeCubed = MathF.Pow(time, 3); float timeQuad = MathF.Pow(time, 4); float timeQuint = MathF.Pow(time, 5); float endAngle; if (reverse) { endAngle = startAngle + MathF.TwoPi * (1 - ((6 * timeQuint) + (-15 * timeQuad) + (10 * timeCubed))); } else { endAngle = startAngle + MathF.TwoPi * ((6 * timeQuint) + (-15 * timeQuad) + (10 * timeCubed)); } const float r1 = 7f; const float r2 = r1 - 0.4f; const float r3 = r2 - 0.4f; const float r4 = r3 - 0.4f; api.DrawMaterial("MenuDim", loadingX + 50f, loadingY, Alignment.Center, new ColorRgba(1f, 0.7f * isLoadingAnimation), 40f, 10f); BatchInfo mat1 = device.RentMaterial(); mat1.Technique = DrawTechnique.Alpha; mat1.MainColor = new ColorRgba(0f, 0.2f * isLoadingAnimation); canvas.State.SetMaterial(mat1); canvas.DrawCircleSegment(loadingX + 1.6f, loadingY + 1.6f, r1, startAngle, endAngle); canvas.DrawCircleSegment(loadingX + 1.6f, loadingY + 1.6f, r2, startAngle, endAngle); canvas.DrawCircleSegment(loadingX + 1.6f, loadingY + 1.6f, r3, startAngle, endAngle); canvas.DrawCircleSegment(loadingX + 1.6f, loadingY + 1.6f, r4, startAngle, endAngle); BatchInfo mat2 = device.RentMaterial(); mat2.Technique = DrawTechnique.Alpha; mat2.MainColor = new ColorRgba(0.95f, 0.8f * isLoadingAnimation); canvas.State.SetMaterial(mat2); canvas.DrawCircleSegment(loadingX, loadingY, r1, startAngle, endAngle); canvas.DrawCircleSegment(loadingX, loadingY, r2, startAngle, endAngle); canvas.DrawCircleSegment(loadingX, loadingY, r3, startAngle, endAngle); canvas.DrawCircleSegment(loadingX, loadingY, r4, startAngle, endAngle); api.DrawStringShadow(ref charOffset, "loading".T(), loadingX + r1 + 10f, loadingY + 2f, Alignment.Left, new ColorRgba(0.48f, 0.5f * isLoadingAnimation), 0.8f, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.88f); } } else { api.DrawStringShadow(ref charOffset, "menu/play custom/single/empty".T(), center.X, center.Y, Alignment.Center, new ColorRgba(0.62f, 0.44f, 0.34f, 0.5f), 0.9f, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.88f); } api.DrawMaterial("MenuLine", 0, center.X, topLine, Alignment.Center, ColorRgba.White, 1.6f); api.DrawMaterial("MenuLine", 1, center.X, bottomLine, Alignment.Center, ColorRgba.White, 1.6f); }
protected override void OnFixedUpdate(float timeMult) { collisions.Clear(); api.FindCollisionActorsByAABB(this, AABBInner, ResolveCollisions); Vector3 pos = Transform.Pos; bool found = false; foreach (ActorBase collision in collisions) { // ToDo: This code only works with one player Player player = collision as Player; if (player != null) { if (player != lastPlayer) { if (player.Speed.Y < -0.5f) { continue; } lastPlayer = player; } found = true; Vector3 coords = player.Transform.Pos; int length = bridgePieces.Count; // This marks which bridge piece is under the player and should be positioned // lower than any other piece of the bridge. float lowest = (coords.X - pos.X) / (bridgeWidth * 16f) * length; // This marks the maximum drop in height. // At the middle of the bridge, this is purely the height factor, // which is simply (16 - bridge toughness) multiplied by the length of the bridge. // At other points, the height is scaled by an (arbitrarily chosen) power that // gives a nice curve. // Additionally, the drop is reduced based on the player position so that the // bridge seems to bend somewhat realistically instead of snapping from one position // to another. float drop = Math.Max(0, Math.Min(coords.Y - pos.Y + 32, (1f - MathF.Pow(Math.Abs(2f * lowest / length - 1f), 0.8f)) * heightFactor)); pos.Y = Math.Min(originalY + drop, Math.Max(originalY, coords.Y)); Transform.Pos = pos; // Update the position of each bridge piece. for (int j = 0; j < length; ++j) { Piece piece = bridgePieces[j]; coords = piece.Transform.Pos; if (lowest > 0 && lowest < length) { float dropPiece; if (j <= lowest) { dropPiece = MathF.Pow(j / lowest, 0.6f) * drop; piece.Transform.Angle = dropPiece * 0.006f; } else { dropPiece = MathF.Pow((length - 1 - j) / (length - 1 - lowest), 0.6f) * drop; piece.Transform.Angle = -dropPiece * 0.006f; } coords.Y = originalY + dropPiece; } else { coords.Y = originalY; piece.Transform.Angle = 0f; } piece.Transform.Pos = coords; } } } if (!found) { // The player was not touching the bridge, so reset all pieces to the default height. for (int j = 0; j < bridgePieces.Count; ++j) { Vector3 coords = bridgePieces[j].Transform.Pos; coords.Y = originalY; bridgePieces[j].Transform.Pos = coords; bridgePieces[j].Transform.Angle = 0f; } pos.Y = originalY; Transform.Pos = pos; lastPlayer = null; } }