Example #1
0
        public void FindCollisionActorsByRadius(float x, float y, float radius, Func <ActorBase, bool> callback)
        {
            AABB aabb = new AABB(x - radius, y - radius, x + radius, y + radius);

            collisions.Query((actor) => {
                if ((actor.CollisionFlags & CollisionFlags.CollideWithOtherActors) == 0)
                {
                    return(true);
                }

                // Find the closest point to the circle within the rectangle
                float closestX = MathF.Clamp(x, actor.AABB.LowerBound.X, actor.AABB.UpperBound.X);
                float closestY = MathF.Clamp(y, actor.AABB.LowerBound.Y, actor.AABB.UpperBound.Y);

                // Calculate the distance between the circle's center and this closest point
                float distanceX = (x - closestX);
                float distanceY = (y - closestY);

                // If the distance is less than the circle's radius, an intersection occurs
                float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
                if (distanceSquared < (radius * radius))
                {
                    return(callback(actor));
                }

                return(true);
            }, ref aabb);
        }
Example #2
0
        private void RenderTexturedBackground(IDrawDevice device)
        {
            if (!cachedTexturedBackground.IsAvailable)
            {
                return;
            }

            float timeMult = Time.TimeMult;

            backgroundX     += timeMult * 1.2f;
            backgroundY     += timeMult * -0.2f + timeMult * MathF.Sin(backgroundPhase) * 0.6f;
            backgroundPhase += timeMult * 0.001f;

            Vector3 renderPos = new Vector3(0, 0, 600);

            // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets
            renderPos.X = MathF.Round(renderPos.X);
            renderPos.Y = MathF.Round(renderPos.Y);
            if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2)
            {
                renderPos.X += 0.5f;
            }
            if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2)
            {
                // AMD Bugfix?
                renderPos.Y -= 0.004f;
            }

            // Reserve the required space for vertex data in our locally cached buffer
            int neededVertices = 4;

            if (cachedVertices == null || cachedVertices.Length < neededVertices)
            {
                cachedVertices = new VertexC1P3T2[neededVertices];
            }

            // Render it as world-space fullscreen quad
            cachedVertices[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z);
            cachedVertices[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z);
            cachedVertices[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z);
            cachedVertices[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z);

            cachedVertices[0].TexCoord = new Vector2(0.0f, 0.0f);
            cachedVertices[1].TexCoord = new Vector2(1f, 0.0f);
            cachedVertices[2].TexCoord = new Vector2(1f, 1f);
            cachedVertices[3].TexCoord = new Vector2(0.0f, 1f);

            cachedVertices[0].Color = cachedVertices[1].Color = cachedVertices[2].Color = cachedVertices[3].Color = ColorRgba.White;

            // Setup custom pixel shader
            BatchInfo material = device.RentMaterial();

            material.Technique   = texturedBackgroundShader;
            material.MainTexture = cachedTexturedBackground;
            material.SetValue("horizonColor", horizonColor);
            material.SetValue("shift", new Vector2(backgroundX, backgroundY));
            material.SetValue("parallaxStarsEnabled", 0f);

            device.AddVertices(material, VertexMode.Quads, cachedVertices, 0, 4);
        }
Example #3
0
            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;
                }
Example #4
0
        public void AddGems(int count)
        {
            gems += count;

            attachedHud?.ShowGems(gems);

            PlaySound("PickupGem", 1f, MathF.Min(0.7f + gemsPitch * 0.05f, 1.3f));

            gemsTimer = 120f;
            gemsPitch++;
        }
Example #5
0
        public void AddGems(int count)
        {
            gems += count;
#if !SERVER
            attachedHud?.ShowGems(gems);
#endif
            PlaySound("PickupGem", 1f, MathF.Min(0.7f + gemsPitch * 0.05f, 1.3f));

            gemsTimer = 120f;
            gemsPitch++;

#if MULTIPLAYER && SERVER
            ((LevelHandler)levelHandler).OnPlayerAddGems(this, count);
#endif
        }
Example #6
0
        protected override async Task OnActivatedAsync(ActorActivationDetails details)
        {
            bridgeWidth = details.Params[0];
            bridgeType  = (BridgeType)details.Params[1];
            if (bridgeType > BridgeType.Lab)
            {
                bridgeType = BridgeType.Rope;
            }

            int toughness = details.Params[2];

            heightFactor = MathF.Sqrt((16 - toughness) * bridgeWidth) * 4f;

            // Request metadata here to allow async loading
            await RequestMetadataAsync("Bridge/" + bridgeType.ToString("G"));

            Vector3 pos = Transform.Pos;

            originalY = pos.Y - 6;

            bridgePieces = new List <Piece>();

            int[] widthList = PieceWidths[(int)bridgeType];

            int widthCovered = widthList[0] / 2;

            for (int i = 0; (widthCovered <= bridgeWidth * 16 + 6) || (i * 16 < bridgeWidth); i++)
            {
                Piece piece = new Piece();
                piece.OnActivated(new ActorActivationDetails {
                    Api    = api,
                    Pos    = new Vector3(pos.X + widthCovered - 16, pos.Y - 20, LevelHandler.MainPlaneZ + 10),
                    Params = new[] { (ushort)bridgeType, (ushort)i }
                });
                api.AddActor(piece);

                bridgePieces.Add(piece);

                widthCovered += (widthList[i % widthList.Length] + widthList[(i + 1) % widthList.Length]) / 2;
            }

            collisionFlags = CollisionFlags.CollideWithOtherActors | CollisionFlags.SkipPerPixelCollisions;
        }
Example #7
0
        private void OnRender(IDrawDevice device)
        {
            if (framesLeft <= 0)
            {
                OnCinematicsEnd(true);
                return;
            }

            frameProgress += Time.TimeMult;

            if (frameProgress >= frameDelay)
            {
                frameProgress -= frameDelay;
                framesLeft--;

                PrepareNextFrame();
            }

            // Render current frame
            canvas.Begin(device);

            BatchInfo material = device.RentMaterial();

            material.MainTexture = videoTexture;
            canvas.State.SetMaterial(material);

            Vector2 targetSize = device.TargetSize;

            float ratioTarget = targetSize.Y / targetSize.X;
            float ratioSource = (float)height / width;
            float ratio       = MathF.Clamp(ratioTarget, ratioSource - 0.16f, ratioSource);

            float fillHeight = targetSize.X * ratio;
            float yOffset    = (targetSize.Y - fillHeight) * 0.5f;

            canvas.FillRect(0, yOffset, targetSize.X, fillHeight);

            canvas.End();
        }
Example #8
0
        public bool AddFastFire(int count)
        {
            const int FastFireLimit = 9;

            int current = (weaponUpgrades[(int)WeaponType.Blaster] >> 1);

            if (current >= FastFireLimit)
            {
                return(false);
            }

            current = MathF.Min(current + count, FastFireLimit);

            weaponUpgrades[(int)WeaponType.Blaster] = (byte)((weaponUpgrades[(int)WeaponType.Blaster] & 0x1) | (current << 1));

            PlaySound("PickupAmmo");

#if MULTIPLAYER && SERVER
            ((LevelHandler)levelHandler).OnPlayerRefreshWeaponUpgrades(this, WeaponType.Blaster, weaponUpgrades[(int)WeaponType.Blaster]);
#endif
            return(true);
        }
