예제 #1
0
        /// <summary>
        /// Выделить внутренний массив под игровое поле.
        /// </summary>
        /// <param name="newWidth"></param>
        /// <param name="newHeight"></param>
        private void Relocate(int newWidth, int newHeight)
        {
            if (newWidth < 0)
            {
                throw new ArgumentOutOfRangeException("newWidth", newWidth, "Negative width is not allowed.");
            }
            if (newHeight < 0)
            {
                throw new ArgumentOutOfRangeException("newHeight", newHeight, "Negative height is not allowed.");
            }

            if (m_Width > 0 && m_Height > 0)
            {
                CellPlate[] newArray = new CellPlate[newWidth * newHeight];
                for (int x = 0; x < m_Width && x < newWidth; x++)
                {
                    for (int y = 0; y < m_Height && y < newHeight; y++)
                    {
                        newArray[y * newWidth + x] = internalPlateArray[y * m_Width + x];
                    }
                }

                m_Width            = newWidth;
                m_Height           = newHeight;
                internalPlateArray = newArray;
            }
            else
            {
                m_Width            = newWidth;
                m_Height           = newHeight;
                internalPlateArray = new CellPlate[m_Width * m_Height];
            }
        }
 /// <summary>
 /// Конструктор: задаём шашку, чтобы знали, где нажим происходит.
 /// </summary>
 /// <param name="cell">Шашка, на которую действует вытесняющая сила.</param>
 public CellClickEventArgs(CellPlate cell)
 {
     if (cell == null)
     {
         throw new ArgumentNullException("cell");
     }
     m_Cell = cell;
 }
 /// <summary>
 /// Вызывает запуск анимации при помощи внутренного AnimationManager.
 /// </summary>
 /// <param name="cell">Какая ячейка должна прокатится?</param>
 /// <param name="startPosition">С какого места исходит каталово?</param>
 internal void AddTransition(
     CellPlate cell,
     Rectangle startPosition)
 {
     animationManager.StartTransition(
         cell,
         startPosition);
 }
        // Стили окна для "пухлой" границы.

        // Специальные методы для кеширования графических объектов.

        /// <summary>
        /// Отрисовка игрового поля, с бортиками, направляющими,
        /// цельным боками и хорошо проклеенным дном.
        /// </summary>
        /// <param name="e">Обычный параметр. См. описание у базового класса.</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            UpdateGraphics();
            e.Graphics.FillRectangle(
                backBrush,
                e.ClipRectangle);


            e.Graphics.PixelOffsetMode    = PixelOffsetMode.HighQuality;
            e.Graphics.CompositingMode    = CompositingMode.SourceOver;
            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
            //e.Graphics.=CompositingMode.SourceOver;

            for (int x = 0; x < Cells.Width; x++)
            {
                for (int y = 0; y < Cells.Height; y++)
                {
                    CellPlate cell = Cells[x, y];
                    if (cell != null && cell != m_movingCell)
                    {
                        AnimationManager.TransitionInfo transition = animationManager[cell];

                        if (transition == null)
                        {
                            painter.DrawCell(
                                e,
                                cell,
                                CellBackColor,
                                ForeColor,
                                Font);
                        }
                        else
                        {
                            painter.DrawCellTransition(
                                e,
                                cell,
                                CellBackColor,
                                ForeColor,
                                Font,
                                transition.StartPosition,
                                transition.CompletionRatio);
                        }
                    }
                }
            }

            if (m_movingCell != null)
            {
                painter.DrawCell(
                    e,
                    m_movingCell,
                    CellBackColor,
                    ForeColor,
                    Font);
            }
        }
            /// <summary>
            /// Создание "судьбы".
            /// </summary>
            /// <param name="cell">Шашка, которая поедет на своё место.</param>
            /// <param name="startPosition">Старое состояние шашки.</param>
            public TransitionInfo(
                CellPlate cell,
                Rectangle startPosition)
            {
                Cell          = cell;
                StartPosition = startPosition;
                StartTime     = DateTime.Now;

                TransitionArea = PaintUtils.Union(startPosition, cell.CellRectangle);
            }
