Obiekty graficzne na przykładzie prostej gry- strzelanie
W tej części dodamy rozwiązanie pozwalające strzelać graczom zgodnie z kierunkiem ustawionej lufy. Do siódmej części będziemy potrzebować kod z części szóstej, który można pobrać z tego linku (pobierz kod z części 6)
Właściciel pocisku- czyli kto strzela?
W klasie Pocisk musimy dodać zmienną przechowującą właściciela pocisku. To pole ułatwi nam rozwiązanie odejmowania punktów życia trafionego celu. Po prostu- zakładamy, że nie można w siebie samego strzelić. I po tym polu w czasie wykrywania kolizji pocisku z celami będziemy rozróżniać trafienia.
Przechodzimy do pliku Pocisk.cs i dodajemy wiersz kodu public Czolg wlasciciel;
Wskazówka:
namespace czolg_1
{
internal class Pocisk
{
int[] klatki = {0,1,2,3};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
public float x, y;//pozycja we współrzednych ekranowych
private float x0, y0;//pozycja współrzednych wystrzału
public int idKlatka = 0;
public bool fZniszcz = false;
//opóźnienie
private const byte GRANICA_OPOZNIENIE = 3;
private byte licznikOpoznienia = 0;
private byte kierunek;
private float v = 10.0f;//predkośc pocisku
private float zasieg = 0;//zasięg pocisku
//
public Czolg wlasciciel;
//konstruktor
Modyfikujemy konstruktora klasy Pocisk poprzez dodanie zmiennej typu Czolg jako kolejny argument w konstruktorze. Patrz poniższy kod
Wskazówka:
//konstruktor
public Pocisk(float _x, float _y, int _wys, int _szer, byte _kierunek, Czolg _w)
{
wys = _wys;
szer = _szer;
//zapamietaj współrzędne strzalu
x = _x;
y = _y;
x0 = _x;
y0 = _y;
//kierunek strzalu
kierunek = _kierunek;
//ustaw zasięg na 6 kafli świata
zasieg = 6 * 48;
wlasciciel = _w;
}
Ta zmiana spowoduje pojawienie się komunikatu błędu. Musimy przejść do pliku Form1.cs i dokonać zmiany w funkcji TestPocisku(). Zmiana dotyczy jednej linii kodu (swiat.listaPociskow.Add?)
Wskazówka:
private void TestPocisku()
{
int x, y;//tymczasowe wspołrzedne testowych eksplozji
Random los = new Random();
x = los.Next(8, this.Width - 8);
y = los.Next(8, this.Height - 8);
//zero to strzal na pólnoc
swiat.listaPociskow.Add(new Pocisk(x, y, 8, 8, 0,czolgA));
}
Można przetestować program. Jako takich zauważalnych zmian nie ma, testujemy tylko aby sprawdzić czy modyfikacje nie wprowadziły błędów.
Na bazie funkcji TestPocisku tworzymy nową o nazwie Strzal. Nowej funkcji wstępnie przypiszemy trzy argumenty: właściciel, współrzędna X i współrzędna Y. Na moment przejdziemy do pliku Czolg.cs i dopiszemy funkcje- metody zwracające współrzędne X,Y czołgu gracza oraz numer klatki obrazu bitmapy. Numer indeksu tablicy klatek wykorzystujemy do ustalenia kierunku ruchu (N,E,S,W)
Wskazówka:
//funkcja odczytu max predkosci
public float Vmax { get { return maxV; } }
//zwróć wpsółrzędne obiektu ze świata gry
public float X { get { return x; } }
public float Y { get { return y; } }
//zwróc klatke kierunku ruchu, potrzebne do strzelania
public byte IdKlatka { get { return (byte)idKlatka; } }
Dodajemy funkcję Strzal w pliku Form1.cs napisana na bazie funkcji TestPocisku
Wskazówka:
private void Strzal(Czolg cz)
{
swiat.listaPociskow.Add(
new Pocisk(cz.X, cz.Y, 8, 8, cz.IdKlatka, cz)
);
}
Wywołanie funkcji strzelania wykonujemy w funkcji private void Form1_KeyDown(object sender, KeyEventArgs e) przez podmianę TestPocisku na Strzal. Patrz poniżej
Wskazówka:
//testowe eksplozje
if (e.KeyCode == Keys.T)
{
TestEksplozji();
}
//testowe pociski
if (e.KeyCode==Keys.Enter)
{
Strzal(czolgA);
}
Skompiluj program i sprawdź efekt działania. Czołg z lewego górnego narożnika może strzelać ale tylko na północ. W pozostałych kierunkach nie. Nie jest to błąd. Po prostu w części szóstej nie napisaliśmy kodu dla kierunków strzału innych niż kierunek północny
Strzelamy w każdym kierunku
Przechodzimy do pliku Pocisk.cs i dopisujemy kod pozwalający strzelać w każdym kierunku. Zmiany robimy w funkcji Ruch()
Wskazówka:
public void Ruch()
{
//kierunek pólnoc
switch (kierunek)
{
//na Pólnoc
case 0:y -= v;break;
//na Wschod
case 1:x += v;break;
//na Południe
case 2: y += v; break;
//na Zachód
case 3: x -= v; break;
}
if (Math.Abs(x - x0) > zasieg || Math.Abs(y - y0) > zasieg)
fZniszcz = true;
}
Skompiluj program i sprawdź efekt działania. Czołg z górnego lewego rogu może strzelać w każdym kierunku gdy naciskamy klawisz ENTER.
Można zauważyć, że jest jeden mankament w czasie strzelania. Pociski wylatują ze środka wieży. Trzeba to poprawić tak, aby pociski wylatywały z końca lufy.
Justowanie pocisku względem końca lufy
Ustawienie pozycji wylotu pocisku z lufy jest zmienne w zależności od kierunku strzału. Współrzędne końca lufy są inne. Przesunięci najłatwiej jest wyznaczyć otwierając grafikę zasobów na przykład w programie GIMP i odpowiednim narzędziem GIMP?a zmierzyć wartość przesunięcia w pikselach.
Wprowadzamy zmiany w konstruktorze klasy Pocisk. Przechodzimy do pliku Pocisk.cs i przeprogramowujemy konstruktora klasy
Wskazówka:
//konstruktor
public Pocisk(float _x, float _y, int _wys, int _szer, byte _kierunek, Czolg _w)
{
//przesuniecie dla konca lufy
float dx = 0, dy = 0;
wys = _wys;
szer = _szer;
//kierunek strzalu
kierunek = _kierunek;
switch (kierunek)
{
//Północ
case 0:dy = -24.0f;break;
//Wschód
case 1:dx = 24.0f; break;
//Polódnie
case 2:dy = 24.0f;break;
//Zachód
case 3:dx = -24.0f;break;
}
//zapamietaj współrzędne strzalu
x = _x + dx;
y = _y + dy;
x0 = _x;
y0 = _y;
//ustaw zasięg na 6 kafli świata
zasieg = 6 * 48;
wlasciciel = _w;
}
Skompiluj program i sprawdź efekt działania. Poniższy zrzut ekranu pokazuje efekt zmian. Widać, że pocisk wylatuje z lufy a nie ze środka wieży.
Strzelamy na dwa czołgi
Aby czołg drugiego gracza mógł strzelać wystarczy dodać obsługę strzału dla innego klawisza niż ENTER. Ustalimy, że klawiszem SPACJA strzela gracz A, a klawiszem ENTER strzela gracz B. Przechodzimy do pliku Form1.cs i wprowadzamy zmiany w funkcji Form1_KeyDown
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;
}
//strzela czołg A
if (e.KeyCode == Keys.Space)
{
Strzal(czolgA);
}
//strzela czołg B
if (e.KeyCode==Keys.Enter)
{
Strzal(czolgB);
}
}
Skompiluj program i sprawdź jak działa. Prawidłowo działający program pozwala strzelać obu graczom. Patrz poniższa ilustracja
I to tyle w tej części. Poniżej pełne kody aktualnych plików gry
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));
}
private void TestPocisku()
{
int x, y;//tymczasowe wspołrzedne testowych eksplozji
Random los = new Random();
x = los.Next(8, this.Width - 8);
y = los.Next(8, this.Height - 8);
//zero to strzal na pólnoc
swiat.listaPociskow.Add(new Pocisk(x, y, 8, 8, 0,czolgA));
}
private void Strzal(Czolg cz)
{
swiat.listaPociskow.Add(
new Pocisk(cz.X, cz.Y, 8, 8, cz.IdKlatka, cz)
);
}
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");
bmp.WczytajBmpPocisku("./g/pocisk.png",8,8);
}
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;
}
//strzela czołg A
if (e.KeyCode == Keys.Space)
{
Strzal(czolgA);
}
//strzela czołg B
if (e.KeyCode==Keys.Enter)
{
Strzal(czolgB);
}
}
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);
}
}
}
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 List<Pocisk> listaPociskow = new List<Pocisk>();
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);
}
public void RysujWszystkiePociski(Graphics g, List<Bitmap> bmp)
{
foreach (var e in listaPociskow)
{
e.Rysuj(g, bmp, e.idKlatka);
e.LicznikKlatek();
e.Ruch();
}
//przeglądnij listę i usun te które zakończyły zycie
//czyli trafiły w cel, przeszkodę lub osiągneły maksymalny zasięg
for (int i = 0; i < listaPociskow.Count; i++)
if (listaPociskow[i].fZniszcz)
{
listaEksplozji.Add(new Eksplozja(listaPociskow[i].x,
listaPociskow[i].y, 48, 48));
listaPociskow.RemoveAt(i);
}
}
}
}
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 Pocisk
{
int[] klatki = {0,1,2,3};
private int wys, szer;//wysokośc i szerokośc klatki świata gry
public float x, y;//pozycja we współrzednych ekranowych
private float x0, y0;//pozycja współrzednych wystrzału
public int idKlatka = 0;
public bool fZniszcz = false;
//opóźnienie
private const byte GRANICA_OPOZNIENIE = 3;
private byte licznikOpoznienia = 0;
private byte kierunek;
private float v = 10.0f;//predkośc pocisku
private float zasieg = 0;//zasięg pocisku
//
public Czolg wlasciciel;
//konstruktor
public Pocisk(float _x, float _y, int _wys,
int _szer, byte _kierunek, Czolg _w)
{
//przesuniecie dla konca lufy
float dx = 0, dy = 0;
wys = _wys;
szer = _szer;
//kierunek strzalu
kierunek = _kierunek;
switch (kierunek)
{
//Północ
case 0:dy = -24.0f;break;
//Wschód
case 1:dx = 24.0f; break;
//Polódnie
case 2:dy = 24.0f;break;
//Zachód
case 3:dx = -24.0f;break;
}
//zapamietaj współrzędne strzalu
x = _x + dx;
y = _y + dy;
x0 = _x;
y0 = _y;
//ustaw zasięg na 6 kafli świata
zasieg = 6 * 48;
wlasciciel = _w;
}
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 Ruch()
{
//kierunek pólnoc
switch (kierunek)
{
//na Pólnoc
case 0:y -= v;break;
//na Wschod
case 1:x += v;break;
//na Południe
case 2: y += v; break;
//na Zachód
case 3: x -= v; break;
}
if (Math.Abs(x - x0) > zasieg || Math.Abs(y - y0) > zasieg)
fZniszcz = true;
}
public void LicznikKlatek()
{
licznikOpoznienia++;
if (licznikOpoznienia > GRANICA_OPOZNIENIE)
{
idKlatka++;
licznikOpoznienia = 0;
}
if (idKlatka > 3)
{
idKlatka = 0;
//flagę zniszcenia trzeba wywołac gdy trafiono w cel
//przeszkodę lub osiągnieto maksymalny zasięg
//fZniszcz = true;
}
}
}
}
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; } }
//zwróć wpsółrzędne obiektu ze świata gry
public float X { get { return x; } }
public float Y { get { return y; } }
//zwróc klatke kierunku ruchu, potrzebne do strzelania
public byte IdKlatka { get { return (byte)idKlatka; } }
//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;
}
}
}
}
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,
zasobyBmpPocisk;
//lista klatek wycinanych bitmapek
private List<Bitmap> bitmaps = new List<Bitmap>();
private List<Bitmap> bitmapsPocisk = 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);
//rysuj pociski
swiat.RysujWszystkiePociski(gEkranGry, bitmapsPocisk);
//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 WczytajBmpPocisku(string plik,int _w,int _h)
{
//funkcja wczytuje bitmapę pocisku z pliku graficznego
zasobyBmpPocisk = new Bitmap(plik);
//wczytany plik zasobów potnij na klatki o wymiarach _w x _h
//w programie przyjałem 8 x 8 piksele
int ileKolumn = zasobyBmpPocisk.Width / _w;
int ileWierszy = zasobyBmpPocisk.Height / _h;
for (int i = 0; i < ileWierszy; i++)
for (int j = 0; j < ileKolumn; j++)
{
bitmapsPocisk.Add(new Bitmap(_w,_h,
System.Drawing.Imaging.PixelFormat.Format32bppArgb)
);
Graphics g = Graphics.FromImage(bitmapsPocisk[bitmapsPocisk.Count - 1]);
g.DrawImage(zasobyBmpPocisk, 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();
zasobyBmpPocisk.Dispose();
foreach (Bitmap b in bitmaps) { b.Dispose(); }
//zwolnij bufor rysowania ekranu gry
bmpBuforEkranGry.Dispose();
gEkranGry.Dispose();
}
}
}
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;
}
}
}
}