예제 #1
0
        public void ObjectClick(GameBoardObject clickedObject)
        {
            Debug.WriteLine($"CLICKED ON {clickedObject.GetType()}");
            // Если нет выбранного объекта
            if (SelectedObject is null)
            {
                SelectObject(clickedObject);
            }
            // Если выбирается тот же объект
            else if (clickedObject == SelectedObject)
            {
                ClearSelection();
            }
            // Если выбирается другой объект
            else
            {
                // Если соседний объект
                if ((clickedObject.worldPos - SelectedObject.worldPos).Magnitude == 1.0)
                {
                    // Запоминаем какие объекты меняем, чтобы потом поменять их обратно
                    objectSwap1 = clickedObject;
                    objectSwap2 = SelectedObject;
                    // Меняем местами их позиции
                    SwapObjectPositions(clickedObject, SelectedObject);

                    ClearSelection();
                    currentGamePhase = GamePhase.ElementSwap;
                }
                // Если не соседний объект
                else
                {
                    ClearSelection();
                }
            }
        }
예제 #2
0
 /// <summary>
 /// Конструктор.
 /// </summary>
 /// <param name="linkedObject">Привязанный обеъект на игровом поле.</param>
 /// <param name="blocking">Блокирует ли анимация переход в следующее состояние игры.</param>
 public PulseAnimation(GameBoardObject linkedObject, bool blocking = false)
 {
     this.linkedObject = linkedObject;
     this.blocking     = blocking;
     timePassed        = 0.0;
     active            = true;
 }
예제 #3
0
 /// <summary>
 /// Конструктор.
 /// </summary>
 /// <param name="baseObject">Базовый объект.</param>
 /// <param name="pos">Клетка игрового поля.</param>
 /// <param name="spritePos">Позиция спрайта.</param>
 public BombBonus(GameBoardObject baseObject, Vector2Int pos, Vector2 spritePos) : base(pos, spritePos)
 {
     sprite      = baseObject.sprite;
     spriteScale = baseObject.spriteScale;
     objectType  = baseObject.objectType;
     bombSprite  = Game1.bombSprite;
 }
예제 #4
0
        /// <summary>
        /// Обновляет состояние игрового поля.
        /// </summary>
        public void Update(GameTime gameTime)
        {
            // Пытаемся изменить состояние игры
            ChangeState();

            // Действие разрушителей
            List <Destroyer> destroyerListCopy = new List <Destroyer>(destroyerList);

            foreach (Destroyer destroyer in destroyerListCopy)
            {
                foreach (GameBoardObject gameBoardObject in objectList)
                {
                    Rectangle boundingBox      = gameBoardObject.GetScreenBoundingBox();
                    bool      boundingBoxHit   = boundingBox.Contains(GameBoardObject.WorldToScreen(destroyer.spriteWorldPos));
                    bool      alreadyImploding = implodingObjects.Contains(gameBoardObject);
                    if (boundingBoxHit && !alreadyImploding)
                    {
                        implodingObjects.Add(gameBoardObject);
                        ScaleAnimation implodeAnimation = new ScaleAnimation(
                            gameBoardObject,
                            beginScale: 1.0,
                            endScale: 0.0,
                            delay: 0.0,
                            blocking: true,
                            finishedCallback: _ => objectList.Remove(gameBoardObject)
                            );
                        activeAnimations.Add(implodeAnimation);
                        score++;
                        // Если это LineBonus
                        if (gameBoardObject.GetType() == typeof(LineBonus))
                        {
                            TriggerLineBonus((LineBonus)gameBoardObject);
                        }
                        // Если это BombBonus
                        if (gameBoardObject.GetType() == typeof(BombBonus))
                        {
                            TriggerBombBonus((BombBonus)gameBoardObject);
                        }
                    }
                }
            }

            // Обновляем состояние анимаций
            activeAnimations.ForEach(animation => animation.Update(gameTime));
            // Удаляем завершившиеся анимации
            List <Animation> animationsToDelete = activeAnimations.FindAll(animation => !animation.active);

            animationsToDelete.ForEach(animation => animation.OnDelete());
            activeAnimations = activeAnimations.Except(animationsToDelete).ToList();

            // Синхронизируем список implodingObjects с основным списком
            implodingObjects = implodingObjects.Intersect(objectList).ToList();

            // Уменьшаем остаток времени
            if (currentGamePhase != GamePhase.MainMenu && currentGamePhase != GamePhase.GameOver)
            {
                timeRemaining -= gameTime.ElapsedGameTime.TotalSeconds;
            }
        }
