NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.

Diskuze: XNA - políčková grafika

V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
matesax
Tvůrce
Avatar
matesax:14.10.2012 20:39

Dobrý den,
jak co nejjednodušeji dostat z aktuální pozice nejbližší políčkovou? (Políčka jsou 32x32) Děkuji.

 
Odpovědět
14.10.2012 20:39
Avatar
matesax
Tvůrce
Avatar
Odpovídá na matesax
matesax:14.10.2012 22:15

Asi tedy takto:

x - (x % 32)
:)
 
Nahoru Odpovědět
14.10.2012 22:15
Avatar
TomBen
Tvůrce
Avatar
Odpovídá na matesax
TomBen:14.10.2012 22:21

Ty si chlape celkem vystačíš sám, co? :D

Nahoru Odpovědět
14.10.2012 22:21
Za posledních 200 miliónů let se nic zvláštního nestalo, akorát dinosauři vymřeli a opice se naučily programovat.
Avatar
Kit
Tvůrce
Avatar
Odpovídá na TomBen
Kit:14.10.2012 22:25

No co? Nečekal, až pochopíme jeho dotaz a hledal i jinde. To je v pořádku.

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

Nehledal - vymyslel... :)

Původně jsem využíval celočíselného dělení:

(x / 32) * 32 - to se mi ale nelíbilo, tak jsem sem napsal. A v jiné části kódu zase umožňuji změnit směr jen při modulo 32 na 0...

if (Keyboard.GetState().IsKeyDown(Keys.Up) && monster.x % 32 == 0 && monster.TestCollision(monster.x, monster.y - 1))
    monster.direction = Direction.Up;
else if (Keyboard.GetState().IsKeyDown(Keys.Down) && monster.x % 32 == 0 && monster.TestCollision(monster.x, monster.y + 33))
    monster.direction = Direction.Down;
else if (Keyboard.GetState().IsKeyDown(Keys.Left) && monster.y % 32 == 0 && monster.TestCollision(monster.x - 1, monster.y))
    monster.direction = Direction.Left;
else if (Keyboard.GetState().IsKeyDown(Keys.Right) && monster.y % 32 == 0 && monster.TestCollision(monster.x + 33, monster.y))
    monster.direction = Direction.Right;
using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;

namespace Cunteka
{
    public enum Direction { Stop, Up, Down, Left, Right }


    public class Monster
    {
        public int x = 32, y = 32;
        public Direction direction = 0;
        private List<Vector2> tiles;

        public Monster(List<Vector2> tiles)
        {
            this.tiles = tiles;
        }

        public void Move()
        {
            switch (direction)
            {
                case Direction.Up:

                    if (TestCollision(x, y - 1) || y % 32 != 0)
                        y--;
                    break;

                case Direction.Down:

                    if (TestCollision(x, y + 33) || y % 32 != 0)
                        y++;
                    break;

                case Direction.Left:

                    if (TestCollision(x - 1, y) || x % 32 != 0)
                        x--;
                    break;

                case Direction.Right:

                    if (TestCollision(x + 33, y) || x % 32 != 0)
                        x++;
                    break;
            }
        }

        public bool TestCollision(int x, int y)
        {
            int X = x - (x % 32), Y = y - (y % 32);

            if (tiles.Contains(new Vector2(X, Y)))
                if (new Rectangle(X, Y, 32, 32).Intersects(new Rectangle(x, y, 32, 32)))
                    return false;

            return true;
        }
    }
}

Neměl by jsi zase nějakou připomínku? Jinak proč je to takto - nechci, aby se směr zmenil hned - ale jen když to má smysl - takto se mi to zastaví jen v bezvýhodné situaci - ne když se uživatel rozhodne probourat zeď... :)

Jo a:

x % 32 != 0

To je kvůli drobečkům - něco jako když se zbavíš desetiny převodem na int... (Pro mě je celé číslo jen to, které je dělitelné 32...)

Editováno 14.10.2012 22:34
 
Nahoru Odpovědět
14.10.2012 22:32
Avatar
Kit
Tvůrce
Avatar
Kit:14.10.2012 22:51
monster.TestCollision(monster.x, monster.y - 1)

Testuješ kolizi monster se sebou samým? Hmm.

x%32 != 0 // je ukázkou posunutí desetinné čárky. Je to regulérní technika.

Rozlišovat proměnné jen velikostí písma (x vs. X) je hodně nebezpečné. Doporučuji přejmenovat.

A ten switch ... však už víš, na co myslím.

Místo

public Direction direction = 0;

má být zřejmě

public Direction direction = Direction.Stop;
Editováno 14.10.2012 22:52
Nahoru Odpovědět
14.10.2012 22:51
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:14.10.2012 23:07

Testuji přeci kolizi sebe s něčím jiným - to je trestné? (Nemohu použít aktuální pozici - nevěděl bych co přičítat a co odečítat - takto pošlu zpracovaná data...) Dobrá s mapou se nějak poperu - chtěl jsem si užít krásu enum... :)

// je ukázkou posunutí desetinné čárky. Je to regulérní technika. - proč jsi to psal? (Z té věty jaksi nic nevyplývá... :) )

public Direction direction = 0; == public Direction direction = Direction.Stop;

C# přiřazuje vždy čísla (dle pořadí)...

Editováno 14.10.2012 23:08
 
Nahoru Odpovědět
14.10.2012 23:07
Avatar
Kit
Tvůrce
Avatar
Kit:14.10.2012 23:18

Trestné to není, ale souřadnice x a y jsou už součástí objektu monster. Proto mi přišlo divné, proč je dáváš jako parametry vlastní metodě.

