Vytvorenie izometrických svety: Primer pre vývojárov hier, pokračoval
() translation by (you can also view the original English article)
V tomto tutoriále, budeme nadväzovať na pôvodný náter vytvárať izometrické svetov, a dozvedieť sa o implementáciu snímače, dlaždice spúšťač, úroveň prohozením, cestu nájsť a nasledujúcich, úroveň rolovanie, izometrický výška a Izometrický strely.
- Tvorba izometrických svety: Primer pre vývojárov hier
- Rýchly Tip: Lacné "n" jednoduchý izometrickej úrovne
- Juwal's book, Starling hra rozvoj Essentials.
1. snímače
Snímače sú položky, ktoré môžu byť zozbierané do úrovne, zvyčajne jednoducho pešo cez ne - napríklad mince, drahokamy, peniaze a munície.
Vyzdvihnutie údajov je možné aj priamo do našej úrovni údajov ako je uvedené nižšie:
1 |
[[1,1,1,1,1,1], |
2 |
[1,0,0,0,0,1], |
3 |
[1,0,8,0,0,1], |
4 |
[1,0,0,8,0,1], |
5 |
[1,0,0,0,0,1], |
6 |
[1,1,1,1,1,1]] |
V tejto úrovni údaje používame 8 na označenie vyzdvihnutie (1 a 0 predstavujú steny a schodný dlaždice resp. ako predtým).
Je dôležité pochopiť, že 8 vlastne označuje dve dlaždice, nie len jeden: to znamená, že musíme najprv umiestniť dlaždice schodný trávy a potom miesto vyzdvihnutia na vrchole. To znamená, že každé vyzdvihnutie bude vždy na tráve dlaždice. Ak chceme aby bolo na schodný tehla dlaždice, potom budeme potrebovať ďalšiu dlaždicu označené iným číslom, hovoria 9, ktorá predstavuje "pickup na tehlové dlaždice".
Typické izometrickej umenia bude mať viacero schodný dlaždice - Predpokladajme, že máme 30. Uvedený prístup znamená, že ak máme N snímače budeme potrebovať (N * 30) dlaždice okrem 30 originálne dlaždice, ako každú dlaždicu budú musieť mať jedna verzia so snímačmi a jeden bez. Toto nie je veľmi účinný; namiesto toho sme sa mali snažiť na dynamicky vytvoriť týchto kombinácií.
Na tento účel môžeme použiť iné pole s vyzdvihnutie údaje sám, a pouzit miesto vyzdvihnutia obkladov na vrchole úroveň usporiadanie údajov:
1 |
// Level layout data
|
2 |
[[1,1,1,1,1,1], |
3 |
[1,0,0,0,0,1], |
4 |
[1,0,0,0,0,1], |
5 |
[1,0,0,0,0,1], |
6 |
[1,0,0,0,0,1], |
7 |
[1,1,1,1,1,1]] |
... plus:
1 |
// Pickup layout data
|
2 |
[[0,0,0,0,0,0], |
3 |
[0,0,0,0,0,0], |
4 |
[0,0,8,0,0,0], |
5 |
[0,0,0,8,0,0], |
6 |
[0,0,0,0,0,0], |
7 |
[0,0,0,0,0,0]] |
.. .results v:



Tento postoj zabezpečuje, že potrebujeme iba 30 originálne dlaždice okrem N vyzdvihnutie dlaždice, ako môžeme vytvoriť akúkoľvek kombináciu zmiešaním oboch umelecké diela, keď renderovanie úroveň.
Zdvihol snímačmi
Detekcia snímače sa vykonáva rovnakým spôsobom ako detekcia kolízie dlaždice, ale po presune charakter.
1 |
tile coordinate= getTileCoordinates (isoTo2D (Iso point) , tile height); |
2 |
if(isPickup(tile coordinate)) { |
3 |
pickupItem(tile coordinate); |
4 |
}
|
V funkcia isPickup(tile coordinate), skontrolujeme, či vyzdvihnutie údajov pole hodnota v danom koordinovať je vyzdvihnutie dlaždice alebo nie. Číslo v poli pickup na ktoré dlaždice ladia označuje druh pickup.
Sme skontrolovať kolízie pred prechodom charakteru ale skontrolovať snímače potom, pretože v prípade kolízie znak by zaberať miesto ak už je obsadený kolízie dlaždice, ale v prípade snímače znak je voľne pohybovať nad ním.
Ďalšie vec k poznámke je, že zvyčajne nikdy zmien údajov kolízie, ale vyzdvihnutie údajov sa zmení vždy, keď sme vyzdvihnúť položky. (Zvyčajne len jedná zmeníte hodnotu v poli pickup, povedať, 8 k 0.)
To vedie k problém: čo sa stane, keď budeme musieť reštartovať úroveň, a tak obnoviť všetky snímače späť do ich pôvodných pozícií? Nemáme informácie na to, ako vyzdvihnutie pole zmenilo aktéra zdvihol položiek. Riešenie je použiť duplicitné pole pre snímače, zatiaľ čo v hre a zachováte pôvodný vyzdvihnutie array - napríklad používame [pickupsArray] a [pickupsLive], klon posledne z bývalého na začiatku úrovne, a iba zmeny [pickupsLive] počas hrania.
Mali by ste oznámenie, že sme skontrolovať snímače vždy, keď znak je na dlaždicu. To môže nastať viackrát do druhej (môžeme skontrolovať iba vtedy, keď používateľ presunie, ale môžeme ísť dookola do dlaždice) ale vyššom logika nebude zlyhať; pretože sme stanovili vyzdvihnutie pole údajov 0 prvýkrát odhalíme vyzdvihnutie, všetky následné isPickup(tile) kontroly sa vracia false pre dlaždicu.
2. spúšťacie dlaždice
Ako už názov napovedá, dlaždice spúšťač spôsobiť niečo stane, keď hráč kroky na nich alebo stlačí kláves počas šliapania na nich. Môžu teleport hráč do iného umiestnenia, otvorte brány alebo spawn nepriateľa, dať niekoľko príkladov. V istom zmysle, snímače sú len osobitnú formu spúšť dlaždice: keď hráč kroky na kameň obsahujúce mince, mince zmizne a ich mince počítadlo zvyšuje.
Pozrime sa ako by sme mohli realizovať dvere, ktoré má hráč na inú úroveň. Dlaždíc vedľa dverí bude spúšťač dlaždice; keď hráč stlačí medzerníka, budete pokračovať do ďalšej úrovne.



