Projektowanie kompletnego systemu AI w praktyce Część I


Warsztat - Programowanie gier komputerowych :: Projektowanie kompletnego systemu AI w praktyce: Część I







Strona główna Forum Szukaj Lista użytkowników
Grupy
Zarejestruj Zaloguj

Artykuły
Kliknij na kategorię żeby dodać artykuł Szukaj
Programowanie gier » Artykuły » Sztuczna Inteligencja
[Wersja do drukowania]
Projektowanie kompletnego systemu AI w praktyce: Część
I
Opis Jak budować sztuczną inteligencję dia gier RTS'o
podobnych.
Autor Geoff Howland (tlumaczyl: ryBens) Data Sob 09 Paź,
2004 2:04 am Typ *
Słowa klucze
Kategoria Sztuczna Inteligencja
Odsłony 602


Projektowanie kompletnego systemu AI w praktyce: Część I
Jak budować sztuczną inteligencję dia gier RTS'o
podobnych.

Przez długi czas Sztuczna Inteligencja (AI) w
projektowaniu gier, była uważana za mało ważną i
spychana na drugi plan. W końcu musiało się to zmienić.
Już teraz zaczyna być widoczny nowy trend, stawiający na
gry z bardzo rozbudowanym i szczegółowym systemem AI.
Jeśli więc AI twojej gry nie sprosta nowym wymaganiom
graczy, twoja gra bardzo na tym ucierpi i szybko
zostanie uznana za przestarzałą.

AI w grach to nie tylko sieci neuronowe, systemy uczące
się czy skomplikowane matematyczne zależności.
Najważniejszą rolą AI w grze jest stworzenie pozorów
myślenia czyli inteligentnie wyglądających zachowań.

Kluczem do stworzenia kompletnego systemu AI, jest
zdefiniowanie jak ma wyglądać końcowy rezultat i budować
system kierując się tymi wytycznymi. Wszystko sprowadza
się do tego co gracz może zobaczyć. Jeśli element
systemu nie daje widocznych rezultatów, to system będzie
działał dobrze bez niego.

Przytoczone poniżej rozważania i przykłady powstały w
oparciu o gry typu RTS, jednakże część pomysłów może być
z powodzeniem zaadoptowana do większości typów gier.
Przykładowe struktury danych zostały napisane w formacie
C.

Mechanizm Stanów (State Machine)

Mechnizm Stanów Skończonych (Finite State Machine - FSM)


Mechnizm stanów skończonych (FSM) jest to system
posadający ograniczoną liczbę stanów danej operacji.
Przykładem z naszego świata mógłby być przycisk do
włączania światła, który ma 2 stany włączony lub
wyłączony, albo zegar z budzikiem, który może mieć 4
stany: odliczanie czasu, dzwonienie budzika, ustawianie
budzika, ustawianie czasu. Każdy obiekt, który posiada
ograniczoną liczbę możliwości, z których każda da się
opisać przy pomocy jednego stanu (lub ich kombinacji),
można przedstawić w postaci FSM.

FSM są naturalną częścią każdego programu komputerowego.
Zrozumienie jak efektywnie ich używać w tworzeniu
systemu AI dla gier, jest tak samo trudne jak
zrozumienie systemu, który chcemy stworzyć. Wszystko
zależy od tego jak bardzo szczegółowe ma być AI.


Jak używać FSM

Wśród wielu możliwości użycia FSM w grach, jedną z
najtrudniejszych jest zaprojektowanie modelu zachowania
obiektów, a głównie zasymulowanie ludzkich zachowań.
Przykładem tego może być wiele bardzo szczegółowych i
rozbudowanych systemów AI, które nie sprawdziły się w
praktyce i zostały uznane przez graczy za pomyłkę.

Mimo iż istnieją systemy zaprojektowane by dokładniej
odzwierciedlić sposób zdobywania wiedzy i myślenie
człowieka, trzeba pamiętać, ucząc się o sztucznej
inteligencji i systemach uczących się, że niekiedy
najlepszym rozwiązaniem jest najprostsze a nie bardziej
naukowe.

Nie zrozumcie tego jako opozycji wobec Sieci
Neuronowych, Algorytmów Genetycznych czy innych systemów
sztucznej inteligencji, po prostu nie wybierajcie
ciekawszych algorytmów, uważając, że są lepszym
rozwiązaniem jeśli nie dadzą lepszych rezultatów. Swój
wybór oprzyjcie na tym co jest wam potrzebne by uzyskać
zaplanowany efekt, a nie na najnowszych trendach.

