Skript for turbasert strategi. Utvikle en strategi steg for steg. Hovedstadier i å lage en strategi

Hei alle sammen! Nå skal jeg fortelle deg hvordan du lager en enkel RTS (RTS - Real Time Strategy, det vil si en sanntidsstrategi) åpner en hengekøye 8.1 (operabilitet er ikke garantert på 8.0) lag et objControl-objekt, det vil si at dette blir hovedobjektet vårt, opprette en opprettelseshendelse ( Opprett) Legg til hendelse => Oppretting (Legg til hendelse => Opprett) opprettelseshendelsen gjøres kun én gang - når du oppretter, klikker du på kontrollfanen i høyre vertikal meny og høyreklikker på Utfør kode (utfør kode) og skriv koden (det er best å ikke kopiere kode, og å skrive den selv gjør det mye lettere å huske):

200?"200px":""+(this.scrollHeight+5)+"px");">startx=0; //Deklarer en variabel for startpunktet til x
starty=0; //Deklarer en variabel for begynnelsen av punktet ved y
draw_rect=false; //Ikke tegne et utvalgsrektangel


Variabel: Et minne som inneholder informasjon. De har sitt eget navn som du kan kontakte dem med. Variabler i GML kan inneholde et reelt tall eller en streng. For eksempel er et bord en variabel, tre eller glass er en verdi
Nå lager vi en trinnhendelse (Step, Add Event => Step) og utfører operasjonen på nytt (høyreklikk på Utfør kode):

200?"200px":""+(this.scrollHeight+5)+"px");">
if mouse_check_button_pressed(mb_left) //Hvis LMB er trykket
{
draw_rect=true; //Vi tegner et rektangel
startx=mus_x; //Start x posisjon = mus x posisjon
starty=mus_y; //Startposisjon = museposisjon
med alle valgt=false; //Dette er ennå ikke en deklarert variabel, vi vil finne ut hva den vil gjøre senere
}

If mouse_check_button_released(mb_left) //If LMB slippes
{
draw_rect=false; //Vi tegner ikke et rektangel
for(i=0;i<=instance_number(par);i+=1) //Читайте про цикл for ниже
{
ii=forekomstfinn(par,i); //Vi ser etter en gjenstand som ennå ikke er laget
if(collision_rectangle(startx,starty,mouse_x,mouse_y,ii,true,false)) //Her er vårt kollisjonsrektangel (kontakt)
{
ii.selected=true;
}
}
}

Koden er stor og kompleks mens vi lærer om den betingede setningen:
Koden med if utføres slik:

200?"200px":""+(this.scrollHeight+5)+"px");">
hvis (tilstand)
{
handling
}

Den kan også inneholde en else-setning (ellers), eksempel:

200?"200px":""+(this.scrollHeight+5)+"px");">if (tilstand)
{
handling
}
ellers
{
handling 2
}

Og for er en loop-operator, utføres den slik:

200?"200px":""+(this.scrollHeight+5)+"px");">
for (<переменная> ; <выражение> ;<действие переменной>)
{
<действия>
}


For-operatøren er en veldig kraftig ting, den hjelper mye i vanskelige situasjoner

Operator - handlinger innebygd i et språk, for eksempel, de vanligste er int, if, else, string, switch, for, case, break, exit, etc., etc., etc.

Nå lager vi også en tegnehendelse (tegning) og skriver på samme måte:

200?"200px":""+(this.scrollHeight+5)+"px");">hvis draw_rect=true
{
alfa=0,8;
tegne_rektangelfarge(startx,starty,mus_x,mus_y,c_grønn,c_grønn,c_grønn,c_grønn,true);
}

Alt er enkelt her, her er det samme bare på russisk:
hvis vi trenger å tegne et rektangel, velger vi gjennomsiktighet og tegner et rektangel
her er argumentene

200?"200px":""+(this.scrollHeight+5)+"px");">draw_rectangle_color(x1,y1,x2,y2,farge 1, farge 2, farge 3, farge 4, omriss)


disposisjon - om bare kanten (sann) eller det fylte rektangelet (false) vil bli tegnet
Vi fant et nytt ord - konstant, dette er et numerisk uttrykk eller kode erstattet med et ord, hengekøyen har innebygde konstanter:

200?"200px":""+(this.scrollHeight+5)+"px");">sant - 1
usant - 0
pi - 3,1415...


Vel, vi fant det ut, nå må vi skape nytt objekt- et overordnet objekt som vil knytte seg til barna sine. La oss kalle det par (for å endre navnet må du endre koden i kontrollobjektets trinnhendelse), skriv i opprettelseshendelsen:

200?"200px":""+(this.scrollHeight+5)+"px");">selected=false; //Her er variabelen vår, om objektet er valgt

Dette er alt. Nå trenger vi selvfølgelig et objekt som kan bevege seg, vi kaller det objTest, og skriver koden i opprettelseshendelsen:

200?"200px":""+(this.scrollHeight+5)+"px");">gox=x; //Hvor skal jeg dra...
goy=y; //av y
valgt=false; //Vi er ikke valgt =)
object_set_parent(self,par) //Her er valget av forelder

Ny handling:

200?"200px":""+(this.scrollHeight+5)+"px");">object_set_parent(ind,obj)

Setter det overordnede objektet til objektet kalt ind.
OG ny operatør: selv, betyr det at handlingen vil gå til seg selv
Ikke vær redd, det er fortsatt litt igjen i step-arrangementet:

