Example #1
0
        /// <summary>
        /// 壁コリジョンを生成するための部屋の縁を求める
        /// 縁は幅1の矩形の集合として返す
        /// </summary>
        /// <returns></returns>
        public IEnumerable<Rectangle> GetOutlines()
        {
            var result = new List<Rectangle>();

            var leftX = LeftTopCoord.X - 1;
            var rightX = LeftTopCoord.X + Width.X;
            var topY = LeftTopCoord.Y - 1;
            var bottomY = LeftTopCoord.Y + Width.Y;

            // 部屋の各辺にポータルがあるか
            // left, right, top bottom の順
            bool[] edgeHasPortal = { false, false, false, false };

            foreach (var portal in Portals)
            {
                if (portal.ConnectedPaths.Count == 0)
                {
                    continue;
                }

                var pathWidth = portal.ConnectedPaths[0].Width;

                if (portal.Position.X == leftX || portal.Position.X == rightX)
                {
                    // ポータルが部屋の左右にある場合

                    if (portal.Position.X == leftX)
                    {
                        edgeHasPortal[0] = true;
                    }
                    else if (portal.Position.X == rightX)
                    {
                        edgeHasPortal[1] = true;
                    }

                    var outline0 = new Rectangle(
                        portal.Position.X,
                        LeftTopCoord.Y,
                        1,
                        portal.Position.Y - LeftTopCoord.Y - pathWidth / 2);
                    result.Add(outline0);
                    result.Add(new Rectangle(
                        portal.Position.X,
                        portal.Position.Y + 1 + pathWidth / 2,
                        1,
                        Width.Y - outline0.Height - pathWidth));
                }
                else if (portal.Position.Y == topY || portal.Position.Y == bottomY)
                {
                    // ポータルが部屋の上下にある場合

                    if (portal.Position.Y == topY)
                    {
                        edgeHasPortal[2] = true;
                    }
                    else if (portal.Position.Y == bottomY)
                    {
                        edgeHasPortal[3] = true;
                    }

                    var outline0 = new Rectangle(
                        LeftTopCoord.X,
                        portal.Position.Y,
                        portal.Position.X - LeftTopCoord.X - pathWidth / 2,
                        1);
                    result.Add(outline0);
                    result.Add(new Rectangle(
                        portal.Position.X + 1 + pathWidth / 2,
                        portal.Position.Y,
                        Width.X - outline0.Width - pathWidth,
                        1));
                }
            }

            // ポータルがない辺の縁を生成
            
            // 左辺
            if (!edgeHasPortal[0])
            {
                result.Add(new Rectangle(leftX, topY + 1, 1, Width.Y));
            }

            // 右辺
            if (!edgeHasPortal[1])
            {
                result.Add(new Rectangle(leftX + Width.X + 1, topY + 1, 1, Width.Y));
            }

            // 上辺
            if (!edgeHasPortal[2])
            {
                result.Add(new Rectangle(leftX + 1, topY, Width.X, 1));
            }

            // 下辺
            if (!edgeHasPortal[3])
            {
                result.Add(new Rectangle(leftX + 1, topY + Width.Y + 1, Width.X, 1));
            }

            return result;
        }