Když už používáš enum, tak si to vychutnej a nespoléhej na to, že Direction.Stop == 0. Enum se dá použít i v kombinaci s mapou.

O tom posunutí des. čárky jsem psal jen to, že ta myšlenka je správná.

Editováno 14.10.2012 23:19
Nahoru Odpovědět
14.10.2012 23:18
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:15.10.2012 6:05

No jo, ale jak zařídím toto?

x--;/x++;/y--;/y++;

Napadá mne jak to udělat - ale tak proč bych nemohl nechat switch?

K těm souřadnicím - jak píši - neznal bych testovaná data - jen poslední souřadnice - a tak bych musel udělat druhý switch - takhle vytvářím správná data rovnou při vzniku události...

 
Nahoru Odpovědět
15.10.2012 6:05
Avatar
Kit
Tvůrce
Avatar
Odpovídá na matesax
Kit:15.10.2012 6:41

Jo takhle to myslíš! To se dělá tak, že metodě předáš parametr, kterým směrem se chceš pohybovat. Metoda inkrementuje/de­krementuje čítače, ale při možné kolizi místo pohybu jen vyhodí výjimku.

V uvedeném příkladu by volání mohlo vypadat třeba takto:

if (Keyboard.GetState().IsKeyDown(Keys.Up))
    monster.Move(Direction.Up);

Jen je potřeba upravit metodu Move a přidat do ní test kolize.

Nahoru Odpovědět
15.10.2012 6:41
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:15.10.2012 6:57

A co asi píši - musel bych použít druhý switch...

if (Keyboard.GetState().IsKeyDown(Keys.Up))
    monster.Move(Direction.Up);

Takže tam stejmě budu muset použít switch... :) Pořád to neřeší x++;/x--;/...

Navíc mi to ještě uškodí - nechci se pohybovat předem určeným směrem, ale tím směrem, který není kolizní... Takže jsem to udělal tak, že směr je prvek třídy Creature z ní je zděděn Monster a budou z ní dědeny i NPC. (Je v ní i test kolize.) Takže je v ní uložena určitá hodnota. A v hlavní třídě (Game) testuji, má-li cenu měnit směr. Když jej ale nezměním, jak by se pak mohl provést pohyb? Právě proto, že směr je uložen již ve tříde Creature. No a protože by to pak v bezvýhodné situaci mohlo projít zdí, musím přidat druhý test - přímo v Creature...

Editováno 15.10.2012 6:58
 
Nahoru Odpovědět
15.10.2012 6:57
Avatar
matesax
Tvůrce
Avatar
matesax:15.10.2012 7:06
if (Keyboard.GetState().IsKeyDown(Keys.Up) && monster.x % 32 == 0 && TestMonsterCollision(Direction.Up))
    monster.direction = Direction.Up;
else if (Keyboard.GetState().IsKeyDown(Keys.Down) && monster.x % 32 == 0 && TestMonsterCollision(Direction.Down))
    monster.direction = Direction.Down;
else if (Keyboard.GetState().IsKeyDown(Keys.Left) && monster.y % 32 == 0 && TestMonsterCollision(Direction.Left))
    monster.direction = Direction.Left;
else if (Keyboard.GetState().IsKeyDown(Keys.Right) && monster.y % 32 == 0 && TestMonsterCollision(Direction.Right))
    monster.direction = Direction.Right;

if (monster.x > Window.ClientBounds.Width)
    monster.x = -31;
else if (monster.x + 32 < 0)
    monster.x = Window.ClientBounds.Width;
else if (monster.y > Window.ClientBounds.Height)
    monster.y = -31;
else if (monster.y + 32 < 0)
    monster.y = Window.ClientBounds.Height;

monster.Move(); //pohyb se provede vždy

Nahoře právě měním směr - není-li kolize...

 
Nahoru Odpovědět
15.10.2012 7:06
Avatar
matesax
Tvůrce
Avatar
Odpovídá na Kit
matesax:15.10.2012 7:13

Dotaz - mám generátor zdí - a vygenerované pozice potřebuji testovat - jenže instanci této třídy má hlavní třída a ostatní se k ní nemohou dostat. (Zaprvé dával-li bych to jako parametr - bylo by jich hodně, zadruhé - mám v nich parametry k věcem, které se naplní až v průběhu hry - takže bych nemohl dodržet OOP model.) Nedal by se výsledný List nějak zveřejnit? (Bez toho, abych si jej posílal jako dáreček...)

Editováno 15.10.2012 7:13
 
Nahoru Odpovědět
15.10.2012 7:13
Avatar
matesax
Tvůrce
Avatar
matesax:15.10.2012 7:28

Tak zatím jsem to vyřešil takto:

using System;
using Microsoft.Xna.Framework;

public enum Direction { Stop, Up, Down, Left, Right }

public class Creature
{
    public int x { get; set; }
    public int y { get; set; }
    public Direction direction { get; set; }
    public System.Collections.Generic.List<Vector2> tiles { get; set;}

    public bool TestCollision(int x, int y)
    {
        int X = x - (x % 32), Y = y - (y % 32);

        if (tiles.Contains(new Vector2(X, Y)))
            if (new Rectangle(X, Y, 32, 32).Intersects(new Rectangle(x, y, 32, 32)))
                return false;

        return true;
    }
}
public Monster(List<Vector2> tiles)
{
    this.tiles = tiles;

    x = 32;
    y = 32;
    direction = Direction.Stop;
}

Bojím se, že budu potřebovat metodu použít k jiným testům - ale asi to udělám přes overload...

 
Nahoru Odpovědět
15.10.2012 7:28
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 14 zpráv z 14.