예제 #6
0
        /// <summary>
        /// Метод, который внешний код вызывает для отрисовки статической шашки (шашки, которая не движется).
        /// </summary>
        /// <param name="e">Стандартный параметр метода OnPaint любого контрола. Совмещает полотно для отрисовки и границы.</param>
        /// <param name="cell">Шашка, которую нужно нарисовать.</param>
        /// <param name="cellBackColor">В каком тоне следует рисовать шашку.</param>
        /// <param name="cellCaptionColor">В каком тоне следует рисовать циферки.</param>
        /// <param name="font">Каким вообще-то шрифтом нужно рисовать цифры.</param>
        public void DrawCell(
            PaintEventArgs e,
            CellPlate cell,
            Color cellBackColor,
            Color cellCaptionColor,
            Font font)
        {
            Rectangle cellRect = cell.CellRectangle;

            DrawCellAt(
                cellRect,
                e, cell, cellBackColor, cellCaptionColor, font);
        }
예제 #7
0
        /// <summary>
        /// Чтобы расставить шашки, есть только один путь.
        /// </summary>
        /// <param name="x">Координата шашки (колонка).</param>
        /// <param name="y">Координата (строка).</param>
        /// <returns>Созданная и расставленная шашка.</returns>
        public CellPlate CreateCell(int x, int y)
        {
            if (this[x, y] != null)
            {
                throw new ArgumentException("Cell at this point is already present.");
            }

            CellPlate result = new CellPlate(this, x, y);

            internalPlateArray[y * Width + x] = result;

            result.Invalidate();

            return(result);
        }
        /// <summary>
        /// Обрабатываем клик на контроле, находим шашку и проводим по бумагам как клик на шашке.
        /// </summary>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            mousePos = new Point(e.X, e.Y);

            base.OnMouseUp(e);

            m_Cells.IsCellRectangleValid = false;
            CellPlate movingCell = m_movingCell;

            m_movingCell = null;

            if (movingCell != null)
            {
                for (int x = 0; x < Cells.Width; x++)
                {
                    for (int y = 0; y < Cells.Height; y++)
                    {
                        CellPlate cell = Cells[x, y];
                        if (cell == null)
                        {
                            if (m_Cells.emptyRect.Contains(mousePos))
                            {
                                Cells.InternalShiftCellRelative(movingCell, x - movingCell.X, y - movingCell.Y, true);
                                Invalidate();
                                return;
                            }
                        }
                        else if (cell.CellRectangle.Contains(mousePos))
                        {
                            if (cell == movingCell)
                            {
                                OnCellClick(new CellClickEventArgs(cell));
                            }
                            else
                            {
                                Cells.InternalShiftCellRelative(movingCell, x - movingCell.X, y - movingCell.Y, false);
                            }
                            Invalidate();
                            return;
                        }
                    }
                }

                Invalidate();
            }
        }
예제 #9
0
        // Методы для упрощения кешированием графических объектов.
        // Если, например, цвет кисте совпадает с требуемым, то кисть используется как есть.
        // Просто аккуратная работа.

        /// <summary>
        /// Внутренний метод класса-рисовальщика CellPainter.
        /// Рисует шашку в некоторой позиции.
        /// </summary>
        /// <param name="cellRect">Позиция, где должна быть порисована шашка.</param>
        /// <param name="e">Стандартный параметр OnPaint.</param>
        /// <param name="cell">Шашка собственной персоной.</param>
        /// <param name="cellBackColor">Цвет фона шашки.</param>
        /// <param name="cellCaptionColor">Цвет шрифта шашки.</param>
        /// <param name="font">Шрифт для циферок. Очень удобно.</param>
        private void DrawCellAt(
            Rectangle cellRect,
            PaintEventArgs e,
            CellPlate cell,
            Color cellBackColor,
            Color cellCaptionColor,
            Font font)
        {
            if (cell == null)
            {
                throw new ArgumentNullException("cell");
            }

            if (!e.ClipRectangle.IntersectsWith(cellRect))
            {
                return;
            }

            UpdateGraphics(cellBackColor, cellCaptionColor);

            cellRect.Inflate(-2, -2);

            Rectangle fillRect = cellRect;

            //fillRect.Offset(0,-1);

            e.Graphics.FillRectangle(
                backBrush,
                fillRect);

            DrawCellBorder(e, cellRect);

            // caption

            Rectangle captionRect = cellRect;

            captionRect.Inflate(-2, -2);
            captionRect.Offset(1, 1);

            e.Graphics.DrawString(
                cell.Caption,
                font,
                captionBrush,
                captionRect,
                SF);
        }