Example #2
0
        void CutPortalOutlines(ref Rectangle[] outlines, int cut, int direction)
        {
            for (var i = 0; i < 2; ++i)
            {
                var connectedPortal = Portals[i];

                var realcut = cut;

                // 通路同士のポータルの場合、幅は広い方になるので余分に削る
                if (connectedPortal.ConnectedPaths.Count == 2)
                {
                    var maxWidth = MathUtil.Max(
                        connectedPortal.ConnectedPaths[0].Width,
                        connectedPortal.ConnectedPaths[1].Width);

                    // 向こうの通路がこちらより広ければ
                    if (maxWidth > Width)
                    {
                        realcut += (maxWidth - Width) / 2;
                    }
                }

                // 水平通路で
                if (direction == 0)
                {
                    // 左がポータルなら
                    if (outlines[0].X == connectedPortal.Position.X)
                    {
                        outlines[0].X += realcut;
                        outlines[1].X += realcut;
                        outlines[0].Width -= realcut;
                        outlines[1].Width -= realcut;
                    }

                    // 右がポータルなら
                    if (outlines[0].X + outlines[0].Width == connectedPortal.Position.X)
                    {
                        outlines[0].Width -= realcut - 1;
                        outlines[1].Width -= realcut - 1;
                    }
                }
                // 垂直通路で
                else if (direction == 1)
                {
                    // 上がポータルなら
                    if (outlines[0].Y == connectedPortal.Position.Y)
                    {
                        outlines[0].Y += realcut;
                        outlines[1].Y += realcut;
                        outlines[0].Height -= realcut;
                        outlines[1].Height -= realcut;
                    }

                    // 下がポータルなら
                    if (outlines[0].Y + outlines[0].Height == connectedPortal.Position.Y)
                    {
                        outlines[0].Height -= realcut - 1;
                        outlines[1].Height -= realcut - 1;
                    }
                }
            }
        }
