Obiekty graficzne na przykładzie prostej gry- animacja poklatkowa
Animacja poklatkowa polega na wyświetlaniu kolejnych statycznych gotowych obrazów (klatek animacji) sprawiających wrażenie ruchu. W tej części stworzymy model animacji poklatkowej eksplozji pocisku. Rozwiązanie umieścimy w osobnej klasie o nazwie Eksplozja.
Do tej części bedziemy potrzebować kodu z poprzedniej części (pobierz pełny kod z poprzeniej cześci)
Klatki animacji wybuchu
Kolejne obrazy wybuchu umieścimy w już istniejących zasobach graficznych. Dla ułatwienia i ujednolicenia kodowania klatki animacji będą mieć ten sam rozmiar co pozostałe, czyli 48 x 48 pikseli
Mój zasób graficzny wygląda jak poniżej
Indeksy klatek animacji wybuchu to 24,25? 30. Pokazuje to poniższa ilustracja
Te indeksy uwzględnimy w tablicy klatek animacji tworzonej klasy Eksplozja
Klasa Eksplozja
W projekcie inicjujemy klasę Eksplozja
Obsługę grafiki zrobimy na tej samej zasadzie co obsługę grafiki czołgu w klasie Czolg. Indeksy kolejnych klatek przechowamy tablicy jednowymiarowej. Wstępna zawartość pliku tworzonej klasy ma postać jak poniżej
Wskazówka:
namespace czolg_1
{
internal class Eksplozja
{
int[] klatki = {24,25,26,27,28,29,30};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
}
}
Konstruktor klasy Eksplozja
Konstruktor tworzonej klasy Eksplozja będzie bardzo prosty. Do konstruktora przekażemy współrzędne wybuchu oraz rozmiar klatki animacji.
Kod konstruktora
Wskazówka:
namespace czolg_1
{
internal class Eksplozja
{
int[] klatki = {24,25,26,27,28,29,30};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
//konstruktor
public Eksplozja(float _x,float _y, int _wys, int _szer)
{
wys = _wys;
szer = _szer;
//zapamietaj współrzędne wybuchu
x = _x;
y = _y;
}
}
}
Funkcja rysująca klatkę wybuchu
Rysowanie wybranej klatki wybuchu zrobimy tak samo jak rysowanie klatki czołgu. Możemy skopiować odpowiedni fragment kodu z klasy Czolg. Dodamy jedynie argument indeksu zmienianej klatki animacji
Wskazówka:
public void Rysuj(Graphics g, List<Bitmap> bmp, int id)
{
g.DrawImage(bmp[klatki[id]],
new Rectangle((int)x - szer / 2, (int)y - wys / 2, szer, wys),
new Rectangle(0, 0, szer, wys),
GraphicsUnit.Pixel);
}
Test eksplozji
Docelowo eksplozja powinna pojawić się w grze przy trafieniu pociskiem w cel. Na tym etapie tworzenia naszej prostej gry 2D sprawdzimy testowo jak jest inicjowana w grze animacja wybuchu. Eksplozje będziemy wywoływać przez wciśnięcie klawisza t. W tym celu w głównym kodzie utworzymy funkcje o nazwie TestEksplozji
Przyjęty model rysowania świata jest podobny do warstw, pomimo ze wykorzystywana jest jedna warstwa. Efekt warstw uzyskamy kolejnością rysowanych obiektów. W pierwszej kolejności rysowane jest tło, potem obiekty graczy, pociski, a na końcu eksplozje.
Eksplozji może być w jednym czasie kilka i trzeba je wszystkie obsłużyć. W tym celu użyjemy listy, która jest najwygodniejszym rozwiązaniem ze względu na jej elastyczność rozmiaru. W klasie Swiat dodajemy listę oraz funkcję, która obsłuży rysowanie eksplozji
Wskazówka:
internal class Swiat
{
static int ileKlatekX = 20, ileKlatekY = 15;
int[,] plansza=new int[ileKlatekY,ileKlatekX];
public List<Eksplozja> listaEksplozji = new List<Eksplozja>();
public int IleKlatekX
{ //zwróc ilośc kolumn
Funkcja przeglądająca listę aktywnych eksplozji pod względem rysowania ma postać
Wskazówka:
public void RysujWszystkieEksplozje(Graphics g,List<Bitmap> bmp)
{
foreach (var e in listaEksplozji)
{
e.Rysuj(g, bmp, 0);
}
}
Wywołanie rysowania eksplozji wykonujemy w klasie bitmapy na końcu wszystkich rysowań. Przechodzimy do pliku bitmapy.cs i wprowadzamy zmiany w funkcji RysujSwiatGryBufor
Wskazówka:
private void RysujSwiatGryBufor(Swiat swiat,Czolg czolgA,Czolg czolgB)
{
swiat.RysujSwiat(gEkranGry, bitmaps,W,H);
//na teraz testowe rysowania czolgu graczaA
czolgA.Rysuj(gEkranGry, bitmaps);
//na teraz testowe rysowania czolgu graczaB
czolgB.Rysuj(gEkranGry, bitmaps);
//rysuj eksplozje na koncu, tak jak na ostatniej warstwie
//która przykrywa wszystkie obiekty graficzne
swiat.RysujWszystkieEksplozje(gEkranGry, bitmaps);
}
Testowanie eksplozji wykonamy w głównej klasie gry, przechodzimy do pliku Form1.cs i dodajemy poniższy kod
Wskazówka:
private void TestEksplozji()
{
int x, y;//tymczasowe wspołrzedne testowych eksplozji
Random los= new Random();
x = los.Next(48, this.Width - 48);
y = los.Next(48, this.Height - 48);
swiat.listaEksplozji.Add(new Eksplozja(x,y,bmp.H,bmp.W));
}
Testowanie eksplozji wykonamy przez wciśnięcie klawisza t. Przechodzimy do funkcji Form1_KeyDown i dopisujemy ostatni linijki tego kodu
Wskazówka:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//klawiszologia
//dla gracza A
if (e.KeyCode == Keys.A) czolgA.Obracaj(-1);
if (e.KeyCode == Keys.D) czolgA.Obracaj(1);
if (e.KeyCode == Keys.W)
{
czolgA.fRuch = true;
czolgA.v= czolgA.Vmax;
}
if (e.KeyCode == Keys.S)
{
czolgA.fRuch = true;
czolgA.v = -czolgA.Vmax;
}
//dla gracza B
if (e.KeyCode == Keys.Left) czolgB.Obracaj(-1);
if (e.KeyCode == Keys.Right) czolgB.Obracaj(1);
if (e.KeyCode == Keys.Up)
{
czolgB.fRuch = true;
czolgB.v = czolgB.Vmax;
}
if (e.KeyCode == Keys.Down)
{
czolgB.fRuch = true;
czolgB.v = -czolgB.Vmax;
}
//testowe eksplozje
if (e.KeyCode == Keys.T)
{
TestEksplozji();
}
}
Teraz skompiluj program i sprawdź efekt działania. Prawidłowo wykonane czynności prowadzą do uzyskania losowo wywołanych eksplozji. Na tą chwilę będzie to pierwsza klatka wybuchu
Animacja eksplozji
Aby animować eksplozję musimy obsłużyć iterację klatek animacji po każdym cyklu przebiegu zegara gry. Dodatkowo trzeba pamiętać, że gdy licznik klatek przekroczy górną granicę należy zniszczyć bieżący obiekt eksplozji.
Modyfikujemy klasę Eksplozja. W pliku Eksplozja.cs wprowadzamy te zmiany
Wskazówka:
internal class Eksplozja
{
int[] klatki = {24,25,26,27,28,29,30};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
public int idKlatka = 0;
public bool fZniszcz = false;
Dopisujemy funkcję licznika klatek
Wskazówka:
public void LicznikKlatek()
{
idKlatka++;
if (idKlatka > 6)
{
idKlatka = 0;
fZniszcz = true;
}
}
Przechodzimy do pliku Swiat.cs i modyfikujemy funkcję odpowiedzialna za rysowani eksplozji
Wskazówka:
public void RysujWszystkieEksplozje(Graphics g,List<Bitmap> bmp)
{
foreach (var e in listaEksplozji)
{
e.Rysuj(g, bmp, e.idKlatka);
e.LicznikKlatek();
}
}
Skompiluj program i sprawdź efekt działania. Teraz po każdorazowym wciśnięciu klawisza t pojawia się nowa eksplozja, która cyklicznie zmienia klatki animacji ale nigdy się nie kończy
Zakończenie eksplozji
Czas życia eksplozji trwa do momentu narysowania ostatniej klatki. W tym przykładzie klatek jest 7. Licząc od indeksu 0, koniec będzie gdy licznik osiągnie wartość większą niż 6. Do klasy Eksplozja dodajemy zmienną logiczna o nazwie fZniszcz
Wskazówka:
internal class Eksplozja
{
int[] klatki = {24,25,26,27,28,29,30};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
public int idKlatka = 0;
public bool fZniszcz = false;
Modyfikujemy również funkcję LicznikKlatek
Wskazówka:
public void LicznikKlatek()
{
idKlatka++;
if (idKlatka > 6)
{
idKlatka = 0;
fZniszcz = true;
}
}
Przeglądanie listy eksplozji w celu wyszukania tych eksplozji, które zakończyły animację wymaga zmodyfikowania funkcji RysujWszystkieEksplozje zapisanej w klasie Swiat. Przechodzimy do pliku Swiat.cs i wprowadzamy modyfikacje wspomnianej funkcji
Wskazówka:
public void RysujWszystkieEksplozje(Graphics g,List<Bitmap> bmp)
{
foreach (var e in listaEksplozji)
{
e.Rysuj(g, bmp, e.idKlatka);
e.LicznikKlatek();
}
//przeglądnij listę i usun te które zakończyły animację
for(int i = 0; i < listaEksplozji.Count; i++)
if(listaEksplozji[i].fZniszcz)listaEksplozji.RemoveAt(i);
}
Teraz możemy skompilować i uruchomić nasz program. Prawidłowo działająca aplikacja po wciśnięciu klawisza t będzie tworzyć w losowym miejscu wybuch, który będzie usuwany po skończeniu animacji
Spowalniamy animację eksplozji
Animacja wybuchu działa dość szybko. Wywołanie poszczególnych klatek możemy spowolnić wprowadzając licznik opóźnień. Wartość licznika będzie się zwiększać przy każdorazowym obiegu zegara gry, i gdy osiągnie ustaloną wartość to zwiększy klatkę animacji, a sam się wyzeruje. Górną granice licznika opóźnień należy dobrać do własnych wrażeń wzrokowych i mocy używanego komputera. Ja w kodzie programu granicę ustaliłem równą 5.
Wprowadzamy zmiany w pliku Eksplozja.cs
Wskazówka:
internal class Eksplozja
{
int[] klatki = {24,25,26,27,28,29,30};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
public int idKlatka = 0;
public bool fZniszcz = false;
//opóźnienie
private const byte GRANICA_OPOZNIENIE = 5;
private byte licznikOpoznienia = 0;
Modyfikujemy funkcję licznika klatek animacji eksplozji
Wskazówka:
public void LicznikKlatek()
{
licznikOpoznienia++;
if (licznikOpoznienia > GRANICA_OPOZNIENIE)
{
idKlatka++;
licznikOpoznienia = 0;
}
if (idKlatka > 6)
{
idKlatka = 0;
fZniszcz = true;
}
}
Skompiluj program i sprawdź efekt działania. Prawidłowo działający program po każdorazowym wciśnięciu klawisza t wywoła eksplozje animowaną dużo wolniej niż poprzednio
W tej części to tyle. Poniżej pełne kody poszczególnych klas
Zawartośc pliku Eksplozja.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace czolg_1
{
internal class Eksplozja
{
int[] klatki = {24,25,26,27,28,29,30};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
public int idKlatka = 0;
public bool fZniszcz = false;
//opóźnienie
private const byte GRANICA_OPOZNIENIE = 5;
private byte licznikOpoznienia = 0;
//konstruktor
public Eksplozja(float _x,float _y, int _wys, int _szer)
{
wys = _wys;
szer = _szer;
//zapamietaj współrzędne wybuchu
x = _x;
y = _y;
}
public void Rysuj(Graphics g, List<Bitmap> bmp, int id)
{
g.DrawImage(bmp[klatki[id]],
new Rectangle((int)x - szer/2,(int)y - wys/2, szer, wys),
new Rectangle(0, 0, szer, wys),
GraphicsUnit.Pixel);
}
public void LicznikKlatek()
{
licznikOpoznienia++;
if (licznikOpoznienia > GRANICA_OPOZNIENIE)
{
idKlatka++;
licznikOpoznienia = 0;
}
if (idKlatka > 6)
{
idKlatka = 0;
fZniszcz = true;
}
}
}
}
Zawartość pliku Swiat.cs
Wskazówka:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
namespace czolg_1
{
internal class Swiat
{
static int ileKlatekX = 20, ileKlatekY = 15;
int[,] plansza=new int[ileKlatekY,ileKlatekX];
public List<Eksplozja> listaEksplozji = new List<Eksplozja>();
public int IleKlatekX
{ //zwróc ilośc kolumn
get { return ileKlatekX; }
}
public int IleKlatekY
{ //zwróc ilośc wierszy
get { return ileKlatekY; }
}
//konstruktor
public Swiat(string plik)
{
//odczytaj wskazany plik z mapą świata gry
string[] txt=System.IO.File.ReadAllLines(plik);
for(int i= 0; i < txt.Count(); i++)
{
//odczytaj wiersze i ustaw znak separatora na spację
string[]wiersz=txt[i].Split(' ');
//czytaj liczby zapisane w wierszach
for (int j = 0; j < wiersz.Length; j++)
{
int k = int.Parse(wiersz[j]);
//przypisz odczyatne indeksy klatek do
//tablicy planszy mapy świata gry
plansza[i, j] = k;
}
}
}
public void RysujSwiat(Graphics g, List<Bitmap> bmp,int w,int h)
{
for(int i=0;i< ileKlatekY;i++)
for (int j = 0; j < ileKlatekX; j++)
{
int idKlatka = plansza[i,j];
g.DrawImage(bmp[idKlatka],
new Rectangle(j*w, i*h, w, h),
new Rectangle(0, 0, w, h),
GraphicsUnit.Pixel);
}
}
public void RysujWszystkieEksplozje(Graphics g,List<Bitmap> bmp)
{
foreach (var e in listaEksplozji)
{
e.Rysuj(g, bmp, e.idKlatka);
e.LicznikKlatek();
}
//przeglądnij listę i usun te które zakończyły animację
for(int i = 0; i < listaEksplozji.Count; i++)
if(listaEksplozji[i].fZniszcz)listaEksplozji.RemoveAt(i);
}
}
}
Zawartość pliku bitmapy.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace czolg_1
{
internal class bitmapy
{
public Bitmap zasobyBmp;
//lista klatek wycinanych bitmapek
private List<Bitmap> bitmaps = new List<Bitmap>();
private Bitmap bmpBuforEkranGry;//bufor graficzny
private Graphics gEkranGry;
private int w, h,//szerkość klatki
ileKolumn, ileWierszy;//ilosc kolumn i wierszy swiata gry
public int W {//zwroc,ustaw szerokość klatki
get { return w; }
set { w = value;}
}
public int H
{ //zwroc,ustaw wysokość klatki
get { return h; }
set { h = value; }
}
//konstruktor
public bitmapy(int ileK,int ileW,int _w,int _h)
{
this.w = _w;
this.h = _h;
this.ileKolumn = ileK;
this.ileWierszy = ileW;
//przygotuj bufor rysowania ekranu gry
bmpBuforEkranGry = new Bitmap(this.ileKolumn*this.w,
this.ileWierszy*this.h,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
//skojarz moduł graficzny z buforem rysowania ekranu gry
gEkranGry= Graphics.FromImage(bmpBuforEkranGry);
}
private void RysujSwiatGryBufor(Swiat swiat,Czolg czolgA,Czolg czolgB)
{
swiat.RysujSwiat(gEkranGry, bitmaps,W,H);
//na teraz testowe rysowania czolgu graczaA
czolgA.Rysuj(gEkranGry, bitmaps);
//na teraz testowe rysowania czolgu graczaB
czolgB.Rysuj(gEkranGry, bitmaps);
//ryuj eksplozje na koncu, tak jak na ostatniej warstwie
//która przykrywa wszystkie obiekty graficzne
swiat.RysujWszystkieEksplozje(gEkranGry, bitmaps);
}
public void PokazEkranGry(IntPtr uchwyt, Swiat swiat, Czolg czolgA, Czolg czolgB)
{
Graphics g = Graphics.FromHwnd(uchwyt);
RysujSwiatGryBufor(swiat, czolgA, czolgB);
g.DrawImage(bmpBuforEkranGry, 0, 0);
g.Dispose();
}
public void WczytajBmp(string plik)
{
//funkcja wczytuje bitmapę z pliku graficznego
zasobyBmp = new Bitmap(plik);
//wczytany plik zasobów potnij na klatki o wymiarach W x H
//w programie przyjałem 48 x 48 pikseli
int ileKolumn = zasobyBmp.Width / W;
int ileWierszy= zasobyBmp.Height / H;
for (int i = 0; i < ileWierszy; i++)
for (int j = 0; j < ileKolumn; j++)
{
bitmaps.Add(new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb));
Graphics g = Graphics.FromImage(bitmaps[bitmaps.Count-1]);
g.DrawImage(zasobyBmp, new Rectangle(0, 0, w, h),
new Rectangle(j*w, i*h, w, h),
GraphicsUnit.Pixel);
g.Dispose();
}
}
public void testPokazBmp(Graphics g, int x, int y, int w, int h)
{
//funkcja testowa, pokazuje pierwszą klatkę ze współrzednych (0,0,0+w,0+h)
g.DrawImage(zasobyBmp,
new Rectangle(x,y,w,h),
new Rectangle(0, 0, w, h),
GraphicsUnit.Pixel);
}
public void pokazKlatke(Graphics g, int idKlatka, int x, int y)
{
//funkcja testowa, pokazuje dowolną klatkę
g.DrawImage(bitmaps[idKlatka],
new Rectangle(x, y, w, h),
new Rectangle(0, 0, w, h),
GraphicsUnit.Pixel);
}
//destruktor
~bitmapy()
{
//zwolnij pamięc zajmowaną przez zasoby graficzne
zasobyBmp.Dispose();
foreach (Bitmap b in bitmaps) { b.Dispose(); }
//zwolnij bufor rysowania ekranu gry
bmpBuforEkranGry.Dispose();
gEkranGry.Dispose();
}
}
}
Zawartość pliku Form1.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace czolg_1
{
public partial class Form1 : Form
{
bitmapy bmp;
Swiat swiat;
Czolg czolgA, czolgB;
private void TestEksplozji()
{
int x, y;//tymczasowe wspołrzedne testowych eksplozji
Random los= new Random();
x = los.Next(48, this.Width - 48);
y = los.Next(48, this.Height - 48);
swiat.listaEksplozji.Add(new Eksplozja(x,y,bmp.H,bmp.W));
}
public Form1()
{
InitializeComponent();
swiat = new Swiat("swiat1.txt");
//buduj swiat 20x15- 20 kolumn na 15 wierszy po 48x48 pikseli
bmp =new bitmapy(swiat.IleKlatekX,swiat.IleKlatekY,48,48);
//rob czolg zwrocony na południe
czolgA = new Czolg(2,0, 0, bmp.H, bmp.W);
czolgA.LadujKlatkiKierunku(0,1,2,3);
//rób czołg zwrócony na połnoc
czolgB = new Czolg(0,14, 19, bmp.H, bmp.W);
czolgB.LadujKlatkiKierunku(8, 9, 10, 11);
}
private void Form1_Load(object sender, EventArgs e)
{
//wczytaj bitmape na sztwyno z pliku
//zakładamy, że plik grafiki istnieje
//więc nie musimy sprawdzać czy istnieje
bmp.WczytajBmp("./g/czolg.png");
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
bmp.PokazEkranGry(this.Handle, swiat, czolgA, czolgB);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//klawiszologia
//dla gracza A
if (e.KeyCode == Keys.A) czolgA.Obracaj(-1);
if (e.KeyCode == Keys.D) czolgA.Obracaj(1);
if (e.KeyCode == Keys.W)
{
czolgA.fRuch = true;
czolgA.v= czolgA.Vmax;
}
if (e.KeyCode == Keys.S)
{
czolgA.fRuch = true;
czolgA.v = -czolgA.Vmax;
}
//dla gracza B
if (e.KeyCode == Keys.Left) czolgB.Obracaj(-1);
if (e.KeyCode == Keys.Right) czolgB.Obracaj(1);
if (e.KeyCode == Keys.Up)
{
czolgB.fRuch = true;
czolgB.v = czolgB.Vmax;
}
if (e.KeyCode == Keys.Down)
{
czolgB.fRuch = true;
czolgB.v = -czolgB.Vmax;
}
//testowe eksplozje
if (e.KeyCode == Keys.T)
{
TestEksplozji();
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
//klawiszologia
//dla gracza A
if (e.KeyCode == Keys.W ||
e.KeyCode == Keys.S)
czolgA.fRuch = false;
//dla gracza B
if (e.KeyCode == Keys.Up ||
e.KeyCode == Keys.Down)
czolgB.fRuch = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
zegarGry();
}
private void zegarGry()
{
czolgA.Ruch();
czolgB.Ruch();
bmp.PokazEkranGry(this.Handle, swiat, czolgA, czolgB);
}
}
}
Zawartość pliku Czolg.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace czolg_1
{
internal class Czolg
{
int[] klatki = new int[4];
static float maxV = 2.0f;
private int idKlatka;
private int wiersz,kolumna;//pozycja w klatkach swiata gry
private int wys, szer;//wysokośc i szerokośc klatki świata gry
private float x, y;//pozycja we współrzednych ekranowych
public float v = maxV;//predkosc
public bool fRuch = false;
public int Wiersz
{//zwroc,ustaw pozycje w klatkach swiata gry
get { return wiersz; }
set { wiersz = value; }
}
public int Kolumna
{//zwroc,ustaw pozycje w klatkach swiata gry
get { return kolumna; }
set { kolumna = value; }
}
//funkcja odczytu max predkosci
public float Vmax { get { return maxV; } }
//konstruktor
public Czolg(int _idKlatka,int _wiersz,int _kolumna,int _wys,int _szer)
{
idKlatka = _idKlatka;
Wiersz = _wiersz;
Kolumna = _kolumna;
wys =_wys;
szer = _szer;
//oblicz współrzedne startu
x = Kolumna * szer + szer/2;
y = Wiersz * wys + wys/2;
}
public void LadujKlatkiKierunku(int _N,int _E,int _S,int _W)
{
klatki[0] = _N;//na północ
klatki[1] = _E;//na wschód
klatki[2] = _S;//na południe
klatki[3] = _W;//na zachód
}
public void Rysuj(Graphics g, List<Bitmap> bmp)
{
g.DrawImage(bmp[klatki[idKlatka]],
new Rectangle((int)x-szer/2, (int)y-wys/2, szer, wys),
new Rectangle(0, 0, szer, wys),
GraphicsUnit.Pixel);
}
public void Obracaj(int i)
{
idKlatka += i;
if (idKlatka < 0) idKlatka = 3;
if (idKlatka > 3) idKlatka = 0;
}
public void Ruch()
{
if (!fRuch) return;
switch (idKlatka){
//na północ
case 0:y -= v;break;
//na wschód
case 1: x += v; break;
//na południe
case 2: y += v; break;
//na zachód
case 3: x -= v; break;
}
}
}
}