Mechanizmy Stanów w grach

Tworzenie wiarygodnego środowiska dla swojej gry,
oznacza rozważenie jak wiele szczegółowych elementów
może przyciągnąć uwagę gracza tak jak twoją. Im więcej
tych, które podczas gry i testowania wydały Ci się
nieciekawe, tym bardziej nudne bedzie śrdowisko gry dla
gracza je poznającego.

By twoja gra mogła działać, będziesz potrzebował
przynajmniej dwóch mechnizmów stanów. Pierwszy będzie
obsługiwał interfejs gry, czyli czy gra jest zatrzymana;
czy są jakieś inne tryby gry, które gracz może
uaktywnić; jakie rzeczy gracz widzi lub nie; oraz
wszystkie pozostałe flagi, które mogą być potrzebne w
konkretnym interfejsie.

Drugi mechnizm stanów będzie obsługiwał co aktualnie
dzieje się w trakcie gry: obecny stan środowiska;
zadania, które gracz zdołał wypełnić lub nie; i
wszystkie pozostałe zmienne potrzebne by prowadzić i
wyzywać gracza.

Możesz także posiadać system alarmowy, w którym
przeciwnik by stale kontrolował, czy gracz nie został
wykryty lub czy nie został oddany strzał albo flagi
określające czy konkretne, ważne miejsca zostały
zniszczone lub nie. Wszystkie te rzeczy można
przedstawić przy pomocy struktury podobnej do tej:


struct GameLevelState {

int alert; // Stan gotowości wśród przeciwników //
struct Position shot; // Miejsce oddania ostatniego
strzału //
int shotTime; // Cykl gry, w którym padł ostatni
strzał //
int hostage; // Zakładnicy odbici //
int explosives; // Ładunek wybuchowy uruchomiony lub
nie //
int tank; // Czołg zniszczony lub nie //
int dialogue; // Zmienna dialogów //
int complete; // Misja ukończona //

};


Elastyczność

Utrzymanie elastyczności twojego systemu AI jest bardzo
ważne. Im bardziej modułowo będzie on zbudowany, tym
większa będzie twoja swoboda w wyborze odpowiednich
rozwiązań. Ważne jest zrozumienie, że projektowanie AI
dla gry jest w ogromnej części bardzo interaktywnym
procesem, musisz stale wybróbowywać rozwiązania w czasie
pracy na nimi.

Akcje jednostek

W grze gdzie gracz kontroluje jednostki, jest bardzo
ważne by posiadać całą potrzebną i dobrze zorganizowaną
wiedzę o nich. Bez tego, przystosowanie jednostek do
gracza będzie trudniejsze na czym może ucierpieć
interfejs użytkownika. Jeśli gracz nie czuje, że posiada
kontrolę nad oddziałami, nie otrzymuje od nich
odpowiedniej informacji, wtedy pozostaje mu tylko
klikanie po całym interfejcie. Oznacza to, że gracz nie
będzie czerpał satysfakcji z naszej gry i szybko może
się nią znurzyć.

By rozjaśnić do jakich rodzajów imformacji możesz chcieć
zapewnić graczowi dostęp, przyjrzyj się przykładowej
strukturze.


struct Character {

struct Position pos; // Pozycja na mapie //
int screenX, screenY; // Pozycja na ekranie //
int animDir, animAction, animNum; // Informacja o
animacji, akcji i numerze klatki animacji //
int rank; // Ranga //
int health; // Zdrowie //
int num; // Numer jednostki //
int group; // Numer grupy //
int style; // Rodzaj jednostki (człowiek, elf) //
struct AnimationObject animObj; // Obiekt dla
bardziej złożonych animacji//

};


Krótkie definicje zmiennych:

Zmienna pos przechowuje pozycje jednostki w świecie gry,
a screenX, screenY są przydatne do prostego dodania na
ekranie informacji dookoła jednostki, takiej jak zdrowie
czy zaznaczenie.

Wartości animDir, animAction and animNum odpowiadają
aktualnemu stanowi animacji jednostki, potrzebych do jej
narysowania.

Zmienne rank i health nie wymagaja wiekszych wyjasnień
poza tym, że są bardzo uproszczone.

Zmienna num przechowuje numer jednostki w głównej
tablicy jednostek.

Wartość group określa do jakiej grupy należy jednostka.
Oddziały powinny przynależeć do grup prawie cały czas
wyłączając tylko moment kiedy jednostka jest martwa.