Example #3
0
        /// <summary>
        /// 壁コリジョン生成のための通路の縁を計算する
        /// </summary>
        /// <returns></returns>
        public IEnumerable<Rectangle> GetOutlines()
        {
            var result = new List<Rectangle>();

            // 現在地点
            var position = new int[2] { Portals[0].Position.X, Portals[0].Position.Y };

            // 進む方向(水平か垂直か)
            var direction = IsHorizontal ? 0 : 1;

            // 1回に進む歩数(正か負か)
            var stepValue = new int[2]
            { 
                Math.Sign(Portals[1].Position.X - Portals[0].Position.X),
                Math.Sign(Portals[1].Position.Y - Portals[0].Position.Y)
            };

            for (var i = 0; i < steps.Count; ++i)
            {
                var start = new Point(position[0], position[1]);

                position[direction] += stepValue[direction] * steps[i];

                var end = new Point(position[0], position[1]);

                var outlines = new Rectangle[2];

                // まずstepの長さの壁を作る

                if (direction == 0)
                {
                    // 上側の壁
                    outlines[0].X = MathUtil.Min(start.X, end.X);
                    outlines[0].Y = start.Y - (Width / 2) - 1;
                    outlines[0].Width = steps[i];
                    outlines[0].Height = 1;

                    // 下側の壁
                    outlines[1].X = MathUtil.Min(start.X, end.X);
                    outlines[1].Y = start.Y + (Width / 2) + 1;
                    outlines[1].Width = steps[i];
                    outlines[1].Height = 1;
                }
                else if (direction == 1)
                {
                    // 左側の壁
                    outlines[0].X = start.X - (Width / 2) - 1;
                    outlines[0].Y = MathUtil.Min(start.Y, end.Y);
                    outlines[0].Width = 1;
                    outlines[0].Height = steps[i];

                    // 右側の壁
                    outlines[1].X = start.X + (Width / 2) + 1;
                    outlines[1].Y = MathUtil.Min(start.Y, end.Y);
                    outlines[1].Width = 1;
                    outlines[1].Height = steps[i];
                }

                // 曲がり角の内側の壁を削って外側の壁を伸ばす
                // 曲がり角の向きと進行方向によって8パターンある

                // 削る量
                var cut = (Width / 2) + 1;
                // 伸ばす量
                var add = (Width / 2) + 1;

                // 最初の通路でなければ始点をいじる
                if (i > 0)
                {
                    // 水平通路で
                    if (direction == 0)
                    {                        
                        // 前の通路が下から上で
                        if (stepValue[1 - direction] < 0)
                        {
                            // この通路が右から左なら
                            if (stepValue[direction] < 0)
                            {
                                // 下側の壁の右を削る
                                // 上側の壁の右を伸ばす
                            }
                            // この通路が左から右なら
                            else
                            {
                                // 下側の壁の左を削る
                                outlines[1].X += cut;
                                // 上側の壁の左を伸ばす
                                outlines[0].X -= add;
                            }

                            outlines[0].Width += add;
                            outlines[1].Width -= cut;
                        }
                        // 前の通路が上から下で
                        else
                        {
                            // この通路が右から左なら
                            if (stepValue[direction] < 0)
                            {
                                // 上側の壁の右を削る
                                // 下側の壁の右を伸ばす
                            }
                            // この通路が左から右なら
                            else
                            {
                                // 上側の壁の左を削る
                                outlines[0].X += cut;
                                // 下側の壁の左を伸ばす
                                outlines[1].X -= add;
                            }

                            outlines[0].Width -= cut;
                            outlines[1].Width += add;
                        }
                    }
                    // 垂直通路で
                    else if (direction == 1)
                    {
                        // 前の通路が右から左で
                        if (stepValue[1 - direction] < 0)
                        {
                            // この通路が下から上なら
                            if (stepValue[direction] < 0)
                            {
                                // 右側の壁の下を削る
                                // 左側の壁の下を伸ばす
                            }
                            // この通路が上から下なら
                            else
                            {
                                // 右側の壁の上を削る
                                outlines[1].Y += cut;
                                // 左側の壁の上を伸ばす
                                outlines[0].Y -= add;
                            }

                            outlines[0].Height += add;
                            outlines[1].Height -= cut;
                        }
                        // 前の通路が左から右で
                        else
                        {
                            // この通路が下から上なら
                            if (stepValue[direction] < 0)
                            {
                                // 左側の壁の下を削る
                                // 右側の壁の下を伸ばす
                            }
                            // この通路が上から下なら
                            else
                            {
                                // 左側の壁の上を削る
                                outlines[0].Y += cut;
                                // 右側の壁の上を伸ばす
                                outlines[1].Y -= add;
                            }

                            outlines[0].Height -= cut;
                            outlines[1].Height += add;
                        }
                    }
                }
                // 最初のstepならポータル部分を削る
                else
                {
                    CutPortalOutlines(ref outlines, cut, direction);                  
                }

                // 最後の通路でなければ終点をいじる
                if (i < steps.Count - 1)
                {
                    // 水平通路で
                    if (direction == 0)
                    {
                        // 次の通路が下から上で
                        if (stepValue[1 - direction] < 0)
                        {
                            // この通路が右から左なら
                            if (stepValue[direction] < 0)
                            {
                                // 上側の壁の左を削る
                                outlines[0].X += cut;
                                // 下側の壁の左を伸ばす
                                outlines[1].X -= add;
                            }
                            // この通路が左から右なら
                            else
                            {
                                // 上側の壁の右を削る
                                // 下側の壁の右を伸ばす
                            }

                            outlines[0].Width -= cut;
                            outlines[1].Width += add;
                        }
                        // 次の通路が上から下で
                        else
                        {
                            // この通路が右から左なら
                            if (stepValue[direction] < 0)
                            {
                                // 下側の壁の左を削る
                                outlines[1].X += cut;
                                // 上側の壁の左を伸ばす
                                outlines[0].X -= add;
                            }
                            // この通路が左から右なら
                            else
                            {
                                // 下側の壁の右を削る
                                // 上側の壁の右を伸ばす
                            }

                            outlines[0].Width += add;
                            outlines[1].Width -= cut;
                        }
                    }
                    // 垂直通路で
                    else if (direction == 1)
                    {
                        // 次の通路が右から左で
                        if (stepValue[1 - direction] < 0)
                        {
                            // この通路が下から上なら
                            if (stepValue[direction] < 0)
                            {
                                // 左側の壁の上を削る
                                outlines[0].Y += cut;
                                // 右側の壁の上を伸ばす
                                outlines[1].Y -= add;
                            }
                            // この通路が上から下なら
                            else
                            {
                                // 左側の壁の下を削る
                                // 右側の壁の下を伸ばす
                            }

                            outlines[0].Height -= cut;
                            outlines[1].Height += add;
                        }
                        // 次の通路が左から右で
                        else
                        {
                            // この通路が下から上なら
                            if (stepValue[direction] < 0)
                            {
                                // 右側の壁の上を削る
                                outlines[1].Y += cut;
                                // 左側の壁の上の伸ばす
                                outlines[0].Y -= add;
                            }
                            // この通路が上から下なら
                            else
                            {
                                // 右側の壁の下を削る
                                // 左側の壁の下を伸ばす
                            }

                            outlines[0].Height += add;
                            outlines[1].Height -= cut;
                        }
                    }
                }
                // 最後のstepならポータル部分を削る
                else
                {
                    CutPortalOutlines(ref outlines, cut, direction);
                }

                result.AddRange(outlines);

                direction = 1 - direction;
            }

            return result;
        }
