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


David Hartinger:11.9.2012 22:27
Tohle jsem řešil takto:
if (!zamerovacZvyseni)
zamerovacAlfa -= 0.02f;
else
zamerovacAlfa += 0.02f;
if (zamerovacAlfa > 0.5)
zamerovacZvyseni = false;
if (zamerovacAlfa < 0.2)
zamerovacZvyseni = true;
Pulzuje mezi 0.2 a 0.5. Je to zbastlené, šlo by to lépe, ale zatím jsem to neřešil
Také se tě na něco zeptám, používáš GameComponents? Já jsem se na
tom šíleně zasekl
GameComponents:
----------------------
1. GameComponents:
metody volané automaticky: Initialize() a Upadate()
2.DrawableGameComponent:
autamaticky volané metody: vlastně všechny (tzn.: Initialize(), LoadContent(), UnloadContent(), Update(), Draw() )
Použití Components:
public class Trida: DrawableGameComponent
{
public Trida(Game game)
: base(game)
{
}
protected override void Initialize()// přetížené metody "volané automaticky"
{
base.Initialize(); // v teto metode povine => vola se metoda LoadContent(), v ostatnich metodach jen pokud mas vnoreny Komponenty
}
protected override void LoadContent()
{
...
}
protected override void UnloadContent()
{
...
}
public override void Draw()
{
...
}
atd...
}
Game1.cs:
protected override void Initialize()
{
Trida trida = new Trida(this);
Components.Add(trida); // Zaregistrovani komponenty
}
Snad to pomohlo ,myslim ze
jsem na nic nezapomel...
Jinak diky za tip, uz jsem to nejak takto taky zkousel osetrit, v tom hlavni
problem nebude... Asi budu mit nekde nejakou blbou chybku... zase do toho moc
dlouho cumim
user:12.9.2012 0:12
Jo a jeste musis mit v Game1.cs ve vsech metodach: base.NazavMetody();
napr:base.Initialize();
Jinak se ti dana metoda na Komponente automaticky nezavola.
David Hartinger:12.9.2012 11:23
Ahoj, jsem rád, že s tím také děláš Toto jsem ještě pochopil.
První problém je s tím, co je to komponenta. Po zběsilém hodinovém Googlení jsem zjistil, že MS asi nijak nedeklaruje, pro co by se komponenta měla použít, jen popisuje jak funguje. Ani nikde jinde jsem nenašel kloudné vysvětlení. Spokojil jsem se s tím, že komponenty budu používat pro všechno, co má nějakou logiku v update a vykreslování.
V mém Tetrisu jsou komponenty: Menu, Obrazovka autoři, Obrazovka HiScore, GamePlay, HraciPole, Kostka.
Problém mám hlavně s tím, jak do komponenty dostanu závislosti. V konstruktrou se předává objekt typu obecné Game. Tak si mohu vytvořit věci jako SpriteBatch a podobně, o tom žádná. Když ale 3 komponenty využívají tu samou texturu, nebudu ji přece 3x načítat v LoadContent, nějak ji předám.
Napadlo mě změnit konstruktor na:
public Trida(TetrisGame game) : base(game)
{
this.game = game;
}
Potom budu vidět proměnné a metody mojí specifické hry, tam si mohu vystavit textury, případně metodu JdiDoMenu(), kterou když komponenta zavolá, hra ji zastaví a zapne komponentu menu.
V tutoriálu přímo od někoho z Microsoftu jsem viděl předání instance
konkrétní hry přes statiku na té třídě, fuj
Ma hra bezi jen na jedne komponente ScreenManager, ta se stara o zobrazeni
obrazovek (jako: MenuScreen, GamePlayScreen, HelpMenuScreen, GameOverScreen
atp...), v ni pak volam na prislusnych mistech metody (Initialize(),
LoadContent() atp...) obrazovky ktera je zrovna aktivni. Pak mam jeste
abstraktni tridu GameScreen z ktere ostatni obrazovky dedi. Mohu zde i nacitat
spolecny obsah. Pokud bych v nektere obrazovce zaregistroval dalsi komponentu,
jeji metody by se volali jen pokud by byla obrazovka aktivni - zatim
nevyzkouseno, ale melo by to tak byt.
Snad to neni vysvetleno moc abstraktne
Na zadny lepsi zpusob vyuziti komponent sem zatim neprisel.
David Hartinger:12.9.2012 18:57
IMHO bys měl mít komponentu pro více věcí ve hře, často jsem vídával
např. komponentu sprite, která měla texture, velocity, position, speed a tak
dále. U hvězdné střílečky jsem viděl komponentu na pozadí, kde se
vygenerovaly hvězdy, které potom jely různou rychlostí. Vše bylo
zapouzdřené v komponentě, aby se to nemíchalo s další logikou hry. Jediný
problém je ty komponenty nějak zmanažovat, povypínat ty které
nepotřebuješ v dané obrazovce. Z toho co jsem viděl ale usuzuji, že v XNA
prostě není dán jeden základní přístup, viděl jsem hodně bastlů, tak
snad to nějak udělám Teď
si od toho dávám pauzu, včera jsem do půlnoci komponentoval
Rád sem potom dám svůj
zdroják, co na to řekneš, jen nevím, kdy to konečně dodělám. Hra jako
taková mi zabrala pár dní, ale architekturu již měním týden a stále se
mi nelíbí.
user:12.9.2012 19:25
Jo s architekturou s tebou plne souhlasim, s tou nebudu asi nikdy spokojeny,
porad je co vylepsovat. Komponenty je urcite dobre pouzivat, vsude tam kde aspon
trochu zprehledni kod, jen vim ze jsem s tim taky nekdy pred koncem prazdnin
silene zapasil, moc jsem toho nevymyslel, tak jsem si dal pauzu as doted . Components pro zaregistrovani
komponenty je obycejny List, mela by z nej jit komponenta odebrat, nevim, spise
se ptam? Mas problem jen s architektonickym navrhem kodu, nebo i s
"funkcnosti"?
Jinak se tesim na tvuj vytvor, jsem zvedav na vysledek.
David Hartinger:12.9.2012 19:28
Funkční hru mám již týden, vůbec se nemění. Ale desítky hodin
překopávám návrh Ono by
to chtělo, aby každá obrazovka měla svůj seznam komponent a ty pak
screenmanager vypnul, je tam nějaká vlastnost Enabled. Asi si taky udělám tu
třídu GameScreen. Ta ti dědí z GameComponent, ne?
David Hartinger:12.9.2012 19:48
Úplně špatné není tohle, až na to příšernou statiku: http://blogs.microsoft.co.il/…14-last.aspx
David Hartinger:12.9.2012 20:29
A jak funguje? Pokud tam máš ty metody jako LoadContent, Initialize, Update atd, tak by to skoro měla být komponenta, ne? Můžeš sem hodit kód?
David Hartinger:12.9.2012 20:33
Já měl předtím hru složenou jen z tříd, co měly metodu draw a tam se předával spritebatch, ale chci to udělat celé z těch komponent.
user:12.9.2012 21:01
ScreenManager:
public class ScreenManager : DrawableGameComponent
{
List<GameScreen> screens = new List<GameScreen>();
List<GameScreen> currentScreens = new List<GameScreen>();
InputState input = new InputState();
ContentManager content;
SpriteBatch spriteBatch;
SpriteFont gameFont;
public InputState Input
{
get { return input; }
}
public ContentManager Content
{
get { return content; }
}
public SpriteBatch SpriteBatch
{
get { return spriteBatch; }
}
public ScreenManager(Game game)
: base(game)
{
content = new ContentManager(game.Services, "Content");
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
content.Unload();
}
public void Add(GameScreen screen)
{
screen.ScreenManager = this;
screen.LoadContent();
screens.Add(screen);
}
public void Remove(GameScreen screen)
{
screen.UnloadContent();
screens.Remove(screen);
}
public override void Update(GameTime gameTime)
{
input.Update();
currentScreens.Clear();
foreach (GameScreen screen in screens)
currentScreens.Add(screen);
bool firstActiveScreen = true;
while (currentScreens.Count > 0)
{
GameScreen screen = currentScreens[currentScreens.Count - 1];
currentScreens.RemoveAt(currentScreens.Count - 1);
if (screen.ScreenState == ScreenState.Inactive)
continue;
if (screen.ScreenState == ScreenState.Active)
{
if (firstActiveScreen)
{
screen.HandleInput();
firstActiveScreen = false;
}
}
screen.Update(gameTime);
}
}
public override void Draw(GameTime gameTime)
{
currentScreens.Clear();
foreach (GameScreen screen in screens)
currentScreens.Add(screen);
foreach (GameScreen screen in currentScreens)
{
if (screen.ScreenState == ScreenState.Inactive)
continue;
else
screen.Draw(gameTime);
}
}
}
GameScreen:
public enum ScreenState
{
TransitionOn,
TransitionOff,
Active,
Frozen,
Inactive
}
public abstract class GameScreen
{
public TimeSpan TransitionOnTime
{
get { return transitionOnTime; }
protected set { transitionOnTime = value; }
}
TimeSpan transitionOnTime = TimeSpan.Zero;
public TimeSpan TransitionOffTime
{
get { return transitionOffTime; }
protected set { transitionOffTime = value; }
}
TimeSpan transitionOffTime = TimeSpan.Zero;
public ScreenState ScreenState
{
get { return screenState; }
set { screenState = value; }
}
ScreenState screenState = ScreenState.TransitionOn;
public float TransitionPercent
{
get { return transitionPercent; }
}
float transitionPercent = 0.00f;
public byte ScreenAlpha
{
get { return (byte)(transitionPercent * 255); }
}
public float TransitionSpeed
{
get { return transitionSpeed; }
}
float transitionSpeed = 2f;
public int TransitionDirection
{
get { return transitionDirection; }
}
int transitionDirection = 1;
public ScreenManager ScreenManager
{
get { return screenManager; }
internal set { screenManager = value; }
}
ScreenManager screenManager;
public virtual void LoadContent() { }
public virtual void UnloadContent() { }
public virtual void Update(GameTime gameTime)
{
if (screenState == ScreenState.TransitionOn)
{
if (transitionPercent >= 1)
{
screenState = ScreenState.Active;
transitionDirection *= -1;
}
else
ScreenTransition(gameTime, transitionOnTime, transitionDirection);
}
else if (screenState == ScreenState.TransitionOff)
{
if (transitionPercent <= 0)
{
RemoveScreen();
}
else
ScreenTransition(gameTime, transitionOffTime, transitionDirection);
}
}
public virtual void RemoveScreen()
{
screenManager.Remove(this);
}
private void ScreenTransition(GameTime gameTime, TimeSpan transitionTime, int direction)
{
float transitionDelta;
if (transitionTime == TimeSpan.Zero)
transitionDelta = 1;
else
transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / transitionTime.TotalMilliseconds);
transitionPercent += transitionDelta * direction * transitionSpeed;
transitionPercent = MathHelper.Clamp(transitionPercent, 0, 1);
}
public virtual void HandleInput()
{
if (screenState != ScreenState.Active)
return;
}
public abstract void Draw(GameTime gameTime);
public virtual void ExitScreen()
{
screenState = ScreenState.TransitionOff;
}
public void FreezeScreen()
{
screenState = ScreenState.Frozen;
}
}
Pak napr: Game1.cs:
Initialize()
{
screenManager.Add(new MainMenuScreen());
}
David Hartinger:12.9.2012 21:27
No jelikož tam máš ty Update a Draw, tak je to také vlastně komponenta,
jen má něco navíc. Zapínání/vypínání komponent to také neřeší.
Takže to dělám vlastně podobně, to je dobré vědět
BTW proč máš takhle rozepsané ty vlastnosti? Stačí jen:
public TimeSpan TransitionOnTime { get; protected set; }
Udělám tam injekci do konstruktoru přes tu třídu s hrou, změním Game
na TetrisGame a bude Jen
nevím, kdy se k tomu zas dostanu, už mi to sežralo moooc hodin.
user:12.9.2012 21:42
Myslim, ze by slo vypinani/zapinani udelat na zpusob jaky jsi uz tady navrhoval, nebylo by to spatne. U kazde obrazovky by jsi mel ten List s nazvy komponent, po kazdym volani screenManager.Add(new MainMenuScreen()) nebo ExitScreen() by si prosel List a povypinal/pozapinal komponenty. To neni spatnej napad, nebo co se na nem nezda?
David Hartinger:13.9.2012 12:07
Zdá se mi, myslím, že je to v pořádku, i se o to tak pokusím Musím ale hru rozdělit nejprve do
komponent a to je porod, když to je vše zamotané do sebe.
Zobrazeno 17 zpráv z 17.