Zmienne style i animObj podają więcej informacji jak
obiekt powinien zostać narysowany.

Budowanie na solidnych podstawach

Kiedy już podstawowe założenia systemu działają na
przykładzie prostych oddziałow jak opisany powyżej,
przyszedł czas na wbudowanie dodatkowych danych, by
jednostki naprawdę ożyły.

Musisz się zastanoowić jakie akcje i reakcje chcesz by
jednostki posiadały. Czy chcesz by były kontrolowane
przez emocje? Czy chcesz by miały możliwość ucieczki,
atakowania jak szaleniec, szarży?

Jeśli już to zrobiłeś, dodanie kilku zmiennych
opisujących stany emocjonalne może być następnym
krokiem. Najlepszym sposobem na zrozumienie jakie
elementy będą potrzebne twoim jednostkom, jest
zrozumienie samego siebie i odpowiedzenie na pytanie jak
Ty byś sobie poradził w sytuacji w jakiej one są. By
stworzyć zachowania wyglądające na ludzkie, musisz
opierać się na rzeczywistych zachowaniach ludzi.

Jest też inna możliwość, prawie całkowicie przeciwna
systemowi opartemu na ludzkich reakcjach, której
podstawowym założeniem jest sztuczne doświadczenie, nie
bazujące na rzeczywistości ale stanowiące wyzwanie dla
gracza. W przeciwieństwie tworzenia jednostek opartych
na Twoim instynkcie, będziesz musiał pomyśleć nad każdym
rodzajem reakcji posiadanym przez jednostki. Jeśli nie
będzie to dostatecznie dobrze zrobione sokńczysz z
płytkimi, nudnymi reakcjami, łatwymi do przewidzenia lub
nawet pozornie losowymi. Taka rzecz potrafi zniszczyć
nawet dobrą grę, dlatego włoż w projektowanie sporo
rozmysłu i co najważniejsze, testuj wszystko aż do
upadłego, by mieć pewność, że działa!

Grupowanie

Grupować czy nie grupować?

Jeśli tworzysz grę typu FPS nie będzie wielkim
zaskoczeniem, że grupowanie nie jest dla Ciebie. Jednak
jeśli pracujesz nad grą typu RTS lub inną, w której
gracz ma kontrole nad więcej niż jedną jednostką w tym
samym czasie, musisz sobie zadać to pytanie.

Czy potrzebujesz aby jednostki działały wspólnie w
skoordynowany sposób?

Jeśli odpowiedź brzmi tak, jest duża szansa, że przyda
Ci się grupowanie. Gdy odpowiedzią jest nie, nadal mogą
istnieć pewne korzyści z użycia grupowania, które sam
musisz odkryć w zależności jakie akcje mają podejmować
twoje jednostki.

Zalety grupowania


1. Jednostki mogą poruszać się w formacji poprzez
dostęp do jednej głównej listy z informacjami o ruchu.
Zaletą tego jest, że nie musisz rozprzestrzeniać
informacji do każdej jednostki w grupie, jeśli zmienił
się cel ruchu, ponieważ oddziały pobierają informacje
o swoim ruchu z jednego źródła.
2. Akcje z użyciem wielu oddziałów, takie jak
otaczanie budynków, mogą być kontrolowane centralnie,
w przeciwieństwie do metody gdy każda jednostka
próbuje działać bez relacji z innymi i próbując zająć
pozycje zderza się co chwila z innymi oddziałami.
3. Grupa może posiadać własną strukturę z danymi,
dlatego też wydanie nowych rozkazów zajmuje tyle samo
czasu i pamięci, co wydanie rozkazów pojedyńczej
jednostce. Najważniejsze jest jednak to, że stworzysz
coś co jest łatwe do przeczytania i zrozmienia.
Zmienianie rozkazów na okrągło 25 jednostkom lub
więcej i próbowanie przekazywania im informacji może
być lekko utrudnione, bez wspólnej podstawy.
4. Opierając się na grupach, odnajdywanie i unikanie
przeszkód może być znacznie prostsze a czas
poszukiwania drogi może być znacznie ograniczony,
szczególnie w sytuacji gdy musimy sobie radzić z
bardzo dużą ilością jednostek.


Wielki obraz