Example #4
0
        Rectangle CalcStepRect2(Point start, Point end, bool horizontal)
        {
            // 通路幅の半分だけ幅を広げる
            // 幅3の通路なら1マス広げる
            var additional = Width / 2;

            // 曲がり角部分は削る
            // 幅3の通路なら2マス削る
            var cut = additional + 1;

            // 水平通路ならx方向を削る
            // 垂直通路ならy方向を削る

            var x = Math.Min(start.X, end.X) + (horizontal ? cut : -additional);
            var y = Math.Min(start.Y, end.Y) + (horizontal ? -additional : cut);
            
            var w = Math.Abs(end.X - start.X) + 1;
            w = horizontal ? (w - cut * 2) : Width;
            var h = Math.Abs(end.Y - start.Y) + 1;
            h = horizontal ? Width : (h - cut * 2);

            var result = new Rectangle(x, y, w, h);

            return result;
        }
Example #5
0
        /// <summary>
        /// 通路の曲がり角間の線分一つの矩形(きゅーぶ単位)を返す
        /// </summary>
        Rectangle CalcStepRect(Point start, Point end)
        {
            // 通路幅の半分だけ前後左右を伸ばす
            var additional = Width / 2;

            var result = new Rectangle(
                Math.Min(start.X, end.X) - additional, 
                Math.Min(start.Y, end.Y) - additional,
                Math.Abs(end.X - start.X) + 1 + additional * 2, 
                Math.Abs(end.Y - start.Y) + 1 + additional * 2);

            return result;
        }