예제 #5
0
 /// <summary>
 /// Конструктор.
 /// </summary>
 /// <param name="baseObject">Базовый объект.</param>
 /// <param name="vertical">Направление бонуса.</param>
 /// <param name="pos">Клетка игрового поля.</param>
 /// <param name="spritePos">Позиция спрайта.</param>
 public LineBonus(GameBoardObject baseObject, bool vertical, Vector2Int pos, Vector2 spritePos) : base(pos, spritePos)
 {
     sprite        = baseObject.sprite;
     spriteScale   = baseObject.spriteScale;
     objectType    = baseObject.objectType;
     this.vertical = vertical;
     lineSprite    = Game1.lineBonusSprite;
 }
예제 #6
0
        /// <summary>
        /// Превращает объект в заданной позиции в Line.
        /// </summary>
        public void TurnIntoLine(Vector2Int pos)
        {
            GameBoardObject obj  = GetObjectAtPosition(pos);
            LineBonus       bomb = new LineBonus(obj, true, obj.worldPos, obj.worldPos);

            objectList.Remove(obj);
            objectList.Add(bomb);
        }
예제 #7
0
        /// <summary>
        /// Превращает объект в заданной позиции в круг.
        /// </summary>
        public void TurnIntoCircle(Vector2Int pos)
        {
            GameBoardObject obj          = GetObjectAtPosition(pos);
            CircleObject    circleObject = new CircleObject(obj.worldPos, obj.worldPos);

            objectList.Remove(obj);
            objectList.Add(circleObject);
        }
예제 #8
0
        /// <summary>
        /// Превращает объект в заданной позиции в квадрат.
        /// </summary>
        public void TurnIntoSquare(Vector2Int pos)
        {
            GameBoardObject obj          = GetObjectAtPosition(pos);
            SquareObject    squareObject = new SquareObject(obj.worldPos, obj.worldPos);

            objectList.Remove(obj);
            objectList.Add(squareObject);
        }
예제 #9
0
        /// <summary>
        /// Конструктор.
        /// </summary>
        public GameBoard()
        {
            // Создание объектов на игровом поле
            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                {
                    Vector2Int      pos          = new Vector2Int(x, y);
                    GameBoardObject randomObject = CreateRandomElement(pos, pos);
                    objectList.Add(randomObject);
                }
            }

            // Удаление комбинаций образовавшихся после случайной генерации объектов
            ComboList comboList = GetComboList();
            int       iteration = 1;

            while (comboList.Count > 0)
            {
                Debug.WriteLine($"Iteration: {iteration}");
                GameBoardObject newObject      = null;
                int             objectsChanged = 0;
                foreach (List <GameBoardObject> combination in comboList)
                {
                    GameBoardObject middleObject = combination[combination.Count / 2];
                    switch (combination[0].GetType().Name)
                    {
                    case nameof(SquareObject):   newObject = new CircleObject(middleObject.worldPos, middleObject.worldPos);   break;

                    case nameof(CircleObject):   newObject = new TriangleObject(middleObject.worldPos, middleObject.worldPos); break;

                    case nameof(TriangleObject): newObject = new HexagonObject(middleObject.worldPos, middleObject.worldPos);  break;

                    case nameof(HexagonObject):  newObject = new DiamondObject(middleObject.worldPos, middleObject.worldPos);  break;

                    case nameof(DiamondObject):  newObject = new SquareObject(middleObject.worldPos, middleObject.worldPos);   break;
                    }
                    objectList.Remove(middleObject);
                    objectList.Add(newObject);
                    objectsChanged++;
                }
                Debug.WriteLine($"Objects changed: {objectsChanged}");
                comboList = GetComboList();
                iteration++;
            }

            //TurnIntoSquare(new Vector2Int(5, 2));
            //TurnIntoBomb(new Vector2Int(5, 2));
            //TurnIntoSquare(new Vector2Int(4, 2));

            //TurnIntoSquare(new Vector2Int(2, 3));
            //TurnIntoSquare(new Vector2Int(3, 3));
            //TurnIntoSquare(new Vector2Int(4, 3));
            //TurnIntoSquare(new Vector2Int(6, 3));

            //TurnIntoSquare(new Vector2Int(4, 4));
            //TurnIntoSquare(new Vector2Int(5, 4));
        }