200?"200px":""+(this.scrollHeight+5)+"px");">hvis avstand_til_punkt(gox,goy) > 20
{
mp_potential_step(gox,goy,6,solid);
}
if(selected=true) && mouse_check_button_pressed(mb_right)
{
gox=mus_x;
goy=mus_y;

temapark:
Jeg trenger:
bygge sprite
sprite meny
SPRITES AV ULIKE KNAPPER SLIK:
skriv med inskripsjonen (konstruksjon, konstruksjon, bygg osv.)
et vindu som vises
byggetegning,
1) vi legger til resten selv
2) ordet falsk - skapt av meg selv, fordi vi må forfalske den for å matche kilden vår)
IILla oss komme i gang:
1) lag alt som er skrevet i punkt I unntatt 1)
La oss lage en global variabel kalt penger, angi et hvilket som helst innledende pengebeløp
Vi vil også lage et mus- og tastaturobjekt
La oss lage en tekst, kalle den info, lage en alltid-hendelse og lage en handling i den:
velg info i handlingsvalget velg sett tekst i teksten skriv dette:
"penger: " &(global("penger".
2) legg til en meny, hovedoppgaven til menyen er ikke å forstyrre, men å hjelpe spilleren med å navigere (hvordan kan det forstyrre? - det er enkelt hvis du plasserer det midt i spillet); før vi lager menyen, vil lage et nytt lag, som vi kaller menyen, i dets proporsjoner (innstillinger, alternativer) i visningselementet vi skriver:


vi vil legge til en sprite i den og ta bildet av menyen som var i pre-produksjonsmaterialet (punkt I) og plassere menyen vår på et bortgjemt sted hvor den ikke vil forstyrre, men vil være synlig på skjermen
La oss også plassere en knapp laget av pre-finishing materialer (punkt I) med påskriften BUILD (eller noe sånt)
la oss sette det på menyen
Gå nå til Event Sheet Editor
opprett en hendelse (#blah blah blah# - dette er min melding (forklaring) til deg bare i stedet for blah blah blah vil det være min kommentar for deg; >> - handling; ll - inndeling av vinduer for eksempel:

mus og tastatur ll på objektet klikket ll venstreklikket til objektet #menyknappen din med inskripsjonen BYG (eller noe sånt)##resten senere (se punkt 3)#
3)nå den vanskeligste delen(Jeg delte dette opp i to punkter så det ikke skulle være så komplisert),
lag en sprite fra pre-finishing materialer "et vindu som vil dukke opp"
så lager vi en tom sprite kalt p1, flytter vinduet fra skjermen, og setter p1 på stedet der vinduet ditt skal vises når du trykker på byggeknappen (eller noe sånt CHVER)
flott! Gå nå til redigeringsprogrammet for arrangementsark
La oss skrive ned den uferdige hendelsen til slutten:
Tekst ll sett tekst ll bla-bla-bla)
mus og tastatur ll på objektet klikket ll venstreklikket til objektet #menyknappen din merket BYGG (eller noe sånt)#>>
4)Den andre delen av den vanskeligste delen:
la oss lage en sprite der bildet av bygningen (pre-finishing materialer) skal tegnes, la oss kalle det h1
la oss lage en tom sprite, kall den p2, plasser den nå på stedet der vinduet skal åpnes,
La oss lage en sprite, også et vindu (pre-finishing materialer), i vinduet vil vi vakkert skrive navnet på bygningen, dens pris og beskrivelse (valgfritt) og kalle det i1
la oss lage en annen tom sprite kalt p3, plasser den ved siden av p2, bare slik at den bare berører p2 med det øvre venstre hjørnet
La oss nå lage flere hendelser, men først gjør vi den forrige hendelsen til en ny handling:
mus og tastatur ll på objektet klikket ll venstreklikket for å objekt #knappen på menyen din med inskripsjonen BUILD (eller noe sånt)#>> system ll opprette objekt i forhold til objekt ll #dittvindu# #lagnummer under navnmenyen# # X ;Y-ikke endre# til objekt p1
>>system ll opprette objekt i forhold til objekt ll #ditt andre vindu# #lagnummer under navnemenyen# #X;Y-ikke endre# til objekt p2
Vi må også gi ham en begivenhet tilbake:
kopier hendelsen og inverter den
nytt arrangement
mus&tastatur ll er over objekt ll h1>>system ll opprette objekt til i forhold til objekt ll i1 #lagnummer under navnemenyen# #X;Y-ikke endre# til objekt p3
La oss lage en sprite med en bygning (bruk pre-produksjonsmaterialer) og kalle det hus
La oss lage et vindu der bygningene våre vil vises når de er valgt i menyen, kall det rlo
arrangementer:
mus&tastatur ll på objekt klikket ll venstreklikket til h1>>system ll opprette til objekt i forhold til objekt ll hus #lagnummer under navnemenyen# #X;Y-ikke endre# til objekt rlo
>> systemet vil trekke fra verdien ll #pengebeløp som bør tas bort under bygging#
Nå var det umulig å bygge et arrangement
Jeg skal fortelle deg min tidligere måte forbud (når jeg er ferdig med å skrive, vil jeg utforske en annen metode som gjorde meg blå da jeg husket temaparkens verdensspill)
arrangementer:
hus ll på kollisjon med et annet objekt ll til hus
>>hus vil ødelegge
>> system vil trekke fra verdi ll - #doble beløpet som ble tatt bort under byggingen##merk at du må legge inn - mengde#
stort sett alt.
III hva jeg vil si:

Jeg var veldig opprørt over kollapsen av spillet mitt. Det var et strategispill, og denne artikkelen ble satt sammen i henhold til oppsettet. Jeg ber deg om ikke å kritisere for mye, skrev jeg lenge, hvis du finner noen talefeil, skriv så skal jeg rette dem
og også her er kildekoden for seergleden din, se, i prinsippet er alt det samme som det er skrevet her, bare dette var en demoversjon av spillet. Det viktigste er å ikke endre noe, ellers blir det buggy !
bruk det, eksperimenter, sjekk det, gjør hva du vil, det er greit for meg

KaMiKaZa:
Alle «system»-uttrykk må inkluderes i «Code»-taggen.
Da tror jeg det blir bedre.
Dessuten ser det ut til at skjermbilder ikke ville skade her. Og også kildekoden, for nybegynnere.

