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í.

Lekce 11 - 3D bludiště v XNA - Časujeme

Vítejte po jednadvacáté. V minulém díle, 3D bludiště v XNA - Kolize potřetí a snad naposledy, jsme konečně úplně dodělali náš kolizní systém.

Chvíli jsem přemýšlel, jestli budu i nadále číslovat, ale vzhledem k tomu, že to nikdo jiný nedělá, tak ano, budu :-) V tomto díle si naší pokusnou kuličkou zkusíme projet bludiště na čas. Vytvoříme si komponentu obecného časovače a k tomu další časovač, který pude vykreslovat na obrazovku. Také si jej do hry naroubujeme. Budeme tedy moci projet bludiště na čas :-) Pusťme se do toho.

Timer

Časovačů a jistě dokonalejších najdeme všude hromady. Nám postačí snadňoučký, který půjde odstarovat, vynulovat a zase zastavit. Nic moc těžkého. V metodě Update se bude nasčítávat čas. Přidáme si tedy nový soubor do našeho enginu, konkrétně do složky s komponentami. Třídu nazveme Timer. Učiníme ji veřejnou a tak dále, však to znáte. Dědíme od třídy Component. Čas budeme skladovat v proměnné typu TimeSpan.

public TimeSpan Time{
  get;
  private set;
}

V konstruktoru jej vynulujeme:

public Timer(){
  Time = TimeSpan.Zero;
}

Dodáme také proměnnou pro indikaci zda-li je časovač aktivní:

public bool Running{
  get;
  private set;
}

Nastavování necháme soukromé, nechceme, aby bylo možné s proměnnou manipulovat mimo třídu. Následuje sled veřejných virtuálních metod:

public virtual void Start(){
  Running = true;
}

public virtual void Stop(){
  Running = false;
}

public virtual void Reset(){
  Time = TimeSpan.Zero;
}

Jejich význam není snad potřeba vysvětlovat. Poslední součástí je přepsaná metoda Update, kde nasčítáváme čas. Tedy asi takto:

public override void Update(){
  if(Running)Time += Parent.Engine.GameTime.ElapsedGameTime;
}

Hotovo. Více toho opravdu není. Základní časovač je tedy hotov. My ale potřebujeme čas i ukazovat.

Vykreslovatelný timer

Přidáme si další třídu do složky s komponentami. Já jsem ji nazval GameTimer, ale opět jméno ponechám na vašem uvážení. Dědit budeme od třídy Timer, kterou jsme si připravili nahoře. Opět je třída veřejná, ale to už víte lépe než já. Text budeme vykreslovat skrze SpriteBatch, jak jinak že. Potřebujeme znát jeho pozici:

public Vector2 Pozice{
  get;
  set;
}

Jeho barvu

public Color Color{
  get;
  set;
}

A jakým fontem budeme vykreslovat:

private string fontName;
protected SpriteFont Font;

V konstruktorech všechny parametry nastavíme:

public GameTimer(string font, Vector2 pozice): this(font,pozice,Color.Black){
}

public GameTimer(string font, Vector2 pozice, Color color){
  fontName = font;
  Pozice = pozice;
  Color = color;
}

Tradičně v metodě Load nahrajeme font.

protected override void Load(){
  Font = Parent.Engine.Content.Load<SpriteFont>(fontName);
}

A konečně v metodě Draw vše vykreslíme:

public override void Draw(Microsoft.Xna.Framework.Matrix View, Microsoft.Xna.Framework.Matrix Projection, Microsoft.Xna.Framework.Vector3 CameraPosition){
  Parent.Engine.SpriteBatch.Begin();
  Parent.Engine.SpriteBatch.DrawString(Font, Time.ToString(@"mm\:ss\.ff"), Pozice, Color);
  Parent.Engine.SpriteBatch.End();
}

Vykreslovat počítání času na hodiny snad nebude potřeba. Zkusíme si přidat nový časovač do našeho herního okna.

AddComponent(new GameTimer("Maly", new Vector2(0, 10)));

Hru si pustíme a vidíme náš nádherný čas a také vidíme průšvih.

Chyba v časovači v 3D bludišti v C# .NET XNA - 3D bludiště v XNA

