четверг, 12 января 2012 г.

Mini "Sokoban" за 5 часов...


Заскучал на работе и решил отвлечься, набросал мини игрушку sokoban. Картинки нашел в интернете и вперед, вот что получилось:
Главное окно

Игровое окно



Конструктор уровней

Немножко кода
Основной класс уровня:

public const int indentLeft = 15;
public const int indentUp = 15;

#region Private
 
private int currManPosX = -1;
private int currManPosY = -1;
private bool finished = false;
Timer secondsCounterTimer;
 
#endregion
 
#region Fields
 
private int width;
private int heigth;
private List<item>[,] levelItems;
private int movesCnt;
private int secondsCnt = 0;
 
public int Width { get { return width; } }
public int Heigth { get { return heigth; } }
private List<item>[,] LevelItems { get { return levelItems; } }
public int MovesCnt { get { return movesCnt; } }
public int SecondsCnt { get { return secondsCnt; } }

#endregion 
Конструкторы класса, первый позволяет создать уровень из сущ. файла в режиме игры или в режиме изменения, второй используется для создания нового уровня:

#region Constructors
  
    public Level(string fName, bool constructorMode) 
    {
        if (!constructorMode)
        {
            secondsCounterTimer = new Timer(1000);
            secondsCounterTimer.Elapsed += new ElapsedEventHandler(secondsCounterTimer_Elapsed);
        }
        ReadFromFile(fName); 
    }

    public Level(int _width, int _heigth)
    {
        width = _width;
        heigth = _heigth;
        levelItems = List<item>[_width, _heigth];
    }
 
#endregion
Метод отрисовки уровня:
public void DrawLevel(Graphics g, bool ConstructorMode)
        {
            Brush b = Brushes.White;
            g.FillRegion(b, g.Clip);
            Pen p = new Pen(Brushes.Black);
            for (int i = 0; i < width; i++)
                for (int j = 0; j < heigth; j++)
                {
                    List<Item> itm = GetItem(i, j);
                    if (itm == null)
                    {
                        g.FillRectangle(b, new Rectangle(new Point(i * 35 + indentLeft, j * 35 + indentUp), new Size(35, 35)));
                        if (ConstructorMode)
                            g.DrawRectangle(p, new Rectangle(new Point(i * 35 + indentLeft, j * 35 + indentUp), new Size(35, 35)));
                    }
                    else
                        foreach (Item item in itm)
                            if (item != null)
                            {
                                if (item.ItemImage is Bitmap)
                                    ((Bitmap)item.ItemImage).MakeTransparent(Color.FromArgb(255, 0, 0, 0));
                                g.DrawImage(item.ItemImage, new Point(i * 35 + indentLeft, j * 35 + indentUp));
                                if (ConstructorMode)
                                    g.DrawRectangle(p, new Rectangle(new Point(i * 35 + indentLeft, j * 35 + indentUp), new Size(35, 35)));
                            }
                }
        }