temapark:
Jeg vet ikke hvordan jeg skal ta skjermbilder av hendelser.

Vel, det er ikke nødvendig.

iamnp:
theme_park , det er en spesiell knapp på tastaturet - PrintScreen

temapark:
Jeg vet at noen mennesker bare gjør det annerledes. Dessuten har alle sin egen sprite
og hvis jeg setter opp alle disse sprites, vil få mennesker forstå.
Vel, kanskje noen vil gi et pluss? Ikke rart jeg slet?

burlachenko:
For at en slik leksjon skal være interessant for noen, må den formateres deretter, men her "var det i alle fall."
Og likevel, hvis du vil, litt om gangen, når du har tid, vennligst "forskjønne" det.

temapark:
ok, jeg kommer hjem fra skolen og gjør meg klar.
PS. lagt til kilde

Serega Lebedev:

iamnp, hvor blir disse skjermbildene av senere?

KaMiKaZa:

Til utklippstavlen.
Gå til hvilken som helst tekstredigerer, og utfør "Lim inn"-operasjonen, eller trykk Ctrl+V.

I denne artikkelen kommer jeg neppe til å berøre noe ukjent. Alle beregninger er enkle og forståelige for alle som vet hva Ajax er. Jeg har allerede skrevet en artikkel om hvordan man kombinerer en klient med en server i sanntidsspill (). I denne artikkelen tar jeg for meg de samme problemene som de gjelder for turbaserte spill.

Så hva er turbasert spill? Følgende definisjon finner du på Wikipedia turbasert strategi - dette er en sjanger dataspill, hvor hovedtrekket er at spillere bytter på å gjøre trekk, i motsetning til sanntidsstrategi. Jeg vil forenkle denne definisjonen litt:

  • Steg-for-steg strategi - er et turbasert strategispill.
  • Strategispill - Dette er en sjanger med spill der nøkkelen til å oppnå seier er planlegging og strategisk tenkning..
  • Turn-basert spill - er en sjanger med spill hvis hovedtrekk er at spillere bytter på å gjøre trekk.
Turn-baserte spill inkluderer:
  • Turn-baserte strategier
  • Kortspill
  • Brettspill (sjakk, go, monopol, etc.)
Jeg legger merke til at turbaserte spill legger færre begrensninger på kompleksiteten til interaksjonsprotokollen sammenlignet med sanntidsspill. Nemlig reaksjonstid på en bestemt hendelse spiller ingen nøkkelrolle. Spilleren får vanligvis 10 sekunder på seg til å ta en avgjørelse. Selv om pinget er gigantisk, si 3 sekunder, så har spilleren fortsatt 7 sekunder på seg. I tillegg kan pingen hoppe og hoppe, men vi bryr oss ikke om dette i det hele tatt (i sanntidsspill dreper denne situasjonen praktisk talt enhver protokoll).

Vanligvis (i 95 % av turbaserte spill) tar nøyaktig én spiller avgjørelsen til enhver tid. Følgelig er antallet forespørsler som vi må svare tilstrekkelig på, redusert.

Derfor, når vi oppretter en protokoll, vil vi først og fremst fokusere på den enkle implementeringen og støtten. Dette vil tillate oss å tjene mer på kortere tid.

Resonnementet ovenfor er basert på 2-måneders utvikling av et bestemt kortspill.

Smart eller dum klient?

Først, la oss bestemme hvor "smart" vår klient kan være. Jeg diskuterer om det er verdt å duplisere applikasjonslogikken (spillereglene) på klienten. Selvfølgelig må serveren være smart for å forhindre potensiell hacking av applikasjonen. Men er det verdt å lære kunden forretningslogikk?

Dette avhenger direkte av hvor mye hele mengden data om spillets tilstand veier. Hvis denne datamengden er stor, tar lang tid å samle på serveren og overføres til klienten, er det fornuftig å implementere en del av logikken på klienten for å avlaste serveren. For eksempel, i Civilization er minnemåleren som brukes alltid utenfor kartene. Kan du lage noe lignende, og la bare brukergrensesnittet være igjen på klienten?

På den annen side, jo smartere klienten er, desto dyrere blir spillutviklingen. La meg merke seg at serverutviklingstiden ikke på noen måte avhenger av klientens lærdom. Selv om klienten er super-duper-mega smart, hvis brukeren ønsker å laste nettleservinduet på nytt, vil serveren måtte samle inn og samle all data om spillet for å overføre det til klienten. A la "Laster et lagret spill". Konklusjon: En smart klient kan få fart på en applikasjon, men det vil alltid kreve ekstra ressurser for å utvikle applikasjonen.

Jeg foreslår følgende test:

1. Tillater kanalvolumet?

Estimer gjennomsnittsvekten av hele mengden spillstatusdata. Deretter multipliserer du med gjennomsnittlig antall forespørsler til serveren per sekund. Hvis det resulterende antallet overskrider den utgående datakanalkapasiteten, er den dumme klienten uakseptabel. Hvis dette tallet overstiger 20 % av den utgående kanalen, bør du tenke på om det vil fungere?

2. Er det arbeidskrevende?

Estimer kompleksiteten til spilldatainnsamlingsalgoritmen (i brøkdeler av et sekund). Her må du ta hensyn til alle forespørsler til databasen. Deretter multipliserer du med gjennomsnittlig antall forespørsler til serveren per sekund. Hvis tiden overstiger ett sekund, er en dum klient uakseptabel. Hvis dette tallet overstiger 200 ms, bør du tenke på om det vil vare?

Fortsettelse:

Dannelse av strategi
Du kan ikke stole på amatører:
planene deres kan uventet gå i oppfyllelse,
og ingen er klar for dette.

(A. Cuningham)

