Obecnie pracuję nad klasą, która będzie szkieletowym interfejsem gry. Co to takiego? Otóż będzie to klasa, po której będziemy dziedziczyli podstawowe metody(wirtualne), potem naszą klasę podamy jako parametr do konstruktora klasy CApp(klasa aplikacji- reprezentuje aplikacje to w niej jest pętla główna). Wróćmy jednak do IGame, obecnie ma kilka metod wirtualnych:
- void Update(double step) // aktualizacja gry, parametr krok czasowy;
- void Render() // odrysowanie przebiegu gry;
- bool Init() // inicjalizacja gry;
- bool Uninit() // po zakończeniu gry;
... // jeszcze jakieś można wymyślić.
Ogólnie ta klasa w połączeniu z CApp i innymi ma pomóc przy tworzeniu gry(nie musimy pisać na przykład pętli głównej od początku itp.)
sobota, 23 października 2010
środa, 20 października 2010
Co już jest w silniku ??
W tym poście chce podsumować te kilka tygodni pracy i pokazać co jeszcze zostało do zrobienia, oraz jak wygląda obecnie silnik(podział na części).
Zacznijmy od podsumowania:
- można wyświetlać obraz(wczytany z pliku lub generowany) i tekst na ekranie;
Zacznijmy od podsumowania:
- można wyświetlać obraz(wczytany z pliku lub generowany) i tekst na ekranie;
- jest manager obrazów;
- dostęp do czcionek z plików .ttf;
- można rysować prymitywy;
- można używać klawiatury, myszki;
- dostępny jest wielowyjściowy logger(obecnie wyjscia do pliku i na konsolę dos);
- dostępny timer stałokrokowy;
- animacje z atlasu i manager animacji;
- można rysować prymitywy;
- można używać klawiatury, myszki;
- dostępny jest wielowyjściowy logger(obecnie wyjscia do pliku i na konsolę dos);
- dostępny timer stałokrokowy;
- animacje z atlasu i manager animacji;
- Sprity(zbiór animacji, graficzna reprezentacjia aktora);
- podstawowa obsługa dźwięku(można załadować muzykę z pliku i odtwarzać ją);
- podstawowa obsługa dźwięku(można załadować muzykę z pliku i odtwarzać ją);
- i inne drobnostki.
Ogólny zarys silnika:
Podział na 12 podsystemów(w silniku nazywanych rdzeniami), każdy rdzeń odpowiada za odpowiednią funkcjonalność:
- Graphics Core - odpowiada za to co zobaczymy na ekranie;
- Input Core - odpowiada za sterowanie w grze;
- Sound Core - odpowiada za dźwięk i jego efekty;
- Physic Core - odpowiada za fizykę oraz systemy cząsteczkowe;
- System Core - odpowiada za aplikacje, posiada klasy do obsługi maszyny stanów;
- GUI Core - przyciski, etykiety, okna, czyli GUI i jego obsługa;
- Effect Core - będą tam szablony różnych efektów np. blur i jego odmiany;
- Utility Core - Posiada klasy pomocnicze, Manager Zasobów oraz klasy obsługujące VFS i Archiwa( Zip, RAR, itp.);
- Network Core - odpowiada za komunikacje sieciową
- Script Core - odpowiada za przetwarzanie skryptów pisanych w specjalnie do tego celu stworzonym języku DarkScript;
- Artificial Intelligence Core - odpowiada za sztuczną inteligencję w grze;
- Game Core - odpowiada za całą grę, posiada klasy wyższego poziomu(czytaj: frameworka) które ułatwiają programowanie gier(zawiera klasy reprezentujące poszczególne elementy różnych typów gier).
sobota, 16 października 2010
Co w trawie piszczy ??
W silniku pojawiła się podstawowa obsługa dźwięku. Wreszcie można coś usłyszeć. To na razie tylko tak testowa i atrapowa klasa:
class CSound : public IResource
{
protected:
ALLEGRO_SAMPLE* m_Sound;
ALLEGRO_SAMPLE_ID m_SoundID;
public:
enum EPlayMode {
ONCE = ALLEGRO_PLAYMODE_ONCE,
LOOP = ALLEGRO_PLAYMODE_LOOP,
BIDIR = ALLEGRO_PLAYMODE_BIDIR
};
enum EPanMode {
NONE = -1000,
CENTER = 0,
LEFT = -1,
RIGHT = 1,
};
CSound()
{
m_Type = IResource::RES_TYPE_SOUND;
m_Sound = 0;
memset(&m_SoundID,0,sizeof(m_SoundID));
}
~CSound()
{
Stop();
if (m_Sound != 0)
al_destroy_sample(m_Sound);
}
const CError& LoadFromFile(const std::string & Filename)
{
if (m_Sound == 0)
m_Sound = al_load_sample(Filename.c_str());
if (m_Sound != 0)
{
SetFilename(Filename);
return CError();
}
return CError(CError::TYPE_SYSTEM_ERROR,CError::FILE_LOAD);
}
const CError& Reload()
{
al_destroy_sample(m_Sound);
return LoadFromFile(m_Filename);
}
bool Play(float Gain, float Pan, float Speed = 1.0, int Loop = ONCE)
{
return al_play_sample(m_Sound,Gain,Pan,Speed,Loop,&m_SoundID);
}
void Stop()
{
al_stop_sample(&m_SoundID);
}
};
Jak widać tylko podstawowa funkcjonalność, ale dodam jeszcze miksery i efekty to będzie git. Obsługuje formaty takie jak: .wav, .flac, .ogg, .it, .mod, .s3m, .xm.
Grunt że działa !!!
class CSound : public IResource
{
protected:
ALLEGRO_SAMPLE* m_Sound;
ALLEGRO_SAMPLE_ID m_SoundID;
public:
enum EPlayMode {
ONCE = ALLEGRO_PLAYMODE_ONCE,
LOOP = ALLEGRO_PLAYMODE_LOOP,
BIDIR = ALLEGRO_PLAYMODE_BIDIR
};
enum EPanMode {
NONE = -1000,
CENTER = 0,
LEFT = -1,
RIGHT = 1,
};
CSound()
{
m_Type = IResource::RES_TYPE_SOUND;
m_Sound = 0;
memset(&m_SoundID,0,sizeof(m_SoundID));
}
~CSound()
{
Stop();
if (m_Sound != 0)
al_destroy_sample(m_Sound);
}
const CError& LoadFromFile(const std::string & Filename)
{
if (m_Sound == 0)
m_Sound = al_load_sample(Filename.c_str());
if (m_Sound != 0)
{
SetFilename(Filename);
return CError();
}
return CError(CError::TYPE_SYSTEM_ERROR,CError::FILE_LOAD);
}
const CError& Reload()
{
al_destroy_sample(m_Sound);
return LoadFromFile(m_Filename);
}
bool Play(float Gain, float Pan, float Speed = 1.0, int Loop = ONCE)
{
return al_play_sample(m_Sound,Gain,Pan,Speed,Loop,&m_SoundID);
}
void Stop()
{
al_stop_sample(&m_SoundID);
}
};
Jak widać tylko podstawowa funkcjonalność, ale dodam jeszcze miksery i efekty to będzie git. Obsługuje formaty takie jak: .wav, .flac, .ogg, .it, .mod, .s3m, .xm.
Grunt że działa !!!
Angielski is Good !!!
Dzisiaj o nazewnictwie, dlaczego używam i wielu innych programistów języka angielskiego w pracy? Używam go dlatego, że jest wygodniejszy niż ojczysty, w większości przypadków dużo krótszy, a oto przykład:
metdy typu Get i Set, po polsku to Pobierz, Zmien // prawda, że po angielsku łatwiej zapisać i lepiej wygląda.
Ogólnie, rzecz biorąc nasze ogonki nie mogą być wykorzystywane w programowaniu, więc te wyrazy mają orty i zdarzyło mi się kilka razy zapomnieć co dany wyraz oznacza. Może drugi przykład na potwierdzenie tezy, że angielski jest prostszy w zapisie:
int Speed;
int Predkosc;
// Widać różnice ??
Oczywiście są wyjątki od tej reguły np.
int Mass;
int Masa
// ...
Projekty pisane po angielsku są dużo bardziej czytelniejsze niż te po polsku(mimo że w głowie mamy automat korekcji błędów i sami dodajemy ogonki). Jeszcze jeden powód dla którego warto stosować angielskie słownictwo, otóż na świecie jest dużo więcej osób posługujących się angielskim niż polskim i gdyby jakiś anglik chciał skorzystać z naszej pracy to nawet Trans Googla nie pomoże:)
Czekam na uwagi i opinie do tematu.
metdy typu Get i Set, po polsku to Pobierz, Zmien // prawda, że po angielsku łatwiej zapisać i lepiej wygląda.
Ogólnie, rzecz biorąc nasze ogonki nie mogą być wykorzystywane w programowaniu, więc te wyrazy mają orty i zdarzyło mi się kilka razy zapomnieć co dany wyraz oznacza. Może drugi przykład na potwierdzenie tezy, że angielski jest prostszy w zapisie:
int Speed;
int Predkosc;
// Widać różnice ??
Oczywiście są wyjątki od tej reguły np.
int Mass;
int Masa
// ...
Projekty pisane po angielsku są dużo bardziej czytelniejsze niż te po polsku(mimo że w głowie mamy automat korekcji błędów i sami dodajemy ogonki). Jeszcze jeden powód dla którego warto stosować angielskie słownictwo, otóż na świecie jest dużo więcej osób posługujących się angielskim niż polskim i gdyby jakiś anglik chciał skorzystać z naszej pracy to nawet Trans Googla nie pomoże:)
Czekam na uwagi i opinie do tematu.
piątek, 15 października 2010
Duchy na ekranie:)
Prace nad silnikiem powoli idą do przodu:)
Dzisiaj pragnę przedstawić, a właściwie zapoznać z duchami. Chyba każdy wie kim, a raczej czym jest duch - w folklorze ludowym i według spirytystów istota inteligentna, żyjąca po śmierci fizycznej człowieka, bytująca w świecie pozamaterialnym, tak tym jest właśnie duch. Ale w grafice jest to po prostu dwuwymiarowy obrazek, który wyświetla się na ekranie i fachową nazwą dla niego jest Sprite. W moim silniku, tworzy go klasa o oryginalnej nazwie "CSprite" . Oto jej kod:
//! Klasa zawiera zbiór animacji.
class DLLDARKSTORM2D CSprite : public IResource
{
protected:
AnimationManagerPtr m_Animations;
std::string m_CurrentAnimationName;
AnimationPtr m_CurrentAnimation;
public:
CSprite();
~CSprite();
bool Create(const std::string & CurrentAnimationName,AnimationManagerPtr & Animations);
void Update();
CError& LoadFromFile(const std::string & Filename);
const CError& Reload()
{
// mała atrapa
m_Animations->ReloadAll();
return CError();
}
bool SetAnimation(const std::string & AnimationName)
{
m_CurrentAnimationName = AnimationName;
m_CurrentAnimation = m_Animations->GetResource(AnimationName);
return true;
}
const std::string & GetCurrentAnimationName() const
{
return m_CurrentAnimationName;
}
void Render(float x, float y)
{
m_CurrentAnimation->Render(x,y);
}
};
JAK widać nic nadzwyczajnego, po prostu zbiór animacji. Jedną rzeczą na jaką trzeba zwrócić uwagę jest fakt że nie ma on określonej pozycji i wymiarów(to tylko część wizualna), jest to spowodowane filozofią projektową silnika - pozycja i wymiary będą w wyższej klasie grupującej tą i obiektu fizycznego, zdradzę może jej nazwę: CActor.
Może taka mała uwaga odnośnie nazewnictwa klas mojego projektu, a dokładniej przedrostków w nazwach:
1. C - od klasy "normalnej"
2. I - od interface, czyli klasa interfejsu(wirtualna)
3. S - od Singleton
4. może jeszcze FO od factory objects fabryka obiektów(o tym wspomnę w najbliższym poście).
Dzisiaj pragnę przedstawić, a właściwie zapoznać z duchami. Chyba każdy wie kim, a raczej czym jest duch - w folklorze ludowym i według spirytystów istota inteligentna, żyjąca po śmierci fizycznej człowieka, bytująca w świecie pozamaterialnym, tak tym jest właśnie duch. Ale w grafice jest to po prostu dwuwymiarowy obrazek, który wyświetla się na ekranie i fachową nazwą dla niego jest Sprite. W moim silniku, tworzy go klasa o oryginalnej nazwie "CSprite" . Oto jej kod:
//! Klasa zawiera zbiór animacji.
class DLLDARKSTORM2D CSprite : public IResource
{
protected:
AnimationManagerPtr m_Animations;
std::string m_CurrentAnimationName;
AnimationPtr m_CurrentAnimation;
public:
CSprite();
~CSprite();
bool Create(const std::string & CurrentAnimationName,AnimationManagerPtr & Animations);
void Update();
CError& LoadFromFile(const std::string & Filename);
const CError& Reload()
{
// mała atrapa
m_Animations->ReloadAll();
return CError();
}
bool SetAnimation(const std::string & AnimationName)
{
m_CurrentAnimationName = AnimationName;
m_CurrentAnimation = m_Animations->GetResource(AnimationName);
return true;
}
const std::string & GetCurrentAnimationName() const
{
return m_CurrentAnimationName;
}
void Render(float x, float y)
{
m_CurrentAnimation->Render(x,y);
}
};
JAK widać nic nadzwyczajnego, po prostu zbiór animacji. Jedną rzeczą na jaką trzeba zwrócić uwagę jest fakt że nie ma on określonej pozycji i wymiarów(to tylko część wizualna), jest to spowodowane filozofią projektową silnika - pozycja i wymiary będą w wyższej klasie grupującej tą i obiektu fizycznego, zdradzę może jej nazwę: CActor.
Może taka mała uwaga odnośnie nazewnictwa klas mojego projektu, a dokładniej przedrostków w nazwach:
1. C - od klasy "normalnej"
2. I - od interface, czyli klasa interfejsu(wirtualna)
3. S - od Singleton
4. może jeszcze FO od factory objects fabryka obiektów(o tym wspomnę w najbliższym poście).
Dokumentacja źródłem sukcesów w życiu ...
Dokumentacja jest tak jak w nagłówku źródłem sukcesów. Jest wręcz nie zastąpiona jako pomoc w rozumieniu kodu(choć są wyjątki od tej reguły). Dokumentacja pozwala zrozumieć biblioteki i różne inne projekty(samodzielnie). Czasami jest to dalekie od ideałów, gdy jest chaotyczna, niekompletna, pisana trudnym językiem, itd.. Faktem jest, że jej brak nie jest zbyt korzystny, ani dla twórcy(twórców) projektu, ani potencjalnego użytkownika(można wtedy konsultować się z autorem i dowiadywać się wszystkiego(oczywiście takie rozwiązanie przy dużej liczbie użytkowników, jest bardzo frustrujące dla wszystkich)). Wracając do tematu, czym jest właściwie dokumentacja kodu projektu? Otóż to wszelkie informacje o projekcie, opis kodu, itd.. Prostym sposobem dokumentowania są, uwaga: komentarze:) - to dzięki nim możliwa jest analiza kodu do którego powróciło się po kilku miesiącach. Lepszą formą opisu kodu w większych projektach są generatory dokumentacji, które za pomocą usystematyzowanych komentarzy jak sama nazwa wskazuje generują nam gotową dokumentację kodu w przejrzystej strony html lub innej przyjemnej dla oka formie. Godnym polecenia jest tutaj: Doxygen - darmowy, obsługuje wiele języków, posiada program(Doxywizard), który prowadzi nas przez proces tworzenia dokumentacji, posiada graficzny interfejs. Mały tutek jest na tej stronie: http://wierzba.miks.uj.edu.pl/~gurgul/doxygen/
I teraz zdanie podsumowujące: Dokumentacja jest bardzo ważnym elementem, który wpływa na wiele innych czynników, związanych mniej lub bardziej z projektem(np. popularności, która przy mało przejrzystej dokumentacji będzie prawdopodobnie bardzo niska).
Proszę o uwagi , opinie związane z tematem dokumentacji. Chętnie dowiem się jak sprawa stoi u innych.
I teraz zdanie podsumowujące: Dokumentacja jest bardzo ważnym elementem, który wpływa na wiele innych czynników, związanych mniej lub bardziej z projektem(np. popularności, która przy mało przejrzystej dokumentacji będzie prawdopodobnie bardzo niska).
Proszę o uwagi , opinie związane z tematem dokumentacji. Chętnie dowiem się jak sprawa stoi u innych.
poniedziałek, 11 października 2010
GUI - koncepcja odbioru zdarzeń myszki
Wczoraj trochę(nawet więcej) poszedłem myślami do przodu, a mianowicie do projektowania GUI(graficznego interfejsu użytkownika). Na początek rozważałem zdarzenia myszki i żeby optymalnie je obsługiwać wymyśliłem to:
- jeśli byśmy sprawdzali kolizje z myszką na każdej kontrolce, to zajęłoby to dużo czasu(wyobraź sobie z 100 kontrolek ), a przecież nie musimy sprawdzać wszystkich. Można, więc wykorzystać drzewo czwórkowe, które posłuży do eliminacji kontrolek, których i tak zdarzenie nie będzie dotyczyć. Zanim omówię, jak wykorzystać to w praktyce, trzeba wyjaśnić czym jest to drzewo, otóż wyobraźmy sobie kwadratową(dla uproszczenia)kartkę papieru, teraz dzielimy ją na cztery równe części:
Proszę nic nie sugerować, kolory nie są tak istotne :)
Teraz każdą z tych części dzielimy na cztery równe:
Możemy dalej dzielić te komórki, aż dojdziemy do pojedynczych pikseli,które z reguły są nie podzielne:). Do GUI możemy pozostać na tym poziomie podziału. Teraz skoro już wiemy jak wygląda takie drzewo możemy przejść dalej:
- pierwszy poziom podziału to cztery(a jaka inna liczba powinna być w drzewie czwórkowym??) komórki, możemy, więc stworzyć tablicę Tab1[4][4] - jej typem będzie lista kontrolek które będą znajdowały się w danej komórce. My sprawdzamy hit testem w której komórce jest kursor myszy(najpierw na pierwszym poziomie, potem na drugim, te dane przekazujemy do tabeli i przechodzimy po liście(sprawdzamy kolizje)). Oczywiście tą tabelę musimy wygenerować przed wykorzystaniem. Takie rozwiązanie problemu z myszką powinno zaowocować wydajną pracą GUI(nie musimy sprawdzać wszystkich kontrolek, jeśli jest to nie potrzebne).
Jeśli coś byłoby nie jasne to śmiało można pisać komentarze. A może ktoś rozwiązałby ten problem inaczej. Proszę o opinie na temat tego rozwiązania.
Subskrybuj:
Posty (Atom)