Example #6
0
        /// <summary>
        /// 壁コリジョン生成用の縁を計算する
        /// </summary>
        /// <returns></returns>
        public IEnumerable<Rectangle> GetOutlines()
        {
            var result = new List<Rectangle>();

            // 部屋につながっている
            if (ConnectedRoom != null)
            {
                global::System.Diagnostics.Debug.Assert(ConnectedPaths.Count == 1);

                var pathWidthHalfPlusOne = ConnectedPaths[0].Width / 2 + 1;

                var connectedRoomSide = GetConnectedRoomSide();

                // 部屋の左辺
                if (connectedRoomSide == 0)
                {
                    result.Add(new Rectangle(
                        Position.X - pathWidthHalfPlusOne + 1,
                        Position.Y - pathWidthHalfPlusOne,
                        pathWidthHalfPlusOne,
                        1));
                    result.Add(new Rectangle(
                        Position.X - pathWidthHalfPlusOne + 1,
                        Position.Y + pathWidthHalfPlusOne,
                        pathWidthHalfPlusOne,
                        1));
                }
                // 部屋の右辺
                else if (connectedRoomSide == 1)
                {
                    result.Add(new Rectangle(
                        Position.X,
                        Position.Y - pathWidthHalfPlusOne,
                        pathWidthHalfPlusOne,
                        1));
                    result.Add(new Rectangle(
                        Position.X,
                        Position.Y + pathWidthHalfPlusOne,
                        pathWidthHalfPlusOne,
                        1));
                }
                // 部屋の上辺
                else if (connectedRoomSide == 2)
                {
                    result.Add(new Rectangle(
                        Position.X - pathWidthHalfPlusOne,
                        Position.Y - pathWidthHalfPlusOne + 1,
                        1,
                        pathWidthHalfPlusOne));
                    result.Add(new Rectangle(
                        Position.X + pathWidthHalfPlusOne,
                        Position.Y - pathWidthHalfPlusOne + 1,
                        1,
                        pathWidthHalfPlusOne));
                }
                // 部屋の下辺
                else if (connectedRoomSide == 3)
                {
                    result.Add(new Rectangle(
                        Position.X - pathWidthHalfPlusOne,
                        Position.Y,
                        1,
                        pathWidthHalfPlusOne));
                    result.Add(new Rectangle(
                        Position.X + pathWidthHalfPlusOne,
                        Position.Y,
                        1,
                        pathWidthHalfPlusOne));
                }
            }
            // 2本の通路につながっている
            else if (ConnectedPaths.Count == 2)
            {
                int[] pathWidth = 
                {
                    ConnectedPaths[0].Width,
                    ConnectedPaths[1].Width
                };
                int[] pathWidthHalf =
                {
                    pathWidth[0] / 2,
                    pathWidth[1] / 2
                };

                var maxWidth = MathUtil.Max(pathWidth[0], pathWidth[1]);
                var minWidth = MathUtil.Min(pathWidth[0], pathWidth[1]);

                // とりあえず全方位の壁を作る
                CreateAllOutlines(result, maxWidth, MathUtil.Max(pathWidthHalf[0], pathWidthHalf[1]));

                var removeList = new List<Rectangle>();

                for (var i = 0; i < 2; ++i)
                {
                    var connectedPathSide = GetConnectedPathSide(ConnectedPaths[i]);

                    removeList.Add(result[connectedPathSide]);

                    // 広い通路の方は何も追加せず
                    if (pathWidth[i] == maxWidth)
                    {
                    }
                    // 狭い通路の方は穴を開けて二分割した壁を追加
                    else if (maxWidth > minWidth && pathWidth[i] == minWidth)
                    {
                        if (connectedPathSide == 0 || connectedPathSide == 1)
                        {
                            var outline0 = new Rectangle(
                                result[connectedPathSide].X,
                                result[connectedPathSide].Y,
                                1,
                                (maxWidth - minWidth) / 2);
                            result.Add(outline0);
                            result.Add(new Rectangle(
                                outline0.X,
                                outline0.Y + outline0.Height + minWidth,
                                1,
                                (maxWidth - minWidth) / 2));
                        }
                        else if (connectedPathSide == 2 || connectedPathSide == 3)
                        {
                            var outline0 = new Rectangle(
                                result[connectedPathSide].X,
                                result[connectedPathSide].Y,
                                (maxWidth - minWidth) / 2,
                                1);
                            result.Add(outline0);
                            result.Add(new Rectangle(
                                outline0.X + outline0.Width + minWidth,
                                outline0.Y,
                                (maxWidth - minWidth) / 2,
                                1));
                        }
                    }
                }

                // 元の壁を消す
                removeList.ForEach((rect) => { result.Remove(rect); });
            }
            // 1本の通路につながっている(袋小路)
            else if (ConnectedPaths.Count == 1)
            {
                var pathWidth = ConnectedPaths[0].Width;
                var pathWidthHalf = pathWidth / 2;

                // とりあえず全方位の壁を作る
                CreateAllOutlines(result, pathWidth, pathWidthHalf);

                var connectedPathSide = GetConnectedPathSide(ConnectedPaths[0]);

                // 通路がある方の壁を消去
                result.RemoveAt(connectedPathSide);
            }

            return result;
        }