Code: Select all
SCREEN 480,320,0,1
SetWindow "Painovoimaesimerkki "+Chr(34)+"parannetulla"+Chr(34)+" fysiikkamallinnuksella by SPuntte - © 2010"
//Rajoitetaan ruudunpäivitystaajuutta
Const maksimiFPS = 50
FrameLimit maksimiFPS
//==========================================================================================
//KOKEILE LEIKKIÄ NÄILLÄ
Dim painovoima#, painovoima2#
painovoima = 700.0 //Painovoiman suuruus vaikuttaa pelihahmon hyppykorkeuteen, sekä siihen, miten pitkään hyppy kestää.
painovoima2 = 400.0 //Säätää hyppynäppäimen pohjassa pitämisen vaikutusta hyppykorkeuteen.
Dim hyppyviive% As Integer
hyppyviive = 800 //Aika millisekunteina, jonka jälkeen hyppynäppäimen pohjassa pitäminen ei enää vaikuta hypyn korkeuteen.
Dim vastusMaa#, hyppyimpulssi#, juoksuvoima#, lentokerroin#, massa#, ilmanvastuskerroin, kimmokerroin#, hyvinPieniNopeus# As Float
vastusMaa = 0.05 //Kitka, joka vaikuttaa, kun pelihahmon on maassa eikä juokse.
hyppyimpulssi = 400.0/maksimiFPS //Impulssi (liikemäärä), jonka pelihahmo saa hypätessään.
juoksuvoima = 650.0 //Määrää pelihahmon suurimman nopeuden yhdessä ilmanvastuskertoimen kanssa.
lentokerroin = 0.5 //Juoksuvoiman kerroin, kun pelihahmo ON ilmassa. 0 -> realistinen; liikettä ei voi muuttaa ilmassa
massa = 1.3 //Pelihahmon massa. Suurempi massa vähentää juoksuvoiman, ilmanvastuksen ja hyppyimpulssin vaikutusta.
ilmanvastuskerroin = 28.0 //Vaikuttaa sekä pelihahmon maksiminopeuteen sekä siihen, miten pitkälle pelihahmo liikkuu juoksemisen lopetettuaan.
kimmokerroin = 0.4 //Kuinka paljon pelaajan liike-energiasta säilyy törmättäessä kattoon.
hyvinPieniNopeus = 0.05 //Mikäli pelihahmon nopeus laskee alle tämän, sen katsotaan pysähtyneen
//==========================================================================================
'lataa kartta, siirrä sitä ylöspäin ja animoi se.
Dim kentta
kentta=LoadMap("Media\testmap.til","Media\tileset.bmp")
PositionObject kentta,0,50
PlayObject kentta,0,0,0.5
'lataa animaatiosarja oikealle, maskaa ja piilota se
Dim oikea
oikea=LoadAnimObject("Media\zerorun1.bmp",47,51,0,13)
MaskObject oikea,cbMagenta
ShowObject oikea,OFF
ObjectRange oikea,30,51 'tämä pitää asettaa kaikkiin
'sama vasemmalle
Dim vasen
vasen=LoadAnimObject("Media\zerorun2.bmp",47,51,0,13)
MaskObject vasen,cbMagenta
ShowObject vasen,OFF
ObjectRange vasen,30,51 'tämä pitää asettaa kaikkiin
'Tämä on varsinainen pelihahmo, joka piirretään ja
'jota hallitaan. Sille asetetaan törmäys->kartta
'Tätä EI PIILOTETA.
Dim pelihahmo
pelihahmo=CloneObject(oikea)
SetupCollision pelihahmo,kentta,1,4,2
ObjectRange pelihahmo,30,51 'tämä pitää asettaa kaikkiin
//Muuttujat hahmon nykyiselle ja edelliselle sijainnille
Dim hahmoX#, hahmoY#, vanhaX#, vanhaY# As Float
hahmoX = ObjectX(pelihahmo)
hahmoY = ObjectY(pelihahmo)
vanhaX = hahmoX
vanhaY = hahmoY
'-------------------------------------------------
'Pääsilmukka
Repeat
//Nollataan pelaajaan vaikuttavat voimat varmuuden vuoksi
Dim voimaX#, voimaY#
voimaX# = 0
voimaY# = 0
Dim maassa% As Integer
Dim kitka# As Float
Dim nopeusX#, nopeusY# As Float //Pelihahmon nykyisen ja edellisen sijainnin erotus
//-----------------------------------------------------------------------------------------
//PELIHAHMON KONTROLLOINTI
If RightKey() Then
'juokse oikealle
PaintObject pelihahmo,oikea 'vaihda kuvaa...
If maassa Then PlayObject pelihahmo,2,11,0.25
//Kiihdytetään oikealle (>0)
voimaX = juoksuvoima
ElseIf LeftKey() Then
'juokse vasemmalle
PaintObject pelihahmo,vasen 'vaihda kuvaa...
If maassa Then PlayObject pelihahmo,2,11,0.25
//Kiihtyvyys vasemmalle (<0)
voimaX = -juoksuvoima
Else
'pysäytä animaatio, jos ei juosta
PlayObject pelihahmo,0
EndIf
//Säädetään ilmanvastusta, jos ilmassa
If Not maassa Then voimaX = voimaX * lentokerroin
//Jos ei juosta ja ollaan maassa, hidastetaan pelihahmoa kitkalla
If maassa And voimaX = 0 Then
kitka = vastusMaa
Else
kitka = 0
EndIf
//Ilmanvastus vaikuttaa pelihahmon liikesuuntaa vastaan ja ainoastaan, jos nopeus <> 0
If Abs(nopeusX) > hyvinPieniNopeus Then
voimaX = voimaX -((nopeusX)/Abs(nopeusX))*ilmanvastuskerroin*(nopeusX)*(nopeusX)
Else
nopeusX = 0
vanhaX = hahmoX
EndIf
//-----------------------------------------------------------------------------------------
//HYPPY
Dim hyppyajastin% As Integer
If KeyHit(cbKeyUp) And maassa Then
hyppyajastin = Timer() //Hypyn ajankohtaa tarvitaan myöhemmin
vanhaY = hahmoY - (hyppyimpulssi/massa) //Annetaan pelaajalle impulssi ylöspäin
voimaY = -painovoima2
EndIf
//Tässä vaikutetaan hypyn korkeuteen.
If KeyDown(cbKeyUp) And (Not maassa) And Timer() - hyppyajastin <= hyppyviive Then
voimaY = -painovoima2
Else
voimaY = -painovoima
EndIf
//-----------------------------------------------------------------------------------------
//PELIHAHMON PÄIVITYS
Dim tmpX#, tmpY#
//Lasketaan (itse asiassa Verlet-integroidaan :P) pelaajalle uusi paikka
tmpX = (2-kitka)*hahmoX - (1-kitka)*vanhaX + voimaX/massa*(1.0/maksimiFPS)*(1.0/maksimiFPS)
tmpY = (2-kitka)*hahmoY - (1-kitka)*vanhaY + voimaY/massa*(1.0/maksimiFPS)*(1.0/maksimiFPS)
vanhaX = hahmoX
vanhaY = hahmoY
hahmoX = tmpX
hahmoY = tmpY
//lasketaan uusi nopeus objektin liikuttamista varten
nopeusX = hahmoX - vanhaX
nopeusY = hahmoY - vanhaY
'liikuta pelihahmoa
TranslateObject pelihahmo,(nopeusX),(nopeusY)
UpdateGame 'päivitä törmäys
CloneCameraPosition pelihahmo 'liimaa kamera
//Mikäli törmäys tapahtui, hahmo ei ehkä siirtynyt sinne, minne fysiikka sitä yritti siirtää
//-> päivitetään varmuuden vuoksi, jotta fysiikka ja todellinen sijainti pysyvät synkassa
hahmoX = ObjectX(pelihahmo)
hahmoY = ObjectY(pelihahmo)
//-----------------------------------------------------------------------------------------
//TÖRMÄYSTEN TUNNISTUS JA KÄSITELY
maassa=0 'ilmassa jollei toisin käy ilmi
Dim tormaykset% As Integer
tormaykset=CountCollisions(pelihahmo)
'katsotaan tärmätäänkö kattoon tai lattiaan
Dim i% As Integer
For i=1 To tormaykset
If GetCollision(pelihahmo,i)=kentta
Dim tKulma%
tKulma = CollisionAngle(pelihahmo,i)//Törmäyskulma talteen, ettei tule turhia funktiokutsuja
'lattia
If tKulma=90 Then
maassa=1 'jalat ON maassa
//seinät
ElseIf tKulma = 0 Or tKulma = 180 Then
vanhaX = hahmoX + kimmokerroin*(nopeusX)
'katto
ElseIf tKulma=270 Then
vanhaY = hahmoY + kimmokerroin*(nopeusY)
EndIf
EndIf
Next i
'jos ollaan ilmassa, näytä toisenlainen kuva
If Not maassa Then PlayObject pelihahmo,12,0
DrawGame //Objektit täytyy piirtää, jotta teksti näkyy
Text 5, 5, "FPS: " + FPS()
DrawScreen 'piirrä näyttö
Until EscapeKey()
Koodi näyttää hirveältä siksi, että se on tosiaan vain vähän reilummalla kädellä muokattu versio alkuperäisestä oppitunnista, ja sen sisällöstä varmaan puolet on kommenttirivejä. Ajattelin kuitenkin, että siitä on ehkä näin enemmän hyötyä; tyyppikokoelmat ja muut hienostuneemmat koodikoukerot todennäköisesti nostaisivat tutustumiskynnyksen turhan korkeaksi aloittelijoille.
Tämä on esimerkki, ei valmis fysiikkakirjasto. Osaavampi koodari vääntää tästä luonnollisesti geneerisemmän version, jolloin käyttö suuremmilla objektimassoilla on mahdollista. Soveltaminen omiin projekteihin on sallittua ja suositeltavaa ;)
Koodi on Force Variable Declaration -yhteensopivaa, sillä ilman sitä typofixaus olisi täyttä masokismia.
Fysiikasta:
CB:n objektimoottori on parhaimmillaan alkuperäisessä oppituntikoodissa: yksinkertainen mutta silti täysiverinen tasohyppelymoottori on ängetty reilusti alle sataan riviin(ilman kommentteja). Tarkituksenaani olikin näyttää, että pienellä vaivalla siitä saa hiottua timantin. Periaatteesa mitään alkuperäistä ominaisuutta ei ole poistettu - ainoastaan hypyn ja painovoiman toimintaa on hieman säädetty, mutta objektimoottoria hyödynnetään yhä samalla tavalla. Alkuperäisen ohjauksen tilalla on nyt pari matematiikan ja fysiikan kaavaa (ilmanvastus sekä Verlet-integraattori) eikä muuta.
Esimerkissä ei ole haettu realismia, vaikka muuttujia säätämällä sen lisääminen onnistuukin. "Alitajuiseksi esikuvaksi" voisin mainita Messhofin Punishment: The Punishing -pelin.
Simulaation dynamiikka on siinä mielessä FPS-riippumatonta, että mikäli se pyörii asetetulla maksimiruudunpäivitystaajuudella, ei sen toiminnassa ole suurta eroa. Verlet-algoritmin ominaisuus kuitenkin on, että se ennemminkin hukkaa energiaa kuin lisää sitä. Tämä näkyy siten, että matalammalla FPS-rajoituksella pelihahmo liikkuu hieman hitaammin.
@Grandi: suurenna vastusMaa-muuttujan arvoa. Arvo 1.0 poistaa liukumisen kokonaan.