Je důležité si uvědomit, že pokaždé, když pracujeme se SpriteBatch, je třeba navrátit stav grafické karty do normálu. Takže po vykreslení je navrátíme.

Parent.Engine.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
Parent.Engine.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
Parent.Engine.GraphicsDevice.BlendState = BlendState.Opaque;

Hotovo. Nyní je vše jak má být. Chybí nám už jen časovač odstartovat.

Startovní a cílová podlaha

To se bude dít na těchto našich speciálních podlahách. Začneme se startovní podlahou, kterou až kulička/hráč opustí, tak se časovač spustí. Otevřeme si tedy třídu se startovní podlahou. Změníme třídu od které dědíme na CollidableModel3D. Stejně jako jsme učinili u zdi. Přepíšeme metodu Load. Necháme zavolat metodu Load u předka. Naši kolizní krabici ale musíme na ose Y zvětšit, protože model jen jen placka a my potřebujeme plnou krabici.

this.CollisionSkin.ZakladniKrabice.Max.Y = 15;

Zkusíme si hru spustit, zda-li je vše v pořádku. Je snad jasné, že když na to tak upozorňuji, něco v pořádku nebude. Vůbec se nám nepovede odjet pryč. Nečekaně. Systém nám detekuje kolizi a kuličku nepustí ani o pixel. V našem systému chybí možnost udělat kůži průchozí. Ptáte se proč ji tedy potřebujeme, když se skrze ní dá projít, ale právě o to nám jde. Aby se zavolala událost a aby vše bylo na jednom místě. Podíváme se tedy do naší kůže a do ní přidáme parametr Solid:

public bool Solid{
  get;
  set;
}

V konstruktoru jej nastavíme na true. Vše bude pevné jen na výjimky, které si stanovíme. Jednou takovou je právě uděláme u startovní podlahy, takže nastavíme Solid na false.

this.CollisionSkin.Solid = false;

Ještě jej potřebujeme zohlednit v kolizním manažeru. Do metody Collide přidáme před přidání kůže do seznamu podmínku, zda je pevná:

if (skin.CheckCollision(sphere) && skin.Solid) colliding.Add(skin);

Pokud nyní hru spustíme, tak už se nám povede odjet. To byl onen zádrhel, který jsem avizoval minule. Více se jich snad už nenaskytne. Doufejme.

Poslední věcí, kterou potřebujeme, je odchytit událost, že kulička pole opustila. Přidáme si ji tedy:

this.CollisionSkin.UnCollided += new CollisionEnd(CollisionSkin_Collided);

Zároveň nám to vytvoří i obslužnou metodu. Uvnitř ní najdeme mezi komponentami časovač a spustíme jej:

void CollisionSkin_Collided(BoundingSphere koule){
  GameTimer t = null;
  foreach (Component c in Parent.Components){
    if (c is GameTimer){
      t = c as GameTimer;
      break;
    }
  }

  if (t != null){
    t.Start();
  }
}

Pokud nyní hru spustíme a odjedeme ze startovacího pole, vualáá, časovač jede. Stejný postup aplikujeme u cílové podlahy, jen časovač zastavíme a reagujeme na vstup do políčka ne na výstup. Pokud by měl někdo s tímto problém, tak vás odkazuji na celý kód pod článkem.

Příště, 3D bludiště v XNA - Hráčská kamera, si uděláme kameru a nahradíme jí tak kuličku. Poprvé si bludiště projdeme jako hráči.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 160x (1.8 MB)
Aplikace je včetně zdrojových kódů v jazyce C# XNA

 

Předchozí článek
3D bludiště v XNA - Kolize potřetí a snad naposledy
Všechny články v sekci
3D bludiště v XNA
Přeskočit článek
(nedoporučujeme)
3D bludiště v XNA - Hráčská kamera
Článek pro vás napsal vodacek
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
Vodáček dělá že umí C#, naplno se již pět let angažuje v projektu ŽvB. Nyní studuje na FEI Upa informatiku, ikdyž si připadá spíš na ekonomice. Není mu také cizí PHP a SQL. Naopak cizí mu je Java a Python.
Aktivity