Example #9
0
        public override void OnFixedUpdate(float timeMult)
        {
            base.OnFixedUpdate(timeMult);

            if (frozenTimeLeft > 0)
            {
                return;
            }

            if (canJump)
            {
                if (MathF.Abs(speedX) > float.Epsilon && !CanMoveToPosition(speedX * 4, 0))
                {
                    SetTransition(AnimState.TransitionWithdraw, false, delegate {
                        HandleTurn(true);
                    });
                    isTurning     = true;
                    canHurtPlayer = false;
                    speedX        = 0;
                    PlaySound("Withdraw", 0.4f);
                }
            }

            if (!isTurning && !isWithdrawn && !isAttacking)
            {
                AABB aabb = AABBInner + new Vector2(speedX * 32, 0);
                if (levelHandler.TileMap.IsTileEmpty(ref aabb, true))
                {
                    foreach (Player player in levelHandler.GetCollidingPlayers(aabb + new Vector2(speedX * 32, 0)))
                    {
                        if (!player.IsInvulnerable)
                        {
                            Attack();
                            break;
                        }
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Updates the <see cref="CurrentFrame"/>, <see cref="NextFrame"/> and <see cref="CurrentFrameProgress"/> properties immediately.
        /// This is called implicitly once each frame before drawing, so you don't normally call this. However, when changing animation
        /// parameters and requiring updated animation frame data immediately, this could be helpful.
        /// </summary>
        public void UpdateVisibleFrames()
        {
            // Calculate visible frames
            curAnimFrame     = 0;
            nextAnimFrame    = 0;
            curAnimFrameFade = 0.0f;
            if (animFrameCount > 0 && animDuration > 0)
            {
                // Calculate currently visible frame
                float frameTemp = animFrameCount * animTime / animDuration;
                curAnimFrame = (int)frameTemp;

                // Normalize current frame when exceeding anim duration
                if (animLoopMode == LoopMode.Once || animLoopMode == LoopMode.FixedSingle)
                {
                    curAnimFrame = MathF.Clamp(curAnimFrame, 0, animFrameCount - 1);
                }
                else
                {
                    curAnimFrame = MathF.NormalizeVar(curAnimFrame, 0, animFrameCount);
                }

                // Calculate second frame and fade value
                curAnimFrameFade = frameTemp - (int)frameTemp;
                if (animLoopMode == LoopMode.Loop)
                {
                    nextAnimFrame = MathF.NormalizeVar(curAnimFrame + 1, 0, animFrameCount);
                }
                else
                {
                    nextAnimFrame = curAnimFrame + 1;
                }
            }
            curAnimFrame  = animFirstFrame + MathF.Clamp(curAnimFrame, 0, animFrameCount - 1);
            nextAnimFrame = animFirstFrame + MathF.Clamp(nextAnimFrame, 0, animFrameCount - 1);
        }
Example #11
0
        public override void OnUpdate()
        {
            if (animation < 1f)
            {
                animation = Math.Min(animation + Time.TimeMult * 0.016f, 1f);
            }

            if (ControlScheme.MenuActionHit(PlayerActions.Fire))
            {
                if (levelList.Count > 0)
                {
                    api.PlaySound("MenuSelect", 0.5f);
                    api.SwitchToSection(new StartGameOptionsSection(levelList[selectedIndex].EpisodeName, levelList[selectedIndex].LevelName, null));
                }
            }
            else if (ControlScheme.MenuActionHit(PlayerActions.Menu))
            {
                api.PlaySound("MenuSelect", 0.5f);
                api.LeaveSection(this);
            }

            if (levelList.Count > 1)
            {
                if (ControlScheme.MenuActionPressed(PlayerActions.Up))
                {
                    if (animation >= 1f - (pressedCount * 0.05f) || ControlScheme.MenuActionHit(PlayerActions.Up))
                    {
                        api.PlaySound("MenuSelect", 0.4f);
                        animation = 0f;
                        if (selectedIndex > 0)
                        {
                            selectedIndex--;
                            if (selectedIndex < scrollOffset)
                            {
                                scrollOffset = selectedIndex;
                            }
                        }
                        else
                        {
                            selectedIndex = levelList.Count - 1;
                            scrollOffset  = Math.Max(0, selectedIndex - (maxVisibleItems - 1));
                        }
                        pressedCount = Math.Min(pressedCount + 4, 19);
                    }
                }
                else if (ControlScheme.MenuActionPressed(PlayerActions.Down))
                {
                    if (animation >= 1f - (pressedCount * 0.05f) || ControlScheme.MenuActionHit(PlayerActions.Down))
                    {
                        api.PlaySound("MenuSelect", 0.4f);
                        animation = 0f;
                        if (selectedIndex < levelList.Count - 1)
                        {
                            selectedIndex++;
                            if (selectedIndex >= scrollOffset + maxVisibleItems)
                            {
                                scrollOffset = selectedIndex - (maxVisibleItems - 1);
                            }
                        }
                        else
                        {
                            selectedIndex = 0;
                            scrollOffset  = 0;
                        }
                        pressedCount = Math.Min(pressedCount + 4, 19);
                    }
                }
                else
                {
                    pressedCount = 0;
                }

                if (DualityApp.Keyboard.KeyHit(Key.PageUp))
                {
                    api.PlaySound("MenuSelect", 0.4f);
                    animation = 0f;

                    selectedIndex = MathF.Max(0, selectedIndex - maxVisibleItems);
                    if (selectedIndex < scrollOffset)
                    {
                        scrollOffset = selectedIndex;
                    }
                }
                else if (DualityApp.Keyboard.KeyHit(Key.PageDown))
                {
                    api.PlaySound("MenuSelect", 0.4f);
                    animation = 0f;

                    selectedIndex = MathF.Min(levelList.Count - 1, selectedIndex + maxVisibleItems);
                    if (selectedIndex >= scrollOffset + maxVisibleItems)
                    {
                        scrollOffset = selectedIndex - (maxVisibleItems - 1);
                    }
                }
            }
        }
Example #12
0
        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);
        }
Example #13
0
        public override void OnDraw(Canvas canvas, ref Vector2 pos, bool focused, float animation)
        {
            int charOffset = 0;

            if (focused)
            {
                float size = 0.5f + Ease.OutElastic(animation) * 0.6f;

                api.DrawMaterial("MenuGlow", pos.X, pos.Y, Alignment.Center, ColorRgba.White.WithAlpha(0.4f * size), (title.Length + 3) * 0.5f * size, 4f * size);

                if (description != null)
                {
                    api.DrawMaterial("MenuGlow", pos.X, pos.Y + 20f, Alignment.Center, ColorRgba.White.WithAlpha(0.3f * MathF.Min(1f, animation * 6f)), (description.Length + 3) * 0.4f, 3f);

                    api.DrawString(ref charOffset, description, pos.X, pos.Y + 20f, Alignment.Center,
                                   new ColorRgba(0.44f, 0.42f, 0.4f, 0.5f), 0.7f);
                }

                api.DrawStringShadow(ref charOffset, title, pos.X, pos.Y,
                                     Alignment.Center, null, size, 0.7f, 1.1f, 1.1f, charSpacing: 0.9f);
            }
            else if (!enabled)
            {
                api.DrawString(ref charOffset, title, pos.X, pos.Y, Alignment.Center,
                               new ColorRgba(0.4f, 0.3f), 0.9f);
            }
            else
            {
                api.DrawString(ref charOffset, description, pos.X, pos.Y + 20f, Alignment.Center,
                               new ColorRgba(0.44f, 0.42f, 0.4f, 0.5f), 0.7f);

                api.DrawString(ref charOffset, title, pos.X, pos.Y, Alignment.Center,
                               ColorRgba.TransparentBlack, 0.9f);
            }

            if (description != null)
            {
                pos.Y += 55f;
            }
            else
            {
                pos.Y += 40f;
            }
        }
Example #14
0
        public override void OnPaint(Canvas canvas, Rect view)
        {
            IDrawDevice device = canvas.DrawDevice;

            Vector2 center = device.TargetSize * 0.5f;

            const float topLine    = 131f;
            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));

            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);

            int charOffset = 0;

            api.DrawStringShadow(ref charOffset, "menu/play story/title".T(), center.X, 110f,
                                 Alignment.Center, new ColorRgba(0.5f, 0.5f), 0.9f, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.88f);

            if (episodes.Count > 0)
            {
                float topItem       = topLine - 5f;
                float bottomItem    = bottomLine + 5f;
                float contentHeight = bottomItem - topItem;
                float itemSpacing   = contentHeight / (episodes.Count + 1);

                topItem += itemSpacing;
                float topItemSelected = 0f;

                for (int i = 0; i < episodes.Count; i++)
                {
                    if (selectedIndex == i)
                    {
                        topItemSelected = topItem;
                    }
                    else
                    {
                        if (episodes[i].IsAvailable)
                        {
                            api.DrawString(ref charOffset, episodes[i].Episode.Name, center.X, topItem,
                                           Alignment.Center, ColorRgba.TransparentBlack, 0.9f);
                        }
                        else
                        {
                            api.DrawString(ref charOffset, episodes[i].Episode.Name, center.X, topItem,
                                           Alignment.Center, new ColorRgba(0.4f, 0.4f), 0.9f);
                        }
                    }

                    topItem += itemSpacing;
                }

                // Selected item last
                float expandedAnimation2 = Math.Min(expandedAnimation * 6f, 1f);
                float expandedAnimation3 = (expandedAnimation2 * expandedAnimation2 * (3.0f - 2.0f * expandedAnimation2));

                float size = 0.5f + Ease.OutElastic(selectAnimation) * 0.5f + (1f - expandedAnimation3) * 0.2f;

                if (episodes[selectedIndex].IsAvailable)
                {
                    if (episodes[selectedIndex].Logo.IsAvailable)
                    {
                        api.DrawString(ref charOffset, episodes[selectedIndex].Episode.Name, center.X, topItemSelected,
                                       Alignment.Center, new ColorRgba(0.44f, 0.5f * MathF.Max(0f, 1f - selectAnimation * 2f)), 0.9f - selectAnimation * 0.5f);

                        ContentRef <Material> logo = episodes[selectedIndex].Logo;
                        Texture texture            = logo.Res.MainTexture.Res;

                        Vector2 originPos = new Vector2(center.X, topItemSelected);
                        Vector2 logoSize  = new Vector2(texture.InternalWidth * size, texture.InternalHeight * size);
                        Alignment.Center.ApplyTo(ref originPos, logoSize);

                        ColorRgba logoColor = ColorRgba.White.WithAlpha(1f - expandedAnimation3 * 0.5f);

                        canvas.State.SetMaterial(logo);
                        canvas.State.ColorTint = logoColor;
                        canvas.FillRect(originPos.X, originPos.Y, texture.InternalWidth * size, texture.InternalHeight * size);

                        if (episodes[selectedIndex].IsComplete)
                        {
                            api.DrawMaterial("EpisodeComplete", originPos.X + logoSize.X * 0.7f, originPos.Y + logoSize.Y * 0.4f, Alignment.TopLeft, logoColor, size, size);
                        }

                        if (episodes[selectedIndex].CanContinue)
                        {
                            float moveX = expandedAnimation3 * -24f;

                            api.DrawString(ref charOffset, ">", center.X + 80f + moveX, topItemSelected,
                                           Alignment.Right, new ColorRgba(0.5f, 0.5f * MathF.Min(1f, 0.4f + selectAnimation)), 0.8f, charSpacing: 0.9f);

                            if (expanded)
                            {
                                float expandedAnimation4 = Ease.OutElastic(expandedAnimation) * 0.8f;

                                api.DrawStringShadow(ref charOffset, "menu/play story/restart".T(), center.X + 110f, topItemSelected,
                                                     Alignment.Center, new ColorRgba(0.62f, 0.44f, 0.34f, 0.5f * MathF.Min(1f, 0.4f + expandedAnimation3)), expandedAnimation4, 0.4f, 0.6f, 0.6f, 8f, charSpacing: 0.8f);
                            }
                        }
                    }
                    else
                    {
                        api.DrawStringShadow(ref charOffset, episodes[selectedIndex].Episode.Name, center.X, topItemSelected,
                                             Alignment.Center, null, size, charSpacing: 0.9f);
                    }
                }
                else
                {
                    api.DrawString(ref charOffset, episodes[selectedIndex].Episode.Name, center.X, topItemSelected,
                                   Alignment.Center, new ColorRgba(0.4f, MathF.Max(0.3f, 0.4f - selectAnimation * 0.4f)), MathF.Max(0.7f, 0.9f - selectAnimation * 0.6f));

                    int     index = episodes.IndexOfFirst(entry => entry.Episode.Token == episodes[selectedIndex].Episode.PreviousEpisode);
                    Episode previousEpisode;
                    if (index == -1)
                    {
                        previousEpisode = null;
                    }
                    else
                    {
                        previousEpisode = episodes[index].Episode;
                    }

                    string info;
                    if (previousEpisode == null)
                    {
                        info = "menu/play story/locked".T();
                    }
                    else
                    {
                        info = "menu/play story/locked prev".T(previousEpisode.Name);
                    }

                    api.DrawStringShadow(ref charOffset, info, center.X, topItemSelected,
                                         Alignment.Center, new ColorRgba(0.66f, 0.42f, 0.32f, MathF.Min(0.5f, 0.2f + 2f * selectAnimation)), 0.7f * size, charSpacing: 0.9f);
                }
            }
            else
            {
                api.DrawStringShadow(ref charOffset, "menu/play story/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);
            }
        }
