IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Petr Kubíček:21.3.2018 21:59

Tak jsem tu ještě jednou, se hrou jsem docela dost pohnul, ale narazil jsem na nové problémy.

Zkusím tedy trochu popsat principy hry:
Hra je tvořena ve wpf.

Mám statickou třídu s polem, podle kterého budu generovat mapu.

static class Map
    {
        public static int[,] mapa;
        public static int NumOfFood;
        static Map()
        {
            mapa = new int[,] {
                { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
                { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                { 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 },
                { 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 },
                { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                { 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1 },
                { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
                { 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 },
                { 9, 9, 9, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 9, 9, 9 },
                { 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 9, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1 },
                { 0, 0, 0, 0, 0, 0, 0, 1, 9, 9, 9, 9, 9, 1, 0, 0, 0, 0, 0, 0, 0 },
                { 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1 },
                { 9, 9, 9, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 9, 9, 9 },
                { 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1 },
                { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                { 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1 },
                { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1 },
                { 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1 },
                { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
                { 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1 },
                { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
            };

            GetNumOfFood();
            NumOfFood = 5;
        }

        public static int GetNumOfFood()
        {
            foreach (int i in mapa)
            {
                if (i == 1) NumOfFood++;
            }
            return NumOfFood;
        }
    }

Pak Canvas 630x660px, bloky v něm mají velikost 30x30px.
Vytvořím si bloky, které budu potřebovat, ty zastupují System.Window­s.Shapes.Rectan­gles.

private Rectangle noneBlock;
      public void createNoneBlock()
      {
          noneBlock = new Rectangle();
          noneBlock.Width = BlockSize; noneBlock.Height = BlockSize;
          Panel.SetZIndex(noneBlock, 1);
          noneBlock.Fill = Brushes.White;
          mainCanvas.Children.Add(noneBlock);
      }

      private Rectangle borderBlock;
      public void createBorderBlock()
      {
          borderBlock = new Rectangle();
          borderBlock.Width = BlockSize; borderBlock.Height = BlockSize;
          Panel.SetZIndex(borderBlock, 1);
          borderBlock.Fill = Brushes.IndianRed;
          mainCanvas.Children.Add(borderBlock);
      }

      private Ellipse foodBlock;
      public void createFoodBlock()
      {
          foodBlock = new Ellipse();
          foodBlock.Width = BlockSize / 2; foodBlock.Height = BlockSize / 2;
          Panel.SetZIndex(foodBlock, 1);
          foodBlock.Fill = Brushes.BlueViolet;
          mainCanvas.Children.Add(foodBlock);
      }

Podle čísla v poli pak vykresluji tyto bloky.

public void CreateMap()
        {
            X = 0;
            Y = 0;
            for (int i = 0; i < Map.mapa.GetLength(0); i++)
            {
                for (int j = 0; j < Map.mapa.GetLength(1); j++)
                {
                    switch (Map.mapa[i, j])
                    {
                        case 0:
                            createFoodBlock(); SetTop(foodBlock, Y + 0.5 * foodBlock.Width); SetLeft(foodBlock, X + 0.5 * foodBlock.Width);
                            foodCoor.Add(new Rect(GetLeft(foodBlock), GetTop(foodBlock), foodBlock.Width, foodBlock.Height));
                            break;
                        case 1:
                            createBorderBlock(); SetTop(borderBlock, Y); SetLeft(borderBlock, X);
                            wallsCoor.Add(new Rect(GetLeft(borderBlock), GetTop(borderBlock), borderBlock.Width, borderBlock.Height));
                            break;
                    }
                    X += BlockSize;
                }
                X = 0;
                Y += BlockSize;
            }
        }

Z počátku jsem nepracoval s polem, ale s funkcí intersect na objektech Rect. Každý blok zdi jsem proto uložil do listu.
Měl jsem proto metodu, která zkontroluje intersect se zdí a v případě navrácení false (není ve zdi) nechal pacmana pohybovat se, jinak jsem ho vracel zpět na původní pozici. Což bylo sice funkční, ale ne zrovna estetické. Navíc hrozně náročné, vzhledem k počtu nutných kontrol.

Rect pcmnhrc;
Point currentPos;
private bool CheckWalls()
{
    pcmnhrc = new Rect(GetLeft(PacManHrac), GetTop(PacManHrac), PacManHrac.Width, PacManHrac.Height);
    foreach (Rect r in wallsCoor)
    {
        if (pcmnhrc.IntersectsWith(r))
        {
            return true;
        }
    }
    currentPos = new Point(pcmnhrc.X, pcmnhrc.Y);
    return false;
}

CheckBounds() na procházení zdmi...

private void CheckBounds()
        {
            if (GetLeft(PacManHrac) <= 0) SetLeft(PacManHrac, mainCanvas.Width - PacManHrac.Width - 1); //-1: bez ní se setne na nulu
            if (GetLeft(PacManHrac) >= mainCanvas.Width - PacManHrac.Width) SetLeft(PacManHrac, 1);
        }

Do poslednice jsem musel řešit, aby se pacman trefil do děr, které nebyly spjaté s jinou zdí, protože je nízká šance se trefit ve správný okamžik. To byl pro mě oříšek, ale Vymyslel jsem následující:

  1. Nejprve po stisku klávesy nastavím enum SetDirection, tím pádem mám uložený směr.
  2. Po té vytvořím podmínku (v DispatcherTimeru) která dovolí nastavit konečný enum UseDirection, pokud je zároveň pacman na určitém místě.
  3. A pak jednoduše posouvám pacmana dle nastaveného výčtového typu.
if (SetDirection == SetDirection.right & GetTop(PacManHrac) % 30 == 1) UseDirection = UseDirection.right;
           else if (SetDirection == SetDirection.left & GetTop(PacManHrac) % 30 == 1) UseDirection = UseDirection.left;
           else if (SetDirection == SetDirection.up & GetLeft(PacManHrac) % 30 == 1 ) UseDirection = UseDirection.up;
           else if (SetDirection == SetDirection.down & GetLeft(PacManHrac) % 30 == 1) UseDirection = UseDirection.down;

           int speed = 2;
           if (!CheckWalls())
           {
               if (UseDirection == UseDirection.right)
               {
                   SetLeft(PacManHrac, GetLeft(PacManHrac) + speed);
               }
               else if (UseDirection == UseDirection.left)
               {
                   SetLeft(PacManHrac, GetLeft(PacManHrac) - speed);
               }
               else if (UseDirection == UseDirection.up)
               {
                   SetTop(PacManHrac, GetTop(PacManHrac) - speed);
               }
               else if (UseDirection == UseDirection.down)
               {
                   SetTop(PacManHrac, GetTop(PacManHrac) + speed);
               }
           }
           else
           {
               SetLeft(PacManHrac, currentPos.X);
               SetTop(PacManHrac, currentPos.Y);
           }

A teď k tomu, kde jsem se zasekl na několik hodin a prostě si už nevím rady...
Zkusil jsem tedy použít místo interesct pole, něco ve stylu, když je před tebou zeď, zastav a nebo, když chceš zabočit dolů, nesmíš mít pod sebou zeď.

Udělal jsem si tedy jednoduchou detekci toho, na jakém poli se pacman nachází.

private int LeftArray { get; set; }
        private int TopArray { get; set; }
        private void Detection()
        {
            //Point pointToWindow = Mouse.GetPosition(this);
            //Point pointToScreen = PointToScreen(pointToWindow);
            for (int i = 0; i < Map.mapa.GetLength(0); i++)
            {
                for (int j = 0; j < Map.mapa.GetLength(1); j++)
                {
                    if (GetLeft(PacManHrac) > i * BlockSize & GetLeft(PacManHrac) < i * BlockSize + BlockSize
                        & GetTop(PacManHrac) > j * BlockSize & GetTop(PacManHrac) < j * BlockSize + BlockSize)
                    {
                        LeftArray = i;
                        TopArray = j;
                    }
                }
            }
        }

A následovně jsem začal tvořit tyto podmínky

if (SetDirection == SetDirection.right & GetTop(PacManHrac) % 30 == 1 & Map.mapa[LeftArray + 1, TopArray] != 1) UseDirection = UseDirection.right;
           else if (SetDirection == SetDirection.left & GetTop(PacManHrac) % 30 == 1 & Map.mapa[LeftArray - 1, TopArray] != 1) UseDirection = UseDirection.left;
           else if (SetDirection == SetDirection.up & GetLeft(PacManHrac) % 30 == 1 & Map.mapa[LeftArray, TopArray - 1] != 1) UseDirection = UseDirection.up;
           else if (SetDirection == SetDirection.down & GetLeft(PacManHrac) % 30 == 1 & Map.mapa[LeftArray, TopArray + 1] != 1) UseDirection = UseDirection.down;

nebo ta druhá podmínka

if (UseDirection == UseDirection.right & Map.mapa[LeftArray + 1, TopArray] != 1)
{
    SetLeft(PacManHrac, GetLeft(PacManHrac) + speed);
}
else if (UseDirection == UseDirection.left & Map.mapa[LeftArray - 1, TopArray] != 1)
{
    SetLeft(PacManHrac, GetLeft(PacManHrac) - speed);
}
else if (UseDirection == UseDirection.up & Map.mapa[LeftArray, TopArray - 1] != 1)
{
    SetTop(PacManHrac, GetTop(PacManHrac) - speed);
}
else if (UseDirection == UseDirection.down & Map.mapa[LeftArray, TopArray + 1] != 1)
{
    SetTop(PacManHrac, GetTop(PacManHrac) + speed);
}
else
{
    speed = 0;
}

A zde se to prostě chová dosti zvláštně, nedokážu v tom vypozorovat žádný algoritmus a nevím, kde je chyba.

Takže pokud jste se někdo dočetl až sem, už teď vám patří můj respekt :D, dovedl by mi někdo poradit?
A prosím, nesuďte mě, pokud jsem úplně pitomej. :D ale snažím se k tomu ale už nějakou tu chvíli dopracovat a pomoc by se mi šikla. A na střední škole bohužel není dostatečného vedení. :)

Díky

 
Odpovědět
21.3.2018 21:59
Avatar
Odpovídá na Petr Kubíček
Lukáš Křehula:23.3.2018 12:46

Ahoj,
jenom co se tak letmo koukám na ten kód, tak v podmínkách používáš místo logického operátoru AND který se zapisuje dvěma &, tzn &&, tak používáš bitový operátor AND (bitový součin).
Zkus jenom změnit všechna & na && a uvidíš jestli se něco změní.

 
Nahoru Odpovědět
23.3.2018 12:46
Avatar
Odpovídá na Petr Kubíček
Adam Gajdečka:10.5.2018 18:38

všechny metody by měly mít asi velké počáteční písmeno v C#

 
Nahoru Odpovědět
10.5.2018 18:38
Avatar
HONZ4
Člen
Avatar
Odpovídá na Petr Kubíček
HONZ4:10.5.2018 19:08

Nechce se mě ten kód procházet celý, ale tenhle nesmysl na mě hned vyskočil:

    GetNumOfFood();
    NumOfFood = 5;
}

public static int GetNumOfFood()
{
    foreach (int i in mapa)
    {
        if (i == 1) NumOfFood++;
    }
    return NumOfFood;
}

Mělo by to vypadat takto:

    NumOfFood = GetNumOfFood();
}

public static int GetNumOfFood()
{
    int result = 0;
    foreach (int i in mapa)
    {
        if (i == 1) result++;
    }
    return result;
}
 
Nahoru Odpovědět
10.5.2018 19:08
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 4 zpráv z 4.