I de to foregående utgavene lærte vi lage enkle 2D-spill, kontroller sprites, rull gjennom spillskjermen, spor kollisjoner av spillobjekter, bygg et grensesnitt (knapper, mus, tastatur, tekstområder) og arbeid i fullskjerm- og vindusmodus. Alt dette ble gjort ved å bruke et arkadespill som eksempel.

Denne gangen vil vi gå fra arkadespill til en mer "seriøs" sjanger - strategier. Her må vi mestre en hel rekke nye mekanismer, men det vil ikke være noe komplisert her heller. I denne artikkelen har vi La oss studere strukturen til en turbasert strategi(og også sanntidsstrategi- det er enda enklere å gjøre det med LKI-Creator), og vi lager et spill som et eksempel, men designet kun for flerbruker modus (og også kartredigerer for henne). Vi vil ta for oss enkeltspillermodusen i neste utgave av spalten vår - dedikert til grunnleggende kunstig intelligens .

Siden dette allerede er den tredje leksjonen, vil vi ikke gå i detalj alle eksempelkode - heldigvis har mye blitt gjort akkurat det samme som de to foregående gangene. For referanse er det et eksempelprogram (det er mange kommentarer i det) og tidligere artikler.

Vel, du kan finne materialet fra våre tidligere klasser på vår CD, i «Gjør det selv-spill»-delen spesielt laget for dette formålet.

Formulering av problemet

La oss skrive et strategispill som består av en kamp mellom to fantasihærer. Målet med kampen er å fange flere obelisker, plassert på kartet. Før slaget utplasserer vi troppene våre, bestående av 6 sverdmenn, 4 bueskyttere, 2 riddere, 2 magikere og 1 spøkelse, innenfor det territoriet som er tildelt oss. I tillegg til dem er det nøytrale på kartet drager.

Kjennetegn på jagerfly
Jagerfly Bevegelse Treffer Område Skader Beskyttelse Evner
Swordsman4 8 1 7 2 -
Bueskytter4 5 7 5 1 -
Ridder3 15 1 9 4 Healing, Knight's Strike
trollmann3 12 5 6 0 Brannkule
Spøkelse4 7 2 5 5 Regenerering
Dragen6 30 2 12 5 Flygning

Egenskapene til jagerflyene er presentert i tabellen. Behandling- dette er retten til å helbrede en nabokriger (unntatt et spøkelse) til full helse én gang per kamp. Knight's Strike- Retten til å påføre trippel skade én gang per kamp. Brannkule- Magikerens angrep fjerner treffpunkter ikke bare fra det umiddelbare målet, men også fra omkringliggende firkanter. Regenerering- gjenvinning av 1 treff per sving. Flygning- retten til å bevege seg over hindringer.

Spillet spilles i flerspillermodus, i Hot Seat-versjonen (spill fra én datamaskin, blir én om gangen). Etter at spillerne snur seg, gjør nøytrale drager sin tur, og angriper enhver fiende innenfor en radius på 7 celler.

Festen avsluttes når den ene siden enten fanger mer enn halvparten av obeliskene på kartet eller dør fullstendig.

Kartet ble opprinnelig satt i kartredigereren. Det er obelisker, drager og hindringer (gjenstander du ikke kan bevege deg gjennom eller angripe).

Forbereder til arbeid

Før vi starter, må vi installere pakken på nytt LKI-Creator. Faktum er at det er gjort mange endringer og tillegg i forhold til forrige gang.

(Jeg håper at Delphi du allerede har installert; Hvis ikke, les anbefalinger om dette emnet i vår forrige artikkel - i juniutgaven av magasinet eller på CD-en til denne utgaven eller på nettstedet.)

Det er viktig: den forrige versjonen av LKI-Creator hadde noen kompatibilitetsproblemer med nye versjoner av Delphi. I denne versjonen er de eliminert.

Ta filen med programtekster og bilder fra vår CD (avsnittet "Spill med egne hender") og pakk den ut i prosjektkatalogen.

Nå kan du laste ned nødvendige filer herfra .

Vi bør ha tre underkataloger. One - Units - lagrer DirectX-biblioteker og moduler av LKI-Creator-pakken. I et annet – Prosjekt – skal vi jobbe; bildene som vi trenger er plassert der på forhånd, og forrige versjon arkaden vår. I det tredje - Escort - et ferdig program som vi skal lykkes med.