Example #15
0
        private void DrawLayer(IDrawDevice device, ref TileMapLayer layer, int cacheIndex)
        {
            if (!layer.Visible)
            {
                return;
            }

            Vector2 viewSize   = device.TargetSize;
            Vector3 viewCenter = device.ViewerPos;

            Point2  tileCount = new Point2(layer.LayoutWidth, layer.Layout.Length / layer.LayoutWidth);
            Vector2 tileSize  = new Vector2(tileset.TileSize, tileset.TileSize);

            // Update offsets for moving layers
            if (MathF.Abs(layer.AutoSpeedX) > 0)
            {
                layer.OffsetX += layer.AutoSpeedX * Time.TimeMult;
                if (layer.RepeatX)
                {
                    if (layer.AutoSpeedX > 0)
                    {
                        while (layer.OffsetX > (tileCount.X * 32))
                        {
                            layer.OffsetX -= (tileCount.X * 32);
                        }
                    }
                    else
                    {
                        while (layer.OffsetX < 0)
                        {
                            layer.OffsetX += (tileCount.X * 32);
                        }
                    }
                }
            }
            if (MathF.Abs(layer.AutoSpeedY) > 0)
            {
                layer.OffsetY += layer.AutoSpeedY * Time.TimeMult;
                if (layer.RepeatY)
                {
                    if (layer.AutoSpeedY > 0)
                    {
                        while (layer.OffsetY > (tileCount.Y * 32))
                        {
                            layer.OffsetY -= (tileCount.Y * 32);
                        }
                    }
                    else
                    {
                        while (layer.OffsetY < 0)
                        {
                            layer.OffsetY += (tileCount.Y * 32);
                        }
                    }
                }
            }

            // Get current layer offsets and speeds
            float loX = layer.OffsetX;
            float loY = layer.OffsetY - (layer.UseInherentOffset ? (viewSize.Y - 200) / 2 : 0);

            // Find out coordinates for a tile from outside the boundaries from topleft corner of the screen
            float x1 = viewCenter.X - 70 - (viewSize.X * 0.5f);
            float y1 = viewCenter.Y - 70 - (viewSize.Y * 0.5f);

            if (layer.BackgroundStyle != BackgroundStyle.Plain && tileCount.Y == 8 && tileCount.X == 8)
            {
                const float PerspectiveSpeedX = 0.4f;
                const float PerspectiveSpeedY = 0.16f;
                RenderTexturedBackground(device, ref layer, cacheIndex,
                                         (x1 * PerspectiveSpeedX + loX),
                                         (y1 * PerspectiveSpeedY + loY));
            }
            else
            {
                // Figure out the floating point offset from the calculated coordinates and the actual tile
                // corner coordinates
                float xt = TranslateCoordinate(x1, layer.SpeedX, loX, false, viewSize.Y, viewSize.X);
                float yt = TranslateCoordinate(y1, layer.SpeedY, loY, true, viewSize.Y, viewSize.X);

                float remX = xt % 32f;
                float remY = yt % 32f;

                // Calculate the index (on the layer map) of the first tile that needs to be drawn to the
                // position determined earlier
                int tileX, tileY, tileAbsX, tileAbsY;

                // Get the actual tile coords on the layer layout
                if (xt > 0)
                {
                    tileAbsX = (int)Math.Floor(xt / 32f);
                    tileX    = tileAbsX % tileCount.X;
                }
                else
                {
                    tileAbsX = (int)Math.Ceiling(xt / 32f);
                    tileX    = tileAbsX % tileCount.X;
                    while (tileX < 0)
                    {
                        tileX += tileCount.X;
                    }
                }

                if (yt > 0)
                {
                    tileAbsY = (int)Math.Floor(yt / 32f);
                    tileY    = tileAbsY % tileCount.Y;
                }
                else
                {
                    tileAbsY = (int)Math.Ceiling(yt / 32f);
                    tileY    = tileAbsY % tileCount.Y;
                    while (tileY < 0)
                    {
                        tileY += tileCount.Y;
                    }
                }

                // update x1 and y1 with the remainder so that we start at the tile boundary
                // minus 1 because indices are updated in the beginning of the loops
                x1 -= remX - 32f;
                y1 -= remY - 32f;

                // Save the tile Y at the left border so that we can roll back to it at the start of
                // every row iteration
                int tileYs = tileY;

                // Calculate the last coordinates we want to draw to
                float x3 = x1 + 100 + viewSize.X;
                float y3 = y1 + 100 + viewSize.Y;

                Material  material  = null;
                Texture   texture   = null;
                ColorRgba mainColor = ColorRgba.White;

                // Reserve the required space for vertex data in our locally cached buffer
                int neededVertices = (int)((((x3 - x1) / 32) + 1) * (((y3 - y1) / 32) + 1) * 4);
                if (cachedVertices == null || cachedVertices.Length < neededVertices)
                {
                    cachedVertices = new VertexC1P3T2[neededVertices];
                }

                int vertexIndex = 0;

                int tile_xo = -1;
                for (float x2 = x1; x2 < x3; x2 += 32)
                {
                    tileX = (tileX + 1) % tileCount.X;
                    tile_xo++;
                    if (!layer.RepeatX)
                    {
                        // If the current tile isn't in the first iteration of the layer horizontally, don't draw this column
                        if (tileAbsX + tile_xo + 1 < 0 || tileAbsX + tile_xo + 1 >= tileCount.X)
                        {
                            continue;
                        }
                    }
                    tileY = tileYs;
                    int tile_yo = -1;
                    for (float y2 = y1; y2 < y3; y2 += 32)
                    {
                        tileY = (tileY + 1) % tileCount.Y;
                        tile_yo++;

                        LayerTile tile = layer.Layout[tileX + tileY * layer.LayoutWidth];

                        if (!layer.RepeatY)
                        {
                            // If the current tile isn't in the first iteration of the layer vertically, don't draw it
                            if (tileAbsY + tile_yo + 1 < 0 || tileAbsY + tile_yo + 1 >= tileCount.Y)
                            {
                                continue;
                            }
                        }

                        Point2 offset;
                        bool   isFlippedX, isFlippedY;
                        if (tile.IsAnimated)
                        {
                            if (tile.TileID < animatedTiles.Count)
                            {
                                offset     = animatedTiles[tile.TileID].CurrentTile.MaterialOffset;
                                isFlippedX = (animatedTiles[tile.TileID].CurrentTile.IsFlippedX != tile.IsFlippedX);
                                isFlippedY = (animatedTiles[tile.TileID].CurrentTile.IsFlippedY != tile.IsFlippedY);

                                //mainColor.A = tile.MaterialAlpha;
                                mainColor.A = animatedTiles[tile.TileID].CurrentTile.MaterialAlpha;
                            }
                            else
                            {
                                continue;
                            }
                        }
                        else
                        {
                            offset     = tile.MaterialOffset;
                            isFlippedX = tile.IsFlippedX;
                            isFlippedY = tile.IsFlippedY;

                            mainColor.A = tile.MaterialAlpha;
                        }

                        if (material != tile.Material)
                        {
                            // Submit all the vertices as one draw batch
                            device.AddVertices(
                                material,
                                VertexMode.Quads,
                                cachedVertices,
                                0,
                                vertexIndex);

                            vertexIndex = 0;

                            material = tile.Material.Res;
                            texture  = material.MainTexture.Res;
                        }

                        Rect uvRect = new Rect(
                            offset.X * texture.UVRatio.X / texture.ContentWidth,
                            offset.Y * texture.UVRatio.Y / texture.ContentHeight,
                            tileset.TileSize * texture.UVRatio.X / texture.ContentWidth,
                            tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight
                            );

                        // ToDo: Flip normal map somehow
                        if (isFlippedX)
                        {
                            uvRect.X += uvRect.W;
                            uvRect.W *= -1;
                        }
                        if (isFlippedY)
                        {
                            uvRect.Y += uvRect.H;
                            uvRect.H *= -1;
                        }

                        Vector3 renderPos = new Vector3(x2, y2, layer.Depth);

                        renderPos.X = MathF.Round(renderPos.X);
                        renderPos.Y = MathF.Round(renderPos.Y);
                        if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2)
                        {
                            renderPos.X += 0.5f;
                        }
                        if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2)
                        {
                            renderPos.Y += 0.5f;
                        }

                        cachedVertices[vertexIndex + 0].Pos.X      = renderPos.X;
                        cachedVertices[vertexIndex + 0].Pos.Y      = renderPos.Y;
                        cachedVertices[vertexIndex + 0].Pos.Z      = renderPos.Z;
                        cachedVertices[vertexIndex + 0].TexCoord.X = uvRect.X;
                        cachedVertices[vertexIndex + 0].TexCoord.Y = uvRect.Y;
                        cachedVertices[vertexIndex + 0].Color      = mainColor;

                        cachedVertices[vertexIndex + 1].Pos.X      = renderPos.X;
                        cachedVertices[vertexIndex + 1].Pos.Y      = renderPos.Y + tileSize.Y;
                        cachedVertices[vertexIndex + 1].Pos.Z      = renderPos.Z;
                        cachedVertices[vertexIndex + 1].TexCoord.X = uvRect.X;
                        cachedVertices[vertexIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H;
                        cachedVertices[vertexIndex + 1].Color      = mainColor;

                        cachedVertices[vertexIndex + 2].Pos.X      = renderPos.X + tileSize.X;
                        cachedVertices[vertexIndex + 2].Pos.Y      = renderPos.Y + tileSize.Y;
                        cachedVertices[vertexIndex + 2].Pos.Z      = renderPos.Z;
                        cachedVertices[vertexIndex + 2].TexCoord.X = uvRect.X + uvRect.W;
                        cachedVertices[vertexIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H;
                        cachedVertices[vertexIndex + 2].Color      = mainColor;

                        cachedVertices[vertexIndex + 3].Pos.X      = renderPos.X + tileSize.X;
                        cachedVertices[vertexIndex + 3].Pos.Y      = renderPos.Y;
                        cachedVertices[vertexIndex + 3].Pos.Z      = renderPos.Z;
                        cachedVertices[vertexIndex + 3].TexCoord.X = uvRect.X + uvRect.W;
                        cachedVertices[vertexIndex + 3].TexCoord.Y = uvRect.Y;
                        cachedVertices[vertexIndex + 3].Color      = mainColor;

                        vertexIndex += 4;
                    }
                }

                // Submit all the vertices as one draw batch
                device.AddVertices(
                    material,
                    VertexMode.Quads,
                    cachedVertices,
                    0,
                    vertexIndex);
            }
        }