Projektowanie grup, tak jak tworzenie całej reszty AI,
polega na zastanowieniu się nad końcowym efektem jaki
chesz osiągnąć. Główną ideą grupowania jest stworzenie
centralnego miejsca informacji, skąd może być szybko
znaleziona i dzielona między jednostkami. Powoduje to
także zysk pamięci, gdyż dane nie są dublowane i
znajdują się w jednym konkretnym miejscu. Ważne jest by
były one logicznie uporządkowane by w czasie
późniejszych prac przy rozbudowie AI nowe elementy z
łatwością wpasowały się w logiczną całość.

Z mojego doświadczenia wynika, że wszystko co ma związek
z ruchem i akcjami, czyli to co próbujemy zorganizować i
scentralizować, powinno znaleźć się w strukturze danych
grupy a pozostałe infomacje dotyczące poszczególnych
oddziałów w strukturze danych jednostki.

Oznacza to, że jednostka samotnie nie będzie posiadała
informacji dokąd zmierza lub co aktualnie robi, poza
danymi taki jak pozycja w świecie gry czy klatka
animacji. Powoduje to, że oddział musi ZAWSZE
przynależeć do jakiejś grupy, dopóki ma możliwość
poruszania się lub wykonywania akcji. Jeśli jednostka
jest samotna to tworzy po prostu jednoosobową grupę.

Jeden z wielu

W poszukiwaniu sprawnego skoordynowanego systemu
działania grupy, trzeba pamiętać, że nasza grupa
zbudowana jest z pojedyńczych elementów, które mogą
działać indywidualnie. Dlatego powinna istnieć możliwość
śledzenia z osobna co każda jednostka robi, by móc
rozbić grupę na mniejsze części, mające podobne lub
różne cele. Do tego celu stworzyłem strukturę danych:


struct GroupUnit {

int unitNum; // Numer jednostki //
struct Unit *unit; // Dane jednostki //
struct Position waypoint[50]; // Droga w postaci
punktów kontrolnych //
int action[50]; // Akcje na punktach kontrolnych //
int stepX, stepY; // Krok o jaki jednostkę przesuwamy
na mapie//
int run, walk, sneak, fire, hurt, sprint, crawl; //
Akcje //
int target; // Cel jednostki //
struct Position targetPos; // Pozycja celu //

};


Wyjaśnienie zmiennych:

unitNum to numer jednostki w gupie. Jeśli maksymalna
lilość jednostek w grupie to 10, pierwsza będzie miała
unitNum równy 0, a ostatnia unitNum = 9.

Zmienna unit jest wskaźnikiem do struktury
przechowującej informacje o jednostce, takie jak:
aktualna pozycja, zdrowie i każdy inny rodzaj
indywidualnej informacji. Jest ważne by zdrowie
jednostki mogło być monitorowane z poziomu grupy, byś w
prosty sposób mógł sprawdzić czy jednostka jest ranna i
przekazać to pozostałym członkom grupy, lub podjąć inne
czynnośći.

Tablica waypoint przechowuje pozycje kolejnych miejsc,
do których jednostka musi dojść. Wszystkie akcje i
punkty kontrolne są przechowywane w strukturze GroupUnit
tylko gdy grupa nie działa jak formacja i każda
jednostka musi poruszać się samodzielnie.

Tablica action zawiera informacje o akcjach związanych z
ruchem do określonego punktu kontrolnego. Pozwala to na
stworzenie bardziej szczegółowych łańcuchów komend np.:
każąc jednostce skradać się przez część obszaru,
następnie szybkim sprintem przebyć kolejny odcinek. Daje
to graczowi możliwość tworzenia bardziej przemyślanych i
strategicznych posunięć.

Zmienne stepX i stepY mogą być użyte dla przyspieszenia
działania systemu. W każdej klatce przesuwamy jednostke
o podany krok na mapie świata. Użyte poprawnie zmienne,
mogą być dostosowane do każdej sytuacji tworząc prosty,
szybki i łatwy do zaimplementowania system.

Zmienne run, walk, sneak... są powiązane z różnymi
stanami w jakich znajduje się jednostka. Nie są to
informacje o animacji ale stany akcji, które mogą być
łatwo włączane i powodować różne efekty gdy więcej niż
jedna jest włączona.

Zmienne target i targetPos są używane do przechowania id
jednostki wroga i jego aktualnej pozycji. Pozycja wroga
tak samo jak jego zdrowie i inne cechy, mogą być po
prostu otrzymane na podstawie numeru jednostki. Dla
czytelności kodu zdecydowałem się by trzymać kopię
pozycji wroga w strukturze.

Psychika tłumu

