ObjectSight tile-muotoiseen dataan (Raycast)
Author: VesQ
Added: 11. tammikuuta 2012 kello 18.51
Edited: 16. huhtikuuta 2012 kello 22.04
Category: Sovellukset
Description
NetMatchin node.js -palvelinta varten minun piti luoda ObjectSightia vastaava toiminnallisuus ilman CB:n objekteja, joten koodasin tämän. Tämä funktio tarkistaa, onko pisteiden A ja B välissä seinää ja jos on, niin palauttaa sen pisteen koordinaatit, johon säde pisteestä A pisteeseen B törmää.
Funktio on lähes suora porttaus tästä: http://dev.mothteeth.com/2011/11/2d-ray-casting-on-a-grid-in-as3/
Tämä on paljon nopeampi kuin mistheman vastaava (http://www.coolbasic.com/phpBB3/viewtopic.php?f=12&t=2729), koska törmäystarkistus tehdään kokonaisluvuilla ja vain yksittäisten tilejen reunoilla. misthema kirjoitti ongelmastaan blogipostauksen (http://indiebitz.org/post/2012/01/09/DroneWars-Hiding-enemies-behind-walls.aspx), jossa ratkaisuksi muodostui tämä funktio.
Joten tässä se on olkaatten hyvät! Tämä koodi sisältää esimerkin ja varsinaisen funktion. Kommentteja löytyy koodista, mm. esimerkin näppäimet ovat siellä.
Tästä funktiosta on myös gisti: https://gist.github.com/1584536
Code
Select all1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | // CBRAYCASTER
// -----------
// Esimerkin näppäimet:
// - Enter: Vaihtaa debug-tilaa
// - Välilyönti: Generoi kartan uudelleen
// - Hiiren rulla: Muuttaa kartan satunnaisuuden astetta
// - WASD: Liikuttaa objektia
// - Nuolet vasen-oikea: Kääntää objektia
// - Nuolet ylös-alas: Lisää/vähentää tarkistusmatkan pituutta
Const MAPW = 30
Const MAPH = 20
// Yhden tilen leveys ja korkeus
Const TILEW = 32
Const TILEH = 20
// Näihin globaaleihin tallennetaan osumakohdan koordinaatit
Global gCastX#, gCastY#
// Piirrelläänkö debug-tavaraa?
Global gDebug
gDebug = True
SCREEN MAPW*TILEW, MAPH*TILEH
Dim TILEMAP(MAPW, MAPH)
// Jännästi täällä jo funktio joka resetoi TILEMAP-taulun valitulla randomisuudella
Function resetTileMap(randomness = 4)
If randomness < 1 Then randomness = 1
For x = 0 To MAPW-1
For y = 0 To MAPH-1
If Rand(randomness)=1 Then TILEMAP(x, y) = 1 Else TILEMAP(x, y) = 0
Next y
Next x
EndFunction
randyrandom = 4
resetTileMap(randyrandom)
// Testaillaan objektilla
obj = LoadObject("Media\guy.bmp", 72)
speed = 2
angle = Rand(0,360)
// Kuinka pitkältä katsotaan, alustetaan se neljän laatan pituudelle
length = TILEW*4
// Luodaan kuva tilekartasta
tilemapImg = InitTileMap()
ClsColor cbBlack
Color 255, 0, 0
Repeat
// Debug-tilaa voi vaihtaa Enterillä
If KeyHit(cbKeyReturn) Or KeyHit(cbKeyEnter) Then gDebug = Not gDebug
// Välilyönnillä voi randomisoida kartan uudelleen
If KeyHit(cbKeySpace) Then
resetTileMap(randyrandom)
tilemapImg = InitTileMap()
EndIf
// Hiiren rullalla voi vaihtaa kartan randomisuutta
randyrandom = randyrandom + MouseMoveZ()
DrawImage tilemapImg, 0, 0
// WASD liikuttaa objektia
TranslateObject obj, (KeyDown(cbKeyD)-KeyDown(cbKeyA))*speed, (KeyDown(cbKeyW)-KeyDown(cbKeyS))*speed
// Oikea ja vasen nuolinäppäin kääntää objektia
angle = angle + (RightKey()-LeftKey())*2
RotateObject obj, -angle
startX = WorldToScreenX(ObjectX(obj))
startY = WorldToScreenY(ObjectY(obj))
// Ylös ja alas nuolinäppäimet muuttavat tarkistusmatkan pituutta
length = length + (UpKey()-DownKey())*2
endX = startX + Cos(angle)*length
endY = startY + Sin(angle)*length
If gDebug Then
If hit Then Color 255, 255, 255
Circle2(startX, startY, length)
Line startX, startY, endX, endY
EndIf
Color 0,255,0
hit = CastRay(startX, startY, endX, endY)
If hit Or gDebug Then
// Jos osui seinään tai debug-tilassa, niin piirretään osumapiste
Color 0, 0, 255
DrawToWorld ON
Circle2World(ScreenToWorldX(gCastX), ScreenToWorldY(gCastY), 5)
DrawToWorld OFF
EndIf
// Näytetään FPS
Color cbWhite
Text 0, 0, "FPS: " + FPS()
DrawScreen
Forever
// PORTED FROM http://dev.mothteeth.com/2011/11/2d-ray-casting-on-a-grid-in-as3/
Function CastRay(origX1#, origY1#, origX2#, origY2#)
// Pisteiden normalisaatio
x1# = origX1 / TILEW
y1# = origY1 / TILEH
x2# = origX2 / TILEW
y2# = origY2 / TILEH
If RoundDown(x1) = RoundDown(x2) And RoundDown(y1) = RoundDown(y2) Then
// Ei ylitä minkään laatan rajoja, joten ei voi olla törmäystä.
// Asetetaan loppupiste muuttujiin gCastX ja gCastY
gCastX = origX2
gCastY = origY2
Return False
EndIf
// Kumpaan suuntaan mennään x- ja y-suunnassa
If x2 >= x1 Then stepX = 1 Else stepX = -1
If y2 >= y1 Then stepY = 1 Else stepY = -1
// Säteen suunta
rayDirX# = x2 - x1
rayDirY# = y2 - y1
// Kuinka pitkälle liikutaan kummallakin akselilla kun toisella akselilla hypätään seuraavaan
// kokonaiseen tileen
ratioX# = rayDirX / rayDirY
ratioY# = rayDirY / rayDirX
deltaY# = x2 - x1
deltaX# = y2 - y1
deltaX = Abs(deltaX)
deltaY = Abs(deltaY)
// Alustetaan testiä varten käytettävät kokonaislukumuuttujat alkutilekoordinaatteihin
// Huom: Käytetään normalisoituja versioita parametreista origX1 ja origY1
testX = RoundDown(x1)
testY = RoundDown(y1)
// Alustetaan ei-kokonaislukuhyppäys liikkumalla seuraavan tilen reunalle ja jakamalla saatu
// arvo vastakkaisen akselin kokonaisluvulla.
// Jos liikutaan positiiviseen suuntaan, siirrytään nykyisen tilen päähän, muulloin alkuun.
If stepX > 0 Then
maxX# = deltaX * (1.0 - (x1 Mod 1))
Else
maxX# = deltaX * (x1 Mod 1)
EndIf
If stepY > 0 Then
maxY# = deltaY * (1.0 - (y1 Mod 1))
Else
maxY# = deltaY * (y1 Mod 1)
EndIf
endTileX = RoundDown(x2)
endTileY = RoundDown(y2)
// Nyt liikutaan!
hit = False
colX# = 0.0
colY# = 0.0
While (testX <> endTileX Or testY <> endTileY)
// Piirretään debuggailua varten boksi sen tilen ympärille, jossa tällä hetkellä ollaan.
If gDebug Then Box testX*TILEW, testY*TILEH, TILEW, TILEH, OFF
If maxX < maxY Then
maxX = maxX + deltaX
testX = testX + stepX
If testX >= 0 And testX <= MAPW-1 Then
// Jos ollaan tilekartan rajojen sisällä, tarkistetaan onko tässä tilessä törmäystä.
hit = TILEMAP(testX, testY)
Else
// Jos taas ollaan tilekartan rajojen ulkopuolella niin asetetaan törmäys heti.
hit = 1
EndIf
If hit Then
colX = testX
If stepX < 0 Then colX = colX + 1.0 // Jos mennään vasemmalle päin, lisätään yksi.
colY = y1 + ratioY * (colX - x1)
colX = colX * TILEW // Skaalataan törmäyspiste ylöspäin
colY = colY * TILEH
// Asetetaan "paluuarvot"
gCastX = colX
gCastY = colY
'SetWindow "Hit in tile (" + testX + ", " + testY + ")"
Return True
EndIf
Else
maxY = maxY + deltaY
testY = testY + stepY
If testY >= 0 And testY <= MAPH-1 Then
hit = TILEMAP(testX, testY)
Else
hit = 1
EndIf
If hit Then
colY = testY
If stepY < 0 Then colY = colY + 1.0 // Add one if going up
colX = x1 + ratioX * (colY - y1)
colX = colX * TILEW // Skaalataan törmäyspiste ylöspäin
colY = colY * TILEH
gCastX = colX
gCastY = colY
'SetWindow "Hit in tile (" + testX + ", " + testY + ")"
Return True
EndIf
EndIf
Wend
// Ei löydetty törmäystä, palautetaan loppupiste
gCastX = origX2
gCastY = origY2
'SetWindow "No hit in tile (" + testX + ", " + testY + ")"
Return False
EndFunction
// Piirtää ympyrän keskikoordinaattien mukaan
Function Circle2(x, y, r, fill=0)
Circle x-r,y-r,r*2,fill
EndFunction
// Piirtää ympyrän keskikoordinaattien mukaan maailmankoordinaatistossa
Function Circle2World(x, y, r, fill=0)
Circle x-r,y+r,r*2,fill
EndFunction
// Muuttaa maailmankoordinaatit näytönkoordinaateiksi, kun kameraa ei olla liikuteltu
Function WorldToScreenX#(x#)
Return x + MAPW * TILEW / 2
EndFunction
Function WorldToScreenY#(y#)
Return -y + MAPH * TILEH / 2
EndFunction
// Muuttaa näyttökoordinaatit maailmankoordinaateiksi, kun kameraa ei olla liikuteltu
Function ScreenToWorldX#(x#)
Return x - MAPW * TILEW / 2
EndFunction
Function ScreenToWorldY#(y#)
Return MAPH * TILEH / 2 - y
EndFunction
// Alustaa TILEMAP-taulukon
Function InitTileMap()
img = MakeImage(MAPW*TILEW, MAPH*TILEH)
DrawToImage img
Color 255, 0, 0
For x=0 To MAPW-1
For y=0 To MAPH-1
If TILEMAP(x, y) Then
Box x*TILEW, y*TILEH, TILEW, TILEH
EndIf
Next y
Next x
DrawToScreen
Return img
EndFunction
|
Comments
No comments. You can be first!
Leave a comment
You must be logged in to comment.