Tag Archives: framework

Պրոցեդուրային գեներացում: Մաս 1

1.1 Ներածություն
Այս խորագրի ներքո այսուհետ կներկայացվեն հոդվածներ ժամանակակից ծրագրավորման առջև դրված հետաքրքիր խնդիրների դասի՝ պրոցեդուրային գեներացման (procedural generation) վերաբերյալ: Պրոցեդուրային գեներացումը նվիրված է հաշվիչ մեքենաների միջոցով պսեվդո-պատահական պատկերների ստացմանը և մեծ կիրառություն ունի համակարգչային գրաֆիկայում և խաղերի դիզայնում: Հոդվածները հաճախ կուղեկցվեն ծրագրային կոդի հատվածներով, հարկ եղած դեպքում կոդը կուղեկցվի հարակից բացատրություններով: Օրինակները աշխատացնելու համար պահանջվող գրադարանների և կոմպոնենտների մասին կնշվի առանձին, ամեն օրինակի հետ:
Պրոցեդուրային գեներացումը անհնար կլիներ առանց պսեվդո-պատահական թվերի ստացման մեթոդների: Մենք չենք սևեռի մեր ուշադրությունը այս ոլորտի վրա, փոխարենը կօգտագործենք պսեվդո-պատահական թվեր գեներացնող .Net Framework-ի գրադարանի System.Random դասը:

1.2 Ռեալիստիկ լանդշաֆտի ստացում, միջնակետի տեղաշարժման ալգորիթմ

Դիտարկենք հետևյալ խնդիրը: Պահանջվում է գեներացնել և պատկերել իրական [Երկիր մոլորակի] լանդշաֆտի ուրվագծին նման ուրվագիծ: Պարզության համար կդիտարկենք ոչ թե եռաչափ լանդշաֆտի գեներացումը, այլ երկչափինը: Կարելի է վերաբերվել դրան որպես եռաչափ լանդշաֆտի ուղղահայաց հատույթի: Նայեք նկարին, որպեսզի պարզ լինի, ինչի մասին է խոսքը:
image

Նման պատկեր կարելի է տեսնել օրինակ երեկոյան հեռվից սարերի/բլուրների խմբին նայելիս: Նման խնդրի լուծման զանազան ալգորիթմներ կան, առավել պարզը դրանցից (ընդ որում, պարզ != վատ) միջնակետի տեղաշարժման ալգորիթմն է:

1. Սկզբում ունենք մի հորիզոնական հատված

midpoint02. Հատվածի ամեն սեգմենտը միջնակետում բաժանում ենք 2 մասի, միջնակետը [-range, range] միջակայքում ընկած պատահական չափով տեղաշարժում ենք վերև կամ ներքև
midpoint3. range թիվը բազմապատկում ենք roughness-ով (խորդուբորդության գործակից): Այն 0.0 – 1.0 միջակայքի ինչ-որ թիվ է: Որքան փոքր է այն, այնքան հղկված ու «փափուկ» է ստացվում ուրվագիծը:
4. Կրկնում ենք 2 և 3 քայլերը պահանջված անգամ: Դժվար չէ նկատել, որ ամեն անգամ 2-րդ քայլն անելուց հետո հատվածների քանակը կրկնապատկվում է:

Դիտողություն: Ռեալիստիկ պատկեր ստանալու համար կարելի է ալգորիթմն աշխատացնել սեգմենտների բավականին մեծ քանակ պահանջելով: Կարելի է նաև ստանալ համեմատաբար քիչ թվով կետեր (սեգմենտների փոքր թիվ տալ մուտքում) և դրանք ինտերպոլացնել գծայնորեն:

Դիտողություն 2: Շատերի մոտ կարող է այս ալգորիթմը ռեկուրսիվ իրականացնելու «ախորժակ» առաջանա: Մի շտապեք, իտերատիվ տարբերակը ճիշտ իրականացնելիս ավելի էֆեկտիվ է:

Այս, առաջին հայացքից պարզ հրամանները կարող են տալ շատ հզոր արդյունք: Իրականում այս ալգորիթմը ծնունդ է առել ծրագրավորման բոլորովին այլ՝ պատկերների ֆրակտալ կոմպրեսիայի ոլորտում կատարված հետազոտությունների արդյունքում: Սա ուղղված է պատկերները պահելու համար պիքսելների մասին ինֆորմացիա պահելու փոխարեն այլ տվյալներ պահելուն, պատկերի զբաղեցրած հիշողության ծավալը փոքրացնելու նպատակով:

Ստորև բերվում է C#-ով գրված ֆունկցիա, որն իրականացնում է ալգորիթմը:

private List<Point> GeneratePoints(int S, float roughness, int range)
{
List<Point> pts = new List<Point>();
pts.Insert(0, new Point(800, 200));
pts.Insert(0, new Point(0, 200));
int segments = 1;
Random rand = new Random();

            while (segments < S)
{
for (int i = 0; i < segments; i++)
pts.Insert(1 + 2 * i, new Point((pts[2*i].X + pts[2*i + 1].X) / 2, (pts[2*i].Y + pts[2*i + 1].Y) / 2 + rand.Next(-range, range)));

                segments *= 2;
range = (int)((float)range * roughness);
}

return pts;
}

Կարող եք բեռնել և փորձարկել նաև Midpoint Displacement ծրագիրը: Այն թույլ է տալիս աշխատանքի ընթացքում կարգավորել սեգմենտնետի քանակը, հեռահարությունն ու խորդուբորդության գործակիցը: Այն աշխատացնելու համար անհրաժեշտ է ունենալ .Net Framework Redistributable 4.0-ն:

midpoint

Եթե ցանկանում եք ստանալ այս ծրագրի կոդը, գրեք մեկնաբանություններում կամ էլեկտրոնային փոստով:
Հաջորդ անգամ (հաջորդ սերիայում Open-mouthed smile) կդիտարկենք նույն խնդիրը լուծող մեկ այլ մեթոդ՝ Pimsleur (չգիտեմ հայերեն էս ոնց են արտասանում…) Noise ֆունկցիայի վրա հիմնված: Կդիտարկենք նաև տարածված ծրագրերում և խաղերում այս մեթոդների կիրառությունների օրինակներ:

Թողնել մեկնաբանություն

Filed under Ծրագրավորում

Օձ. Net – Մաս 1

Արդեն 2 շաբաթ է, ինչ ուսումնասիրում եմ Microsoft .Net պլատֆորման՝ մասնավորապես Windows միջավայրում կլիենտային ծրագրերի ստեղծման Windows Forms տեխնոլոգիան: Ուզում եմ կիսվել իմ ձեռք բերած փորձով: Բլոգում կթողարկեմ Օձ .Net վերնագրով հոդվածներ: Մեր հեռահար նպատակն է C# լեզվով գրել հին ու բարի Snakes խաղի ժամանակակից տարբերակը: Ասեմ միանգամից, որ մեր նախագծից գերժամանակակից գրաֆիկա ու շեյդերների տեղատարափ սպասող ընթերցողը կարող է միանգամից թողնել ընթերցումը և ինտերնետում կամ որևէ այլ տեղ որոնել DirectX SDK-ի կամ նման այլ գրաֆիկական գրադարանի մասին հոդվածներ: Ասեմ, որ հոդվածիս կկցեմ նախագծի ամբողջ կոդը: Ընթացքում հնարավորինս պարզ ձևով կբացատրեմ կոդի բացատրություն պահանջող կտորները: Կշոշափվեն նաև C#-ի և .Net-ի հետ կապված հարցեր: Ծրագիրը թարգմանելու համար ձեզ պետք կգա C#-ի թարգմանիչ, որը անվճար կարելի է բեռնել Microsoft-ի կայքից, Ցանկալի է ունենալ ժամանակակից IDE (Integrated Development Environment), ինչպիսին է օրինակ Microsoft Visual Studio .Net-ը: Ծրագիրը աշխատացնելու համար անհրաժեշտ է .Net Framework 2.0 կամ ավելի նոր տարբերակը: Նախաբանն այսքանն էր, իսկ այժմ անցնենք գործին:

Մի քանի խոսք նախագծի մասին
Դե բնական է, խաղի «վիզուալ միջուկը» գրելու համար պետք է օգտվել ինչ-որ գրաֆիկական API-ից: Հատուկ .Net պլատֆորմայի համար նախագծվել է երկչափ վեկտորական գրաֆիկայի ու տեքստի արտածման GDI+ API-ն, որն իրենից ներկայացնում է հին Windows API-ի GDI-ի (Graphics Device Interface) համալրված ու կատարելագործված տեսակը: Ես նախատեսել եմ, որ ծրագրում ոչ մի ռաստերային ռեսուրսներ (bitmap նկարներ և այլն) չօգտագործեմ (մի տեսակ հաճելի է զուտ վեկտորային պատկերը): Առաջին մասում մենք կհասցնենք ստեղծել Windows-ի Form (հայերեն լեզվով ասած՝ պատուհան), «պատկերենք» նրա մեջ 20×20 չափերով տախտակ ու նկարենք ինչ որ դիրքում մեր օձին: Պատկերենք բառը այստեղ վերցված է փակագծերի մեջ, որովհետև էֆեկտիվության նկատառումներով տախտակի վանդակներ, որպես այդպիսիք չենք նկարելու: Փոխարենը ժամանակավորապես (պրոֆիլակտիկ նպատակներով) ցանց կնկարենք պատուհանի մեջ, որպեսզի տեսնենք, ճիշտ ենք տեղադրում օձին, թե ոչ:

Ստորև բերվում է ծրագրի կոդը:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
class Snakes : Form
{
static public int direction = 0, ifieldx, ifieldy,
fieldsize, snakelen = 5;
public int snposx = 7, snposy = 8;
private Rectangle[] Snake;
public static void Main()
{
Application.Run(new Snakes());
}
public Snakes()
{
Text = “Օձ .Net”;
Width = 400;
Height = 400;
BackColor = Color.ForestGreen;
ResizeRedraw = true;
fieldsize = 20;
ifieldx = this.ClientRectangle.Width / fieldsize;
ifieldy = this.ClientRectangle.Height / fieldsize;
Snake = new Rectangle[]{
new Rectangle((snposx-4)%fieldsize*ifieldx, snposy%fieldsize*ifieldy, ifieldx, ifieldy),
new Rectangle((snposx-3)*ifieldx, snposy*ifieldy, ifieldx, ifieldy),
new Rectangle((snposx-2)*ifieldx, snposy*ifieldy, ifieldx, ifieldy),
new Rectangle((snposx-1)*ifieldx, snposy*ifieldy, ifieldx, ifieldy),
new Rectangle(snposx*ifieldx, snposy*ifieldy, ifieldx, ifieldy),
new Rectangle(0, 0, 0, 0),
new Rectangle(0, 0, 0, 0),
new Rectangle(0, 0, 0, 0)
};
}

protected override void OnPaint(PaintEventArgs e)
{
Graphics gfx = e.Graphics;
Pen p = new Pen(Color.Black, 0);
//gfx.SmoothingMode = SmoothingMode.HighQuality;
//gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
Brush snakeb = Brushes.Indigo;
int i = 0;
for (i = 0; i < fieldsize*ifieldx; i += ifieldx)
{
gfx.DrawLine(p, new Point(i, 0), new Point(i, ifieldy * fieldsize));
}
for (i = 0; i < fieldsize*ifieldy; i += ifieldy)
{
gfx.DrawLine(p, new Point(0, i), new Point(ifieldx * fieldsize, i));
}
gfx.FillRectangles(snakeb, Snake);
}
}