Naszym ostatecznym celem jest scentralizowanie jak
największej ilości informacji i utrzymanie jak
największej prostoty systemu. Spójrzmy chwilę na
przykładową strukturę danych.


struct Group {

int numUnits; // Ilość jednostek w grupie //
struct GroupUnit unit[4]; // Informacje o jednostkach
//
int formation; // Informacje o rodzaju formacji grupy
//
struct Position destPos; // Miejsce przeznaczenia //

int destPX, destPY; // Pozycja na ekranie miejsca
przeznaczenia //
struct Position wayX[50]; // Ścieżka w postaci
punktów kontrolnych //
float formStepX, formStepY; // Wartość kroku formacji
w grupowym ruchu //
int formed; // Czy grupa porusza się w formacji //
int action, plan; // Akcje i zadania grupy //
int run, walk, sneak, sprint, crawl, sniper; // Akcje
//
struct Position spotPos; // Pozycja celu snajpera //
int strategyMode; // Rodzaj strategii grupy //
int orders[5]; // Rozkazy dla grupy //
int goals[5]; // Cele grupy //
int leader; // Przywódca grupy //
struct SentryInfo sentry; // Lista posterunków //
struct AIState aiState; // Stan AI //

};


Zmienna numUnits oznacza liczbę jednostek w grupie, a
tablica unit przechowuje informacje GroupUnit. Dla tej
konkretnej grupy liczba jednostek została ograniczona w
kodzie do 4.

Flaga formation decyduje w jakim rodzaju formacji
znajduje się grupa. Oddziały mogą być sformowane w
kolumnę, klin, romb w bardzo prosty sposób poprzez
zmianę tej zmiennej i pozwolenie jednostkom dostosować
się do nowej formacji.

Zmienne destPos oraz destPX,destPY pozwalają kontrolować
drogę do końcowego celu grupy i szybko przekazać te
informacje graczowi. Punkty kontrolne i kroki działają
tak jak w przypadku pojedyńczej jednostki, tyle że
oddziały w formacji mają tę samą prędkość, przez co
trzymają szyk. Nie ma więc potrzeby liczenia kroków i
punktów kontrolnych dla każdego oddziału odzielnie gdy
grupa działa jak formacja.

Zmienna formed jest jedną z ważniejszych, gdyż decyduje
o tym czy oddziały działają jak formacja, czy
indywidualnie. Jeśli grupa porusza się w formacji na
wszystkich jednostkach w każdym cyklu wykonywana jest ta
sama operacja. Jeśli istnieje powód, że oddziały nie
mogą poruszać sie w ten sam sposób np.: wrogowie atakują
lub trzeba ominąć przeszkodę, jednostki muszą poruszać
się na własną rękę.

Akcje są identyczne jak w przypadku indywidualnych
jednostek. Zauważ też, że w strukturze Group istnieje
zmienna sniper, której nie ma w GroupUnit. Powdem jest
brak sensu tworzenia grupy, w której jedna jednostka
jest snajperem, a reszta biega dookoła. Logiczne jest
żeby wyodrębnić tą jednostkę do własnej grupy i
kontrolować jej działania na poziomie grupy. To jest
właśnie sposób planowania, który musisz opanować i
zdecydować jaka informacja pasuję do konkretnej
struktury.

Zmienna strategyMode pozwala szybko stwierdzić jak
jednostki reagują na oddziały przeciwnika. Czy to będzie
tryb agresywny, obronny, ucieczka? Posiadanie szybkiego
dostępu do rodzaju reakcji jest dobrym sposobem na
zmniejszenie ilości indywidualnych kalkulacji wśród
jednostek. Pozwala to też graczowi kontrolować
zachowania poszczególnych grup ustawiając dla nich różne
rodzaje reakcji na wroga.

Tablice orders i goals wskazują na rozkazy i cele w
umieszczone w jakiejś bazie informacji.

Zmienne sentry i aiState przechowują infomacje do
własnego użytku o miejscach postoju i dodatkowe dane do
stworzenia bardziej szczegółowych wzorców zachowań.

Łączenie wszystkiego razem

Jaki będzie następny krok, gdy już posiadamy kilka
struktur opisujących grupy? Kolejnym etapem będzie
znalezienie sposobu użycia tych informacji w grze.

