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.
Tvůrce
Zobrazeno 14 zpráv z 14.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
No co? Nečekal, až pochopíme jeho dotaz a hledal i jinde. To je v pořádku.
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...)
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;
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í)...
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á.
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...
Jo takhle to myslíš! To se dělá tak, že metodě předáš parametr, kterým směrem se chceš pohybovat. Metoda inkrementuje/dekrementuje čí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.
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...
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...
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...)
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...
Zobrazeno 14 zpráv z 14.