Diskuze: Hra Had

C# .NET .NET (C# a Visual Basic) Hra Had American English version English version

Avatar
matesax
Redaktor
Avatar
matesax:

Dobrý den,
ztroskotal jsem na takovéto banalitě... :)

Tělo je List:

using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;

namespace WGBD
{
    class Snake
    {
        public List<Vector2> snakeBody = new List<Vector2>();
        public int direction = 0;

        public LetterGenerator()
        {
            snakeBody.Add(new Vector2(20, 20));
        }

        public void MoveBody()
        {
            if (direction != 0)
                for (int index = snakeBody.Count - 1; index > 0; index--)
                    snakeBody[index] = snakeBody[index - 1];
        }

        public bool MoveHead()
        {
            Vector2 rough = new Vector2();

            switch (direction)
            {
                case 1:

                    rough = new Vector2(snakeBody[0].X + 2, snakeBody[0].Y);
                    break;

                case 2:

                    rough = new Vector2(snakeBody[0].X - 2, snakeBody[0].Y);
                    break;

                case 3:

                    rough = new Vector2(snakeBody[0].X, snakeBody[0].Y + 2);
                    break;

                case 4:

                    rough = new Vector2(snakeBody[0].X, snakeBody[0].Y - 2);
                    break;
            }

            if (IsCollision(rough))
                return false;

            snakeBody[0] = rough;
            return true;
        }

        public bool IsCollision(Vector2 testedPosition)
        {
            List<Vector2> mud = new List<Vector2>(snakeBody);

            mud.RemoveAt(0);

            if (mud.Count > 0)
            for (int x = -6; x < 7; x++)
                for (int y = -6; y < 7; y++)
                    if (mud.Contains(new Vector2(snakeBody[0].X + x, snakeBody[0].Y + y)))
                        return true;

            return false;
        }
    }
}
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Timers;

namespace WGBD
{
    public class Game1 : Game
    {
        private Random r = new Random();

        private string foodChar;
        private Vector2 foodPosition;
        private bool successfully = true;
        private LetterGenerator snake = new LetterGenerator();
        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;

        private void RandomizeFood()
        {
            foodChar = Convert.ToChar(r.Next(97, 122)).ToString();
            foodPosition = new Vector2(r.Next(6, Window.ClientBounds.Width - 6), r.Next(6, Window.ClientBounds.Height - 6));
        }

        private bool IsFoodCollision()
        {
            for (int x = -6; x < 7; x++)
                for (int y = -6; y < 7; y++)
                    if (foodPosition == new Vector2(snake.snakeBody[0].X + x, snake.snakeBody[0].Y + y))
                        return true;

            return false;
        }

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            RandomizeFood();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

        }