Обработчик движения человечка:
 public void MoveAction(Graphics g, MoveDirections moveDirections)
        {
            if (finished)
                return;

            if (secondsCounterTimer.Enabled == false)
                secondsCounterTimer.Enabled = true;

            // проверяем есть ли кого двигать
            if (currManPosX == -1 || currManPosY == -1)
            {
                bool founded = false;
                // выполняем проход по элементам и ищем человечка
                for (int i = 0; i < width; i++)
                    for (int j = 0; j < heigth; j++)
                        if (levelItems[i, j] != null)
                            foreach (Item itm in levelItems[i, j])
                                if (itm.ItemType == ItemType.Man)
                                {
                                    founded = true;
                                    currManPosX = itm.XPos;
                                    currManPosY = itm.YPos;
                                }
                if (!founded)
                    throw new Exception("Некого двигать!");
            }

            int offsetX = 0, offsetY = 0;
            switch (moveDirections)
            {
                case MoveDirections.Rigth:
                    offsetX = 1;
                    if (currManPosX + offsetX >= width)
                        return;
                    break;
                case MoveDirections.Left:
                    offsetX = -1;
                    if (currManPosX + offsetX < 0)
                        return;
                    break;
                case MoveDirections.Up:
                    offsetY = -1;
                    if (currManPosY + offsetY < 0)
                        return;
                    break;
                case MoveDirections.Down:
                    offsetY = 1;
                    if (currManPosY + offsetY >= heigth)
                        return;
                    break;
            }

            if (levelItems[currManPosX + offsetX, currManPosY + offsetY] != null)
            {
                foreach (Item item in levelItems[currManPosX + offsetX, currManPosY + offsetY])
                {
                    if (item.ItemType == ItemType.Wall) // стенка?
                        return;
                    if (item.ItemType == ItemType.Package) // коробка и ее необходимо сдвинуть...
                    {
                        bool move = false;
                        switch (moveDirections)
                        {
                            case MoveDirections.Rigth:
                                offsetX = 1;
                                if (currManPosX + (offsetX * 2) >= width)
                                    return;
                                break;
                            case MoveDirections.Left:
                                offsetX = -1;
                                if (currManPosX + (offsetX * 2) < 0)
                                    return;
                                break;
                            case MoveDirections.Up:
                                offsetY = -1;
                                if (currManPosY + (offsetY * 2) < 0)
                                    return;
                                break;
                            case MoveDirections.Down:
                                offsetY = 1;
                                if (currManPosY + (offsetY * 2) >= heigth)
                                    return;
                                break;
                        }
                        //проверяем возможность движения коробки вправо
                        // если коробку не куда двигать, отменяем действие
                        if (levelItems[currManPosX + (offsetX * 2), currManPosY + (offsetY * 2)] != null)
                        {
                            foreach (Item itm in levelItems[currManPosX + (offsetX * 2), currManPosY + (offsetY * 2)])
                            {
                                if (itm.ItemType == ItemType.Wall) // стенка?
                                    return;
                                if (itm.ItemType == ItemType.Package) // другая коробка?
                                    return;
                            }
                            move = true;
                        }
                        if (move) // двигаем!
                        {
                            Item PckgToDel = null;
                            // у старой позиции удаляем коробку
                            foreach (Item itm in levelItems[currManPosX + offsetX, currManPosY + offsetY])
                                if (item.ItemType == ItemType.Package)
                                    PckgToDel = item;
                            if (PckgToDel != null)
                                levelItems[currManPosX + offsetX, currManPosY + offsetY].Remove(PckgToDel);
                            // добавляем коробку в новое положение
                            // проверяем есть ли во всех элементах goal, если есть то вид коробки нужно изменить
                            // создаем новый вид человечка в соответствии с направлением движения
                            Item newBoxItem;
                            switch (item.Code)
                            {
                                case 4:
                                case 6:
                                    newBoxItem = new Item(ItemsCollection.GetItemByCode(4));
                                    foreach (Item itm in levelItems[currManPosX + (offsetX * 2), currManPosY + (offsetY * 2)])
                                        if (itm.Code == 5)
                                            newBoxItem = new Item(ItemsCollection.GetItemByCode(6));
                                    break;
                                case 27:
                                case 29: newBoxItem = new Item(ItemsCollection.GetItemByCode(27));
                                    foreach (Item itm in levelItems[currManPosX + (offsetX * 2), currManPosY + (offsetY * 2)])
                                        if (itm.Code == 28)
                                            newBoxItem = new Item(ItemsCollection.GetItemByCode(29));
                                    break;
                                case 30:
                                case 32: newBoxItem = new Item(ItemsCollection.GetItemByCode(30));
                                    foreach (Item itm in levelItems[currManPosX + (offsetX * 2), currManPosY + (offsetY * 2)])
                                        if (itm.Code == 31)
                                            newBoxItem = new Item(ItemsCollection.GetItemByCode(32));
                                    break;
                                default:
                                    return;

                            }
                            newBoxItem.XPos = currManPosX + (offsetX * 2);
                            newBoxItem.YPos = currManPosY + (offsetY * 2);

                            levelItems[currManPosX + (offsetX * 2), currManPosY + (offsetY * 2)].Add(newBoxItem);
                            RedrawItemAtCoords(g, currManPosX + (offsetX * 2), currManPosY + (offsetY * 2));
                            break;
                        }
                        else return;
                    }
                }
                Item ManToDel = null;

                // у старой позиции удаляем человечка
                foreach (Item item in levelItems[currManPosX, currManPosY])
                    if (item.ItemType == ItemType.Man)
                        ManToDel = item;
                if (ManToDel != null)
                    levelItems[currManPosX, currManPosY].Remove(ManToDel);
                RedrawItemAtCoords(g, currManPosX, currManPosY); // перерисовывает старую позицию уже без человечка

                // создаем новый вид человечка в соответствии с направлением движения
                Item newManItem = null;
                switch (moveDirections)
                {
                    case MoveDirections.Rigth:
                        newManItem = new Item(ItemsCollection.GetItemByCode(23));
                        break;
                    case MoveDirections.Left:
                        newManItem = new Item(ItemsCollection.GetItemByCode(24));
                        break;
                    case MoveDirections.Up:
                        newManItem = new Item(ItemsCollection.GetItemByCode(22));
                        break;
                    case MoveDirections.Down:
                        newManItem = new Item(ItemsCollection.GetItemByCode(25));
                        break;
                }
                currManPosX = currManPosX + offsetX;
                currManPosY = currManPosY + offsetY;
                newManItem.XPos = currManPosX;
                newManItem.YPos = currManPosY;

                // добавляем человечка на новой позиции
                levelItems[currManPosX, currManPosY].Add(newManItem);
                RedrawItemAtCoords(g, currManPosX, currManPosY);
                movesCnt++;
                isFinished();
            }
        }

Комментариев нет:

Отправить комментарий