Մեր Snakes դասը ժառանգած է System.Windows.Forms.Form դասից: Static Public տեսակի սահմանված են direction, ifieldx, ifieldy, snakelen փոփոխականներ: Առաջինը հետագայում ցույց է տալու օձի շարժման ուղղությունը, երկրորդն ու երրորդը՝ երևակայական տախտակի վանդակի չափսերը, վերժինը՝ ինչպես կարելի է կռահել անունից, օձի երկարությունն է և սկսբնարժեքավորած է 5: snposx և snposy փոփոխականներում պահված է օձի գլխի տվյալ պահի կոորդինատները տախտակի վրա: Օձը իրենից ներկայացնում է Rectangle դասի մասիվ:
С#-ում static մոդիֆիկատորը նշանակում է, որ static հայտարարված փոփոխականը/ֆունկցիան/օբյեկտը/և այլն հասանելի է առանց այդ դասի նմուշ (instance) ստեղծելու: Այլ կերպ ասած, դասի static անդամները ստեղծվում են ծրագրի աշխատանքի սկսվելուց: Ահա թե ինչու Main ֆունկցիան միշտ հայտարարվում է static: Application.Run(new Snakes()) դիմումով Snakes-ի կառուցիչով ստեղծվում է Form և այն բերվում է էկրան: Ավելի ծավալուն ու հետաքրքիր է Snakes-ի կառուցիչը: Այստեղ արժեքավորվում են Form դասի որոշ Property-ները: Property-ն նորամուծություն է C#-ում և ինչ-որ միջին տեղ է զբաղեցնում ֆունկցիայի և անդամ-փոփոխականի միջև: Նրանում կարելի է ստանդարտ set և get ֆունկցիաներ սահմանել, որոնց միջոցով կարելի է կատարել մուտքագրվող տվյալների ստուգում: Form.Text-ում պահվում է Form-ի վերնագիրը (caption),  Form.Width ու Form.Height-ը Form-ի (ուշադրությու՛ն Form-ի, և ոչ թե դրա Client Area-ի): Form.ResizeRedraw-ի true լինելու դեպքում պատուհանի չափերը փոխելուց կանչվում է OnPaint ֆունկցիան (այն կքննարկենք մի փոքր ուշ):  Ի միջի այլոց նշեմ, որ C#-ը լիովին ապահովում է Unicode-ի նորմալ արտածումը, այնպես որ առանց խուսափելու կարելի է հայերեն, ռուսերեն և ցանկացած լեզվով տեքստ օգտագործել որպես սիմվոլային տողեր, ինչպես նաև որպես իդենտիֆիկատորներ .CS ֆայլերում: Այնուհետև մեր դասի կառուցիչում արժեքներ ենք վերագրում fieldsize-ին: Հաշվի առնելով դրա արժեքը, հաշվում ենք ifieldx, ifieldy-ը: Արժեքներ ենք վերագրում նաև Snake-ի էլեմենտներին: Ուշադրություն դարձրեք օրինակ
(snposx — 4) % fieldsize * ifieldx  արտահայտությանը: Այն ավելի մանրամասն կքննարկենք հաջորդ մասերում, երբ կփորձենք շարժել մեր օձին: Սա թույլ չի տալիս, որ օձը դուրս գա մեր ցանցից: Երբ, օրինակ, այն դուրս է գալիս ցանցի աջ կողմից, դրա գլուխը հայտնվում է ցանցի ձախ կողմում: Մասիվի վերջին երեք էլեմենտները պահեստային կարգավիճակում են: Մեր օձը խաղի ընթացքում, ըստ մտահղության, բոյովանալու է J:
Եվ վերջապես քննարկենք OnPaint գերբեռնված ֆունկցիան: Այն ամենը, ինչ GDI+-ի միջոցով նկարելու ենք էկրանին, նկարելու ենք այստեղ: Գրաֆիկական սարքին դիմելու համար ստեղծում ենք Graphics դասի օբյեկտ, որը փոխանցվում է OnPaint ֆունկցիային արգումենտի տեսքով: Սրան հաջորդող հայտարարված սև Pen-ով գծելու ենք ցանցը: snakeb Brush-ով  ներկելու ենք օձի մարմինը կազվող Rectangle-ները: GDI+-ում կա ստանդարտ, նախապես որոշված 141 ARGB գույն (բացի սիստեմային գույներից), դրանք բոլորը հասանելի են որպես Color դասի Property-ներ: Մեկնաբանությունների մեջ առնված երկու տողերը միացնում են AntiAliasing-ը: Պիքսելների մշակման այս մեթոդը լայնորեն կիրառվում է վեկտորական գրաֆիկայում և midtone-ների միջոցով ավելի հարթ ու հղկված է դարձնում վեկտորական պատկերների եզրերը: Եթե Ձեր համակարգիչը բավականին հզոր է, կարող ես միացնել AntiAliasing-ը և տեսնել տարբերությունը:
Հաջորդող 2 for ցիկլերում նկարվում են ցանցի նախ ուղղահայաց, հետո հորիզոնական գծերը: Ուշադրություն դարձրեք, որ GDI+-ում գիծ գծելու համար անհրաժեշտ է միայն մի ֆունկցիայի դիմում: Վերջին մեթոդը ներկում է Snake մասիվի տարրեր հանդիսացող Rectangle-ները, դրանով տեսանելի դարձնելով մեր օձը: Արդյունքում պետք է ստանաք նման մի բան.

Համոզվելպւց հետո, որ օձը կանգնած է ճիշտ տեղում, ունի ճիշտ գույնը և երկարությունը, կարելի է մաքրել ցանցը պատկերող կոդը, քանի որ այն այլևս մեզ պետք չի գա:
Շարունակելի…

Մեկնաբանություններ (2)

Filed under Ծրագրավորում