Decydującą sprawą jest staranne zaplanowanie działania
AI, by było elastyczne i zbudowane modułowo, przez co
późniejsze modyfikacje będą znacznie prostsze. Sposobem
na to są: dobrze zorganizowane struktury danych i
funkcje na nich operujące, które wykonują ściśle
określone zadania na ściśle określonych rodzajach
danych. Jeśli chcemy wykonać ponownie jakieś zadanie,
wywołujemy przetestowane i działające na określonych
częściach danych funkcje. Później gdy trafisz na problem
z twoim AI, nie będziesz musiał polować na błąd po całym
kodzie systemu.

Tips

Ucz się podstaw, pracuj na podstawach, dodawaj bardziej
skomplikowane rozwiązania gdy ich naprawdę potrzebujesz.
Nie używaj danej metody tylko dlatego, że jest ona
popularna i wszyscy dookoła jej używają. Ludzie
posługują się nimi gdyż odpowiadają one ich potrzebom
ale nie koniecznie mogą odpowiadać twoim. Czasem metoda
jest używana tylko dlatego, że to standart chociaż może
nie być najlepszym rozwiązaniem.

Twoim celem powinno być zawsze osiągnięcie najlepszych
rezultatów, a nie używanie modnych rozwiązań. Jeśli
metoda działa, użyj jej. Mottem twórców gier powinno być
zdanie: "Jeśli coś wygląda dobrze, to jest dobre".

Faktem jest, że nigdy nie zbudujesz idealnej repliki
rzeczywistości. Dlatego musisz budować swoją własną
wystarczająco dobrą rzeczywistość.


Administrator praw autorskich napisał:Oryginalny tekst
pochodzi z www.lupinegames.com
Tytuł oryginału: Practical Guide to Building a Complete
Game AI: Volume I
Autor: Geoff Howland
Tłumaczenie: ryBens


Skocz do: Wybierz forumWarsztat - Programowanie
gier komputerowych|--Szkółka| |--Szkółka -
języki| |--Szkółka - grafika| |--Szkółka -
inne|--Programowanie gier| |--Ogólnie|
|--Dźwięk| |--Sztuczna Inteligencja|
|--Inne|--Programowanie grafiki|
|--Programowanie grafiki| |--OpenGL|
|--DirectX|--Produkcja| |--Pomysły|
|--Projektowanie| |--Projekty| |--Grafika|
|--Ogłoszenia|--O czym innym| |--Konferencje,
spotkania| |--Warsztat| |--Aktualności|
|--Artykuły| |--Wykłady| |--Compo|
|--Lepperlandia|--Śmietnik| |--Z odrzutu



Powered by Knowledge Base, wGEric (C) 2002 PHPBB.com MOD
This script (Knowledge Base - MX Addon v. 1.03e) is modified
by Haplo





W1.5b (C) 2004
[admin: ayufan, g[R]eK, Goliatus, mikael_, Regedit]
Wszystkie czasy w strefie CET (Europa)

Powered by phpBB2 Plus 1.52 based on phpBB 2.0.10 © 2001, 2002 phpBB
Group :: FI Theme :: Mody i Podziękowania












Wyszukiwarka

Podobne podstrony:
Projektowanie kompletnego systemu AI w praktyce Część II
Adamczewski Zintegrowane systemy informatyczne w praktyce Początek, Spis treści
Adamczewski Zintegrowane systemy informatyczne w praktyce  System CRM tendencje rozwojowe syste
Adamczewski Zintegrowane systemy informatyczne w praktyce  Spis rysunków
Adamczewski Zintegrowane systemy informatyczne w praktyce  Scenariusze realizacji ZSI
Adamczewski Zintegrowane systemy informatyczne w praktyce  Organizacja prac wdrożeniowych ZSI
Podstawowe zasady tworzenia projektu dla STM32F4 w środowisku uVision 4 czesc I
Adamczewski Zintegrowane systemy informatyczne w praktyce  Ewolucja systemów informatycznych zarz
Adamczewski Zintegrowane systemy informatyczne w praktyce  Rady praktyczne
Adamczewski Zintegrowane systemy informatyczne w praktyce  Realizacja ZSI na tle cyklu życia syst
Podstawowe zasady tworzenia projektu dla STM32F4 w środowisku uVision 4 czesc II
Adamczewski Zintegrowane systemy informatyczne w praktyce  Procedura wyboru gotowego ZSI
Adamczewski Zintegrowane systemy informatyczne w praktyce  Zakres i struktura zintegrowanego syst
Adamczewski Zintegrowane systemy informatyczne w praktyce  Zestawienie skrótów

więcej podobnych podstron