La oss nå installere (installere på nytt) LKI-Creator. I Delphi-menyen åpner du komponenten og velger Installer komponent. Hvis du allerede har installert denne pakken, hold deg på Inn i eksisterende pakke-fanen, ellers gå til Into new package-fanen og fyll ut de tomme linjene som vist på figuren (i den øverste linjen er den enkleste måten å velge LKI2dEngine. pas-fil ved å bruke Bla gjennom-knappen, og skriv ned LKI nederst. Klikk deretter OK og velg Installer. I topppanel Delphi bør du se LKI-fanen.

Nå gjenstår det bare å laste opp prosjektet vårt. I Fil-menyen, velg Åpne, åpne filen Project\Obelisk.dpr...

Hvor er kartet, Billy? Vi trenger et kart!

Men før vi kommer inn på de store tingene, må vi jobbe litt mer med grafikkmotoren.

I Star Escort, vårt forrige prosjekt, hadde "kartet" ingen betydning: stjernene ble plassert tilfeldig og påvirket ingenting, og posisjonen til andre objekter ble enten spesifisert direkte i koden eller bestemt ved en tilfeldighet. Dette er ikke egnet for alle prosjekter. Dette betyr at det er på tide for oss å legge til motoren vår områdekart.

Du kan sikkert allerede gjette hvordan det vil se ut - vi legger et kartobjekt på prosjektvinduet, og registrerer det så i eiendommen Kart motoren vår.

Sånn er det... men vi har mer enn én klasse kort. La oss ta en nærmere titt...

Typer kort

Kartet består av noe landskap Og gjenstander installert på den. Landskapet er oftest (men ikke alltid) delt inn i celler kalt fliser- fliser.

Som vi vet fra et skolegeometrikurs, kan et plan dekkes uten hull eller overlapp med vanlige polygoner av tre typer: trekant (likesidet), firkant, sekskant. Trekantede felt er ikke spesielt praktiske, så kvadratiske celler eller sekskanter brukes oftere.

På en måte er det lettere å leve med firkanter: hvis vi har en todimensjonal rekke celler, er det umiddelbart klart hvordan man finner cellene ved siden av en gitt celle. Disse er +1 og -1 for hver av de to indeksene. Med sekskanter er alt litt mer komplisert... men det sekskantede brettet har en veldig verdifull egenskap: alle retninger i den er like. Dette er ikke tilfellet med et firkantet rutenett: diagonalene er vesentlig forskjellige fra horisontale og vertikale. Derfor, for seriøse strategiske beregninger, kan sekskanter være bedre enn kvadrater.

Det finnes også kort uten fliser. LKI-Creator støtter to typer: graf og lappeteppe.

Et grafkart er et kart der bare noen få nøkkelpunkter har betydning, pluss kanskje spesielle områder (for eksempel ufremkommelige), og resten er bare et mønster som ikke har noen spilleffekt. Slik lages ofte stjernekart, som i for eksempel Master of Orion: stjerner og sorte hull er nøkkelpunkter, resten er bakgrunn. I denne modusen lager de noen ganger globale kart, for eksempel for et rollespill.

Patchwork-kartet er delt inn i områder, og innenfor området er alle punktene like; du kan ikke bevege deg langs "patchworket". Dette er bra for globale strategier, der en provins er minimumsenheten for territorium.

Eksempler på kort fra ulike spill, som indikerer typen, er på bildene.

Så flertallet todimensjonal kart (tredimensjonale - en spesiell artikkel) kan deles inn i fire klasser:

  • Rektangulær- TLKIRectMap. Dette er et flislagt kart, cellene er firkanter. Et slikt kart, for eksempel i Civilization III.
  • Sekskantet- TLKIHexMap. Flislagt kart med sekskantede celler. Brukt i mange krigsspill, og ikke bare: dette er for eksempel hvordan kampkartet Heroes of Might & Magic tradisjonelt ble laget.

    Disse to typene kort er etterkommere av den generelle klassen TLKITileMap.

  • Graphovaya- TLKIGraphMap. Dette kortet har bakgrunn (bakgrunnsegenskap) og nøkkelpunktene som er uthevet på den er statiske objekter. Plasseringen til andre objekter på dette kartet uttrykkes enten ved vanlige koordinater (som et romskip i interstellart rom) eller ved referanse til et objekt (det samme skipet i bane rundt en planet). Dette er kortene Master of Orion, Arcanum (global) og så videre.
  • Lappeteppe- TLKIClusterMap. Den har en bakgrunnsegenskap, som grafen en, og en andre egenskap - maske, som bestemmer hvilket punkt som tilhører hvilken region, og eiendommen Grenser, som definerer forbindelsene mellom "shreds". Slik er kart ordnet, for eksempel i middelalderen: Total krig eller Victoria.

Det er viktig: kartklasser er ikke beskrevet i LKI2dEngine-modulen, men i LKI2dMap.

Vippevinkler

Men hvis du tror at dette uttømmer mulighetene til LKI-Creator for å vise kart, så tar du veldig feil.

Kartet kan presenteres ovenfra eller isometrisk- se i en vinkel til vertikalen. For eksempel er kartet over Civilization III eller Heroes of Might & Magic IV isometrisk, men Civilization I har en ovenfra-ned-visning.

Vanligvis brukes isometri for flislagte kart, mens grafkart brukes med toppvisning, siden skalaen til grafkart vanligvis er mindre. Men det er unntak: for eksempel i Medieval: Total War er det et lappeteppet isometrisk kart.

Kartegenskapen er ansvarlig for isometrisitet Isometrisk og to parametere som angir vinkelen som kameraet vårt ser på: Phi Og Theta.

Den første er ansvarlig for rotasjonen av kartet i forhold til den vertikale aksen: hvis du for eksempel setter den til 45 grader (det måles i grader), vil den rektangulære rutenettcellen være orientert med en oppadgående vinkel, som i Civilization . Ved Phi=0 vil en av sidene av cellen være horisontal.

Den andre kontrollerer kameraets tilt i forhold til vertikalen. For enkelhets skyld er det gitt som forholdet mellom horisontale og vertikale lengdeenheter. La oss si at hvis vi vil at cellen vår skal tegnes halvparten så høy som den er bred, må vi sette Theta til 2.

Med et flislagt kart har vi ikke lov til å velge disse vinklene vilkårlig: vi har tross alt (ennå) ikke 3D. De avhenger direkte av parametrene til flisene. For eksempel, hvis vi har en diamantformet akse med en oppadgående vinkel, og den vertikale aksen er halvparten av størrelsen på den horisontale aksen, må vi sette parameterne 45 og 2.

Men graf- og lappekart gir deg rett til å tildele disse parameterne som du vil (og til og med, om ønskelig, endre dem i prosessen), men du bør ikke la deg rive med av dette - i tillegg til at slike svinger tar en mye tid, de ser heller ikke veldig kule ut. Og ikke glem at hvis kartet ditt er kunstnerisk, med bilder, inskripsjoner, osv., så vil de snu med det... Generelt er det noen ganger lettere å tegne et lappeteppekart som tar hensyn til den nødvendige rotasjonen - heldigvis avstander spiller ofte ingen rolle der.

Ledd

Patchwork kart, sett ovenfra.

Flisekart har et annet problem - flissammenføyning. Den styres av parameteren TileBorderStyle. Oftest dette flisRett, en modus der flisene ganske enkelt passer sammen uten noen kanteffekter, eller tileBorder, der linjer er tegnet som skiller en flis fra en annen - cellegrensene (i sistnevnte tilfelle, ikke glem å definere farge gitter i parameter TileBorderColor).

Men det er et mer utspekulert alternativ, når identiske fliser er ved siden av hverandre uten endringer, og forskjellige brukes ved å bruke en spesiell "overgangs" flis. Dette gjøres vanligvis hvis kartet hovedsakelig består av brede vidder av en type territorium, for eksempel store grønne områder, og en individuell celle ikke er viktig og ikke bør legges merke til av spilleren. Dette er Heroes of Might Magic-kortet. Men hvis hver celle behandles separat, som i Civilization, er denne metoden ikke egnet, og det er bedre å tydelig skille cellene fra hverandre. "Fused" teknologi (også kalt maske) spesifiseres av TileBorderStyle-verdien lik tileMasket. Vi vil snakke om strukturen deres en annen gang - dette er et ganske komplekst emne.

Tile

Kartelement - klasseobjekt TLKITile- har en enkel struktur. Den inneholder i utgangspunktet: koordinater, spriten som tegner den, flistypekoden (som bestemmer hva vi har her - en bakke, ørken, vei, hav?) og langrennsevne (dette er relevant i de fleste spill). Den siste er antall flytteenheter som brukes på å bevege seg gjennom denne flisen land troppen. For ufremkommelige fliser er dette et negativt tall.

En annen parameter - Objekter, en liste over objekter som ligger på denne flisen (skriv TLKIGameObject).

For å finne ut hvilken celle som ble klikket på, har kartet en metode Museflis(x,y) returnerer den valgte flisen.

Tile metoder inkluderer Er Nabo(Fliser, Avstand). Denne funksjonen returnerer sann hvis flisen ikke er mer enn avstandsceller unna den gitte flisen (som standard er denne parameteren lik én, det vil si at hvis du bare skriver IsNeighbour(Tile), vil funksjonen returnere sant for flisen rett ved siden av til den gitte flisen. For et firkantet rutenett regnes de flisene som grenser diagonalt også som "naboer".

Funksjoner FirstNeighbour Og Neste Nabo brukes til å sjekke alle celler ved siden av en gitt. Den første av dem peker på en nabocelle, og den andre kan bare ringes etter å ha ringt den første, og den gir ut de neste naboene, en om gangen.

Oppregning av naboer

// Gjør skade på en celle

fremgangsmåte TObeliskTile.Damage(dmg: heltall);

hvis(Objects.Count > 0) og// Vi har kanskje

// ikke mer enn ett objekt per celle

(Objekter.ID > 0) // Passive objekter

// ikke skadet

des(Objects.Hits,

// Trekk automatisk fra beskyttelse mot skade

Max(0,dmg-(Objekter som TObeliskGameObject).Forsvar);

hvis Objekter.Hitsthen Die; // Vi fjerner de døde

// Ildkuleangrep

fremgangsmåte TObeliskTile.Fireball;

var Nabo: TObeliskTile;

Nabo:= FirstNeighbour som TObeliskTile;

Nabo.Skade(6);

Neighbor:= NextNeighbour som TObeliskTile;

før Nabo = null; // Helt til naboene går tom

Et eksempel er i sidefeltet "Tælle opp naboer". Denne prosedyren beregner ildkulen som treffer en celle og alle dens naboer.

Dette er interessant: for hennes arbeid det spiller ingen rolle i det hele tatt, vi har et sekskantet gitter eller et kvadratisk.

Ofte trenger vi noen andre parametere, og vanligvis klassen av fliser som utgjør kartet - etterkommer TLKITile. Så i eksemplet - TObeliskTile er arvet fra TLKITile.

Det er viktig: Hvis vi tar med et flislagt kart inn i spillskjermen vår, vil koordinatene, så vel som de avstandsrelaterte TLKIGameObject-metodene, som standard begynne å måle avstand i fliser i stedet for poeng. Koordinatene til knapper, ikoner osv. fortsett å bli målt i piksler! Men denne modusen kan slås av - dette kan være nyttig for sanntidsstrategier.

Velge et kort

Så la oss starte med et rektangulært gitter (TLKIRectMap), en isometrisk kartlegging (vinkelparametere 0, 1,5). La rutenettet tegnes (tileBorder-stil). La oss fortelle motoren at dette spesielle kartet skal vises. Så langt har alle nødvendige handlinger blitt fullført uten å skrive en eneste kodelinje.

Disse operasjonene må gjøres før motorinitialisering, samt skriftdeklarasjon.

Vi vil erklære figurene, som før, som sprites.

Kartredaktør

Patchwork kart, isometrisk.

Det er ganske mange vanskeligheter her. Nøyaktig den samme motoren, de samme flisdeklarasjonene... Grensesnittet, som å velge en flis, lasting/lagring osv., kan enkelt gjøres standard betyr Delphi: ingen tvinger oss til å bytte den til fullskjermmodus. Vi vil ikke analysere dette her - alt er i eksempelfilen. Eksempelkoden er bevisst brukt den enkleste måten; Om ønskelig kan du for eksempel gjøre objektpaletten og flispaletten grafisk.

Redaktøren har bare to funksjoner som er ukjente for oss. Den første er ganske enkel: det er den ny funksjon en mus designet spesielt for flislagte kart. Funksjon TLKIRectMap.SelectTile returnerer en peker til den eksakte flisen som ble klikket på, slik at vi enkelt kan håndtere klikket.

Men det andre nye produktet fortjener mer nøye vurdering.

Faktisk er det mange måter å lagre data til og lese data fra den. Vi valgte metoden som er kodet i filen CannonBase. Cannon er et verktøy for å lese og skrive etterkommerobjekter TCannonObject med typekontroll og noen andre funksjoner.

La oss se på koden ("Skriv kort").

Ta opp et kort

fremgangsmåte TObeliskMap.Save;

var i,j: heltall;

InitSave(FName);

WriteStr(Kartnavn);

Write(Map.Width, SizeOf(Map.Width));

Write(Map.Height, SizeOf(Map.Height));

til i:=0 til Kart.Bredde-1 gjøre

for j:=0 til Kart.Høyde-1 gjøre

Write(Map.Tiles.Code, SizeOf(heltall);

Slik fungerer det. Først må du åpne filen ved å bruke en spesiell prosedyre InitSave, hvis eneste parameter er filnavnet. Deretter lagrer vi overskriften for typekontroll ved hjelp av en spesiell prosedyre WriteHeader. Deretter skriver vi ned alt vi trenger ved hjelp av prosedyren WriteStr for strenger, og for alle andre felt - Skrive(den andre parameteren er størrelsen på de skrevne dataene i byte). Du kan skrive egne prosedyrer for objektfelt etter behov Lagre med en topptekst. Til slutt lukker vi filen med prosedyren FinSave.

Alle objekter som har egen overskrift må deklareres separat. I kapittel Initialisering modul (valgfri del som kommer etter Gjennomføring, som inneholder kommandoer som må utføres helt i begynnelsen, når du starter programmet), bør du for eksempel skrive følgende linje:

RegisterUserName(tpMap, "TObeliskMap");

TpMap er en konstant som du også må erklære. Lik det for eksempel til 1. Og i konstruktøren til TObeliskMap-objektet, tilordne verdien av denne konstanten til parameteren TypeID.

Hvorfor alt dette oppstyret? I tillegg til typematching, får du en veldig viktig fordel.

Hvis filformatet endres, for eksempel på grunn av tilføyelse av nye felt, trenger du ikke å skrive noen "konverterere" som konverterer de gamle filene til nye. Koden din vil automatisk lese dem.

Denne koden vil automatisk initialisere det nye feltet som tomt hvis det ikke er lagret i filen. Og du kan skrive en fil ved å legge til WriteStr(Name)-linjen helt til slutt.

Kommentar: Hvis du fortsatt ikke forstår hva denne prosessen er til for, ikke bekymre deg. Du kan bruke mer konvensjonelle opptaks- og lagringsmetoder. Men i virkelig storskala spillprosjekter gir denne veien betydelige fordeler.

La oss leke

Først av alt må vi skape ny klasse, avledet fra TLKIGameObject. Vi kommer til å savne egenskapene til den gamle. I den nye klassen må du legge til felt for grunnleggende egenskaper: rekkevidde, bevegelse og så videre.

Det er viktig: Vår gamle hastighetsparameter forblir med oss, men den indikerer hastigheten til brikken som beveger seg over skjermen, og ikke avstanden den vil reise per sving. Hvis vi skulle lage en sanntidsstrategi, ville vi ikke trengt en ny parameter, men ellers må vi innføre den.

På skjermen vår vil vi bruke TLKI-knapper i form av bueskyttere, sverdmenn, magikere, spøkelser, riddere.

Først har vi ordningen. La oss definere plasseringssonen for den ene siden som de tre øverste "linjene" på kartet, for den andre - som de tre nederste "linjene".

Koden fungerer slik. Når du trykker på en av knappene, aktiveres installasjonen av det tilsvarende jagerflyet; Ved å klikke på en ledig rute i plasseringsområdet plasseres figuren der og knappen deaktiveres. Så snart alle knappene er deaktivert, overføres trekket til fienden.

I begynnelsen av hvert nytt trekk slås alle knappene på igjen: dette gjøres slik at det er lettere for en person å legge merke til hvem han ennå ikke har lignet. Følgelig, klikk på knappen velger figuren, og så snart et trekk er gjort, forsvinner knappen. En annen knapp - "Avslutt sving" - vises først etter plasseringsfasen.

Forrige gang gjorde vi allerede operasjoner for å aktivere og deaktivere grensesnittelementer, så vi vil ikke analysere denne operasjonen i detalj - se på eksempelkoden.

Flytt av figuren

// Hvis den valgte cellen er okkupert av fienden, angriper vi,

// hvis det er ledig, beveger vi oss rundt, hvis det er opptatt med vårt eget

// eller en hindring - ignorer klikket

Tile:= Map.MouseTile(MouseX, MouseY);

hvis(Til = null)// Klikk utenfor spillvinduet

deretter exit;

// Flytte

hvis(Tile.Objects.Count = 0)

og(Dist(selv)

og ikke Flyttet deretter

// La oss sjekke om vi kan komme dit

hvis ikke HasWay (Til) deretter exit;

MoveObj(ID, Tile.x, Tile.y);

// Spillet er turbasert - flytt umiddelbart

Flyttet:= sant;

//

hvis Angrepet deretter

Icon.IsVisible:= falsk;

// Angrep

hvis(Tile.Objects.Count > 0)

og(Dist(selv)

og ikke Angrepet deretter

Obj:= Tile.Objects;

// Vi angriper bare fiender

hvis Obj.Side = Side deretter exit;

Obj.Damage(dmg);

Angrepet:= sant;

// Hvis flyttingen er fullført, fjern ikonet

hvis Flyttet deretter

Icon.IsVisible:= falsk;

Flyttingen behandles som følger (se "Stykkflytting"). Den klikkede cellen er lokalisert. Hvis det er en fiende på den, og de er innenfor rekkevidde, blir han skadet; hvis den er tom og innenfor rekkevidde, beveger brikken seg (hvis hindringer tillater det); hvis den er okkupert, men ikke av en fiende, ignoreres klikket .

Da begge sider nærmet seg, handlet dragene. De opererer veldig enkelt: de velger den nærmeste ikke-dragen som er innenfor 7 ruter fra dem og angriper. Se Dragon Actions-koden.

Dragehandlinger

// Sjekke fliser innenfor 7 ruter fra dragen

til i:= Maks(0, x - 7) til Min(MaxSize, x + 7) gjøre

til j:= Maks(0, y - 7) til Min(MaxSize, y + 7) gjøre

if (Map.Tiles.Objects.Count > 0) og

(Map.Tiles.Objects.Code>1)

// 0 - hinderkode, 1 - drage

deretter begynne

// Velge et punkt å flytte

hvis x=i deretterøks:=i

ellers hvis x>i deretter ax:=i+2

ellers ax:= i-2;

hvis y=j deretter ay:= j

ellers hvis y>j deretter ay:= j+2

ellers ay:= j-2;

MoveObj(NEI, øks, ay);

// La oss angripe

Map.Tiles.Damage(12);

// Bryte syklusen: ikke mer enn ett angrep

// hver drage per runde

Til slutt gjenstår det bare å sjekke om mer enn halvparten av obeliskene er okkupert av tropper fra den ene siden - og hvis de er det, så stopp spillet og erklær vinneren!


Så vi har et strategispill. Men for fullstendig lykke, det som mangler, først av alt, er kunstig intelligens, som vil tillate spillet å ha en enkeltspillermodus ( enkleste prosedyren Vi teller ikke dragekontroll). Det er det vi skal gjøre neste gang. Vi sees om en måned!

I fremtidige utgaver

I følgende utgaver vil vi snakke om:

  • partikkelsystemer for visning av røyk, gnister, etc.;
  • arbeider med åpenhet;
  • tredimensjonale motorer;
  • grunnleggende AI;
  • feilsøking av programmet;
  • lage en spilleplan og manus,
  • skrive et designdokument;
  • spillbalanse;
  • tenke gjennom spillkarakterer og deres linjer;
  • arbeider med Photoshop og 3D-pakker;
  • animasjoner;
  • musikk og stemmeskuespill;
  • og mye mer.

Det er fullt mulig å lære å gjøre alt dette med egne hender. Du vil snart se dette.

Skriv til oss...

For de som tror at pakken kan suppleres med noe: for det første, ikke glem at det er nei Siste versjon pakken, men bare den som implementerer funksjonene beskrevet i artiklene våre. Kanskje noen av ideene dine allerede er implementert og venter på tur (se sidefeltet "I fremtidige utgaver"). Og i alle fall: når du gir oss en idé, prøv å begrunne hvorfor forslaget ditt er nyttig for mange spill samtidig, og ikke bare for ditt spesifikke.

For selvstendig arbeid

Mens du venter på neste utgave, kan du jobbe med ditt eget prosjekt, eller du kan prøve å forbedre dette. Her er noen ideer for din egen implementering:

  • del hindringer inn i ødeleggende (trær og busker) og uforgjengelige (steiner), og sørg for at ildkuler og dragens pust brenner vegetasjonen;
  • lage groper (brun celle) eller en brann som brenner i flere svinger (rød celle) på stedet der brannangrepet ble utløst;
  • la sverdmenn og riddere dekke sine naboer, og gi dem +1 til forsvar;
  • gjør bevegelsen av figurer på skjermen jevn.

Hva om i sanntid?

Det er ikke vanskeligere å lage et strategispill i sanntid hvis du bare gir spillerne forskjellige inputmidler. Den enkleste måten å gjøre dette på er over nettverket - vi vil snakke om dette i en av de kommende utgavene. Følgende endringer vil også være nødvendig:

  • ingen felt nødvendig GameSpeed på timen TObeliskObject- bruk Speed ​​​​fra basismotoren (bevegelseshastigheten over skjermen er lik spillhastigheten);
  • heltallsberegning av avstander er deaktivert;
  • figurens bevegelseskode skrives om, under hensyntagen til det faktum at det er nødvendig å tegne en bane rundt hindringer;
  • "Slutt på trekk"-knappen er fjernet.

Det er alt. Vil du prøve å gjøre det selv?

Jeg anser din bedrift som en av de sterkeste på markedet for konsulenttjenester i vårt land. Jeg liker at du berører et bredt spekter av ledelsesproblemer og dekker dem med tilstrekkelig kvalitet og dybde. Jeg finner mye nyttig informasjon i bedriftens publikasjoner, siden det alltid er interessant å bli kjent med erfaringene til fagfolk og lære av dem.

Borisyuk Yuri Aleksandrovich, ledelseskonsulent, lege tekniske vitenskaper

Jeg liker virkelig serien med mesterklasser du underviser i. Personlig, etter å ha vært leder for en fabrikk, begynte jeg å endre mine tilnærminger til ledelse, inkl. takket være informasjonen mottatt fra deg. Hun reagerte på en eller annen måte på det jeg gjorde og observerte på fabrikken. Siden den gang begynte jeg å tenke på hvor ineffektive Russlands industrielle kapasiteter er og hvor enormt potensialet er og hvordan dette kan realiseres. Å bli personlig kjent med problemene ulike virksomheter(noen ganger inviterer venner meg som ekspert) Jeg ser hvor mye som kan gjøres, hvordan man kan øke både effektiviteten og effektiviteten.

Dryagin Oleg Borisovich

Ja, jeg liker mesterklassene dine, en svært systematisk tilnærming, kunnskap om stoffet på høyt nivå og selvfølgelig mye praktisk erfaring i de problemstillingene som vurderes. Det som tiltrekker meg er det Alexanders profesjonalitet og høye faglige kunnskap om emnet gjør at jeg kan se annerledes på allerede kjente ting. Fra mitt ståsted er dette Det er veldig viktig og nødvendig å se på ting du vet på en ny måte, fordi... Under kirurgisk arbeid blir øyet veldig ofte "uskarpt", og du slutter å se, faktisk, åpenbare ting.

Elena Fedash, HR-direktør, ATB Corporation, Dnepropetrovsk.