예제 #10
0
        /// <summary>
        /// Нужно рассчитать положения шашек в точных пикселах.
        /// Пока ничего не двигается, специальный флажок "запирает" пересчёт,
        /// то есть насчитанные прямоугольники используются.
        /// При изменении пересчёт вызывается один раз для всего поля.
        /// </summary>
        internal void NeedCellRectangle()
        {
            if (IsCellRectangleValid)
            {
                return;
            }

            Rectangle tableRect = new Rectangle(
                Point.Empty,
                Pool.ClientRectangle.Size);

            tableRect.Inflate(-6, -6);

            Size cellSize = new Size(
                tableRect.Width / Width,
                tableRect.Height / Height);

            int adjX = tableRect.Width - cellSize.Width * Width;
            int adjY = tableRect.Height - cellSize.Height * Height;

            tableRect.Offset(adjX / 2, adjY / 2);
            tableRect.Width  -= adjX - adjX / 2;
            tableRect.Height -= adjY - adjY / 2;

            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    CellPlate cell = this[x, y];
                    Rectangle rect = new Rectangle(
                        tableRect.X + cellSize.Width * x,
                        tableRect.Y + cellSize.Height * y,
                        cellSize.Width,
                        cellSize.Height);
                    if (cell != null)
                    {
                        cell.SetCellRectangle(rect);
                    }
                    else
                    {
                        emptyRect = rect;
                    }
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Метод, который внешний код вызывает для отрисовки движущейся шашки.
        /// Класс AnimationManager отвечает за то, чтобы этот метод был вызван, но не занимается рисованием.
        /// </summary>
        /// <param name="e">Стандартный параметр метода OnPaint.</param>
        /// <param name="cell">Шашка, которая должна быть запечатлена в движении.</param>
        /// <param name="cellBackColor">Цвет фона шашки.</param>
        /// <param name="cellCaptionColor">Цвет цифер на шашке.</param>
        /// <param name="font">Шрифт для цифер. Желательно, разборчивый.</param>
        /// <param name="startPosition">Начальная позиция шашки. То место, с которого она едет.</param>
        /// <param name="completionRatio">Свой путь земной пройдя до половины...</param>
        public void DrawCellTransition(
            PaintEventArgs e,
            CellPlate cell,
            Color cellBackColor,
            Color cellCaptionColor,
            Font font,
            Rectangle startPosition,
            decimal completionRatio)
        {
            Rectangle transitionRect = PaintUtils.Transition(
                startPosition,
                cell.CellRectangle,
                completionRatio);

            DrawCellAt(
                transitionRect,
                e, cell, cellBackColor, cellCaptionColor, font);
        }
        /// <summary>
        /// Запуск анимации ячейки. Пройдёт время и анимация закончится, не стоит об этом беспокоиться.
        /// Всё работу берёт на себя AnimationManager.
        /// </summary>
        /// <param name="cell">Шашечка, которая поедет в дальний край. Шашка официально должна находится на финальной позиции.</param>
        /// <param name="startPosition">Позиция, с которой начинается движение.</param>
        public void StartTransition(
            CellPlate cell,
            Rectangle startPosition)
        {
            TransitionInfo transition = transitionByCell[cell] as TransitionInfo;

            if (transition != null)
            {
                transition.InvalidateTransitionArea();
                transitionByCell.Remove(cell);
            }

            transition = new TransitionInfo(
                cell,
                startPosition);

            transitionByCell[cell] = transition;

            UpdateTimer();
        }
예제 #13
0
        /// <summary>
        /// Сместить шашку.
        /// </summary>
        /// <param name="cell">Шашка.</param>
        /// <param name="relativeX">Координата (колонка).</param>
        /// <param name="relativeY">Координата (строка).</param>
        /// <param name="toEmpty"></param>
        internal void InternalShiftCellRelative(CellPlate cell, int relativeX, int relativeY, bool toEmpty)
        {
            CellPlate oldCell = this[cell.X + relativeX, cell.Y + relativeY];

            if (oldCell != null)
            {
                if (toEmpty)
                {
                    throw new InvalidOperationException("Cannot shift, position is not empty.");
                }
                oldCell.SetXY(cell.X, cell.Y);
            }
            else
            {
                emptyCell.Offset(-relativeX, -relativeY);
            }
            internalPlateArray[cell.Y * Width + cell.X] = oldCell;
            cell.SetXY(cell.X + relativeX, cell.Y + relativeY);
            internalPlateArray[cell.Y * Width + cell.X] = cell;
        }
        /// <summary>
        /// Запуск анимации ячейки. Пройдёт время и анимация закончится, не стоит об этом беспокоиться.
        /// Всё работу берёт на себя AnimationManager.
        /// </summary>
        /// <param name="cell">Шашечка, которая поедет в дальний край. Шашка официально должна находится на финальной позиции.</param>
        /// <param name="startPosition">Позиция, с которой начинается движение.</param>
        public void StartTransition(
            CellPlate cell,
            Rectangle startPosition)
        {
            TransitionInfo transition = transitionByCell[cell] as TransitionInfo;

            if (transition != null)
            {
                transition.InvalidateTransitionArea();
                transitionByCell.Remove(cell);
            }

            transition = new TransitionInfo(
                cell,
                startPosition);

            transitionByCell[cell] = transition;

            UpdateTimer();
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            mousePos = new Point(e.X, e.Y);
            Focus();

            base.OnMouseDown(e);

            m_movingCell = null;
            for (int x = 0; x < Cells.Width; x++)
            {
                for (int y = 0; y < Cells.Height; y++)
                {
                    CellPlate cell = Cells[x, y];
                    if (cell != null &&
                        cell.CellRectangle.Contains(mousePos))
                    {
                        m_Cells.IsCellRectangleValid = true;
                        m_movingCell = cell;
                        return;
                    }
                }
            }
        }
예제 #16
0
        /// <summary>
        /// Выделить внутренний массив под игровое поле.
        /// </summary>
        /// <param name="newWidth"></param>
        /// <param name="newHeight"></param>
        private void Relocate(int newWidth, int newHeight)
        {
            if (newWidth < 0)
                throw new ArgumentOutOfRangeException("newWidth", newWidth, "Negative width is not allowed.");
            if (newHeight < 0)
                throw new ArgumentOutOfRangeException("newHeight", newHeight, "Negative height is not allowed.");

            if (m_Width > 0 && m_Height > 0)
            {
                CellPlate[] newArray = new CellPlate[newWidth*newHeight];
                for (int x = 0; x < m_Width && x < newWidth; x++)
                    for (int y = 0; y < m_Height && y < newHeight; y++)
                        newArray[y*newWidth + x] = internalPlateArray[y*m_Width + x];

                m_Width = newWidth;
                m_Height = newHeight;
                internalPlateArray = newArray;
            }
            else
            {
                m_Width = newWidth;
                m_Height = newHeight;
                internalPlateArray = new CellPlate[m_Width*m_Height];
            }
        }
 /// <summary>
 /// Получение информации о шашке: движется ли она и в какой точке пути.
 /// Оракул раскрывает судьбу.
 /// </summary>
 public TransitionInfo this[CellPlate cell]
 {
     get { return transitionByCell[cell] as TransitionInfo; }
 }
            /// <summary>
            /// Создание "судьбы".
            /// </summary>
            /// <param name="cell">Шашка, которая поедет на своё место.</param>
            /// <param name="startPosition">Старое состояние шашки.</param>
            public TransitionInfo(
                CellPlate cell,
                Rectangle startPosition)
            {
                Cell = cell;
                StartPosition = startPosition;
                StartTime = DateTime.Now;

                TransitionArea = PaintUtils.Union(startPosition, cell.CellRectangle);
            }
 /// <summary>
 /// Вызывает запуск анимации при помощи внутренного AnimationManager.
 /// </summary>
 /// <param name="cell">Какая ячейка должна прокатится?</param>
 /// <param name="startPosition">С какого места исходит каталово?</param>
 internal void AddTransition(
     CellPlate cell,
     Rectangle startPosition)
 {
     animationManager.StartTransition(
         cell,
         startPosition);
 }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            mousePos = new Point(e.X, e.Y);
            Focus();

            base.OnMouseDown(e);

            m_movingCell = null;
            for (int x = 0; x < Cells.Width; x++)
                for (int y = 0; y < Cells.Height; y++)
                {
                    CellPlate cell = Cells[x, y];
                    if (cell != null
                        && cell.CellRectangle.Contains(mousePos))
                    {
                        m_Cells.IsCellRectangleValid = true;
                        m_movingCell = cell;
                        return;
                    }
                }
        }