        protected override void UnloadContent()
        {

        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (Keyboard.GetState().IsKeyDown(Keys.Left))
                snake.direction = 2;
            else if (Keyboard.GetState().IsKeyDown(Keys.Right))
                snake.direction = 1;
            else if (Keyboard.GetState().IsKeyDown(Keys.Up))
                snake.direction = 4;
            else if (Keyboard.GetState().IsKeyDown(Keys.Down))
                snake.direction = 3;

            snake.MoveBody();

            if (IsFoodCollision())
            {
                RandomizeFood();

                int x = 0, y = 0;

                switch (snake.direction)
                {
                    case 1:

                        x = -8;
                        break;

                    case 2:

                        x = -8;
                        break;

                    case 3:

                        y = -8;
                        break;

                    case 4:

                        y = 8;
                        break;
                }

                snake.snakeBody.Add(new Vector2(snake.snakeBody[0].X + x, snake.snakeBody[0].Y + y));
            }

            successfully = snake.MoveHead();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            if (successfully)
            {
                foreach (Vector2 link in snake.snakeBody)
                    spriteBatch.DrawString(Content.Load<SpriteFont>("SpriteFont1"), Convert.ToChar(r.Next(65, 90)).ToString(), link, Color.DarkBlue);

                spriteBatch.DrawString(Content.Load<SpriteFont>("SpriteFont1"), foodChar, foodPosition, Color.DarkBlue);
            }
            else
                spriteBatch.DrawString(Content.Load<SpriteFont>("SpriteFont1"), "Konec hry!", new Vector2(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2), Color.DarkBlue);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

Jakmile sním jídlo, hra zkončí - nevíte proč? (Počítám s tím, že jeden znak zabere pole o rozměrech 6x6.) Děkuji.

Editováno 9.10.2012 16:36
 
Odpovědět 9.10.2012 16:34
Avatar
matesax
Redaktor
Avatar
Odpovídá na matesax
matesax:

Již asi chápu - počítal jsem s rozdílem 2 - ale já testuji dozadu až do -6 - což dává rozdíl 8 - tedy 14 by mělo fungovat - ale to tedy není dobé řešení (Různé vzdálenosti mezi články.). Jak bych měl vyřešit to testování kolize hlavy s tělem? Děkuji.

 
Nahoru Odpovědět 9.10.2012 16:40
Avatar
matesax
Redaktor
Avatar
matesax:

Vyřešeno:

for (int x = 1; x < 13; x++)
    for (int y = 1; y < 13; y++)
 
Nahoru Odpovědět 9.10.2012 16:47
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

Není mi jasné, proč v metodě MoveBody používáš cyklus, když to jde udělat jedním příkazem pro posunutí prvků v seznamu a přidání dalšího. Vlastně ani nevím, proč ho posunuješ, když stačí přidat další prvek na konec.

Hada bych nedělal jako seznam, ale jako dvourozměrnou bitmapu. Kolize se budou detekovat mnohem snáze a nebude se s rostoucí délkou snižovat rychlost hada.

Nahoru Odpovědět 9.10.2012 18:02
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Protože první pozice je hlava...

 
Nahoru Odpovědět 9.10.2012 18:06
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Aha - špatně jsi to pochopil - nic nepřidávám... (Move = pohyb) :) Přdávám jinde...

 
Nahoru Odpovědět 9.10.2012 18:14
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

A kdo říká, že hlava nemůže být na konci seznamu?

A k čemu máš ten cyklus v MoveBody když můžeš použít metodu Insert()?

Nahoru Odpovědět 9.10.2012 18:19
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

No ale když bude hlava nakonci, a pak s tím zamýchám, tak to přeci nepůjde...

Insert je další nesmysl - nechci nic přidávát... (Navíc by to stejně chtělo cyklus...)

Editováno 9.10.2012 18:25
 
Nahoru Odpovědět 9.10.2012 18:24
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

A co ta metoda snakeBody.Insert()? Ta ti stále nefunguje?

Zacházení se seznamem jako s polem je zvěrstvo. Tohle není C, ale C#.

Editováno 9.10.2012 18:28
Nahoru Odpovědět 9.10.2012 18:27
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

Jaktože nepřidáváš? Posouváš všechny prvky v seznamu a na nultou pozici dáváš novou pozici hlavy. To je klasický Insert() jak z učebnice. Uvědom si, že programuješ v C#.

Editováno 9.10.2012 18:32
Nahoru Odpovědět 9.10.2012 18:31
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Neumím si to představit. A jak píši - na to Insert bych stejně musel použít cyklus...

Právě že vůbec neměním počet prvků... Vše po hlavu posouvám o jedno dopředu. Nakonec mi tam zbydou 2 hlavy - 2 stejné pozice - následně ale posunu hlavu a tím je posunut celý had...

Editováno 9.10.2012 18:46
 
Nahoru Odpovědět 9.10.2012 18:43
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:
public bool Move()
{
    if (direction != 0)
    {
        Vector2 rough = new Vector2();

        switch (direction)
        {
            case 1:

                rough = new Vector2(snakeBody[0].X + 12, snakeBody[0].Y);
                break;

            case 2:

                rough = new Vector2(snakeBody[0].X - 12, snakeBody[0].Y);
                break;

            case 3:

                rough = new Vector2(snakeBody[0].X, snakeBody[0].Y + 12);
                break;

            case 4:

                rough = new Vector2(snakeBody[0].X, snakeBody[0].Y - 12);
                break;
        }

        if (IsCollision(rough))
            return false;

        snakeBody.RemoveAt(snakeBody.Count - 1);
        snakeBody.Insert(0, rough);
    }

    return true;
}

public bool IsCollision(Vector2 testedPosition)
{

    foreach (Vector2 position in snakeBody)
        if (new Rectangle((int)testedPosition.X, (int)testedPosition.Y, 12, 12).Intersects(new Rectangle((int)position.X, (int)position.Y, 12, 12)))
            return true;

    return false;
}
Editováno 9.10.2012 20:42
 
Nahoru Odpovědět 9.10.2012 20:40
Avatar
Kit
Redaktor
Avatar
Kit:

Tak vidíš, jde to i bez cyklů. Teď je na řadě switch. Ten tam také není nutný. Ne, opravdu nemám na mysli dávat místo něho špagetu if-else.

Nahoru Odpovědět 9.10.2012 20:50
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Ternary operator? :)

 
Nahoru Odpovědět 9.10.2012 21:03
Avatar
Kit
Redaktor
Avatar
Nahoru Odpovědět 9.10.2012 21:04
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