예제 #10
0
        /// <summary>
        /// Создать бонус Bomb.
        /// </summary>
        /// <param name="baseObject">Базовый объект.</param>
        public void CreateBombBonus(GameBoardObject baseObject)
        {
            // Создаем объект
            BombBonus newBombBonus = new BombBonus(baseObject, baseObject.worldPos, baseObject.worldPos);

            objectList.Add(newBombBonus);
            // Запускаем анимацию появления
            ScaleAnimation spawnAnimation = new ScaleAnimation(newBombBonus, 0.0, 1.0, blocking: true);

            activeAnimations.Add(spawnAnimation);
        }
예제 #11
0
        /// <summary>
        /// Рисует объект на экране.
        /// </summary>
        public virtual void Draw(SpriteBatch spriteBatch)
        {
            // Позиция спрайта на экране
            Vector2 spriteScreenPos = GameBoardObject.WorldToScreen(spriteWorldPos);
            // Центр спрайта
            Vector2 spriteOffset = new Vector2(sprite.Width / 2, sprite.Height / 2);
            // Масштабирование спрайта
            float finalSpriteScale = Game1.cellSize / sprite.Width * spriteScale * spriteAnimatedScale * Game1.globalSpriteScale;

            // Отрисовка спрайта
            spriteBatch.Draw(sprite, spriteScreenPos, null, Color.White, 0f, spriteOffset, finalSpriteScale, SpriteEffects.None, 0f);
        }
예제 #12
0
 /// <summary>
 /// Конструктор.
 /// </summary>
 /// <param name="linkedObject">Привязанный обеъект на игровом поле.</param>
 /// <param name="blocking">Блокирует ли анимация переход в следующее состояние игры.</param>
 public ScaleAnimation(GameBoardObject linkedObject, double beginScale, double endScale, double delay = 0.0, bool blocking = false, Action <GenericObject> finishedCallback = null)
 {
     this.linkedObject     = linkedObject;
     this.beginScale       = beginScale;
     this.endScale         = endScale;
     this.blocking         = blocking;
     this.finishedCallback = finishedCallback;
     this.delay            = delay;
     duration   = 0.3;
     timePassed = -delay;
     active     = true;
 }
예제 #13
0
        /// <summary>
        /// Активирует бонус Bomb.
        /// </summary>
        public void TriggerBombBonus(BombBonus bombBonus)
        {
            // Объекты вокруг бомбы
            for (int x = bombBonus.worldPos.x - 1; x <= bombBonus.worldPos.x + 1; x++)
            {
                for (int y = bombBonus.worldPos.y - 1; y <= bombBonus.worldPos.y + 1; y++)
                {
                    if (x == bombBonus.worldPos.x && y == bombBonus.worldPos.y)
                    {
                        continue;
                    }
                    GameBoardObject obj = GetObjectAtPosition(x, y);
                    if (obj is null)
                    {
                        continue;
                    }
                    implodingObjects.Add(obj);
                    ScaleAnimation implodeAnimation = new ScaleAnimation(
                        obj,
                        beginScale: 1.0,
                        endScale: 0.0,
                        delay: 0.25,
                        blocking: true,
                        finishedCallback: _ => objectList.Remove(obj)
                        );
                    activeAnimations.Add(implodeAnimation);
                    score++;
                    // Если это LineBonus
                    if (obj.GetType() == typeof(LineBonus))
                    {
                        TriggerLineBonus((LineBonus)obj);
                    }
                    // Если это BombBonus
                    if (obj.GetType() == typeof(BombBonus))
                    {
                        TriggerBombBonus((BombBonus)obj);
                    }
                }
            }
            // Сама бомба
            implodingObjects.Add(bombBonus);
            ScaleAnimation bombImplodeAnimation = new ScaleAnimation(
                bombBonus,
                beginScale: 1.0,
                endScale: 0.0,
                delay: 0.0,
                blocking: true,
                finishedCallback: _ => objectList.Remove(bombBonus)
                );

            activeAnimations.Add(bombImplodeAnimation);
            score++;
        }
예제 #14
0
        /// <summary>
        /// Меняет местами позиции объектов.
        /// </summary>
        public void SwapObjectPositions(GameBoardObject object1, GameBoardObject object2)
        {
            Debug.WriteLine($"Swapping {object1} and {object2}");
            // Меняем позиции
            Vector2Int object1Pos = object1.worldPos;
            Vector2Int object2Pos = object2.worldPos;

            object1.worldPos = object2Pos;
            object2.worldPos = object1Pos;
            // Запускаем анимации
            MoveAnimation moveAnimation1 = new MoveAnimation(object1, object1Pos, object2Pos, duration: 0.3, blocking: true);
            MoveAnimation moveAnimation2 = new MoveAnimation(object2, object2Pos, object1Pos, duration: 0.3, blocking: true);

            activeAnimations.Add(moveAnimation1);
            activeAnimations.Add(moveAnimation2);
        }