예제 #21
0
        // Методы для упрощения кешированием графических объектов.
        // Если, например, цвет кисте совпадает с требуемым, то кисть используется как есть.
        // Просто аккуратная работа.
        /// <summary>
        /// Внутренний метод класса-рисовальщика CellPainter.
        /// Рисует шашку в некоторой позиции.
        /// </summary>
        /// <param name="cellRect">Позиция, где должна быть порисована шашка.</param>
        /// <param name="e">Стандартный параметр OnPaint.</param>
        /// <param name="cell">Шашка собственной персоной.</param>
        /// <param name="cellBackColor">Цвет фона шашки.</param>
        /// <param name="cellCaptionColor">Цвет шрифта шашки.</param>
        /// <param name="font">Шрифт для циферок. Очень удобно.</param>
        private void DrawCellAt(
            Rectangle cellRect,
            PaintEventArgs e,
            CellPlate cell,
            Color cellBackColor,
            Color cellCaptionColor,
            Font font)
        {
            if (cell == null)
                throw new ArgumentNullException("cell");

            if (!e.ClipRectangle.IntersectsWith(cellRect))
                return;

            UpdateGraphics(cellBackColor, cellCaptionColor);

            cellRect.Inflate(-2, -2);

            Rectangle fillRect = cellRect;
            //fillRect.Offset(0,-1);

            e.Graphics.FillRectangle(
                backBrush,
                fillRect);

            DrawCellBorder(e, cellRect);

            // caption

            Rectangle captionRect = cellRect;
            captionRect.Inflate(-2, -2);
            captionRect.Offset(1, 1);

            e.Graphics.DrawString(
                cell.Caption,
                font,
                captionBrush,
                captionRect,
                SF);
        }