Ve třídě si nadefinuješ 2 konstantní pole:

int[] posunX={0, 12, -12, 0, 0}
int[] posunY={0, 0, 0, 12, -12}

a místo celého toho obludného switche dáš jen

rough=new Vector2(snakeBody[0].X+posunX[direction], snakeBody[0].Y+posunY[direction]);

a je to. Nejsi přece placený za počet řádek, že ne?

Nahoru Odpovědět 9.10.2012 21:19
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
 
Nahoru Odpovědět 9.10.2012 21:27
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Napadá tě co s tímhle?

if (snake.snakeBody[0].X + 12 < 0)
    snake.snakeBody[0] = new Vector2(Window.ClientBounds.Width, snake.snakeBody[0].Y);
if (snake.snakeBody[0].X > Window.ClientBounds.Width)
    snake.snakeBody[0] = new Vector2(0, snake.snakeBody[0].Y);
if (snake.snakeBody[0].Y + 12 < 0)
    snake.snakeBody[0] = new Vector2(snake.snakeBody[0].X, Window.ClientBounds.Height);
if (snake.snakeBody[0].Y > Window.ClientBounds.Height)
    snake.snakeBody[0] = new Vector2(snake.snakeBody[0].X, 0);
 
Nahoru Odpovědět 9.10.2012 21:46
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

Předpokládám, že ty podmínky jsou chybně. Podle mne by to mělo vypadat asi takto:

snake.snakeBody[0] = new Vector2(
   Math.max(Math.min(snake.snakeBody[0].X, Window.ClientBounds.Width), 12),
   Math.max(Math.min(snake.snakeBody[0].Y, Window.ClientBounds.Height), 12)
);

Konstanty si případně uprav podle sebe.

Nahoru Odpovědět 9.10.2012 22:10
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Ale já bych chtěl nastavovat hodnotu jen když je třeba - jinak to akorát bude zbytečně zdržovat - ne? (Podmínky fungují - takže asi chybně nebudou... :) )

Aha mi si nerozumíme - tvoje nepropouští - já chci ale normálního hada - který propouští... (Viz. Pacman.)

Poslal jsem ti to akorát na vylepšení - je-li nějaké možné... (Mě se ten kus kódu moc nelíbí...)

Editováno 9.10.2012 22:16
 
Nahoru Odpovědět 9.10.2012 22:14
Avatar
Kit
Redaktor
Avatar
Odpovídá na matesax
Kit:

V tom případě tam patří konstanty -12.

Pomalé to není, to si klidně můžeš změřit. Je fakt, že mé řešení není úplně ekvivalentní, protože pokaždé vytváří novou instanci Vector2. Jenže podle všeho ji stejně potřebuješ a vytváříš jednu zbytečnou o kousek výš.

Snaž se vyhýbat podmínkám a cyklům. Nekamarádí se s multiprocesorovými systémy. Podmínky a cykly se totiž nedají paralelizovat. Takové programy jsou pak uvězněny na jednom procesorovém jádře.

Nahoru Odpovědět 9.10.2012 22:24
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Redaktor
Avatar
Odpovídá na Kit
matesax:

Pořád mě nechápeš - chci normálně procházet jako v Pacmanu... 12 tam je jen z jednoho důvodu - vykresluje se směrem dolů a doprava:

dddd
d
d
d

A pozice určuje počátek tohoto rozkolu:

Dd
d

Takže v místě kontaktu pozice písmena

dddd
d
d
d

by byl přechod trhavý - proto jej posunuji o 12...

Zatímco vzdálenější konec přejde až když nastane kontakt s pozicí jeho majitele...

 
Nahoru Odpovědět 9.10.2012 22:46
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 22 zpráv z 22.