On muutamia ohjelmia jotka lähes jokainen ohjelmointiharrastaja tulee joskus tekemään: hirsipuu, tekstiseikkailu, lukkarieditori, 3d-moottori ja asteroids-klooni.
Tämä on sellainen pikkuprojekti jonka koodasin koulussa hyppytunnilla. Koodi on aika simppeliä, tästä ei ole mitään uutta, mutta onpahan esimerkki trogonometrian käytöstä objektien liikuttamiseen.
Koulussa on kiva koodata, siellä on niin vähän DOS-muistia niin ohjelmista ei tule turhan pitkiä :) (tai siis mielestäni tämä ei ole kovinkaan pitkä pelin sorsaksi)
Tässä binaarina kun jotkut sitä tuntuvat vonkaavan. Exessä ei kuiteskaan ole hidastusta koska koulussa ei riittäny muisti sen lisäämiseen koodiin :(
http://sooda.dy.fi:8080/mordor/dl/ASTEROID.EXE
'Elikkäs tässä on minun ASTEROIDS-klooni
'ei toimi ihan samoin kuin esikuvansa, sillä vauhtia voi tässä myös hidastaa jne mutta yhteistä on ainakin obstaakkeleiden seassa lentely
'napit on
'ylöös: lisää kaasua
'alaas: vähemmän kaasua
'vasen ja oikea: väistöliikkeet (kääntyminen)
'enter tai space: ampus
'esc: lopetus
DECLARE SUB killasteroid (i!) 'asteroidin räjäytyssubi
DECLARE SUB newasteroid (x!, y!, hor!, ver!, radius!, nodes!, angle!, spin!, lifetime!) 'tekee uuden asteroidin ensimmäiseen vapaaseen asteroidipaikkaan
TYPE asteroidtype
nodes AS INTEGER 'montako kulmaa
x AS SINGLE
y AS SINGLE
angle AS SINGLE 'mintenkä asteroidi on pyörähtänyt
hor AS SINGLE 'horisontaalinen liikkumisnopeus
ver AS SINGLE 'vertikaalinen liikkumisnopeus
spin AS SINGLE 'pyörimisnopeus
radius AS SINGLE 'halkaisija pikseleinä
lifetime AS INTEGER 'jos -1, asteroidi elää kunnes ammutaan, jos > 0 asteroidi elää niin monta framea kuin lifetime määrää (eli kyseessä on asteroidinsirpale, splintteri)
END TYPE
TYPE shottype
x AS SINGLE
y AS SINGLE
angle AS SINGLE 'liikkumissuunta
speed AS SINGLE
lifetime AS INTEGER 'kuinka monta framea rojektiili lentelee vielä
END TYPE
'en ole laskenut noita boundeja, mutta niissä on kai reilusti pelivaraa. voi koittaa laskea jos kokee tarpeelliseksi
DIM SHARED asteroid(1 TO 999) AS asteroidtype
DIM SHARED shot(30) AS shottype
CONST factor = 3.141592 / 180
'pls = pelaajan nopeus
'pla = pelaajan liikkumissuunta asteina
'shotdelay = montako frame odotetaan ennen kuin voi ampua uudestaan
'throttle = kaasu (+ / - / off)
'turning = kääntyminen (vasen / oikea / off)
'throttlen ja turningin itseisarvo määrää kuinka monta framea niiden vaikutus kestää
SCREEN 7, , 1, 0 'toinen sivu on aktiivinen, toinen se mikä näytetään (olikohan nimeltään tuplabufferointi?)
'tilastotietoja
DIM SHARED frags AS INTEGER 'tuhottujen asteroidien lkm
DIM SHARED shots AS INTEGER 'ammutut laukaukset
pls = -2 'pelaajan nopeus (negatiivinen vie eteenpäin)
asteroids = 120 'asteroidin lukumäärä alussa
cx = 320 / 2: cy = 200 / 2 'kentän keskikohta
'asteroidien sijoittuminen kartalle
fieldwidth = 1000 'kartan leveys
fieldheight = 1000 'kartan pituus
'tehdään aloitusasteroidit
FOR i = 1 TO asteroids
x = RND * fieldwidth - fieldwidth / 2 + cx
y = RND * fieldheight - fieldheight / 2 + cy
r = RND * 10 + 7 'säde
newasteroid x, y, (RND - .5) / 5, (RND - .5) / 5, r, r * .7, RND * 360, RND * 10 - 5, -1
NEXT
DIM foo AS STRING 'Foo = viimeksi painettu INKEY$
DO: foo = INKEY$
CLS
'piirretään pelaajan vesseli ja käännetään sitä pelaajan liikkumiskulman mukaan
a = (pla - 90) * factor
x1 = COS(a) * 15 + cx
y1 = SIN(a) * 15 + cy
a = (pla + 90) * factor
x4 = COS(a) * 5 + cx
y4 = SIN(a) * 5 + cy
a = (pla + 90 + 45) * factor
x2 = COS(a) * 15 + cx
y2 = SIN(a) * 15 + cy
a = (pla + 90 - 45) * factor
x3 = COS(a) * 15 + cx
y3 = SIN(a) * 15 + cy
LINE (x1, y1)-(x2, y2), 1
LINE (x2, y2)-(x4, y4), 1
LINE (x1, y1)-(x3, y3), 1
LINE (x4, y4)-(x2, y2), 1
LINE (x4, y4)-(x3, y3), 1
PAINT (cx, cy), 11, 1
'lasketaan, kuinka paljon asteroideja täytyy liikuttaa
'(on simppelinpää tehdä se näin että asteroidit liikkuvat eikä pelaaja)
a = (pla - 90) * factor
x = COS(a) * pls
y = SIN(a) * pls
'silmukka jokaiselle asteroidille
FOR i = 1 TO UBOUND(asteroid)
IF asteroid(i).radius > 0 THEN
'liikutetaan asteroidia sekä pelaajan että asteroidin nopeuden perusteella
asteroid(i).x = asteroid(i).x + x + asteroid(i).hor
asteroid(i).y = asteroid(i).y + y + asteroid(i).ver
'katotaan ettei asteroid(i).angle ylitä 360 ja käännetään asteroidia
asteroid(i).angle = asteroid(i).angle MOD 360
asteroid(i).angle = asteroid(i).angle + asteroid(i).spin
IF asteroid(i).lifetime > 0 THEN
asteroid(i).lifetime = asteroid(i).lifetime - 1
IF asteroid(i).lifetime <= 0 THEN asteroid(i).radius = 0 'hävitetään asteroidinsirpale kun se on riehunut kentällä riittävän kauan
END IF
'määrätään asteroideille eri piirtoväri kuin sirpaleille selvyyden vuoksi
IF asteroid(i).lifetime = -1 THEN fill = 7: border = 8 ELSE fill = 8: border = 1
'piirretään monikulmio eli asteroidi
FOR a = asteroid(i).angle TO 360 + asteroid(i).angle STEP 360 / asteroid(i).nodes
x1 = COS(a * factor) * asteroid(i).radius + asteroid(i).x
y1 = SIN(a * factor) * asteroid(i).radius + asteroid(i).y
a2 = a - (360 / asteroid(i).nodes)
x2 = COS(a2 * factor) * asteroid(i).radius + asteroid(i).x
y2 = SIN(a2 * factor) * asteroid(i).radius + asteroid(i).y
LINE (x1, y1)-(x2, y2), border
NEXT
'täytetään monikulmio eli asteroidi (omg :p)
PAINT (asteroid(i).x, asteroid(i).y), fill, border
'mitataan asteroidin etäisyys pelaajan pythagoraan käskyllä a^2 + b^2 = c^2
ex = asteroid(i).x - cx: ey = asteroid(i).y - cy
dist = SQR(ex * ex + (ey * ey))
IF dist < asteroid(i).radius + 3 AND asteroid(i).lifetime <= 0 THEN killasteroid i: EXIT DO
END IF
NEXT
'silmukka ampuksille
FOR i = 0 TO UBOUND(shot)
IF shot(i).lifetime > 0 THEN
'jotta ammus ei lentelisi loputtomiin vähennetään lifetimeä:
shot(i).lifetime = shot(i).lifetime - 1
'liikutetaan ampusta
a = (shot(i).angle - 90) * factor
shot(i).x = COS(a) * shot(i).speed + shot(i).x
shot(i).y = SIN(a) * shot(i).speed + shot(i).y
'piirretään komea KELTAINEN lasersäde:
a = (shot(i).angle + 90) * factor
LINE (shot(i).x, shot(i).y)-(COS(a) * 5 + shot(i).x, SIN(a) * 5 + shot(i).y), 14
'tarkistetaan mahd. osuma asteroidiin
FOR d = 1 TO UBOUND(asteroid)
IF asteroid(d).radius > 0 THEN
'jos asteroidi elää, mitataan sen etäisyys ammukseen:
ex = asteroid(d).x - shot(i).x: ey = asteroid(d).y - shot(i).y
dist = SQR(ex * ex + (ey * ey))
'jos osuma, tapetaan asteroidi ja ammus
IF dist < asteroid(d).radius AND asteroid(d).lifetime <= 0 THEN
killasteroid d 'tuhoa asteroidi
shot(i).lifetime = 0 'hävitä ammus
exit for 'älä tarkista uusia asteroiditörmäyksiä tälle samalle ammukselle, muuten tämä ammus tuhoaisi killasteroid-subissa syntyvät asteroidinsirpaleet
END IF
END IF
NEXT
END IF
NEXT
'kiihdytetään (nopeudellisesti) ja käännetään pelaajaa (melkein purkkaa mutta ei ihan)
'jos throttle != 0, throttlea lähennetään kohti nollaa ja kiihdytetään pelaajan vauhtia (pls on siis pelaajan nopeus)
IF throttle <> 0 THEN
throttle = throttle - SGN(throttle)
pls = pls - SGN(throttle) / 25
ELSE
'tämä on kitkaefekti (en tiedä onko validi mutta toimii ja on järkeenkäypä)
pls = pls - (.0005 * SGN(pls))
IF ABS(pls) < .0005 THEN pls = 0
END IF
'pelaajan kääntäminen toimii samalla tavalla kuin yllä paitsi että kitkavaikutus on otettu pois
'(tietenkin, muutenhan nokka hakeutuisi kokoajan pohjoiseen, eikä sitä haluta)
IF turning <> 0 THEN
turning = turning - SGN(turning)
pla = pla + SGN(turning) * 5
END IF
'napit
SELECT CASE INP(&H60)
CASE 75: turning = -2 'vasen
CASE 72: throttle = 10 'ylös
CASE 77: turning = 2 'oikea
CASE 80: throttle = -10 'alas
CASE 28, 57: 'käysisään tai avaruus
IF shotdelay <= 0 THEN
'etsitään eka tyhjä ammus (joka ei ole liikenteessä) ja lähetetään se matkaan
FOR i = 0 TO UBOUND(shot)
IF shot(i).lifetime <= 0 THEN
shot(i).lifetime = 32 'ammus lentää 32 frame eli lifetime * speed pikselin matkan
shot(i).x = cx
shot(i).y = cy
shot(i).angle = pla
shot(i).speed = 3
EXIT FOR
END IF
NEXT
shotdelay = 5 'milloin voidaan ampua uusiks?
shots = shots + 1
END IF
END SELECT
IF shotdelay > 0 THEN shotdelay = shotdelay - 1
'tehdään kuvalle raamit koska muuten PAINT sekoilisi (voit testata miten jos otat 2 riviä alta poies)
LINE (10, 10)-(309, 189), 1, B
PAINT (1, 1), 1
PCOPY 1, 0 'nyt kun piiräminen on valmis, siirretään piirretty kuva näkyviin
'tässä on delay hidastamaan turhan nopeeta juoksua
alkuaika = TIMER
DO: LOOP UNTIL TIMER - alkuaika => .01
LOOP UNTIL foo$ = CHR$(27)
SCREEN 0, , 0, 0
WIDTH 80, 25
CLS
COLOR 15
PRINT "NYT TULI KOLLIISSIO :("
PRINT ""
PRINT "Ampuksia:"; shots
PRINT "Kaatoja:"; frags; "/"; asteroids
PRINT
PRINT
'lasketaan accuracy eli osumistarkkuusprossa:
IF shots = 0 THEN a = 0 ELSE a = INT(frags / shots * 1000) / 10
PRINT " OSUMISTARKKAILU:"; a; "%"
COLOR 8: LOCATE 23, 53: PRINT "Puhveli teki 10.3.2005"
SLEEP
COLOR 7: CLOSE : END: STOP: SYSTEM
SUB killasteroid (i)
'tämä subi räjäyttää asteroidin kirjaimellisesti palasiksi
'i = asteroidin arrayindexi
IF asteroid(i).lifetime = -1 THEN
IF asteroid(i).radius > 11 THEN
'jos asteroidi on iso, se halkeaa kahtia
FOR CountDown = 1 TO 2
a = RND * 360 * factor
s = RND * 1.5
newasteroid asteroid(i).x, asteroid(i).y, COS(a) * s, SIN(a) * s, asteroid(i).radius * .8, RND * 4 + 4, RND * 360, RND * 40 - 20, -1
NEXT
END IF
'tehdään asteroidille sirpaleita (niiden lukumäärä riippuu asteroidin koosta)
FOR CountDown = 1 TO asteroid(i).radius / 3 + 2
a = RND * 360 * factor
s = RND * 4 + 1
newasteroid asteroid(i).x, asteroid(i).y, COS(a) * s, SIN(a) * s, RND * 4 + 2, RND * 3 + 3, RND * 360, RND * 40 - 20, RND * 30 + 5
NEXT
END IF
asteroid(i).radius = 0
frags = frags + 1
END SUB
SUB newasteroid (x, y, hor, ver, radius, nodes, angle, spin, lifetime)
'etsitään ensimmäinen vapaa asteroidipaikka ja länttäistään asteroidin tiedot siihen
'(vihaan tätä vaihetta, siinä on liikaa monotonista kirjoittamista, mutta jonkun minun sen on tehtävä)
FOR i = 1 TO UBOUND(asteroid)
IF asteroid(i).radius = 0 THEN
asteroid(i).x = x
asteroid(i).y = y
asteroid(i).hor = hor
asteroid(i).ver = ver
asteroid(i).radius = radius
asteroid(i).nodes = nodes
asteroid(i).angle = angle
asteroid(i).spin = spin
asteroid(i).lifetime = lifetime
EXIT SUB
END IF
NEXT
END SUB
'Huhhuh se on siinä. Tulipas kommentoituaOnhan nuitä nähty
Aika niinku vähän koodia noin hienolle pelille :)
Puhveli kirjoitti:
COLOR 7: CLOSE : END: STOP: SYSTEM
:D
Misiköhän tämä muuten edes on täällä..? Muistaakseni poistin tämän heti kun ajattelin että vinkiksi on aika turha :D
Rupesin virittelemään edelleen ja tässä on valmis: http://sooda.dy.fi:8080/mordor/dl/asteroid.exe
Ihan kiva. Muuttujia olisi kannattanut määritellä enemmän kokonaisluvuiksi, niin olisi nopeuttanut. Esim. kaikki taulukkoindeksit.
Muuten hiano, mutta hyvä näppäimistö handleri ois paikallaan :)
ei toimi (valittaa eka et 8080 on liikaa ja sit sitä tiedostoo ei oo siel)
Aihe on jo aika vanha, joten et voi enää vastata siihen.