예제 #15
0
        /// <summary>
        /// Возвращает список комбинаций (в определенном направлении) элементов, стоящих в ряд.
        /// </summary>
        /// <param name="vertical">Вертикальное направление, иначе горизонтальное.</param>
        /// <returns>Список комбинаций в определенном направлении, где каждая комбинация это список объектов, входящих в комбинацию.</returns>
        private ComboList CheckCombo(bool vertical)
        {
            string directionString = vertical ? "Вертикальное" : "Горизонтальное";

            // Определение комбо
            ComboList allComboList = new ComboList();
            List <GameBoardObject> tempComboList = new List <GameBoardObject>();

            for (int i = 0; i < 8; i++)
            {
                tempComboList.Clear();
                GameBoardObject.GameBoardObjectType comboType = GameBoardObject.GameBoardObjectType.None;
                for (int j = 0; j < 8; j++)
                {
                    GameBoardObject obj = vertical ? GetObjectAtPosition(i, j) : GetObjectAtPosition(j, i);
                    if (obj is null)
                    {
                        comboType = GameBoardObject.GameBoardObjectType.None;
                        continue;
                    }
                    if (obj.objectType == comboType)
                    {
                        tempComboList.Add(obj);
                    }
                    else
                    {
                        if (tempComboList.Count >= 3)
                        {
                            allComboList.Add(new List <GameBoardObject>(tempComboList));
                            Debug.WriteLine($"{directionString} комбо {comboType} x{tempComboList.Count}");
                        }
                        tempComboList.Clear();
                        tempComboList.Add(obj);
                        comboType = obj.objectType;
                    }
                }
                if (tempComboList.Count >= 3)
                {
                    allComboList.Add(new List <GameBoardObject>(tempComboList));
                    Debug.WriteLine($"{directionString} комбо {comboType} x{tempComboList.Count}");
                }
            }

            return(allComboList);
        }
예제 #16
0
        /// <summary>
        /// Создает случайный элемент.
        /// </summary>
        /// <param name="pos">Позиция объекта на игровом поле.</param>
        public GameBoardObject CreateRandomElement(Vector2Int pos, Vector2 spritePos)
        {
            int             randomNumber       = random.Next(5);
            GameBoardObject newGameBoardObject = null;

            switch (randomNumber)
            {
            case 0: newGameBoardObject = new SquareObject(pos, spritePos);   break;

            case 1: newGameBoardObject = new CircleObject(pos, spritePos);   break;

            case 2: newGameBoardObject = new TriangleObject(pos, spritePos); break;

            case 3: newGameBoardObject = new HexagonObject(pos, spritePos);  break;

            case 4: newGameBoardObject = new DiamondObject(pos, spritePos);  break;
            }
            return(newGameBoardObject);
        }
예제 #17
0
 /// <summary>
 /// Создает новые объекты сверху.
 /// </summary>
 public void CreateNewObjects()
 {
     Debug.WriteLine("Creating new objects");
     for (int x = 0; x < 8; x++)
     {
         // Сдвигаем висящие элементы
         int objectsUnder = 0;
         for (int y = 7; y >= 0; y--)
         {
             GameBoardObject gameBoardObject = GetObjectAtPosition(x, y);
             if (gameBoardObject != null)
             {
                 Vector2Int newPos = new Vector2Int(gameBoardObject.worldPos.x, 7 - objectsUnder);
                 if (gameBoardObject.worldPos != newPos)
                 {
                     MoveAnimation moveAnimation = new MoveAnimation(gameBoardObject, gameBoardObject.worldPos, newPos, duration: 0.3, blocking: true);
                     activeAnimations.Add(moveAnimation);
                     gameBoardObject.worldPos = newPos;
                 }
                 objectsUnder++;
             }
         }
         // Добавляем новые элементы
         int newElementCount = 8 - objectsUnder;
         for (int new_i = 0; new_i < newElementCount; new_i++)
         {
             // Позиция объекта и спрайта
             Vector2Int pos       = new Vector2Int(x, new_i);
             Vector2    spritePos = pos - new Vector2(0, newElementCount);
             // Создание объекта
             GameBoardObject randomObject = CreateRandomElement(pos, spritePos);
             objectList.Add(randomObject);
             // Запуск анимации
             MoveAnimation moveAnimation = new MoveAnimation(randomObject, spritePos, pos, duration: 0.3, blocking: true);
             activeAnimations.Add(moveAnimation);
         }
     }
 }
