Return of the Darth Vader [#1]

Am decis să-mi complic existența și să fac un „joc”, în C++Builder,  utilizând Canvas-ul și câteva imagini.
Ideea ar fi simplă : Ești Darth Vader , lupți cu un monstru , poți împușca , poți fi împușcat (cel mult de 5 ori) .
Mai jos am inclus imaginile de care am avut nevoie :
sprite1 vader fireball hearth over win

Vom avea nevoie de 3 Timere :
Timer1 —  Va face repaint la formă peste fiecare 2,5 secunde . (Pentru a elimina „urmele de laser”)
Timer2 — Va mișca mingea de foc spre jucător/spre stânga (la fiecare TimerTick Fireball->Left se va micșora)
Timer3 — Va face respawn la monstru într-o poziție random pe axa Y  , dar fixă pe X .

Putem adăuga label-uri în care vom arăta scorul curent .
Inițial componentele se vor aranja astfel :

form2

Sub imaginea „Winner is You” , este imaginea „You Lose” , aflată pe aceleași coordonate și având aceeași dimensiune .

Vom declara câteva variabile globale :

int InitX = 8;
int InitY = 8;//Coordonatele initiale ale lui Vader
int MaxX = 30;//Vader nu poate merge mai departe de 30px in dreapta
int MaxY = 400;//Vader poate merge 400px pe axa Y
int Step=15;//Un pas al lui vader = 15px
int VaderSize =40;//Dimensiunea imaginii lui Vader
int Health=5;//Vader are 5 HP
int Score=0;
int EnemyHealth =10;//Monstrul are 10HP

Vom declara antetul funcției ResetSprites:
void ResetSprites();

Vom elabora metoda care limitează spațiul pe care Vader poate merge :

void Margins()
{
if(Form1->VaderImage->Left>=MaxX)
{
Form1->VaderImage->Left=MaxX;
}
if(Form1->VaderImage->Left<=InitX)
{
Form1->VaderImage->Left=InitX;
}
if(Form1->VaderImage->Top<=InitY)
{
Form1->VaderImage->Top=InitY;
}
if(Form1->VaderImage->Top>=MaxY)
{
Form1->VaderImage->Top=MaxY;
}
}

Metoda de mișcare va lucra după principiul „Cangurului”  -va primi un parametru ce va indica direcția .

void PerformStep(int Direction)
{

switch(Direction)
{
case 0 : Form1->VaderImage->Top=Form1->VaderImage->Top-Step; Margins();break;
case 1 : Form1->VaderImage->Top=Form1->VaderImage->Top+Step; Margins();break;
case 2 : Form1->VaderImage->Left=Form1->VaderImage->Left+Step; Margins();break;
case 3 : Form1->VaderImage->Left=Form1->VaderImage->Left-Step; Margins();break;
}

}
Explicație :
Imaginea lui Vader va fi repoziționată în direcția corespunzătoare parametrului cu 20 pixeli (Step=20)
0 —  se va mișca în jos
1 — se va mișca în sus
2 — se va mișca în dreapta
3 — se va mișca în stânga

În continuare vom elabora câteva metode de încheiere a jocului : Stop() , Die() , Win();

void Stop()
{
Form1->Timer3->Enabled=false;
Form1->Timer2->Enabled=false;
Form1->VaderImage->Visible=false;
Form1->Fireball->Visible=false;
Form1->EnemyImage->Visible=false;
}

Metoda Stop(); va opri Timer3 și Timer 2 , care răspund de Respawn-ul monstrului și de acțiunile acestuia . Timer1 nu va fi oprit , pentru a continua repaint-ul formei
Se vor face invizibile imaginile monstrului și  a lui Vader .

void Die()
{
Stop();
Form1->YouLose->Top=104;
Form1->YouLose->Left=24;
Form1->YouLose->Visible=true;
}
În metoda Die() :
Se va apela metoda Stop(); , după care se va face vizibilă imaginea YouLose („Game Over”)

void Win()
{
Stop();
Form1->YouWin->Top=104;
Form1->YouWin->Left=24;
Form1->YouWin->Visible=true;
}

În metoda Win() la fel se va apela metoda Stop(); după care se va face vizibilă imaginea YouWin.

Urmează metoda Shoot() , care va oferi lui Vader abilitatea de a „împușca”

void Shoot()
{
int x,y;

int ShootLength=450;

x=Form1->VaderImage->Left;
y=Form1->VaderImage->Top;
Form1->Canvas->Pen->Color=clRed;
Form1->Canvas->Pen->Width=3;
Form1->Canvas->MoveTo(x+VaderSize,y+VaderSize/2);
Form1->Canvas->LineTo(x+ShootLength,y+VaderSize/2);
if((y+VaderSize/2>= Form1->Fireball->Top) && (y+VaderSize/2<= Form1->Fireball->Top+25))
{
Score++;
EnemyHealth—;

ResetSprites();
Form1->Label2->Caption=AnsiString(Score);

}
}

ShootLength —  cum rezultă și din nume , variabila va indica lungimea liniei ce ar reprezenta urma de laser. Lungimea liniei va fi de 450 pixeli.

Form1->Canvas->Pen->Color=clRed;
Form1->Canvas->Pen->Width=3;
Linia va avea grosimea de 3px și va fi de culoarea roșu.

Form1->Canvas->MoveTo(x+VaderSize,y+VaderSize/2);
După cum e scris mai sus în cod ,
x =  poziția lui Vader pe axa X
y =  poziția lui Vader pe axa Y
Respectiv ,
Cursorul canvasului se mișca pe axa X în poziția  x+VaderSize .
VaderSize = dimensiunea imaginii lui vader = 40 .
Acest lucru se utilizează pentru a începe linia de la capătul drept al imaginii lui Vader.
Pe axa Y cursorul canvasului se va muta pe poziția y+VaderSize/2
Adică la mijlocul pe axa Y a imaginii lui Vader.
Astfel laserul va proni din „sabie”.

Form1->Canvas->LineTo(x+ShootLength,y+VaderSize/2);

Din poziția cursorului se va trasa o linie orizontală (cu aceeași coordonată Y) , către x+ShootLength
, iar ShootLength =450 . Respectiv vom avea o linie orizontală , de 450px pornind de la mijlocul lui Vader.

if((y+VaderSize/2>= Form1->Fireball->Top) && (y+VaderSize/2<= Form1->Fireball->Top+25))
{
Score++;
EnemyHealth—;

ResetSprites();
Form1->Label2->Caption=AnsiString(Score);

}

Această formulă verifică dacă linia trasată se intersectează cu mingea de foc, adică dacă Y-ul liniei nu este mai mic ca Y-ul mingei , dar nici mai mare ca Y-ul mingii +  dimensiunea mingii .
Dacă se intersectează , se incrementează ce trebuie de incrementat , și invers .

În continuare vom elabora o metodă ce va afișa cîte HP-uri mai are vader .

void UpdateHealth()
{
switch(Health)
{
case 4 : Form1->Image1->Visible=false; break;
case 3 : Form1->Image2->Visible=false; break;
case 2 : Form1->Image3->Visible=false; break;
case 1 : Form1->Image4->Visible=false; break;
case 0 : Form1->Image5->Visible=false; Die(); break;
}

}

Metoda operează cu variabila globală Health .
Se vor afișa atâtea inimi , cât e valoarea variabilei Health .
Dacă Health = 0 , se apelează metoda Die();

Vom crea și o metodă care va afișa scorul , și câte HP-uri are monstrul :
void UpdateScore()
{
Form1->Label2->Caption=AnsiString(Score);
Form1->Label4->Caption=AnsiString(EnemyHealth);
}

Urmează metoda care va reseta Monstrul și mingea de foc într-o poziție random pe axa Y , dar fixă pe X.

void ResetSprites()
{
if(EnemyHealth==0)
Win();
else{
Form1->EnemyImage->Visible=true;
Form1->Fireball->Visible=true;
int EnemyX=400 , EnemyY;
int EnemySize=50;
int BallSize=25;
EnemyY = rand()%450;
Form1->EnemyImage->Left=EnemyX;
Form1->EnemyImage->Top=EnemyY;
Form1->Fireball->Left=Form1->EnemyImage->Left-BallSize;
Form1->Fireball->Top=Form1->EnemyImage->Top+10;
}
}

Inițial se verifică dacă monstrul mai are vreun HP , dacă nu , se apelează Win() , dacă da :

Poziția imaginii monstrului (EnemyImage) va fi una aleatorie , pînă la 450
EnemyY = rand()%450;
Form1->EnemyImage->Top=EnemyY;

Apoi , poziția mingii de foc , pe X va fi egală cu margina stînga a EnemyImage — dimensiunea mingii
Iar pe Y se va poziționa le jumătatea monstrului .

Urmează metoda care verifică dacă mingea a nimerit în Vader:

void GotHit()
{
if((Form1->Fireball->Top>=Form1->VaderImage->Top) && (Form1->Fireball->Top<=Form1->VaderImage->Top+VaderSize) )
if(Form1->Fireball->Left<=MaxX)
{
ResetSprites();
Health—;
UpdateHealth();
}

}

În continuare , prelucrăm controlul de la tastatură a lui Vader.
WASD —  Movement
X —  Shoot
void __fastcall TForm1::FormKeyPress(TObject *Sender, char &Key)

{
if(Key == ‘w’)
{
PerformStep(0);
}
if(Key == ‘s’)
{
PerformStep(1);
}
if(Key == ‘a’)
{
PerformStep(3);
}
if(Key == ‘d’)
{
PerformStep(2);
}
if(Key == ‘x’)
{
Shoot();
}
}

La final , prelucrăm fiecare Timer :

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Form1->Repaint();
}
//—————————————————————————
void __fastcall TForm1::Timer3Timer(TObject *Sender)
{
/*
Reseteaza intr-o pozitie random Sprite-ul si fireball-ul
*/
ResetSprites();

}
//—————————————————————————
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
/*
Impusca fireball-ul inspre jucator.
*/
int Speed = 25;
// 25 pixels per 100 ms.
Form1->Fireball->Left-=Speed;
GotHit();
}

Am obținut astfel un joculeț , utilizând componente care nu-s chiar pentru asta 🙂

vader

Source code :
http://www.4shared.com/rar/ziG4feCYba/Vader.html

 

Оставьте комментарий