Mai bine de 2 luni nu am scris aproape nimic cod (în afară de un laborator la SDA … în C :)) )
Așa că planific să revin , cu noi forțe și cu o nouă motivație (care deja s-au epuizat după o zi de coding)
Voi lucra la o aplicație Android. Iaca teaserul :
LoadScreen mainblue
Dacă sincer idee nu am de programare în Android , dar știu cumv a lucra aplicația … deja cum de făcut să lucreze așa cum vreau eu , e o altă întrebare.

revenirea [jurământul #1]

Conectăm Builder-u’ la MySQL [#0.1]

Mai mult pentru mine.
Se va folosi baza de date sakila , care mi-a venit ca bonus la instalarea MySQL ,

1. Start -> odbcad32 .
Va apărea următoarea fereastră :
dbconnect1

Dăm click pe Add , va apărea fereastra de selectare a driver-ului.
Din josul listei alegem MySQL  Driver
dbconnect2

După ce apăsăm Finish , apare fereastra de configurare MySQL/ODBC Data Source Configuration

db3
Se vor specifica numele datasource-ului , dacă se folosește un server local se specifică localhost , în caz contrar IP-ul serverului , se specifică portul conexiunii , numele utilizatorului și parola (dacă e setată).
Se tastează Test . Dacă conexiunea nu a întîmpinat erori , va apărea mesajul  Connection Successful și din lista Database vom putea alege baza de date la care urmează să se conecteze .

Astfel s-a finisat configurarea DataSource-ului cu care va lucra C++Builder .
În continuare vom lansa C++Builder și vom urma pașii :
Din paleta BDE , selectăm componenta Database și o plasăm pe formă
db4

La proprietatea AliasName vom specifica DataSource-ul creat anterior (ds_sakila):
bd5

La proprietatea DatabaseName vom specifica un oarecare nume alternativ bazei de date .
Când vom schimba proprietatea Connected în true , se va solicita re-introducerea username-ului și passwordului
bd6

În continuare vom plasa pe formă componenta Table , din aceeași paletă BDE  .
La proprietatea DatabaseName , vom indica numele alternativ dat anterior.
db7

Iar din proprietatea TableName , vom alege tabela care va fi reprezentată de acest Table .
db8
Setăm proprietatea Active fiind true .

În continuare , din paleta Data Access vom plasa pe formă o componentă DataSource , iar la proprietatea DataSet vom seta Table1 (Table-ul creat anterior)
Iar din paleta DataControl , vom plasa pe formă o componentă DBGrid și vom seta la proprietatea DataSource valorea DataSource1 .

După care , în DBGrid se vor afișa toate înregistrările din tabela indicată în proprietatea TableName a componentei Table1
db11

La execuție însă , iarăși s eva solicita username-ul și password-ul . Pentru a evita acest pas , se selectează componenta Database1 și proprietatea LoginPrompt se echivalează cu false.
Avem o aplicație care „lucrează” cu BD MySQL.

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

 

Mai în glumă , mai în serios … [Cangurul #1]

Zilele astea mi-am amintit de „Cangurul” ce-l învățasem prin a 8-a , ori mai devreme . M-am gândit să fac un re-make , chiar dacă nu la fel de „sofisticat” . De fapt nici nu re-make , dar mai degrabă o parodie.
(Pentru cine nu știe despre ce merge vorba , poftim : )

canguru2

Foc la ghete .
Prescriptum : Se vor face update-uri … probabil 🙂
Programul va lucra după alt concept : Vom avea 4 butoane care vor indica direcția de mișcare , în calitate de „Cangur” va fi un sprite găsit pe net . Pe forma va fi plasat în componenta Image , de dimensiunea 32×32 . Programul va dispune de 2 regimuri : Desenare și Radieră .
sprite
Componentele aranjate pe formă arată în felul următor :
form

Vom declara câteva variabile globale :

int Step=20;// Un „pas” va fi echivalent cu 20 de pixeli.
int InitialLeft=8; // Va indica extremitatea stângă până la care se va putea deplasa cangurul.
int InitialTop=8; // Va indica extremitatea de suspână la care se va putea deplasa cangurul.
int StepsMade=0;// Va păstra numărul pașilor făcuți de cangur.
int MaxLeft=320;// Va indica extremitatea dreaptă până la care se va putea deplasa cangurul.
int MaxTop=470;//Va indica extremitatea de jos până la care se va putea deplasa cangurul.

Extremitățile se vor utiliza la limitarea domeniului de deplasare a cangurului .
Pentru asta , vom crea o funcție care va controla comportamentul cangurului atunci când el va ajunge(și va trece) la una din extremități.
Dacă va ajunge la o extremitate , cangurul va apărea la extremitatea opusă.
void Margins()
{
if(Form1->Image1->Left>=MaxLeft)
{Form1->Image1->Left=InitialLeft;}
//Daca ajunge la extremitatea dreapta , va fi mutat în partea stanga.
if(Form1->Image1->Top>=MaxTop)
{Form1->Image1->Top=InitialTop;}
//Daca ajunge la extremitatea de jos , va aparea sus.
if(Form1->Image1->Left<InitialLeft)
{Form1->Image1->Left=MaxLeft;}
//Daca ajunge la extremitatea stanga , va aparea in dreapta.
if(Form1->Image1->Top<InitialTop)
{Form1->Image1->Top=MaxTop;}
//Daca ajunge la extremitatea de sus , va aparea jos.
}
Această funcție va fi apelată de fiecare dată când se va cere efectuarea unui pas .
Acum vom elabora metoda ce va face update la label-urile ce conțin informații despre numărul de pași , poziția curentă a cangurului.

void UpdateScore()
{
Form1->Label3->Caption=AnsiString(StepsMade);//Numarul de pasi
Form1->Label4->Caption=AnsiString(StepsMade*Step);//Distanta parcursa in pixeli
Form1->Label7->Caption=AnsiString(Form1->Image1->Left);//Pozitia pe x
Form1->Label8->Caption=AnsiString(Form1->Image1->Top);//Pozitia pe y
}

În continuare vom elabora metoda de mișcare .
Vom declara o funcție ce primește ca parametru Direcția de mișcare.

void MakeStep(int Direction)
{
Margins();
//Inainte de a efectua pasul , se verifica daca nu va fi iesire in afara extremitatilor.
switch(Direction)

{
case 0 : Form1->Image1->Top=Form1->Image1->Top-Step; break;
//Efectueaza un pas in sus . Imaginea isi va schimba pozitia pe axa Top cu -20 pixeli (Step=20)
case 1 : Form1->Image1->Left=Form1->Image1->Left+Step; break;
//Efectueaza un pas in dreapta
case 2 : Form1->Image1->Top=Form1->Image1->Top+Step; break;
//Efectueaza un pas in jos
case 3 : Form1->Image1->Left=Form1->Image1->Left-Step;
//Efectueaza un pas in stanga.
}
StepsMade++;
//Se incrementeaza numarul pasilor.
UpdateScore();
/*Se face update la label-urile ce contin informatii despre numarul de pasi , numarul de pixeli , pozitia cangurului.
*/
}

În continuare vom elabora metoda de desenare .
Ea la fel va primi ca parametru direcția . Acest parametru se va folosi și la apelul metodei MakeStep , în interiorul funcției .
void DrawStep(int Par)
{

int LPos1,TPos1,LPos2,TPos2;
LPos1=Form1->Image1->Left;
TPos1=Form1->Image1->Top;
Form1->Canvas->Pen->Width=3;
MakeStep(Par);
Form1->Canvas->MoveTo(Form1->Image1->Left,Form1->Image1->Top);
Form1->Canvas->LineTo(LPos1,TPos1);
}

Explicație : 
LPos , TPos vor memora locația curentă a imaginii .
Se va efectua un pas în direcția corespunzătoare parametrului . Imaginea își va schimba poziția.
Cursorul canvas-ului se va mișca în poziția nouă a imaginii .
Se va trasa o linie din p8oziția nouă a imaginii (poziția cursorului canvasului) spre poziția veche a imaginii .

În continuare pur și simplu vom apela metodele MakeStep , ori DrawStep (în dependență de opțiunea selectată în RadioGroup), pentru fiecare buton .

void __fastcall TForm1::Button4Click(TObject *Sender)
{
if(RadioGroup1->ItemIndex!=0)
MakeStep(1);
else
DrawStep(1);
}
//—————————————————————————

void __fastcall TForm1::Button2Click(TObject *Sender)
{
if(RadioGroup1->ItemIndex!=0)
MakeStep(2);
else
DrawStep(2);
}
//—————————————————————————

void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(RadioGroup1->ItemIndex!=0)
MakeStep(0);
else
DrawStep(0);
}
//—————————————————————————

void __fastcall TForm1::Button3Click(TObject *Sender)
{
if(RadioGroup1->ItemIndex!=0)
MakeStep(3);
else
DrawStep(3);
}
//—————————————————————————

Direcțiile se notează după acele ceasornicului :
0 — Sus
1 — Dreapta
2 — Jos
3 — Stanga

În continuare implementăm opțiunea de a schimba culoarea cu care se desenează :
void __fastcall TForm1::ComboBox1Change(TObject *Sender)
{
switch(ComboBox1->ItemIndex)
{
case 0 : Form1->Canvas->Pen->Color=clBlack; break;
case 1 : Form1->Canvas->Pen->Color=clRed; break;
case 2 : Form1->Canvas->Pen->Color=clGreen; break;
case 3 : Form1->Canvas->Pen->Color=clBlue; break;
case 4 : Form1->Canvas->Pen->Color=clYellow; break;
}
}

Rezultatul final :