예제 #18
0
 /// <summary>
 /// Убрать выделение объекта.
 /// </summary>
 public void ClearSelection()
 {
     selectedObjectPulseAnimation?.OnDelete();
     selectedObjectPulseAnimation = null;
     SelectedObject = null;
 }
예제 #19
0
        /// <summary>
        /// Удаление комбинаций.
        /// </summary>
        public void DeleteCombos(ComboList comboList)
        {
            // Список удаляемых объектов
            List <GameBoardObject> objectsToDelete = comboList.SelectMany(tempList => tempList).ToList();

            score += objectsToDelete.Count;

            // Срабатывание бонусов
            List <LineBonus> lineBonuses = objectsToDelete.FindAll(obj => obj.GetType() == typeof(LineBonus)).Cast <LineBonus>().ToList();

            foreach (LineBonus lineBonus in lineBonuses)
            {
                TriggerLineBonus(lineBonus);
                currentGamePhase = GamePhase.Bonus;
            }
            List <BombBonus> bombBonuses = objectsToDelete.FindAll(obj => obj.GetType() == typeof(BombBonus)).Cast <BombBonus>().ToList();

            foreach (BombBonus bombBonus in bombBonuses)
            {
                TriggerBombBonus(bombBonus);
                currentGamePhase = GamePhase.Bonus;
            }

            // Если бонусы активны, то новые создавать нельзя.
            if (currentGamePhase == GamePhase.Bonus)
            {
                return;
            }

            // Запуск анимации исчезновения
            implodingObjects.Clear();
            foreach (GameBoardObject obj in objectsToDelete)
            {
                implodingObjects.Add(obj);
                ScaleAnimation implodeAnimation = new ScaleAnimation(obj, 1.0, 0.0, blocking: true, finishedCallback: _ => objectList.Remove(obj));
                activeAnimations.Add(implodeAnimation);
            }

            // Бонус Bomb
            // Комбинации из 5 и более
            List <Vector2Int>      newBombPositions       = new List <Vector2Int>();
            ComboList              combinationsOf5AndMore = comboList.FindAll(combination => combination.Count >= 5);
            List <GameBoardObject> combination            = combinationsOf5AndMore.Find(combination => combination.Contains(objectSwap2));

            if (combination != null)
            {
                CreateBombBonus(objectSwap2);
                newBombPositions.Add(objectSwap2.worldPos);
            }
            // Перекрестные комбинации из 3 и более
            CrossList crosses = new CrossList();
            ComboList verticalCombinations   = comboList.FindAll(combination => combination[0].worldPos.x == combination[1].worldPos.x);
            ComboList horizontalCombinations = comboList.FindAll(combination => combination[0].worldPos.y == combination[1].worldPos.y);

            foreach (List <GameBoardObject> verticalCombination in verticalCombinations)
            {
                foreach (List <GameBoardObject> horizontalCombination in horizontalCombinations)
                {
                    List <GameBoardObject> intersection = verticalCombination.Intersect(horizontalCombination).ToList();
                    if (intersection.Count > 0)
                    {
                        GameBoardObject objectAtIntersection = intersection[0];
                        if (!newBombPositions.Contains(objectAtIntersection.worldPos))
                        {
                            CreateBombBonus(objectAtIntersection);
                            newBombPositions.Add(objectAtIntersection.worldPos);
                        }
                    }
                }
            }
            // Бонус Line
            ComboList combinationsOf4 = comboList.FindAll(combination => combination.Count == 4);

            combination = combinationsOf4.Find(combination => combination.Contains(objectSwap2));
            if (combination != null && !newBombPositions.Contains(objectSwap2.worldPos))
            {
                Debug.WriteLine($"Creating line bonus in {objectSwap2.worldPos}");
                bool vertical = combination[0].worldPos.x == combination[1].worldPos.x;
                // Создаем объект
                LineBonus newLineBonus = new LineBonus(objectSwap2, vertical, objectSwap2.worldPos, objectSwap2.worldPos);
                objectList.Add(newLineBonus);
                // Запускаем анимацию появления
                ScaleAnimation spawnAnimation = new ScaleAnimation(newLineBonus, 0.0, 1.0, blocking: true);
                activeAnimations.Add(spawnAnimation);
            }
        }
예제 #20
0
 /// <summary>
 /// Выбор объекта.
 /// </summary>
 public void SelectObject(GameBoardObject gameBoardObject)
 {
     SelectedObject = gameBoardObject;
     selectedObjectPulseAnimation = new PulseAnimation(SelectedObject);
     activeAnimations.Add(selectedObjectPulseAnimation);
 }