Example #1
0
        // Update is called once per frame
        void Update()
        {
            if (Game.instance.isPaused)
            {
                return;
            }

            UpdateTranslation();
            RotateTowardsPlayer();

            time += Time.deltaTime;
            if (time >= Game.instance.tankLaunchPeriod)
            {
                // launching cannonball
                time -= Game.instance.tankLaunchPeriod;

                // start and end positions
                Vector3    start     = transform.localPosition;
                Vector2Int playerBox = TerrainArea.instance.BoxFromLocalPosition(Player.instance.transform.localPosition);
                Vector3    end       = TerrainArea.instance.LocalPositionFromBox(playerBox.x, playerBox.y, TerrainArea.instance.GetBox(playerBox.x, playerBox.y).top + Cannonball.RADIUS);
                float      distance  = (new Vector2(end.z - start.z, end.x - start.x)).magnitude;
                float      duration  = distance / Cannonball.SPEED;
                if (duration < .0001f)
                {
                    duration = 1;
                }

                // binary searching to determine height of cannonball arc
                float low = Mathf.Max(start.y, end.y);
                float high = low * 2;
                float paraA, paraB, paraC;

                // look for height of arc that won't hit boxes
                while (true)
                {
                    Parabola.Create(start.y, high, end.y, out paraA, out paraB, out paraC);
                    if (!Cannonball.CheckBoxCollision(start, end, paraA, paraB, paraC))
                    {
                        // high enough
                        break;
                    }
                    // not high enough.  Double value
                    low   = high;
                    high *= 2;
                    // failsafe
                    if (high > 9999)
                    {
                        return;                         // skip launch
                    }
                }

                // do binary searches to narrow down
                while (high - low > Game.instance.playerParabolaPrecision)
                {
                    float mid = (low + high) / 2;
                    Parabola.Create(start.y, mid, end.y, out paraA, out paraB, out paraC);
                    if (Cannonball.CheckBoxCollision(start, end, paraA, paraB, paraC))
                    {
                        // not high enough
                        low = mid;
                    }
                    else
                    {
                        // too high
                        high = mid;
                    }
                }

                // launch with calculated height
                float      height     = (low + high) / 2;
                Cannonball cannonball = Cannonball.Create(transform.parent, start);
                cannonball.Launch(end, height, duration);

                // set cannon rotation
                SetCannonRotation(Mathf.Atan2(Parabola.Solve(paraA, paraB, paraC, .1f) - Parabola.Solve(paraA, paraB, paraC, 0), .1f) * Mathf.Rad2Deg);
            }
        }
Example #2
0
            public void Execute(ref Translation position, ref ArcState arc)
            {
                float t = ElapsedTime - arc.StartTime;

                if (t > arc.Duration)
                {
                    // Compute the next arc info
                    int2 playerCoords = TerrainSystem.PositionToBlockCoords(position.Value.x, position.Value.z, TerrainSize);
                    int2 dir          = math.clamp(MouseBoxCoords - playerCoords,
                                                   new int2(-1, -1), new int2(1, 1));
                    int2 destCoords = playerCoords + dir;
                    // If destination is outside the terrain bounds, don't move.
                    if (destCoords.x < 0 || destCoords.x >= TerrainSize.x ||
                        destCoords.y < 0 || destCoords.y >= TerrainSize.y)
                    {
                        destCoords = playerCoords;
                    }
                    int playerBlockIndex = TerrainSystem.BlockCoordsToIndex(playerCoords, TerrainSize);
                    int destBlockIndex   = TerrainSystem.BlockCoordsToIndex(destCoords, TerrainSize);
                    // If destination is occupied, don't move.
                    if (IsBlockOccupied[destBlockIndex] != 0)
                    {
                        destCoords     = playerCoords;
                        destBlockIndex = playerBlockIndex;
                    }

                    float playerBlockHeight = BlockHeights[playerBlockIndex];
                    float destBlockHeight   = BlockHeights[destBlockIndex];
                    float parabolaHeight    = math.max(playerBlockHeight, destBlockHeight);
                    if (dir.x != 0 && dir.y != 0)
                    {
                        // If jumping diagonally, the parabola height must take into account the directly
                        // adjacent blocks as well.
                        int2 adjacentCoordsX = playerCoords + new int2(dir.x, 0);
                        if (adjacentCoordsX.x >= 0 && adjacentCoordsX.x < TerrainSize.x)
                        {
                            int   adjacentIndexX  = TerrainSystem.BlockCoordsToIndex(adjacentCoordsX, TerrainSize);
                            float adjacentHeightX = BlockHeights[adjacentIndexX];
                            parabolaHeight = math.max(parabolaHeight, adjacentHeightX);
                        }
                        int2 adjacentCoordsZ = playerCoords + new int2(0, dir.y);
                        if (adjacentCoordsZ.y >= 0 && adjacentCoordsZ.y < TerrainSize.y)
                        {
                            int   adjacentIndexZ  = TerrainSystem.BlockCoordsToIndex(adjacentCoordsZ, TerrainSize);
                            float adjacentHeightZ = BlockHeights[adjacentIndexZ];
                            parabolaHeight = math.max(parabolaHeight, adjacentHeightZ);
                        }
                    }
                    parabolaHeight += BOUNCE_HEIGHT;

                    Parabola.Create(playerBlockHeight, parabolaHeight, destBlockHeight,
                                    out arc.Parabola.x, out arc.Parabola.y, out arc.Parabola.z);
                    arc.StartPos =
                        TerrainSystem.BlockCoordsToPosition(playerCoords, playerBlockHeight, TerrainSize);
                    arc.EndPos =
                        TerrainSystem.BlockCoordsToPosition(destCoords, destBlockHeight, TerrainSize);
                    arc.StartTime = ElapsedTime;
                    float distance = math.distance(playerCoords, destCoords);
                    arc.Duration = math.max(1, distance) * BOUNCE_BASE_DURATION;
                }
                else
                {
                    // Get the current height along the parabola
                    float s = t / arc.Duration;
                    position.Value = new float3(
                        math.lerp(arc.StartPos.x, arc.EndPos.x, s),
                        Parabola.Solve(arc.Parabola.x, arc.Parabola.y, arc.Parabola.z, s),
                        math.lerp(arc.StartPos.z, arc.EndPos.z, s)
                        );
                }
            }