예제 #22
0
        /// <summary>
        /// Метод, который внешний код вызывает для отрисовки движущейся шашки.
        /// Класс AnimationManager отвечает за то, чтобы этот метод был вызван, но не занимается рисованием.
        /// </summary>
        /// <param name="e">Стандартный параметр метода OnPaint.</param>
        /// <param name="cell">Шашка, которая должна быть запечатлена в движении.</param>
        /// <param name="cellBackColor">Цвет фона шашки.</param>
        /// <param name="cellCaptionColor">Цвет цифер на шашке.</param>
        /// <param name="font">Шрифт для цифер. Желательно, разборчивый.</param>
        /// <param name="startPosition">Начальная позиция шашки. То место, с которого она едет.</param>
        /// <param name="completionRatio">Свой путь земной пройдя до половины...</param>
        public void DrawCellTransition(
            PaintEventArgs e,
            CellPlate cell,
            Color cellBackColor,
            Color cellCaptionColor,
            Font font,
            Rectangle startPosition,
            decimal completionRatio)
        {
            Rectangle transitionRect = PaintUtils.Transition(
                startPosition,
                cell.CellRectangle,
                completionRatio);

            DrawCellAt(
                transitionRect,
                e, cell, cellBackColor, cellCaptionColor, font);
        }