Example #16
0
        public unsafe void DrawString(ref int charOffset, string text, float x, float y, Alignment alignment, ColorRgba? color = null, float scale = 1f, float angleOffset = 0f, float varianceX = 4f, float varianceY = 4f, float speed = 4f, float charSpacing = 1f, float lineSpacing = 1f)
        {
            const int MaxColorizeIndex = 7;

            if (string.IsNullOrEmpty(text)) {
                return;
            }

            float phase = (float)Time.GameTimer.TotalSeconds * speed;

            bool hasColor = false;
            // Pre-compute text size
            //int lines = 1;
            float totalWidth = 0f, lastWidth = 0f, totalHeight = 0f;
            float charSpacingPre = charSpacing;
            float scalePre = scale;
            for (int i = 0; i < text.Length; i++) {
                if (text[i] == '\n') {
                    if (lastWidth < totalWidth) {
                        lastWidth = totalWidth;
                    }
                    totalWidth = 0f;
                    totalHeight += (charHeight * scale * lineSpacing);
                    //lines++;
                    continue;
                } else if (text[i] == '\f' && text[i + 1] == '[') {
                    i += 2;
                    int formatIndex = i;
                    while (text[i] != ']') {
                        i++;
                    }

                    if (text[formatIndex + 1] == ':') {
                        int paramInt;
                        switch (text[formatIndex]) {
                            case 'c': // Color
                                hasColor = true;
                                break;
                            case 's': // Scale
                                if (int.TryParse(text.Substring(formatIndex + 2, i - (formatIndex + 2)), out paramInt)) {
                                    scalePre = paramInt * 0.01f;
                                }
                                break;
                            case 'w': // Char spacing
                                if (int.TryParse(text.Substring(formatIndex + 2, i - (formatIndex + 2)), out paramInt)) {
                                    charSpacingPre = paramInt * 0.01f;
                                }
                                break;
                        }
                    }
                    continue;
                }

                Rect uvRect;
                if (!unicodeChars.TryGetValue(text[i], out uvRect)) {
                    byte ascii = (byte)text[i];
                    if (ascii < 128) {
                        uvRect = asciiChars[ascii];
                    } else {
                        uvRect = new Rect();
                    }
                }

                if (uvRect.W > 0 && uvRect.H > 0) {
                    totalWidth += (uvRect.W + baseSpacing) * charSpacingPre * scalePre;
                }
            }
            if (lastWidth < totalWidth) {
                lastWidth = totalWidth;
            }
            totalHeight += (charHeight * scale * lineSpacing);

            VertexC1P3T2[] vertexData = canvas.RentVertices(text.Length * 4);

            // Set default material
            bool colorize, allowColorChange;
            ContentRef<Material> material;
            ColorRgba mainColor;
            if (color.HasValue) {
                mainColor = color.Value;
                if (mainColor == ColorRgba.TransparentBlack) {
                    if (hasColor) {
                        material = materialColor;
                        mainColor = new ColorRgba(0.46f, 0.46f, 0.4f, 0.5f);
                    } else {
                        material = materialPlain;
                        mainColor = ColorRgba.White;
                    }
                } else {
                    material = materialColor;
                }
                colorize = false;

                if (mainColor.R == 0 && mainColor.G == 0 && mainColor.B == 0) {
                    allowColorChange = false;
                } else {
                    allowColorChange = true;
                }
            } else {
                material = materialColor;
                mainColor = ColorRgba.White;
                colorize = true;
                allowColorChange = false;
            }

            Vector2 uvRatio = new Vector2(
                1f / materialPlain.Res.MainTexture.Res.ContentWidth,
                1f / materialPlain.Res.MainTexture.Res.ContentHeight
            );

            int vertexIndex = 0;

            Vector2 originPos = new Vector2(x, y);
            alignment.ApplyTo(ref originPos, new Vector2(lastWidth, totalHeight));
            float lineStart = originPos.X;

            for (int i = 0; i < text.Length; i++) {
                if (text[i] == '\n') {
                    // New line
                    originPos.X = lineStart;
                    originPos.Y += (charHeight * scale * lineSpacing);
                    continue;
                } else if (text[i] == '\f' && text[i + 1] == '[') {
                    // Format
                    i += 2;
                    int formatIndex = i;
                    while (text[i] != ']') {
                        i++;
                    }

                    if (text[formatIndex + 1] == ':') {
                        int paramInt;
                        switch (text[formatIndex]) {
                            case 'c': // Color
                                if (allowColorChange && int.TryParse(text.Substring(formatIndex + 2, i - (formatIndex + 2)), out paramInt)) {
                                    if (paramInt == -1) {
                                        colorize = true;
                                    } else {
                                        colorize = false;
                                        mainColor = colors[paramInt % colors.Length];
                                    }
                                }
                                break;
                            case 's': // Scale
                                if (int.TryParse(text.Substring(formatIndex + 2, i - (formatIndex + 2)), out paramInt)) {
                                    scale = paramInt * 0.01f;
                                }
                                break;
                            case 'w': // Char spacing
                                if (int.TryParse(text.Substring(formatIndex + 2, i - (formatIndex + 2)), out paramInt)) {
                                    charSpacing = paramInt * 0.01f;
                                }
                                break;

                            default:
                                // Unknown formatting
                                break;
                        }
                    }
                    continue;
                }

                Rect uvRect;
                if (!unicodeChars.TryGetValue(text[i], out uvRect)) {
                    byte ascii = (byte)text[i];
                    if (ascii < 128) {
                        uvRect = asciiChars[ascii];
                    } else {
                        uvRect = new Rect();
                    }
                }

                if (uvRect.W > 0 && uvRect.H > 0) {
                    if (colorize) {
                        mainColor = colors[charOffset % MaxColorizeIndex];
                    }

                    Vector3 pos = new Vector3(originPos);

                    if (angleOffset > 0f) {
                        float currentPhase = (phase + charOffset) * angleOffset * MathF.Pi;
                        if (speed > 0f && charOffset % 2 == 1) {
                            currentPhase = -currentPhase;
                        }

                        pos.X += MathF.Cos(currentPhase) * varianceX * scale;
                        pos.Y += MathF.Sin(currentPhase) * varianceY * scale;
                    }

                    pos.X = MathF.Round(pos.X);
                    pos.Y = MathF.Round(pos.Y);

                    float x2 = MathF.Round(pos.X + uvRect.W * scale);
                    float y2 = MathF.Round(pos.Y + uvRect.H * scale);

                    vertexData[vertexIndex + 0].Pos = pos;
                    vertexData[vertexIndex + 0].TexCoord.X = uvRect.X;
                    vertexData[vertexIndex + 0].TexCoord.Y = uvRect.Y;
                    vertexData[vertexIndex + 0].Color = mainColor;

                    vertexData[vertexIndex + 1].Pos.X = pos.X;
                    vertexData[vertexIndex + 1].Pos.Y = y2;
                    vertexData[vertexIndex + 1].Pos.Z = pos.Z;
                    vertexData[vertexIndex + 1].TexCoord.X = uvRect.X;
                    vertexData[vertexIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H * uvRatio.Y;
                    vertexData[vertexIndex + 1].Color = mainColor;

                    vertexData[vertexIndex + 2].Pos.X = x2;
                    vertexData[vertexIndex + 2].Pos.Y = y2;
                    vertexData[vertexIndex + 2].Pos.Z = pos.Z;
                    vertexData[vertexIndex + 2].TexCoord.X = uvRect.X + uvRect.W * uvRatio.X;
                    vertexData[vertexIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H * uvRatio.Y;
                    vertexData[vertexIndex + 2].Color = mainColor;

                    vertexData[vertexIndex + 3].Pos.X = x2;
                    vertexData[vertexIndex + 3].Pos.Y = pos.Y;
                    vertexData[vertexIndex + 3].Pos.Z = pos.Z;
                    vertexData[vertexIndex + 3].TexCoord.X = uvRect.X + uvRect.W * uvRatio.X;
                    vertexData[vertexIndex + 3].TexCoord.Y = uvRect.Y;
                    vertexData[vertexIndex + 3].Color = mainColor;

                    if (MathF.RoundToInt(canvas.DrawDevice.TargetSize.X) != (MathF.RoundToInt(canvas.DrawDevice.TargetSize.X) / 2) * 2) {
                        float align = 0.5f / canvas.DrawDevice.TargetSize.X;

                        vertexData[vertexIndex + 0].Pos.X += align;
                        vertexData[vertexIndex + 1].Pos.X += align;
                        vertexData[vertexIndex + 2].Pos.X += align;
                        vertexData[vertexIndex + 3].Pos.X += align;
                    }

                    if (MathF.RoundToInt(canvas.DrawDevice.TargetSize.Y) != (MathF.RoundToInt(canvas.DrawDevice.TargetSize.Y) / 2) * 2) {
                        float align = 0.5f * scale / canvas.DrawDevice.TargetSize.Y;

                        vertexData[vertexIndex + 0].Pos.Y += align;
                        vertexData[vertexIndex + 1].Pos.Y += align;
                        vertexData[vertexIndex + 2].Pos.Y += align;
                        vertexData[vertexIndex + 3].Pos.Y += align;
                    }

                    vertexIndex += 4;

                    originPos.X += ((uvRect.W + baseSpacing) * scale * charSpacing);
                }
                charOffset++;
            }
            charOffset++;

            // Submit all the vertices as one draw batch
            canvas.DrawDevice.AddVertices(
                material,
                VertexMode.Quads,
                vertexData,
                0,
                vertexIndex);
        }
Example #17
0
        private void RecreateTexturedBackground(TileSet levelTileset, ref TileMapLayer layer)
        {
            int w = layer.LayoutWidth;
            int h = layer.Layout.Length / w;

            Texture targetTexture;

            if (cachedTexturedBackground.IsAvailable)
            {
                targetTexture = cachedTexturedBackground.Res;
            }
            else
            {
                targetTexture = new Texture(w * 32, h * 32, TextureSizeMode.NonPowerOfTwo, TextureMagFilter.Linear, TextureMinFilter.Linear, TextureWrapMode.Repeat, TextureWrapMode.Repeat);
            }

            using (DrawDevice device = new DrawDevice()) {
                device.VisibilityMask = VisibilityFlag.AllFlags;
                device.Projection     = ProjectionMode.Screen;

                using (RenderTarget target = new RenderTarget(AAQuality.Off, false, targetTexture)) {
                    device.Target       = target;
                    device.TargetSize   = new Vector2(w * 32, h * 32);
                    device.ViewportRect = new Rect(device.TargetSize);

                    device.PrepareForDrawcalls();

                    // ToDo
                    Material material = levelTileset.GetDefaultTile(0).Material.Res;
                    Texture  texture  = material.MainTexture.Res;

                    // Reserve the required space for vertex data in our locally cached buffer
                    int neededVertices = 4 * w * h;
                    if (cachedVertices == null || cachedVertices.Length < neededVertices)
                    {
                        cachedVertices = new VertexC1P3T2[neededVertices];
                    }

                    int vertexIndex = 0;

                    for (int x = 0; x < w; x++)
                    {
                        for (int y = 0; y < h; y++)
                        {
                            LayerTile tile = layer.Layout[x + y * layer.LayoutWidth];
                            if (tile.IsAnimated)
                            {
                                continue;
                            }

                            Point2 offset     = tile.MaterialOffset;
                            bool   isFlippedX = tile.IsFlippedX;
                            bool   isFlippedY = tile.IsFlippedY;

                            Rect uvRect = new Rect(
                                offset.X * texture.UVRatio.X / texture.ContentWidth,
                                offset.Y * texture.UVRatio.Y / texture.ContentHeight,
                                levelTileset.TileSize * texture.UVRatio.X / texture.ContentWidth,
                                levelTileset.TileSize * texture.UVRatio.Y / texture.ContentHeight
                                );

                            if (isFlippedX)
                            {
                                uvRect.X += uvRect.W;
                                uvRect.W *= -1;
                            }
                            if (isFlippedY)
                            {
                                uvRect.Y += uvRect.H;
                                uvRect.H *= -1;
                            }

                            Vector3 renderPos = new Vector3(x * 32, y * 32, 0);

                            renderPos.X = MathF.Round(renderPos.X);
                            renderPos.Y = MathF.Round(renderPos.Y);
                            if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2)
                            {
                                renderPos.X += 0.5f;
                            }
                            if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2)
                            {
                                renderPos.Y += 0.5f;
                            }

                            Vector2 tileXStep = new Vector2(32, 0);
                            Vector2 tileYStep = new Vector2(0, 32);

                            cachedVertices[vertexIndex + 0].Pos.X      = renderPos.X;
                            cachedVertices[vertexIndex + 0].Pos.Y      = renderPos.Y;
                            cachedVertices[vertexIndex + 0].Pos.Z      = renderPos.Z;
                            cachedVertices[vertexIndex + 0].TexCoord.X = uvRect.X;
                            cachedVertices[vertexIndex + 0].TexCoord.Y = uvRect.Y;
                            cachedVertices[vertexIndex + 0].Color      = ColorRgba.White;

                            cachedVertices[vertexIndex + 1].Pos.X      = renderPos.X + tileYStep.X;
                            cachedVertices[vertexIndex + 1].Pos.Y      = renderPos.Y + tileYStep.Y;
                            cachedVertices[vertexIndex + 1].Pos.Z      = renderPos.Z;
                            cachedVertices[vertexIndex + 1].TexCoord.X = uvRect.X;
                            cachedVertices[vertexIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H;
                            cachedVertices[vertexIndex + 1].Color      = ColorRgba.White;

                            cachedVertices[vertexIndex + 2].Pos.X      = renderPos.X + tileXStep.X + tileYStep.X;
                            cachedVertices[vertexIndex + 2].Pos.Y      = renderPos.Y + tileXStep.Y + tileYStep.Y;
                            cachedVertices[vertexIndex + 2].Pos.Z      = renderPos.Z;
                            cachedVertices[vertexIndex + 2].TexCoord.X = uvRect.X + uvRect.W;
                            cachedVertices[vertexIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H;
                            cachedVertices[vertexIndex + 2].Color      = ColorRgba.White;

                            cachedVertices[vertexIndex + 3].Pos.X      = renderPos.X + tileXStep.X;
                            cachedVertices[vertexIndex + 3].Pos.Y      = renderPos.Y + tileXStep.Y;
                            cachedVertices[vertexIndex + 3].Pos.Z      = renderPos.Z;
                            cachedVertices[vertexIndex + 3].TexCoord.X = uvRect.X + uvRect.W;
                            cachedVertices[vertexIndex + 3].TexCoord.Y = uvRect.Y;
                            cachedVertices[vertexIndex + 3].Color      = ColorRgba.White;

                            vertexIndex += 4;
                        }
                    }

                    device.AddVertices(material, VertexMode.Quads, cachedVertices, 0, vertexIndex);
                    device.Render();
                }
            }

            cachedTexturedBackground = targetTexture;
        }
Example #18
0
        protected void PrepareVerticesSmooth(ref VertexC1P3T4A1[] vertices, IDrawDevice device, float curAnimFrameFade, ColorRgba mainClr, Rect uvRect, Rect uvRectNext)
        {
            Vector3 pos = this.gameobj.Transform.Pos;

            Vector2 xDot, yDot;

            MathF.GetTransformDotVec(this.gameobj.Transform.Angle, this.gameobj.Transform.Scale, out xDot, out yDot);

            Rect    rectTemp = rect.Transformed(gameobj.Transform.Scale, gameobj.Transform.Scale);
            Vector2 edge1    = rectTemp.TopLeft;
            Vector2 edge2    = rectTemp.BottomLeft;
            Vector2 edge3    = rectTemp.BottomRight;
            Vector2 edge4    = rectTemp.TopRight;

            MathF.TransformDotVec(ref edge1, ref xDot, ref yDot);
            MathF.TransformDotVec(ref edge2, ref xDot, ref yDot);
            MathF.TransformDotVec(ref edge3, ref xDot, ref yDot);
            MathF.TransformDotVec(ref edge4, ref xDot, ref yDot);

            float left       = uvRect.X;
            float right      = uvRect.RightX;
            float top        = uvRect.Y;
            float bottom     = uvRect.BottomY;
            float nextLeft   = uvRectNext.X;
            float nextRight  = uvRectNext.RightX;
            float nextTop    = uvRectNext.Y;
            float nextBottom = uvRectNext.BottomY;

            if ((flipMode & FlipMode.Horizontal) != FlipMode.None)
            {
                edge1.X = -edge1.X;
                edge2.X = -edge2.X;
                edge3.X = -edge3.X;
                edge4.X = -edge4.X;
            }
            if ((flipMode & FlipMode.Vertical) != FlipMode.None)
            {
                edge1.Y = -edge1.Y;
                edge2.Y = -edge2.Y;
                edge3.Y = -edge3.Y;
                edge4.Y = -edge4.Y;
            }

            if (vertices == null /*|| vertices.Length != 4*/)
            {
                vertices = new VertexC1P3T4A1[4];
            }

            vertices[0].Pos.X      = pos.X + edge1.X;
            vertices[0].Pos.Y      = pos.Y + edge1.Y;
            vertices[0].Pos.Z      = pos.Z + VertexZOffset;
            vertices[0].TexCoord.X = left;
            vertices[0].TexCoord.Y = top;
            vertices[0].TexCoord.Z = nextLeft;
            vertices[0].TexCoord.W = nextTop;
            vertices[0].Color      = mainClr;
            vertices[0].Attrib     = curAnimFrameFade;

            vertices[1].Pos.X      = pos.X + edge2.X;
            vertices[1].Pos.Y      = pos.Y + edge2.Y;
            vertices[1].Pos.Z      = pos.Z + VertexZOffset;
            vertices[1].TexCoord.X = left;
            vertices[1].TexCoord.Y = bottom;
            vertices[1].TexCoord.Z = nextLeft;
            vertices[1].TexCoord.W = nextBottom;
            vertices[1].Color      = mainClr;
            vertices[1].Attrib     = curAnimFrameFade;

            vertices[2].Pos.X      = pos.X + edge3.X;
            vertices[2].Pos.Y      = pos.Y + edge3.Y;
            vertices[2].Pos.Z      = pos.Z + VertexZOffset;
            vertices[2].TexCoord.X = right;
            vertices[2].TexCoord.Y = bottom;
            vertices[2].TexCoord.Z = nextRight;
            vertices[2].TexCoord.W = nextBottom;
            vertices[2].Color      = mainClr;
            vertices[2].Attrib     = curAnimFrameFade;

            vertices[3].Pos.X      = pos.X + edge4.X;
            vertices[3].Pos.Y      = pos.Y + edge4.Y;
            vertices[3].Pos.Z      = pos.Z + VertexZOffset;
            vertices[3].TexCoord.X = right;
            vertices[3].TexCoord.Y = top;
            vertices[3].TexCoord.Z = nextRight;
            vertices[3].TexCoord.W = nextTop;
            vertices[3].Color      = mainClr;
            vertices[3].Attrib     = curAnimFrameFade;

            if (pixelGrid)
            {
                vertices[0].Pos.X = MathF.Round(vertices[0].Pos.X);
                vertices[1].Pos.X = MathF.Round(vertices[1].Pos.X);
                vertices[2].Pos.X = MathF.Round(vertices[2].Pos.X);
                vertices[3].Pos.X = MathF.Round(vertices[3].Pos.X);

                if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2)
                {
                    vertices[0].Pos.X += 0.5f;
                    vertices[1].Pos.X += 0.5f;
                    vertices[2].Pos.X += 0.5f;
                    vertices[3].Pos.X += 0.5f;
                }

                vertices[0].Pos.Y = MathF.Round(vertices[0].Pos.Y);
                vertices[1].Pos.Y = MathF.Round(vertices[1].Pos.Y);
                vertices[2].Pos.Y = MathF.Round(vertices[2].Pos.Y);
                vertices[3].Pos.Y = MathF.Round(vertices[3].Pos.Y);

                if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2)
                {
                    vertices[0].Pos.Y += 0.5f;
                    vertices[1].Pos.Y += 0.5f;
                    vertices[2].Pos.Y += 0.5f;
                    vertices[3].Pos.Y += 0.5f;
                }
            }
        }