Zmena úrovne, všetci musíme urobiť, je swap aktuálne pole údaje úrovne s nové úrovne, a nastaviť nové dlaždice poloha a smer pre hrdinu charakter.
Predpokladajme, že existujú dve úrovne s dverami umožniť absolvovanie medzi nimi. Pretože Zem dlaždicu vedľa dverí bude dlaždice spúšťač v oboch úrovniach, môžeme použiť ako novú pozíciu znakov zobrazujú v úrovni.
Vykonávanie logika tu je rovnaký ako snímače a opäť môžeme použiť pole na uloženie hodnoty spúští. To je neefektívna a mali by zvážiť ďalšie dátové štruktúry pre tento účel, ale poďme držať to jednoduchý kvôli tutorial. Nechajte nové úrovne polí sa ako nižšie (7 označuje dvere):
1 |
// Level 1
|
2 |
[[1,1,1,1,1,1], |
3 |
[1,0,0,0,0,1], |
4 |
[1,0,0,0,0,7], |
5 |
[1,0,0,0,0,1], |
6 |
[1,0,0,0,1,1], |
7 |
[1,1,1,1,1,1]]; |
8 |
|
9 |
// Level 2
|
10 |
[[1,1,1,1,1,1], |
11 |
[1,0,0,0,1,1], |
12 |
[7,0,0,0,0,1], |
13 |
[1,0,0,0,0,1], |
14 |
[1,1,0,0,0,1], |
15 |
[1,1,1,1,1,1]]; |
Nech úrovne majú niekoľko snímačov, ako je uvedené nižšie vyzdvihnutie polia:
1 |
[[0,0,0,0,0,0], |
2 |
[0,0,0,0,0,0], |
3 |
[0,0,8,0,0,0], |
4 |
[0,0,0,8,0,0], |
5 |
[0,0,0,0,0,0], |
6 |
[0,0,0,0,0,0]]; |
7 |
|
8 |
[[0,0,0,0,0,0], |
9 |
[0,0,0,0,0,0], |
10 |
[0,0,0,0,0,0], |
11 |
[0,0,0,0,8,0], |
12 |
[0,0,8,0,0,0], |
13 |
[0,0,0,0,0,0]]; |
Nech zodpovedajúce vyvolať dlaždice polia na každej úrovni nižšie:
1 |
[[0,0,0,0,0,0], |
2 |
[0,0,0,0,0,0], |
3 |
[0,0,0,0,2,0], |
4 |
[0,0,0,0,0,0], |
5 |
[0,0,0,0,0,0], |
6 |
[0,0,0,0,0,0]]; |
7 |
|
8 |
[[0,0,0,0,0,0], |
9 |
[0,0,0,0,0,0], |
10 |
[0,1,0,0,0,0], |
11 |
[0,0,0,0,0,0], |
12 |
[0,0,0,0,0,0], |
13 |
[0,0,0,0,0,0]]; |
Hodnoty (1 a 2) označujú úroveň, ktorá sa načíta, keď hráč stlačí priestor.
Tu je kód, ktorý sa spustí, keď hráč udrie tento kľúč:
1 |
// Pseudocode
|
2 |
tile coordinate = getTileCoordinates(isoTo2D(Iso point), tile height); |
3 |
if (isTrigger(tile coordinate)) { |
4 |
doRelevantAction(tile coordinate); |
5 |
}
|
Funkcia isTrigger() skontroluje, či spúšť údajov pole hodnota v danom súradníc je väčšia ako nula. Ak áno, náš kód prechádza táto hodnota doRelevantAction(), rozhoduje funkcia hovor ďalej. Pre naše účely budeme používať jednoduché pravidlo, že ak hodnota leží medzi 1 a 10, je dvere, a tak táto funkcia sa nazýva:
1 |
function swapLevel(level) { |
2 |
// swap level arrays, pickup arrays, and trigger arrays with new level's data
|
3 |
// move player's starting position to tile next to door that leads to previous level
|
4 |
// set character's direction
|
5 |
}
|
Keďže hodnota dlaždice v spúšťač pole označuje úroveň, ktorá musí byť naložené, sme jednoducho prejsť do swapLevel(). To znamená zasa, že naša hra má desať úrovní.
Tu je pracovné demo. Skúste vyzdvihnúť položky pešo cez ne a vymení úrovne stojí vedľa dverí a biť priestor.
Urobil som spúšťač aktivovaný, keď sa uvoľní priestor; Ak počúvame len pre stlačené potom skončíme v slučke, kde budeme swap medzi úrovňami, tak dlho, ako je kláves stlačený, pretože znak vždy trenie v novej úrovni na spúšť dlaždicu.
Tu je celý kód (v AS3):
1 |
import flash.display.Sprite; |
2 |
import com.csharks.juwalbose.IsoHelper; |
3 |
import flash.display.MovieClip; |
4 |
import flash.geom.Point; |
5 |
import flash.filters.GlowFilter; |
6 |
import flash.events.Event; |
7 |
import com.senocular.utils.KeyObject; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.display.Bitmap; |
10 |
import flash.display.BitmapData; |
11 |
import flash.geom.Matrix; |
12 |
import flash.geom.Rectangle; |
13 |
import flash.events.KeyboardEvent; |
14 |
|
15 |
var level1Data=[[1,1,1,1,1,1], |
16 |
[1,0,0,0,0,1], |
17 |
[1,0,0,0,0,7], |
18 |
[1,0,0,0,0,1], |
19 |
[1,0,0,0,1,1], |
20 |
[1,1,1,1,1,1]]; |
21 |
|
22 |
var pickup1Array=[[0,0,0,0,0,0], |
23 |
[0,0,0,0,0,0], |
24 |
[0,0,8,0,0,0], |
25 |
[0,0,0,8,0,0], |
26 |
[0,0,0,0,0,0], |
27 |
[0,0,0,0,0,0]]; |
28 |
|
29 |
var level2Data=[[1,1,1,1,1,1], |
30 |
[1,0,0,0,1,1], |
31 |
[7,0,0,0,0,1], |
32 |
[1,0,0,0,0,1], |
33 |
[1,1,0,0,0,1], |
34 |
[1,1,1,1,1,1]]; |
35 |
|
36 |
var pickup2Array=[[0,0,0,0,0,0], |
37 |
[0,0,0,0,0,0], |
38 |
[0,0,0,0,0,0], |
39 |
[0,0,0,0,8,0], |
40 |
[0,0,8,0,0,0], |
41 |
[0,0,0,0,0,0]]; |
42 |
|
43 |
var trigger1Array=[[0,0,0,0,0,0], |
44 |
[0,0,0,0,0,0], |
45 |
[0,0,0,0,2,0], |
46 |
[0,0,0,0,0,0], |
47 |
[0,0,0,0,0,0], |
48 |
[0,0,0,0,0,0]]; |
49 |
|
50 |
var trigger2Array=[[0,0,0,0,0,0], |
51 |
[0,0,0,0,0,0], |
52 |
[0,1,0,0,0,0], |
53 |
[0,0,0,0,0,0], |
54 |
[0,0,0,0,0,0], |
55 |
[0,0,0,0,0,0]]; |
56 |
|
57 |
|
58 |
var levelData:Array=new Array(); |
59 |
var pickupArray:Array=new Array(); |
60 |
var triggerArray:Array=new Array(); |
61 |
var currentLevel:uint=1; |
62 |
var newLevel:uint=1; |
63 |
|
64 |
var tileWidth:uint = 50; |
65 |
var borderOffsetY:uint = 70; |
66 |
var borderOffsetX:uint = 275; |
67 |
|
68 |
var facing:String = "south"; |
69 |
var currentFacing:String = "south"; |
70 |
var hero:MovieClip=new herotile(); |
71 |
hero.clip.gotoAndStop(facing); |
72 |
var heroPointer:Sprite; |
73 |
var key:KeyObject = new KeyObject(stage);//Senocular KeyObject Class |
74 |
var heroHalfSize:uint=20; |
75 |
var pickupCount:uint=0; |
76 |
|
77 |
//the tiles
|
78 |
var grassTile:MovieClip=new TileMc(); |
79 |
grassTile.gotoAndStop(1); |
80 |
var wallTile:MovieClip=new TileMc(); |
81 |
wallTile.gotoAndStop(2); |
82 |
var pickupTile:MovieClip=new TileMc(); |
83 |
pickupTile.gotoAndStop(3); |
84 |
var doorTile:MovieClip=new TileMc(); |
85 |
doorTile.gotoAndStop(4); |
86 |
|
87 |
//the canvas
|
88 |
var bg:Bitmap = new Bitmap(new BitmapData(650,450)); |
89 |
addChild(bg); |
90 |
var rect:Rectangle=bg.bitmapData.rect; |
91 |
|
92 |
//to handle depth
|
93 |
var overlayContainer:Sprite=new Sprite(); |
94 |
addChild(overlayContainer); |
95 |
|
96 |
//to handle direction movement
|
97 |
var dX:Number = 0; |
98 |
var dY:Number = 0; |
99 |
var idle:Boolean = true; |
100 |
var speed:uint = 5; |
101 |
var heroCartPos:Point=new Point(); |
102 |
var heroTile:Point=new Point(); |
103 |
|
104 |
var spaceKeyUp:Boolean=false; |
105 |
//initial hero position
|
106 |
var spawnPt:Point=new Point(1,3); |
107 |
|
108 |
//add items to start level, add game loop
|
109 |
function createLevel() |
110 |
{
|
111 |
if(currentLevel==1){ |
112 |
levelData=level1Data; |
113 |
pickupArray=pickup1Array; |
114 |
triggerArray=trigger1Array; |
115 |
}else{ |
116 |
levelData=level2Data; |
117 |
pickupArray=pickup2Array; |
118 |
triggerArray=trigger2Array; |
119 |
}
|
120 |
levelData[spawnPt.x][spawnPt.y]=2; |
121 |
|
122 |
var tileType:uint; |
123 |
for (var i:uint=0; i<levelData.length; i++) |
124 |
{
|
125 |
for (var j:uint=0; j<levelData[0].length; j++) |
126 |
{
|
127 |
tileType = levelData[i][j]; |
128 |
placeTile(tileType,i,j); |
129 |
if (tileType == 2) |
130 |
{
|
131 |
//trace(i,j);
|
132 |
levelData[i][j] = 0; |
133 |
}
|
134 |
}
|
135 |
}
|
136 |
|
137 |
depthSort(); |
138 |
addEventListener(Event.ENTER_FRAME,loop); |
139 |
}
|
140 |
|
141 |
//place the tile based on coordinates
|
142 |
function placeTile(id:uint,i:uint,j:uint) |
143 |
{
|
144 |
var pos:Point=new Point(); |
145 |
if (id == 2) |
146 |
{
|
147 |
|
148 |
id = 0; |
149 |
pos.x = j * tileWidth; |
150 |
pos.y = i * tileWidth; |
151 |
pos = IsoHelper.twoDToIso(pos); |
152 |
hero.x = borderOffsetX + pos.x; |
153 |
hero.y = borderOffsetY + pos.y; |
154 |
//overlayContainer.addChild(hero);
|
155 |
heroCartPos.x = j * tileWidth; |
156 |
heroCartPos.y = i * tileWidth; |
157 |
heroTile.x=j; |
158 |
heroTile.y=i; |
159 |
heroPointer=new herodot(); |
160 |
heroPointer.x=heroCartPos.x; |
161 |
heroPointer.y=heroCartPos.y; |
162 |
|
163 |
}
|
164 |
|
165 |
}
|
166 |
|
167 |
//the game loop
|
168 |
function loop(e:Event) |
169 |
{
|
170 |
|
171 |
if (key.isDown(Keyboard.UP)) |
172 |
{
|
173 |
dY = -1; |
174 |
}
|
175 |
else if (key.isDown(Keyboard.DOWN)) |
176 |
{
|
177 |
dY = 1; |
178 |
}
|
179 |
else
|
180 |
{
|
181 |
dY = 0; |
182 |
}
|
183 |
if (key.isDown(Keyboard.RIGHT)) |
184 |
{
|
185 |
dX = 1; |
186 |
if (dY == 0) |
187 |
{
|
188 |
facing = "east"; |
189 |
}
|
190 |
else if (dY==1) |
191 |
{
|
192 |
facing = "southeast"; |
193 |
dX = dY=0.5; |
194 |
}
|
195 |
else
|
196 |
{
|
197 |
facing = "northeast"; |
198 |
dX=0.5; |
199 |
dY=-0.5; |
200 |
}
|
201 |
}
|
202 |
else if (key.isDown(Keyboard.LEFT)) |
203 |
{
|
204 |
dX = -1; |
205 |
if (dY == 0) |
206 |
{
|
207 |
facing = "west"; |
208 |
}
|
209 |
else if (dY==1) |
210 |
{
|
211 |
facing = "southwest"; |
212 |
dY=0.5; |
213 |
dX=-0.5; |
214 |
}
|
215 |
else
|
216 |
{
|
217 |
facing = "northwest"; |
218 |
dX = dY=-0.5; |
219 |
}
|
220 |
}
|
221 |
else
|
222 |
{
|
223 |
dX = 0; |
224 |
if (dY == 0) |
225 |
{
|
226 |
//facing="west";
|
227 |
}
|
228 |
else if (dY==1) |
229 |
{
|
230 |
facing = "south"; |
231 |
}
|
232 |
else
|
233 |
{
|
234 |
facing = "north"; |
235 |
}
|
236 |
}
|
237 |
if (dY == 0 && dX == 0) |
238 |
{
|
239 |
hero.clip.gotoAndStop(facing); |
240 |
idle = true; |
241 |
}
|
242 |
else if (idle||currentFacing!=facing) |
243 |
{
|
244 |
idle = false; |
245 |
currentFacing = facing; |
246 |
hero.clip.gotoAndPlay(facing); |
247 |
}
|
248 |
if (! idle && isWalkable()) |
249 |
{
|
250 |
heroCartPos.x += speed * dX; |
251 |
heroCartPos.y += speed * dY; |
252 |
heroPointer.x=heroCartPos.x; |
253 |
heroPointer.y=heroCartPos.y; |
254 |
|
255 |
var newPos:Point = IsoHelper.twoDToIso(heroCartPos); |
256 |
//collision check
|
257 |
hero.x = borderOffsetX + newPos.x; |
258 |
hero.y = borderOffsetY + newPos.y; |
259 |
heroTile=IsoHelper.getTileCoordinates(heroCartPos,tileWidth); |
260 |
|
261 |
if(isPickup(heroTile)){ |
262 |
pickupItem(heroTile); |
263 |
}
|
264 |
depthSort(); |
265 |
//trace(heroTile);
|
266 |
}
|
267 |
tileTxt.text="Level "+ currentLevel.toString()+" - x: "+heroTile.x +" & y: "+heroTile.y; |
268 |
pickupTxt.text="Pickups Collected: "+pickupCount.toString(); |
269 |
|
270 |
if (spaceKeyUp) |
271 |
{
|
272 |
spaceKeyUp=false; |
273 |
if(isTrigger(heroTile)){ |
274 |
doRelevantAction(heroTile); |
275 |
}
|
276 |
}
|
277 |
}
|
278 |
function doRelevantAction(tilePt:Point):void{ |
279 |
newLevel=triggerArray[tilePt.y][tilePt.x]; |
280 |
|
281 |
if(newLevel==1){ |
282 |
spawnPt=getSpawn(trigger1Array,currentLevel); |
283 |
}else{ |
284 |
spawnPt=getSpawn(trigger2Array,currentLevel); |
285 |
}
|
286 |
|
287 |
swapLevel(newLevel); |
288 |
}
|
289 |
function getSpawn(ar:Array,index:uint):Point{ |
290 |
var tilePt:Point=new Point(); |
291 |
for (var i:uint=0; i<ar.length; i++) |
292 |
{
|
293 |
for (var j:uint=0; j<ar[0].length; j++) |
294 |
{
|
295 |
if(ar[i][j]==index){ |
296 |
tilePt.x=i; |
297 |
tilePt.y=j; |
298 |
break; |
299 |
}
|
300 |
}
|
301 |
}
|
302 |
return tilePt; |
303 |
}
|
304 |
function swapLevel(level:uint):void{ |
305 |
removeEventListener(Event.ENTER_FRAME,loop); |
306 |
currentLevel=level; |
307 |
//trace("load",level);
|
308 |
createLevel(); |
309 |
}
|
310 |
function isPickup(tilePt:Point):Boolean{ |
311 |
return(pickupArray[tilePt.y][tilePt.x]==8); |
312 |
}
|
313 |
function isTrigger(tilePt:Point):Boolean{ |
314 |
return(triggerArray[tilePt.y][tilePt.x]>0); |
315 |
}
|
316 |
function pickupItem(tilePt:Point):void{ |
317 |
pickupCount++; |
318 |
pickupArray[tilePt.y][tilePt.x]=0; |
319 |
}
|
320 |
//check for collision tile
|
321 |
function isWalkable():Boolean{ |
322 |
var able:Boolean=true; |
323 |
var newPos:Point =new Point(); |
324 |
newPos.x=heroCartPos.x + (speed * dX); |
325 |
newPos.y=heroCartPos.y + (speed * dY); |
326 |
switch (facing){ |
327 |
case "north": |
328 |
newPos.y-=heroHalfSize; |
329 |
break; |
330 |
case "south": |
331 |
newPos.y+=heroHalfSize; |
332 |
break; |
333 |
case "east": |
334 |
newPos.x+=heroHalfSize; |
335 |
break; |
336 |
case "west": |
337 |
newPos.x-=heroHalfSize; |
338 |
break; |
339 |
case "northeast": |
340 |
newPos.y-=heroHalfSize; |
341 |
newPos.x+=heroHalfSize; |
342 |
break; |
343 |
case "southeast": |
344 |
newPos.y+=heroHalfSize; |
345 |
newPos.x+=heroHalfSize; |
346 |
break; |
347 |
case "northwest": |
348 |
newPos.y-=heroHalfSize; |
349 |
newPos.x-=heroHalfSize; |
350 |
break; |
351 |
case "southwest": |
352 |
newPos.y+=heroHalfSize; |
353 |
newPos.x-=heroHalfSize; |
354 |
break; |
355 |
}
|
356 |
newPos=IsoHelper.getTileCoordinates(newPos,tileWidth); |
357 |
if(levelData[newPos.y][newPos.x]>=1){ |
358 |
able=false; |
359 |
}else{ |
360 |
//trace("new",newPos);
|
361 |
}
|
362 |
return able; |
363 |
}
|
364 |
|
365 |
//sort depth & draw to canvas
|
366 |
function depthSort() |
367 |
{
|
368 |
bg.bitmapData.lock(); |
369 |
bg.bitmapData.fillRect(rect,0xffffff); |
370 |
var tileType:uint; |
371 |
var mat:Matrix=new Matrix(); |
372 |
var pos:Point=new Point(); |
373 |
for (var i:uint=0; i<levelData.length; i++) |
374 |
{
|
375 |
for (var j:uint=0; j<levelData[0].length; j++) |
376 |
{
|
377 |
tileType = levelData[i][j]; |
378 |
//placeTile(tileType,i,j);
|
379 |
|
380 |
pos.x = j * tileWidth; |
381 |
pos.y = i * tileWidth; |
382 |
pos = IsoHelper.twoDToIso(pos); |
383 |
mat.tx = borderOffsetX + pos.x; |
384 |
mat.ty = borderOffsetY + pos.y; |
385 |
if(tileType==0){ |
386 |
bg.bitmapData.draw(grassTile,mat); |
387 |
}else if(tileType==1){ |
388 |
bg.bitmapData.draw(wallTile,mat); |
389 |
}else if(tileType==7){ |
390 |
bg.bitmapData.draw(doorTile,mat); |
391 |
}
|
392 |
if(pickupArray[i][j]==8){ |
393 |
bg.bitmapData.draw(pickupTile,mat); |
394 |
}
|
395 |
if(heroTile.x==j&&heroTile.y==i){ |
396 |
mat.tx=hero.x; |
397 |
mat.ty=hero.y; |
398 |
bg.bitmapData.draw(hero,mat); |
399 |
}
|
400 |
|
401 |
}
|
402 |
}
|
403 |
bg.bitmapData.unlock(); |
404 |
//add character rectangle
|
405 |
}
|
406 |
function handleKeyUp(e:KeyboardEvent):void{//listen for space key release |
407 |
if(e.charCode==Keyboard.SPACE){ |
408 |
spaceKeyUp=true; |
409 |
}
|
410 |
}
|
411 |
stage.addEventListener(KeyboardEvent.KEY_UP,handleKeyUp); |
412 |
createLevel(); |
3. cesta nález
Hľadanie cesta a cesta je po pomerne zložitý proces. Existujú rôzne prístupy pomocou rôznych algoritmov pre nájdenie cestu medzi dvoma bodmi, ale naša úroveň údajov je 2D array veci sú jednoduchšie, ako by mohli inak byť - budeme mať dobre definované a jedinečné uzly, ktoré hráč môže zaberať a môžeme ľahko skontrolovať či sú schodný.
Podrobný prehľad o pathfinding algoritmov je mimo rozsah tohto článku, ale pokúsim sa vysvetliť najbežnejší spôsob, ako to funguje: Najkratšia cesta algoritmus, ktorý A * a Dijkstrov algoritmus sú slávne implementácií.
Snažíme sa nájsť uzly spájajúce počiatočný uzol a koncový uzol. Z počiatočného uzla navštívte všetkých ôsmich susednými uzlami a označiť všetky ako navštívené; Toto jadro proces sa opakuje pre každú novo navštívil uzol, rekurzívne. Každé vlákno sleduje uzly navštívil. Pri skákaní na susednými uzlami, uzly, ktoré už boli navštívené uzly sú vynechané (Rekurzia zastávky); inak, proces pokračuje, kým dosiahneme koncový uzol, kde Rekurzia konce a celú cestu nasledovať vrátené ako pole uzol. Niekedy koncovým uzlom je nikdy dosiahnutý, v prípade zistenia cesta zlyhá. Sme zvyčajne skončiť nájsť viaceré cesty medzi dvoma uzlami, pričom v tomto prípade berieme s najmenej počet uzlov.
Existuje mnoho štandardných roztokov pre cestu zistenia na 2D polia, takže sme preskočiť znovuobjavenie kolesa. Využime Toto riešenie AS3 (odporúčam, môžete vyskúšať tento skvelý vysvetľujúce demo)).
Riešenie vracia pole s bodmi, ktoré tvoria cestu z východiskového bodu do koncového bodu:
1 |
path = PathFinder.go(start x, start y, end x, end y, levelData); |
Cesta po
Akonáhle budeme mať cestu ako pole uzol, musíme urobiť charakter po nej.
Chceme, aby sa charakter chodiť na kameň, ktorý klikneme na som. Najprv musíme vyhľadať cestu medzi uzol, ktorý znak práve zaberá a uzol, kde sme klikli. Ak úspešnú cestu, potom musíme pohybovať znak prvý uzol v uzol poľa, v ktorom je ako cieľ. Akonáhle sa dostaneme na cieľový uzol, skontrolujeme, ak neexistujú žiadne ďalšie uzly v poli uzol, a ak áno, nastaviť ďalší uzol ako cieľ - a tak ďalej až sa dostaneme konečný uzol.
Môžeme tiež zmeniť smer prehrávač založený na aktuálnom uzle a nový cieľový uzol zakaždým dostaneme uzol. Medzi uzlami, sme jednoducho chodiť v požadovanom smere nedosiahneme cieľový uzol. Je to veľmi jednoduché AI.
Pozrite sa na tento príklad:
Tu je plná zdroj:
1 |
import flash.display.Sprite; |
2 |
import com.csharks.juwalbose.IsoHelper; |
3 |
import flash.display.MovieClip; |
4 |
import flash.geom.Point; |
5 |
import flash.filters.GlowFilter; |
6 |
import flash.events.Event; |
7 |
import com.senocular.utils.KeyObject; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.display.Bitmap; |
10 |
import flash.display.BitmapData; |
11 |
import flash.geom.Matrix; |
12 |
import flash.geom.Rectangle; |
13 |
import flash.events.MouseEvent; |
14 |
|
15 |
import libs.PathFinder.*; |
16 |
|
17 |
var levelData=[[1,1,1,1,1,1,1,1], |
18 |
[1,0,0,0,0,2,0,1], |
19 |
[1,0,0,1,0,0,0,1], |
20 |
[1,1,0,0,0,0,0,1], |
21 |
[1,0,0,0,0,1,1,1], |
22 |
[1,0,0,1,0,0,0,1], |
23 |
[1,0,0,1,0,0,0,1], |
24 |
[1,1,1,1,1,1,1,1]]; |
25 |
|
26 |
var tileWidth:uint = 50; |
27 |
var borderOffsetY:uint = 70; |
28 |
var borderOffsetX:uint = 275; |
29 |
|
30 |
var facing:String = "south"; |
31 |
var currentFacing:String = "south"; |
32 |
var hero:MovieClip=new herotile(); |
33 |
hero.clip.gotoAndStop(facing); |
34 |
var heroPointer:Sprite; |
35 |
var heroHalfSize:uint=20; |
36 |
|
37 |
//the tiles
|
38 |
var grassTile:MovieClip=new TileMc(); |
39 |
grassTile.gotoAndStop(1); |
40 |
var wallTile:MovieClip=new TileMc(); |
41 |
wallTile.gotoAndStop(2); |
42 |
|
43 |
//the canvas
|
44 |
var bg:Bitmap = new Bitmap(new BitmapData(650,450)); |
45 |
addChild(bg); |
46 |
var rect:Rectangle=bg.bitmapData.rect; |
47 |
|
48 |
//to handle depth
|
49 |
var overlayContainer:Sprite=new Sprite(); |
50 |
addChild(overlayContainer); |
51 |
|
52 |
//to handle direction movement
|
53 |
var dX:Number = 0; |
54 |
var dY:Number = 0; |
55 |
var idle:Boolean = true; |
56 |
var speed:uint = 5; |
57 |
var heroCartPos:Point=new Point(); |
58 |
var heroTile:Point=new Point(); |
59 |
|
60 |
var path:Array=new Array(); |
61 |
var destination:Point=new Point(); |
62 |
var stepsTillTurn:uint=5; |
63 |
var stepsTaken:uint; |
64 |
|
65 |
var glowFilter:GlowFilter=new GlowFilter(0x00ffff); |
66 |
|
67 |
//add items to start level, add game loop
|
68 |
function createLevel() |
69 |
{
|
70 |
var tileType:uint; |
71 |
for (var i:uint=0; i<levelData.length; i++) |
72 |
{
|
73 |
for (var j:uint=0; j<levelData[0].length; j++) |
74 |
{
|
75 |
tileType = levelData[i][j]; |
76 |
placeTile(tileType,i,j); |
77 |
if (tileType == 2) |
78 |
{
|
79 |
levelData[i][j] = 0; |
80 |
}
|
81 |
}
|
82 |
}
|
83 |
overlayContainer.addChild(heroPointer); |
84 |
overlayContainer.alpha=0.9; |
85 |
overlayContainer.scaleX=overlayContainer.scaleY=0.3; |
86 |
overlayContainer.y=320; |
87 |
overlayContainer.x=10; |
88 |
depthSort(); |
89 |
|
90 |
addEventListener(Event.ENTER_FRAME,loop); |
91 |
}
|
92 |
|
93 |
//place the tile based on coordinates
|
94 |
function placeTile(id:uint,i:uint,j:uint) |
95 |
{
|
96 |
var pos:Point=new Point(); |
97 |
if (id == 2) |
98 |
{
|
99 |
|
100 |
id = 0; |
101 |
pos.x = j * tileWidth +tileWidth/2; |
102 |
pos.y = i * tileWidth +tileWidth/2; |
103 |
pos = IsoHelper.twoDToIso(pos); |
104 |
hero.x = borderOffsetX + pos.x; |
105 |
hero.y = borderOffsetY + pos.y; |
106 |
//overlayContainer.addChild(hero);
|
107 |
heroCartPos.x = j * tileWidth +tileWidth/2; |
108 |
heroCartPos.y = i * tileWidth +tileWidth/2; |
109 |
|
110 |
heroTile.x=j; |
111 |
heroTile.y=i; |
112 |
heroPointer=new herodot(); |
113 |
heroPointer.x=heroCartPos.x; |
114 |
heroPointer.y=heroCartPos.y; |
115 |
|
116 |
}
|
117 |
var tile:MovieClip=new cartTile(); |
118 |
tile.gotoAndStop(id+1); |
119 |
tile.x = j * tileWidth; |
120 |
tile.y = i * tileWidth; |
121 |
tile.name="tile_"+j.toString()+"_"+i.toString(); |
122 |
overlayContainer.addChild(tile); |
123 |
}
|
124 |
|
125 |
//the game loop
|
126 |
function loop(e:Event) |
127 |
{
|
128 |
aiWalk(); |
129 |
|
130 |
if (dY == 0 && dX == 0) |
131 |
{
|
132 |
hero.clip.gotoAndStop(facing); |
133 |
idle = true; |
134 |
}
|
135 |
else if (idle||currentFacing!=facing) |
136 |
{
|
137 |
//trace(idle,"facing ",currentFacing,facing);
|
138 |
idle = false; |
139 |
|
140 |
currentFacing = facing; |
141 |
hero.clip.gotoAndPlay(facing); |
142 |
}
|
143 |
if (! idle ) |
144 |
{
|
145 |
heroCartPos.x += speed * dX; |
146 |
heroCartPos.y += speed * dY; |
147 |
heroPointer.x=heroCartPos.x; |
148 |
heroPointer.y=heroCartPos.y; |
149 |
|
150 |
var newPos:Point = IsoHelper.twoDToIso(heroCartPos); |
151 |
//collision check
|
152 |
hero.x = borderOffsetX + newPos.x; |
153 |
hero.y = borderOffsetY + newPos.y; |
154 |
heroTile=IsoHelper.getTileCoordinates(heroCartPos,tileWidth); |
155 |
depthSort(); |
156 |
//trace(heroTile);
|
157 |
}
|
158 |
tileTxt.text="Hero is on x: "+heroTile.x +" & y: "+heroTile.y; |
159 |
}
|
160 |
function aiWalk():void{ |
161 |
if(path.length==0){//path has ended |
162 |
dX=dY=0; |
163 |
return; |
164 |
}
|
165 |
if(heroTile.equals(destination)){//reached current destination, set new, change direction |
166 |
//wait till we are few steps into the tile before we turn
|
167 |
stepsTaken++; |
168 |
if(stepsTaken<stepsTillTurn){ |
169 |
return; |
170 |
}
|
171 |
//place the hero at tile middle before turn
|
172 |
var pos:Point=new Point(); |
173 |
pos.x = heroTile.x * tileWidth +tileWidth/2; |
174 |
pos.y = heroTile.y * tileWidth +tileWidth/2; |
175 |
pos = IsoHelper.twoDToIso(pos); |
176 |
hero.x = borderOffsetX + pos.x; |
177 |
hero.y = borderOffsetY + pos.y; |
178 |
heroCartPos.x = heroTile.x * tileWidth +tileWidth/2; |
179 |
heroCartPos.y = heroTile.y * tileWidth +tileWidth/2; |
180 |
heroPointer.x=heroCartPos.x; |
181 |
heroPointer.y=heroCartPos.y; |
182 |
depthSort(); |
183 |
|
184 |
//new point, turn, find dX,dY
|
185 |
stepsTaken=0; |
186 |
destination=path.pop(); |
187 |
if(heroTile.x<destination.x){ |
188 |
dX = 1; |
189 |
}else if(heroTile.x>destination.x){ |
190 |
dX = -1; |
191 |
}else { |
192 |
dX=0; |
193 |
}
|
194 |
if(heroTile.y<destination.y){ |
195 |
dY = 1; |
196 |
}else if(heroTile.y>destination.y){ |
197 |
dY = -1; |
198 |
}else { |
199 |
dY=0; |
200 |
}
|
201 |
if(heroTile.x==destination.x){//top or bottom |
202 |
dX=0; |
203 |
}else if(heroTile.y==destination.y){//left or right |
204 |
dY=0; |
205 |
}
|
206 |
|
207 |
if (dX == 1) |
208 |
{
|
209 |
|
210 |
if (dY == 0) |
211 |
{
|
212 |
facing = "east"; |
213 |
}
|
214 |
else if (dY==1) |
215 |
{
|
216 |
facing = "southeast"; |
217 |
dX = dY=0.5; |
218 |
}
|
219 |
else
|
220 |
{
|
221 |
facing = "northeast"; |
222 |
dX=0.5; |
223 |
dY=-0.5; |
224 |
}
|
225 |
}
|
226 |
else if (dX==-1) |
227 |
{
|
228 |
|
229 |
if (dY == 0) |
230 |
{
|
231 |
facing = "west"; |
232 |
}
|
233 |
else if (dY==1) |
234 |
{
|
235 |
facing = "southwest"; |
236 |
dY=0.5; |
237 |
dX=-0.5; |
238 |
}
|
239 |
else
|
240 |
{
|
241 |
facing = "northwest"; |
242 |
dX = dY=-0.5; |
243 |
}
|
244 |
}
|
245 |
else
|
246 |
{
|
247 |
|
248 |
if (dY == 0) |
249 |
{
|
250 |
facing=currentFacing; |
251 |
}
|
252 |
else if (dY==1) |
253 |
{
|
254 |
facing = "south"; |
255 |
}
|
256 |
else
|
257 |
{
|
258 |
facing = "north"; |
259 |
}
|
260 |
}
|
261 |
}
|
262 |
|
263 |
|
264 |
|
265 |
}
|
266 |
//sort depth & draw to canvas
|
267 |
function depthSort() |
268 |
{
|
269 |
bg.bitmapData.lock(); |
270 |
bg.bitmapData.fillRect(rect,0xffffff); |
271 |
var tileType:uint; |
272 |
var mat:Matrix=new Matrix(); |
273 |
var pos:Point=new Point(); |
274 |
for (var i:uint=0; i<levelData.length; i++) |
275 |
{
|
276 |
for (var j:uint=0; j<levelData[0].length; j++) |
277 |
{
|
278 |
tileType = levelData[i][j]; |
279 |
//placeTile(tileType,i,j);
|
280 |
|
281 |
pos.x = j * tileWidth; |
282 |
pos.y = i * tileWidth; |
283 |
pos = IsoHelper.twoDToIso(pos); |
284 |
mat.tx = borderOffsetX + pos.x; |
285 |
mat.ty = borderOffsetY + pos.y; |
286 |
if(tileType==0){ |
287 |
bg.bitmapData.draw(grassTile,mat); |
288 |
}else{ |
289 |
bg.bitmapData.draw(wallTile,mat); |
290 |
}
|
291 |
if(heroTile.x==j&&heroTile.y==i){ |
292 |
mat.tx=hero.x; |
293 |
mat.ty=hero.y; |
294 |
bg.bitmapData.draw(hero,mat); |
295 |
}
|
296 |
|
297 |
}
|
298 |
}
|
299 |
bg.bitmapData.unlock(); |
300 |
//add character rectangle
|
301 |
}
|
302 |
function handleMouseClick(e:MouseEvent):void{ |
303 |
path.splice(0,path.length); |
304 |
var clickPt:Point=new Point(); |
305 |
clickPt.x=e.stageX-borderOffsetX; |
306 |
clickPt.y=e.stageY-borderOffsetY; |
307 |
clickPt=IsoHelper.isoTo2D(clickPt); |
308 |
clickPt.x-=tileWidth/2; |
309 |
clickPt.y+=tileWidth/2; |
310 |
clickPt=IsoHelper.getTileCoordinates(clickPt,tileWidth); |
311 |
if(clickPt.x<0||clickPt.y<0||clickPt.x>levelData.length-1||clickPt.x>levelData[0].length-1){ |
312 |
//trace("invalid");
|
313 |
//we have clicked outside
|
314 |
return; |
315 |
}
|
316 |
if(levelData[clickPt.y][clickPt.x]==1){ |
317 |
//trace("wall");
|
318 |
//we clicked on a wall
|
319 |
return; |
320 |
}
|
321 |
trace("find ",heroTile, clickPt); |
322 |
destination=heroTile; |
323 |
path= PathFinder.go(heroTile.x, heroTile.y, clickPt.x, clickPt.y, levelData); |
324 |
path.reverse(); |
325 |
path.push(clickPt); |
326 |
path.reverse(); |
327 |
paintPath(); |
328 |
}
|
329 |
function paintPath():void{//show hihglighted path in minimap |
330 |
var sp:Sprite; |
331 |
for (var i:uint=0; i<levelData.length; i++) |
332 |
{
|
333 |
for (var j:uint=0; j<levelData[0].length; j++) |
334 |
{
|
335 |
sp=overlayContainer.getChildByName("tile_"+j.toString()+"_"+i.toString()) as Sprite; |
336 |
sp.filters=[]; |
337 |
}
|
338 |
}
|
339 |
for(i=0;i<path.length;i++){ |
340 |
sp=overlayContainer.getChildByName("tile_"+(path[i].x).toString()+"_"+(path[i].y).toString()) as Sprite; |
341 |
sp.filters=[glowFilter]; |
342 |
overlayContainer.setChildIndex(sp,overlayContainer.numChildren-1); |
343 |
}
|
344 |
overlayContainer.setChildIndex(heroPointer,overlayContainer.numChildren-1); |
345 |
}
|
346 |
stage.addEventListener(MouseEvent.CLICK, handleMouseClick); |
347 |
createLevel(); |
Možno ste si všimli, že som odstránil kolízie Kontrola logiky; nie je potrebné, pretože sme nemôžete manuálne presunúť náš znak pomocou klávesnice. Avšak, potrebujeme odfiltrovať platný kliknite body určením, či sme klikli v rámci pochôdznej plochy, skôr ako obkladačky alebo iné non-schodný dlaždice.
Ďalším zaujímavým bodom pre kódovanie AI: Nechceme znak obrátiť na tvári Ďalšia dlaždica v poli uzol, ako prišiel v súčasnom, ako také okamžite zase výsledky v náš charakter, chôdza na hraniciach dlaždice. Namiesto toho by sme mali počkať, kým znak je pár krokov vnútri dlaždice, než sa pozrieme na ďalší cieľ. Je lepšie, môžete ručne umiestniť hrdinu uprostred aktuálnu dlaždice len pred obraciame, aby sa to všetko dokonalé.
Tiež, ak si prezrieť vyššie demo, môžete si všimnúť, že naša logika čerpať dostane narušený, keď hrdina sa pohybuje šikmo blízko steny dlaždice. Toto je extrémny prípad, kde pre jednu snímku, náš hrdina sa zdá byť vnútri kachličiek. To sa deje, pretože sme vypli kolízie overiť. Jedno riešenie je použitie pathfinding algoritmus, ktorý ignoruje diagonálne riešenia. (Takmer všetky cestu nález algoritmy mať možnosti povoliť alebo zakázať diagonálne chôdze riešenia).
4. strely
Projektil je niečo, čo sa hýbe v určitom smere najmä rýchlosťou, ako strela, kúzlo, loptu a tak ďalej.
Všetko o projektil je rovnaký ako hrdinu charakter, okrem výšky: namiesto valcovanie po zemi, projektily často vznášať nad ním v určitej výške. Guľka prejde nad úrovňou pása postavy, a dokonca lopta musí odraziť okolo.
Jedna zaujímavá vec k poznámke je, že Izometrický výška je rovnaká ako výška v 2D bočný pohľad. Existujú žiadne komplikované konverzie. Ak lopta 10 pixelov nad zemou v karteziánskych súradníc, je 10 pixelov nad zemou v izometrickej súradnice. (V našom prípade relevantné OS je os y.)
Poďme sa pokúsiť realizovať loptou poskakovanie okolo v našej murované trávnych porastov. Budeme ignorovať tlmiace účinky (a aby sa odrazí pokračovať donekonečna) a na dotyk realizmus pridáme tieň na loptu. Sme posunie tieň rovnako ako sme sa presunúť hrdinu charakter (t. j. bez použitia hodnotu výšky), ale na ples musíme pridať hodnotu výšky izometrickej hodnotu Y. Height hodnotu bude zmeniť od rámu k rámu v závislosti od závažnosti a potom, čo lopta dopadne na zem sme budete flip aktuálnu rýchlosť pozdĺž osi y.
Predtým, než sa pustíme do skákacie izometrickej systéme, uvidíme, ako sme môže realizovať v 2D karteziánske systému. Dajte nám predstavujú výšku lopty do premennej zValue. Predstavte si, že začať s, lopta je desať pixelov, takže zValue = 10. Použijeme dve ďalšie premenné: incrementValue, ktorý začína na 0 a gravity, ktorý má hodnotu 1.
Každý rám, pridáme incrementValue do zValue, a odčítanie gravitácie z incrementValue. Pri zValue dosiahne 0, to znamená, guľôčka dosiahla zem; v tomto bode sme flip znamienko incrementValue vynásobením -1 premeniť ju na kladné číslo. To znamená, že bude guľa pohybovať smerom hore od nasledujúcu snímku, teda odráža.
Tu je, ako to vyzerá v kóde:
1 |
zValue=10; |
2 |
gravity=1; |
3 |
incrementValue=0; |
4 |
|
5 |
gameLoop(){ |
6 |
incrementValue-=gravity; |
7 |
zValue-=incrementValue; |
8 |
if(zValue<=0){ |
9 |
zValue=0; |
10 |
incrementValue*=-1; |
11 |
}
|
12 |
}
|
Sme vlastne chystá pomocou mierne upravenú verziu, že:
1 |
zValue=10; |
2 |
gravity=1; |
3 |
incrementValue=0; |
4 |
incrementReset=-12 |
5 |
|
6 |
gameLoop(){ |
7 |
incrementValue-=gravity; |
8 |
zValue-=incrementValue; |
9 |
if(zValue<=0){ |
10 |
zValue=0; |
11 |
incrementValue=incrementReset; |
12 |
}
|
13 |
}
|
To odstraňuje tlmiaci účinok a nechá loptu odraziť navždy.
Použitie tohto nášho loptu, dostaneme nižšie demo:
Tu je plný AS3 kód:
1 |
import flash.display.Sprite; |
2 |
import com.csharks.juwalbose.IsoHelper; |
3 |
import flash.display.MovieClip; |
4 |
import flash.geom.Point; |
5 |
import flash.events.Event; |
6 |
import flash.display.Bitmap; |
7 |
import flash.display.BitmapData; |
8 |
import flash.geom.Matrix; |
9 |
import flash.geom.Rectangle; |
10 |
import com.senocular.utils.KeyObject; |
11 |
|
12 |
var levelData=[[1,1,1,1,1,1], |
13 |
[1,0,0,0,0,1], |
14 |
[1,0,0,0,0,1], |
15 |
[1,0,0,2,0,1], |
16 |
[1,0,0,0,0,1], |
17 |
[1,1,1,1,1,1]]; |
18 |
|
19 |
var tileWidth:uint = 50; |
20 |
var borderOffsetY:uint = 70; |
21 |
var borderOffsetX:uint = 275; |
22 |
|
23 |
var key:KeyObject = new KeyObject(stage); |
24 |
|
25 |
var facing:String = "south"; |
26 |
var currentFacing:String = "south"; |
27 |
var heroHalfSize:uint = 20; |
28 |
|
29 |
//the tiles
|
30 |
var grassTile:MovieClip=new TileMc(); |
31 |
grassTile.gotoAndStop(1); |
32 |
var wallTile:MovieClip=new TileMc(); |
33 |
wallTile.gotoAndStop(2); |
34 |
var pickupTile:MovieClip=new TileMc(); |
35 |
pickupTile.gotoAndStop(3); |
36 |
var ball:Sprite=new Ball(); |
37 |
var shadow_S:Sprite=new Shadow(); |
38 |
|
39 |
//the canvas
|
40 |
var bg:Bitmap = new Bitmap(new BitmapData(650,450)); |
41 |
addChild(bg); |
42 |
var rect:Rectangle = bg.bitmapData.rect; |
43 |
|
44 |
//to handle depth
|
45 |
var heroPointer:Sprite; |
46 |
var overlayContainer:Sprite=new Sprite(); |
47 |
addChild(overlayContainer); |
48 |
|
49 |
//to handle direction movement
|
50 |
var dX:Number = 0; |
51 |
var dY:Number = 0; |
52 |
var speed:uint = 5; |
53 |
var ballCartPos:Point=new Point(); |
54 |
var ballTile:Point=new Point(); |
55 |
|
56 |
var zValue:int = 50; |
57 |
var gravity:int = -1; |
58 |
var incrementValue:Number = 0; |
59 |
|
60 |
//add items to start level, add game loop
|
61 |
function createLevel() |
62 |
{
|
63 |
var tileType:uint; |
64 |
for (var i:uint=0; i<levelData.length; i++) |
65 |
{
|
66 |
for (var j:uint=0; j<levelData[0].length; j++) |
67 |
{
|
68 |
tileType = levelData[i][j]; |
69 |
placeTile(tileType,i,j); |
70 |
if (tileType == 2) |
71 |
{
|
72 |
levelData[i][j] = 0; |
73 |
}
|
74 |
}
|
75 |
}
|
76 |
overlayContainer.addChild(heroPointer); |
77 |
overlayContainer.alpha=0.5; |
78 |
overlayContainer.scaleX=overlayContainer.scaleY=0.5; |
79 |
overlayContainer.y=290; |
80 |
overlayContainer.x=10; |
81 |
|
82 |
depthSort(); |
83 |
addEventListener(Event.ENTER_FRAME,loop); |
84 |
}
|
85 |
|
86 |
//place the tile based on coordinates
|
87 |
function placeTile(id:uint,i:uint,j:uint) |
88 |
{
|
89 |
var pos:Point=new Point(); |
90 |
if (id == 2) |
91 |
{
|
92 |
|
93 |
id = 0; |
94 |
pos.x = j * tileWidth; |
95 |
pos.y = i * tileWidth; |
96 |
pos = IsoHelper.twoDToIso(pos); |
97 |
|
98 |
ball.x = borderOffsetX + pos.x; |
99 |
ball.y = borderOffsetY + pos.y; |
100 |
|
101 |
ballCartPos.x = j * tileWidth; |
102 |
ballCartPos.y = i * tileWidth; |
103 |
ballTile.x = j; |
104 |
ballTile.y = i; |
105 |
|
106 |
heroPointer=new herodot(); |
107 |
heroPointer.x=ballCartPos.x; |
108 |
heroPointer.y=ballCartPos.y; |
109 |
|
110 |
}
|
111 |
var tile:MovieClip=new cartTile(); |
112 |
tile.gotoAndStop(id+1); |
113 |
tile.x = j * tileWidth; |
114 |
tile.y = i * tileWidth; |
115 |
overlayContainer.addChild(tile); |
116 |
|
117 |
}
|
118 |
|
119 |
//the game loop
|
120 |
function loop(e:Event) |
121 |
{
|
122 |
incrementValue -= gravity; |
123 |
zValue -= incrementValue; |
124 |
if (zValue <= 0) |
125 |
{
|
126 |
zValue = 0; |
127 |
incrementValue = -12; |
128 |
}
|
129 |
|
130 |
|
131 |
if (key.isDown(Keyboard.UP)) |
132 |
{
|
133 |
dY = -1; |
134 |
}
|
135 |
else if (key.isDown(Keyboard.DOWN)) |
136 |
{
|
137 |
dY = 1; |
138 |
}
|
139 |
else
|
140 |
{
|
141 |
dY = 0; |
142 |
}
|
143 |
if (key.isDown(Keyboard.RIGHT)) |
144 |
{
|
145 |
dX = 1; |
146 |
if (dY == 0) |
147 |
{
|
148 |
facing = "east"; |
149 |
}
|
150 |
else if (dY==1) |
151 |
{
|
152 |
facing = "southeast"; |
153 |
dX = dY = 0.5; |
154 |
}
|
155 |
else
|
156 |
{
|
157 |
facing = "northeast"; |
158 |
dX = 0.5; |
159 |
dY = -0.5; |
160 |
}
|
161 |
}
|
162 |
else if (key.isDown(Keyboard.LEFT)) |
163 |
{
|
164 |
dX = -1; |
165 |
if (dY == 0) |
166 |
{
|
167 |
facing = "west"; |
168 |
}
|
169 |
else if (dY==1) |
170 |
{
|
171 |
facing = "southwest"; |
172 |
dY = 0.5; |
173 |
dX = -0.5; |
174 |
}
|
175 |
else
|
176 |
{
|
177 |
facing = "northwest"; |
178 |
dX = dY = -0.5; |
179 |
}
|
180 |
}
|
181 |
else
|
182 |
{
|
183 |
dX = 0; |
184 |
if (dY == 0) |
185 |
{
|
186 |
//facing="west";
|
187 |
}
|
188 |
else if (dY==1) |
189 |
{
|
190 |
facing = "south"; |
191 |
}
|
192 |
else
|
193 |
{
|
194 |
facing = "north"; |
195 |
}
|
196 |
}
|
197 |
|
198 |
|
199 |
if (isWalkable()) |
200 |
{
|
201 |
ballCartPos.x += speed * dX; |
202 |
ballCartPos.y += speed * dY; |
203 |
|
204 |
heroPointer.x=ballCartPos.x; |
205 |
heroPointer.y=ballCartPos.y; |
206 |
|
207 |
|
208 |
var newPos:Point = IsoHelper.twoDToIso(ballCartPos); |
209 |
//collision check
|
210 |
ball.x = borderOffsetX + newPos.x; |
211 |
ball.y = borderOffsetY + newPos.y; |
212 |
ballTile = IsoHelper.getTileCoordinates(ballCartPos,tileWidth); |
213 |
|
214 |
}
|
215 |
depthSort(); |
216 |
|
217 |
}
|
218 |
|
219 |
//check for collision tile
|
220 |
function isWalkable():Boolean |
221 |
{
|
222 |
var able:Boolean = true; |
223 |
var newPos:Point =new Point(); |
224 |
newPos.x=ballCartPos.x + (speed * dX); |
225 |
newPos.y=ballCartPos.y + (speed * dY); |
226 |
switch (facing) |
227 |
{
|
228 |
case "north" : |
229 |
newPos.y -= heroHalfSize; |
230 |
break; |
231 |
case "south" : |
232 |
newPos.y += heroHalfSize; |
233 |
break; |
234 |
case "east" : |
235 |
newPos.x += heroHalfSize; |
236 |
break; |
237 |
case "west" : |
238 |
newPos.x -= heroHalfSize; |
239 |
break; |
240 |
case "northeast" : |
241 |
newPos.y -= heroHalfSize; |
242 |
newPos.x += heroHalfSize; |
243 |
break; |
244 |
case "southeast" : |
245 |
newPos.y += heroHalfSize; |
246 |
newPos.x += heroHalfSize; |
247 |
break; |
248 |
case "northwest" : |
249 |
newPos.y -= heroHalfSize; |
250 |
newPos.x -= heroHalfSize; |
251 |
break; |
252 |
case "southwest" : |
253 |
newPos.y += heroHalfSize; |
254 |
newPos.x -= heroHalfSize; |
255 |
break; |
256 |
}
|
257 |
newPos = IsoHelper.getTileCoordinates(newPos,tileWidth); |
258 |
if (levelData[newPos.y][newPos.x] == 1) |
259 |
{
|
260 |
able = false; |
261 |
}
|
262 |
else
|
263 |
{
|
264 |
//trace("new",newPos);
|
265 |
}
|
266 |
return able; |
267 |
}
|
268 |
|
269 |
//sort depth & draw to canvas
|
270 |
function depthSort() |
271 |
{
|
272 |
bg.bitmapData.lock(); |
273 |
bg.bitmapData.fillRect(rect,0xffffff); |
274 |
var tileType:uint; |
275 |
var mat:Matrix=new Matrix(); |
276 |
var pos:Point=new Point(); |
277 |
for (var i:uint=0; i<levelData.length; i++) |
278 |
{
|
279 |
for (var j:uint=0; j<levelData[0].length; j++) |
280 |
{
|
281 |
tileType = levelData[i][j]; |
282 |
//placeTile(tileType,i,j);
|
283 |
|
284 |
pos.x = j * tileWidth; |
285 |
pos.y = i * tileWidth; |
286 |
pos = IsoHelper.twoDToIso(pos); |
287 |
mat.tx = borderOffsetX + pos.x; |
288 |
mat.ty = borderOffsetY + pos.y; |
289 |
if (tileType == 0) |
290 |
{
|
291 |
bg.bitmapData.draw(grassTile,mat); |
292 |
}
|
293 |
else
|
294 |
{
|
295 |
bg.bitmapData.draw(wallTile,mat); |
296 |
}
|
297 |
|
298 |
if (ballTile.x == j && ballTile.y == i) |
299 |
{
|
300 |
mat.tx = ball.x;//+ tileWidth; |
301 |
mat.ty = ball.y;// +tileWidth/2; |
302 |
bg.bitmapData.draw(shadow_S,mat); |
303 |
mat.ty = mat.ty - zValue - heroHalfSize; |
304 |
bg.bitmapData.draw(ball,mat); |
305 |
}
|
306 |
|
307 |
}
|
308 |
}
|
309 |
bg.bitmapData.unlock(); |
310 |
|
311 |
}
|
312 |
createLevel(); |
Pochopiť, že úlohe, ktorú zohráva tieň je veľmi dôležitý, ktorý pridáva realizmus tejto ilúziu. V uvedenom príklade som pridal pol guľa výška do y polohy gule tak, aby to odrazí v správnej polohe vzhľadom na tieň.
Všimnite si, že teraz používame dve obrazovky súradníc (x a y) predstavujú tri rozmery v izometrickej súradnice - y v obrazovkových súradniciach je tiež osi z izometrickej súradníc. To môže byť mätúce!
5. Izometrický rolovanie
Keď úroveň oblasti je oveľa väčšia ako oblasť viditeľné obrazovky, musíme to prejdite.
Viditeľná obrazovka oblasti možno považovať za menší obdĺžnik v rámci väčších obdĺžnik kompletný úrovni oblasti. Posúvanie sa v podstate len pohybom vnútorný obdĺžnik vnútri väčšie:



Zvyčajne, keď takéto rolovanie stane, pozíciu hráča zostáva rovnaká vzhľadom na obrazovke obdĺžnik, obyčajne v strede obrazovky. Všetko čo potrebujeme, implementovať, posúvanie, je sledovať rohový bod vnútorný obdĺžnik:



Tento rohový bod, ktorý je v karteziánskych súradníc (na obrázku môžeme len ukázať izometrickej hodnoty), bude spadať do dlaždice úroveň údajov. Posúvanie, sme prírastkov pozíciu x a y rohový bod v karteziánskych súradníc. Teraz môžeme previesť tento bod izometrickej súradnice a pomocou nakresliť na obrazovku.
Novo konvertovaných hodnôt v izometrickej priestor, musia byť v rohu našej obrazovke príliš, čo znamená, že sú nové (0, 0). Takže pri parsování a kreslenie úroveň údajov, sme odpočítajte túto hodnotu od izometrickej polohy jednotlivých dlaždíc, a len čerpať, ak dlaždicu Nová pozícia spadá do obrazovky. Môžeme to vyjadriť v krokoch takto:
- Aktualizovať karteziánske rohový bod súradníc x a y.
- Previesť do izometrickej priestoru.
- Odpočítajte túto hodnotu od izometrické kreslenie pozície jednotlivých dlaždíc.
- Nakresliť dlaždice, iba ak novú pozíciu izometrické kreslenie spadá do obrazovky.
Pozrite sa na tento príklad (pomocou ŠÍPOK prechádzať):
Tu je plný AS3 zdrojový kód:
1 |
import flash.display.Sprite; |
2 |
import com.csharks.juwalbose.IsoHelper; |
3 |
import flash.display.MovieClip; |
4 |
import flash.geom.Point; |
5 |
import flash.filters.GlowFilter; |
6 |
import flash.events.Event; |
7 |
import com.senocular.utils.KeyObject; |
8 |
import flash.ui.Keyboard; |
9 |
import flash.display.Bitmap; |
10 |
import flash.display.BitmapData; |
11 |
import flash.geom.Matrix; |
12 |
import flash.geom.Rectangle; |
13 |
|
14 |
var levelData=[[1,1,1,1,1,1,1,1,1,1,1,1], |
15 |
[1,0,0,0,0,0,0,0,0,1,0,1], |
16 |
[1,0,0,0,0,0,0,0,0,1,0,1], |
17 |
[1,0,0,1,0,0,0,0,0,0,0,1], |
18 |
[1,0,0,1,2,0,0,0,0,0,0,1], |
19 |
[1,0,0,1,0,0,0,0,0,0,0,1], |
20 |
[1,0,0,0,0,0,0,0,0,1,0,1], |
21 |
[1,0,0,0,0,0,0,0,0,0,0,1], |
22 |
[1,0,0,0,1,1,1,0,0,0,0,1], |
23 |
[1,0,0,0,0,0,0,0,0,0,0,1], |
24 |
[1,0,0,0,0,0,0,0,1,1,0,1], |
25 |
[1,1,0,0,0,0,0,0,0,0,0,1], |
26 |
[1,1,1,1,1,1,1,1,1,1,1,1]]; |
27 |
|
28 |
var tileWidth:uint = 50; |
29 |
var borderOffsetY:uint = 70; |
30 |
var borderOffsetX:uint = 275; |
31 |
|
32 |
var facing:String = "south"; |
33 |
var currentFacing:String = "south"; |
34 |
var hero:MovieClip=new herotile(); |
35 |
hero.clip.gotoAndStop(facing); |
36 |
var heroPointer:Sprite; |
37 |
var key:KeyObject = new KeyObject(stage);//Senocular KeyObject Class |
38 |
var heroHalfSize:uint=20; |
39 |
|
40 |
//the tiles
|
41 |
var grassTile:MovieClip=new TileMc(); |
42 |
grassTile.gotoAndStop(1); |
43 |
var wallTile:MovieClip=new TileMc(); |
44 |
wallTile.gotoAndStop(2); |
45 |
|
46 |
//the canvas
|
47 |
var bg:Bitmap = new Bitmap(new BitmapData(650,450)); |
48 |
addChild(bg); |
49 |
var rect:Rectangle=bg.bitmapData.rect; |
50 |
|
51 |
//to handle depth
|
52 |
var overlayContainer:Sprite=new Sprite(); |
53 |
addChild(overlayContainer); |
54 |
|
55 |
//to handle direction movement
|
56 |
var dX:Number = 0; |
57 |
var dY:Number = 0; |
58 |
var idle:Boolean = true; |
59 |
var speed:uint = 6; |
60 |
var heroCartPos:Point=new Point(); |
61 |
var heroTile:Point=new Point(); |
62 |
|
63 |
var cornerPoint:Point=new Point(); |
64 |
|
65 |
//add items to start level, add game loop
|
66 |
function createLevel() |
67 |
{
|
68 |
var tileType:uint; |
69 |
for (var i:uint=0; i<levelData.length; i++) |
70 |
{
|
71 |
for (var j:uint=0; j<levelData[0].length; j++) |
72 |
{
|
73 |
tileType = levelData[i][j]; |
74 |
placeTile(tileType,i,j); |
75 |
if (tileType == 2) |
76 |
{
|
77 |
levelData[i][j] = 0; |
78 |
}
|
79 |
}
|
80 |
}
|
81 |
overlayContainer.addChild(heroPointer); |
82 |
overlayContainer.alpha=0.5; |
83 |
overlayContainer.scaleX=overlayContainer.scaleY=0.2; |
84 |
overlayContainer.y=310; |
85 |
overlayContainer.x=10; |
86 |
depthSort(); |
87 |
addEventListener(Event.ENTER_FRAME,loop); |
88 |
}
|
89 |
|
90 |
//place the tile based on coordinates
|
91 |
function placeTile(id:uint,i:uint,j:uint) |
92 |
{
|
93 |
var pos:Point=new Point(); |
94 |
if (id == 2) |
95 |
{
|
96 |
|
97 |
id = 0; |
98 |
pos.x = j * tileWidth; |
99 |
pos.y = i * tileWidth; |
100 |
pos = IsoHelper.twoDToIso(pos); |
101 |
hero.x = borderOffsetX + pos.x; |
102 |
hero.y = borderOffsetY + pos.y; |
103 |
//overlayContainer.addChild(hero);
|
104 |
heroCartPos.x = j * tileWidth; |
105 |
heroCartPos.y = i * tileWidth; |
106 |
heroTile.x=j; |
107 |
heroTile.y=i; |
108 |
heroPointer=new herodot(); |
109 |
heroPointer.x=heroCartPos.x; |
110 |
heroPointer.y=heroCartPos.y; |
111 |
|
112 |
}
|
113 |
var tile:MovieClip=new cartTile(); |
114 |
tile.gotoAndStop(id+1); |
115 |
tile.x = j * tileWidth; |
116 |
tile.y = i * tileWidth; |
117 |
overlayContainer.addChild(tile); |
118 |
}
|
119 |
|
120 |
//the game loop
|
121 |
function loop(e:Event) |
122 |
{
|
123 |
if (key.isDown(Keyboard.UP)) |
124 |
{
|
125 |
dY = -1; |
126 |
}
|
127 |
else if (key.isDown(Keyboard.DOWN)) |
128 |
{
|
129 |
dY = 1; |
130 |
}
|
131 |
else
|
132 |
{
|
133 |
dY = 0; |
134 |
}
|
135 |
if (key.isDown(Keyboard.RIGHT)) |
136 |
{
|
137 |
dX = 1; |
138 |
if (dY == 0) |
139 |
{
|
140 |
facing = "east"; |
141 |
}
|
142 |
else if (dY==1) |
143 |
{
|
144 |
facing = "southeast"; |
145 |
dX = dY=0.5; |
146 |
}
|
147 |
else
|
148 |
{
|
149 |
facing = "northeast"; |
150 |
dX=0.5; |
151 |
dY=-0.5; |
152 |
}
|
153 |
}
|
154 |
else if (key.isDown(Keyboard.LEFT)) |
155 |
{
|
156 |
dX = -1; |
157 |
if (dY == 0) |
158 |
{
|
159 |
facing = "west"; |
160 |
}
|
161 |
else if (dY==1) |
162 |
{
|
163 |
facing = "southwest"; |
164 |
dY=0.5; |
165 |
dX=-0.5; |
166 |
}
|
167 |
else
|
168 |
{
|
169 |
facing = "northwest"; |
170 |
dX = dY=-0.5; |
171 |
}
|
172 |
}
|
173 |
else
|
174 |
{
|
175 |
dX = 0; |
176 |
if (dY == 0) |
177 |
{
|
178 |
//facing="west";
|
179 |
}
|
180 |
else if (dY==1) |
181 |
{
|
182 |
facing = "south"; |
183 |
}
|
184 |
else
|
185 |
{
|
186 |
facing = "north"; |
187 |
}
|
188 |
}
|
189 |
if (dY == 0 && dX == 0) |
190 |
{
|
191 |
hero.clip.gotoAndStop(facing); |
192 |
idle = true; |
193 |
}
|
194 |
else if (idle||currentFacing!=facing) |
195 |
{
|
196 |
idle = false; |
197 |
currentFacing = facing; |
198 |
hero.clip.gotoAndPlay(facing); |
199 |
}
|
200 |
if (! idle && isWalkable()) |
201 |
{
|
202 |
heroCartPos.x += speed * dX; |
203 |
heroCartPos.y += speed * dY; |
204 |
|
205 |
cornerPoint.x -= speed * dX; |
206 |
cornerPoint.y -= speed * dY; |
207 |
|
208 |
heroPointer.x=heroCartPos.x; |
209 |
heroPointer.y=heroCartPos.y; |
210 |
|
211 |
var newPos:Point = IsoHelper.twoDToIso(heroCartPos); |
212 |
heroTile=IsoHelper.getTileCoordinates(heroCartPos,tileWidth); |
213 |
depthSort(); |
214 |
//trace(heroTile);
|
215 |
}
|
216 |
tileTxt.text="Hero is on x: "+heroTile.x +" & y: "+heroTile.y; |
217 |
}
|
218 |
|
219 |
//check for collision tile
|
220 |
function isWalkable():Boolean{ |
221 |
var able:Boolean=true; |
222 |
var newPos:Point =new Point(); |
223 |
newPos.x=heroCartPos.x + (speed * dX); |
224 |
newPos.y=heroCartPos.y + (speed * dY); |
225 |
switch (facing){ |
226 |
case "north": |
227 |
newPos.y-=heroHalfSize; |
228 |
break; |
229 |
case "south": |
230 |
newPos.y+=heroHalfSize; |
231 |
break; |
232 |
case "east": |
233 |
newPos.x+=heroHalfSize; |
234 |
break; |
235 |
case "west": |
236 |
newPos.x-=heroHalfSize; |
237 |
break; |
238 |
case "northeast": |
239 |
newPos.y-=heroHalfSize; |
240 |
newPos.x+=heroHalfSize; |
241 |
break; |
242 |
case "southeast": |
243 |
newPos.y+=heroHalfSize; |
244 |
newPos.x+=heroHalfSize; |
245 |
break; |
246 |
case "northwest": |
247 |
newPos.y-=heroHalfSize; |
248 |
newPos.x-=heroHalfSize; |
249 |
break; |
250 |
case "southwest": |
251 |
newPos.y+=heroHalfSize; |
252 |
newPos.x-=heroHalfSize; |
253 |
break; |
254 |
}
|
255 |
newPos=IsoHelper.getTileCoordinates(newPos,tileWidth); |
256 |
if(levelData[newPos.y][newPos.x]==1){ |
257 |
able=false; |
258 |
}else{ |
259 |
//trace("new",newPos);
|
260 |
}
|
261 |
return able; |
262 |
}
|
263 |
|
264 |
//sort depth & draw to canvas
|
265 |
function depthSort() |
266 |
{
|
267 |
bg.bitmapData.lock(); |
268 |
bg.bitmapData.fillRect(rect,0xffffff); |
269 |
var tileType:uint; |
270 |
var mat:Matrix=new Matrix(); |
271 |
var pos:Point=new Point(); |
272 |
for (var i:uint=0; i<levelData.length; i++) |
273 |
{
|
274 |
for (var j:uint=0; j<levelData[0].length; j++) |
275 |
{
|
276 |
tileType = levelData[i][j]; |
277 |
|
278 |
//pos.x = j * tileWidth;
|
279 |
//pos.y = i * tileWidth;
|
280 |
|
281 |
pos.x = j * tileWidth+cornerPoint.x; |
282 |
pos.y = i * tileWidth+cornerPoint.y; |
283 |
|
284 |
pos = IsoHelper.twoDToIso(pos); |
285 |
mat.tx = borderOffsetX + pos.x; |
286 |
mat.ty = borderOffsetY + pos.y; |
287 |
if(tileType==0){ |
288 |
bg.bitmapData.draw(grassTile,mat); |
289 |
}else{ |
290 |
bg.bitmapData.draw(wallTile,mat); |
291 |
}
|
292 |
if(heroTile.x==j&&heroTile.y==i){ |
293 |
mat.tx=hero.x; |
294 |
mat.ty=hero.y; |
295 |
bg.bitmapData.draw(hero,mat); |
296 |
}
|
297 |
|
298 |
}
|
299 |
}
|
300 |
bg.bitmapData.unlock(); |
301 |
//add character rectangle
|
302 |
}
|
303 |
createLevel(); |
Upozorňujeme, že rohový bod sa zvýši v opačnom smere hrdinu pozícia aktualizácia, ako sa pohybuje. Tým zaistíte, že hrdina pobyty kde je vzhľadom na obrazovke:
1 |
heroCartPos.x += speed * dX; |
2 |
heroCartPos.y += speed * dY; |
3 |
cornerPoint.x -= speed * dX; |
4 |
cornerPoint.y -= speed * dY; |
Kresliť logika mení len dva riadky, kde sme sa zistiť Kartézske súradnice jednotlivých dlaždíc. Míňame len rohový bod k východiskovému bodu, ktorý skutočne spája body 1, 2 a 3 uvedené vyššie:
1 |
pos.x = j * tileWidth+cornerPoint.x; |
2 |
pos.y = i * tileWidth+cornerPoint.y; |
Pár poznámok:
- Počas posúvania, budeme musieť čerpať ďalšie dlaždice na obrazovke hraniciach, inak môžeme vidieť dlaždice miznú a objavujú na obrazovke extrémy.
- Ak máte dlaždice, ktoré zaberajú viac než jedného priestoru, potom budete musieť čerpať viac dlaždíc na hraniciach. Napríklad, ak najväčší dlaždice v celý súbor opatrení X y, potom musíte čerpať X viac dlaždice, doľava a doprava a Y viac dlaždice na hornej a dolnej. Tým zaistíte, že rohy väčšie dlaždice stále budú viditeľné pri posúvaní v alebo mimo obrazovku.
- Stále potrebujeme uistite sa, že nemáme prázdnej oblasti na obrazovke, kým sme sa blíži hranice úrovne.
- Úrovne by len posuňte najextrémnejších dlaždice dostane vyvodiť na obrazovke zodpovedajúce extreme - po tomto, znak naďalej uberá priestor obrazovky bez úrovni posúvania. Na tento účel musíme sledovať všetky štyri rohy obdĺžnika, vnútorný displej a throttle rolovanie a hráč pohyb logiku zodpovedajúcim spôsobom. Ste sa na výzvu skúsiť vykonávacie že sami?
Záver
Táto séria je zameraná najmä na začiatočníkov snaží preskúmať izometrickej herných svetov. Mnohé pojmy vysvetlené majú alternatívne prístupy, ktoré sú trochu zložitejšie a zámerne si vybrali tie najjednoduchšie. Môže naplniť všetky scenáre, ktoré sa môžu vyskytnúť, ale vedomosti získané možno stavať tieto koncepcie vytvoriť oveľa zložitejšie riešenia.