예제 #23
0
        /// <summary>
        /// Метод, который внешний код вызывает для отрисовки статической шашки (шашки, которая не движется).
        /// </summary>
        /// <param name="e">Стандартный параметр метода OnPaint любого контрола. Совмещает полотно для отрисовки и границы.</param>
        /// <param name="cell">Шашка, которую нужно нарисовать.</param>
        /// <param name="cellBackColor">В каком тоне следует рисовать шашку.</param>
        /// <param name="cellCaptionColor">В каком тоне следует рисовать циферки.</param>
        /// <param name="font">Каким вообще-то шрифтом нужно рисовать цифры.</param>
        public void DrawCell(
            PaintEventArgs e,
            CellPlate cell,
            Color cellBackColor,
            Color cellCaptionColor,
            Font font)
        {
            Rectangle cellRect = cell.CellRectangle;

            DrawCellAt(
                cellRect,
                e, cell, cellBackColor, cellCaptionColor, font);
        }
 /// <summary>
 /// Получение информации о шашке: движется ли она и в какой точке пути.
 /// Оракул раскрывает судьбу.
 /// </summary>
 public TransitionInfo this[CellPlate cell]
 {
     get { return(transitionByCell[cell] as TransitionInfo); }
 }
        /// <summary>
        /// Обрабатываем клик на контроле, находим шашку и проводим по бумагам как клик на шашке.
        /// </summary>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            mousePos = new Point(e.X, e.Y);

            base.OnMouseUp(e);

            m_Cells.IsCellRectangleValid = false;
            CellPlate movingCell = m_movingCell;
            m_movingCell = null;

            if (movingCell != null)
            {
                for (int x = 0; x < Cells.Width; x++)
                    for (int y = 0; y < Cells.Height; y++)
                    {
                        CellPlate cell = Cells[x, y];
                        if (cell == null)
                        {
                            if (m_Cells.emptyRect.Contains(mousePos))
                            {
                                Cells.InternalShiftCellRelative(movingCell, x - movingCell.X, y - movingCell.Y, true);
                                Invalidate();
                                return;
                            }
                        }
                        else if (cell.CellRectangle.Contains(mousePos))
                        {
                            if (cell == movingCell)
                            {
                                OnCellClick(new CellClickEventArgs(cell));
                            }
                            else
                            {
                                Cells.InternalShiftCellRelative(movingCell, x - movingCell.X, y - movingCell.Y, false);
                            }
                            Invalidate();
                            return;
                        }
                    }

                Invalidate();
            }
        }
 /// <summary>
 /// Конструктор: задаём шашку, чтобы знали, где нажим происходит.
 /// </summary>
 /// <param name="cell">Шашка, на которую действует вытесняющая сила.</param>
 public CellClickEventArgs(CellPlate cell)
 {
     if (cell == null)
         throw new ArgumentNullException("cell");
     m_Cell = cell;
 }
예제 #27
0
 /// <summary>
 /// Сместить шашку.
 /// </summary>
 /// <param name="cell">Шашка.</param>
 /// <param name="relativeX">Координата (колонка).</param>
 /// <param name="relativeY">Координата (строка).</param>
 /// <param name="toEmpty"></param>
 internal void InternalShiftCellRelative(CellPlate cell, int relativeX, int relativeY, bool toEmpty)
 {
     CellPlate oldCell = this[cell.X + relativeX, cell.Y + relativeY];
     if (oldCell != null)
     {
         if (toEmpty)
             throw new InvalidOperationException("Cannot shift, position is not empty.");
         oldCell.SetXY(cell.X, cell.Y);
     }
     else
     {
         emptyCell.Offset(-relativeX, -relativeY);
     }
     internalPlateArray[cell.Y*Width + cell.X] = oldCell;
     cell.SetXY(cell.X + relativeX, cell.Y + relativeY);
     internalPlateArray[cell.Y*Width + cell.X] = cell;
 }
예제 #28
0
        /// <summary>
        /// Чтобы расставить шашки, есть только один путь.
        /// </summary>
        /// <param name="x">Координата шашки (колонка).</param>
        /// <param name="y">Координата (строка).</param>
        /// <returns>Созданная и расставленная шашка.</returns>
        public CellPlate CreateCell(int x, int y)
        {
            if (this[x, y] != null)
                throw new ArgumentException("Cell at this point is already present.");

            CellPlate result = new CellPlate(this, x, y);
            internalPlateArray[y*Width + x] = result;

            result.Invalidate();

            return result;
        }