Example #19
0
        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;
            }
        }
Example #20
0
        protected virtual void OnFixedUpdate(float timeMult)
        {
            if (currentCarryOver.HasValue)
            {
                bool playersReady = true;
                foreach (Player player in players)
                {
                    // Exit type is already provided
                    playersReady &= player.OnLevelChanging(ExitType.None);
                }

                if (playersReady)
                {
                    if (levelChangeTimer > 0)
                    {
                        levelChangeTimer -= timeMult;
                    }
                    else
                    {
                        root.ChangeLevel(currentCarryOver.Value);
                        currentCarryOver = null;
                        initState        = InitState.Disposed;
                        return;
                    }
                }
            }

            if (difficulty != GameDifficulty.Multiplayer)
            {
                if (players.Count > 0)
                {
                    Vector3 pos = players[0].Transform.Pos;
                    int     tx1 = (int)pos.X >> 5;
                    int     ty1 = (int)pos.Y >> 5;
                    int     tx2 = tx1;
                    int     ty2 = ty1;

#if ENABLE_SPLITSCREEN
                    for (int i = 1; i < players.Count; i++)
                    {
                        Vector3 pos2 = players[i].Transform.Pos;
                        int     tx   = (int)pos2.X >> 5;
                        int     ty   = (int)pos2.Y >> 5;
                        if (tx1 > tx)
                        {
                            tx1 = tx;
                        }
                        else if (tx2 < tx)
                        {
                            tx2 = tx;
                        }
                        if (ty1 > ty)
                        {
                            ty1 = ty;
                        }
                        else if (ty2 < ty)
                        {
                            ty2 = ty;
                        }
                    }
#endif

                    // ToDo: Remove this branching
#if __ANDROID__
                    const int ActivateTileRange = 20;
#else
                    const int ActivateTileRange = 26;
#endif
                    tx1 -= ActivateTileRange;
                    ty1 -= ActivateTileRange;
                    tx2 += ActivateTileRange;
                    ty2 += ActivateTileRange;

                    for (int i = 0; i < actors.Count; i++)
                    {
                        if (actors[i].OnTileDeactivate(tx1 - 2, ty1 - 2, tx2 + 2, ty2 + 2))
                        {
                            i--;
                        }
                    }

                    eventMap.ActivateEvents(tx1, ty1, tx2, ty2, initState != InitState.Initializing);
                }

                eventMap.ProcessGenerators(timeMult);
            }

            ResolveCollisions();

            // Ambient Light Transition
            if (ambientLightCurrent != ambientLightTarget)
            {
                float step = timeMult * 0.012f;
                if (MathF.Abs(ambientLightCurrent - ambientLightTarget) < step)
                {
                    ambientLightCurrent = ambientLightTarget;
                }
                else
                {
                    ambientLightCurrent += step * ((ambientLightTarget < ambientLightCurrent) ? -1 : 1);
                }
            }

            // Weather
            if (weatherType != WeatherType.None && commonResources.Graphics != null)
            {
                // ToDo: Apply weather effect to all other cameras too
                Vector3 viewPos = cameras[0].Transform.Pos;
                for (int i = 0; i < weatherIntensity; i++)
                {
                    TileMap.DebrisCollisionAction collisionAction;
                    if (weatherOutdoors)
                    {
                        collisionAction = TileMap.DebrisCollisionAction.Disappear;
                    }
                    else
                    {
                        collisionAction = (MathF.Rnd.NextFloat() > 0.7f
                            ? TileMap.DebrisCollisionAction.None
                            : TileMap.DebrisCollisionAction.Disappear);
                    }

                    Vector3 debrisPos = viewPos + MathF.Rnd.NextVector3((LevelRenderSetup.TargetSize.X / -2) - 40,
                                                                        (LevelRenderSetup.TargetSize.Y * -2 / 3), MainPlaneZ,
                                                                        LevelRenderSetup.TargetSize.X + 120, LevelRenderSetup.TargetSize.Y, 0);

                    if (weatherType == WeatherType.Rain)
                    {
                        GraphicResource res      = commonResources.Graphics["Rain"];
                        Material        material = res.Material.Res;
                        Texture         texture  = material.MainTexture.Res;

                        float scale  = MathF.Rnd.NextFloat(0.4f, 1.1f);
                        float speedX = MathF.Rnd.NextFloat(2.2f, 2.7f) * scale;
                        float speedY = MathF.Rnd.NextFloat(7.6f, 8.6f) * scale;

                        debrisPos.Z = MainPlaneZ * scale;

                        tileMap.CreateDebris(new TileMap.DestructibleDebris {
                            Pos   = debrisPos,
                            Size  = res.Base.FrameDimensions,
                            Speed = new Vector2(speedX, speedY),

                            Scale = scale,
                            Angle = MathF.Atan2(speedY, speedX),
                            Alpha = 1f,

                            Time = 180f,

                            Material       = material,
                            MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)),

                            CollisionAction = collisionAction
                        });
                    }
                    else
                    {
                        GraphicResource res      = commonResources.Graphics["Snow"];
                        Material        material = res.Material.Res;
                        Texture         texture  = material.MainTexture.Res;

                        float scale  = MathF.Rnd.NextFloat(0.4f, 1.1f);
                        float speedX = MathF.Rnd.NextFloat(-1.6f, -1.2f) * scale;
                        float speedY = MathF.Rnd.NextFloat(3f, 4f) * scale;
                        float accel  = MathF.Rnd.NextFloat(-0.008f, 0.008f) * scale;

                        debrisPos.Z = MainPlaneZ * scale;

                        tileMap.CreateDebris(new TileMap.DestructibleDebris {
                            Pos          = debrisPos,
                            Size         = res.Base.FrameDimensions,
                            Speed        = new Vector2(speedX, speedY),
                            Acceleration = new Vector2(accel, -MathF.Abs(accel)),

                            Scale      = scale,
                            Angle      = MathF.Rnd.NextFloat(MathF.TwoPi),
                            AngleSpeed = speedX * 0.02f,
                            Alpha      = 1f,

                            Time = 180f,

                            Material       = material,
                            MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)),

                            CollisionAction = collisionAction
                        });
                    }
                }
            }

            // Active Boss
            if (activeBoss != null && activeBoss.Scene == null)
            {
                activeBoss = null;

                Hud hud = rootObject.GetComponent <Hud>();
                if (hud != null)
                {
                    hud.ActiveBoss = null;
                }

                InitLevelChange(ExitType.Normal, null);
                levelChangeTimer = 300;
            }

            if (initState == InitState.Initializing)
            {
                initState = InitState.Initialized;
            }


            collisionsCountA = 0;
            collisionsCountB = 0;
            collisionsCountC = 0;
        }