Fysiikkamallinnuksia

Oletko tehnyt jotain, mistä muut voisivat hyötyä. Postita vinkit tänne.
SPuntte
Tech Developer
Tech Developer
Posts: 650
Joined: Mon Aug 27, 2007 9:51 pm
Location: Helsinki, Finland
Contact:

Re: Fysiikkamallinnuksia

Post by SPuntte »

Taisin kirjoittaa tämän DJ-Nerdille, kun hän kysyi apua biljardipelinsä kanssa, mutta tämähän on loistava paikka kontribuoida koko yhteisön hyväksi. Siis tällainen typerä biljardifysiikkaesimerkki, joka käyttää bruteforce-törmäystarkistusta. Tämä tarkoittaa, että algoritmin kompleksisuus on luokkaa O(n² - n), eli kauhean montaa palloa se ei jaksa pyörittää tuollaisenaan. Spatial hashing -tekniikalla algoritmin saisi varmasti kantamaan satoja ellei tuhansia palloja reaaliajassa.

Koodia on vähän kommentoitu, mutta kyselkää, jos jotain outoa ilmenee:

Code: Select all

Const SCRW = 950		//Ikkunan mitat
Const SCRH = 550		//|
Const FPSLIMIT = 40 	//FPS-maksimi
Const PALLOJA = 25		//Pallojen määrä
Const COR_SEINA = 1.0	//Seinän kimmokerroin

SCREEN SCRW, SCRH, 0, 1

Type PALLO
	Field obj%	//ruudulla näkyvä objekti
	Field posX#	//x-sijainti
	Field posY#	//y-sijainti
	Field velX#	//x-nopuse
	Field velY#	//y-nopeus
	Field rad#	//pallon säde
	Field mass#	//pallon massa
	Field cor#	//pallon kimmokerroin
EndType

//Luodaan pallot
For i = 1 To PALLOJA
	p.PALLO = New(PALLO)
	p\obj = MakeObject()	//tehdään tyhjä objekti
	
	tmpVel# = Rnd(1, 5)	//Arvotaan kappaleelle sopiva nopeus
	tmpAng# = Rnd(0, 360)
	p\velX = tmpVel*Cos(tmpAng)
	p\velY = tmpVel*Sin(tmpAng)
	
	//Arvotaan pallon kimmokerroin ja säde, ja lasketaan sen massa
	p\cor = 1 //Rnd(0.99, 0.995)
	p\rad = Sqrt(Rnd(100, 1000))
	p\mass = p\rad*p\rad*p\rad
	
	//Arvotaan pallolle sijainti ikkunan sisäpuolelta
	p\posX = Rnd(-SCRW/2 + p\rad, SCRW/2 - p\rad)
	p\posY = Rnd(-SCRH/2 + p\rad, SCRH/2 - p\rad)
	PositionObject p\obj, p\posX, p\posY
	
	//Tässä teksturoidaan pallo-objekti
	tmpTex = MakeImage(Int(2*p\rad), Int(2*p\rad))
	DrawToImage tmpTex
		Color 255, 255, 255
		Circle 0, 0, 2*p\rad, 0
		
		//Numero
		Color Rand(100, 255), Rand(100, 255), Rand(100, 255)
		Text Int(p\rad - 0.5 - 0.5*TextWidth(Str(i))), -Int(p\rad - 0.5 - 0.5*TextHeight(Str(i))), Str(i)
	DrawToScreen
	//Teksturoidaan ja poistetaan turha tekstuuri
	PaintObject p\obj, -tmpTex
	DeleteImage tmpTex
	
Next i

Repeat
	kEnergia# = 0	//Liike-energia
	
	//Päivitetään pallot
	For p.PALLO = Each PALLO
		p\posX = p\posX + p\velX
		p\posY = p\posY + p\velY
		PositionObject p\obj, p\posX, p\posY
		
		//Nämä If-lausekkeet tarkistavat, että pallo pysyy ikkunan sisäpuolella
		//Mikäli pallo osuu seinään, sen vastaava nopeuden komponentti käännetään päinvastaiseen suuntaan
		If p\posX - p\rad <= -SCRW/2 And p\velX < 0 Then
			p\velX = -p\velX*p\cor*COR_SEINA
			p\posX = -SCRW/2 + p\rad
		EndIf
		If p\posX + p\rad >= SCRW/2 And p\velX > 0 Then
			p\velX = -p\velX*p\cor*COR_SEINA
			p\posX = SCRW/2 - p\rad
		EndIf
		If p\posY - p\rad <= -SCRH/2 And p\velY < 0 Then
			p\velY = -p\velY*p\cor*COR_SEINA
			p\posY = -SCRH/2 + p\rad
		EndIf
		If p\posY + p\rad >= SCRH/2 And p\velY > 0 Then
			p\velY = -p\velY*p\cor*COR_SEINA
			p\posY = SCRH/2 - p\rad
		EndIf
		
		//Summataan kokonaisenergia
		kEnergia = kEnergia + 0.5*p\mass*(p\velX*p\velX + p\velY*p\velY)
	Next p
	
	testeja% = 0
	torm1% = 0
	torm2% = 0
	//Törmäystarkistus
	For p1.PALLO = Each PALLO
		For p2.PALLO = Each PALLO
			If p1 <> p2 Then
				testeja = testeja + 1
				
				x12# = p2\posX - p1\posX //Pallojen keskipisteiden yhdysjanavektori
				y12# = p2\posY - p1\posY //|	
				rsum# = p1\rad + p2\rad	//Pallojen säteiden summa
				cdotc# = x12*x12 + y12*y12 //Pallojen etäisyyden neliö (kierretään raskas neliöjuuri)
				
				//Tarkistetaan törmäävätkö pallot
				If cdotc <= rsum*rsum Then
					torm1 = torm1 + 1
					
					cLen# = Sqrt(cdotc)	//yhdysjanan pituus aka pallojen etäisyys
					v1# = (p1\velX*x12 + p1\velY*y12)/cLen //Pallojen nopeudet projisoituna yhdysjanavektorille
					v2# = (p2\velX*x12 + p2\velY*y12)/cLen
					vdiff# = v1 - v2 //Pallojen suhteellisen nopeuden yhdysjanan suuntainen komponentti
					
					//Tarkistetaan, liikkuvatko pallot toisiaan kohti (suhteellinen nopeus positiivinen)
					If vdiff > 0 Then
						torm2 = torm2 + 1
						
						cr# = p1\cor*p2\cor //Pallojen yhdistetty kimmokerroin
						vn1# = (p1\mass*v1 + p2\mass*v2 - p2\mass*cr*vdiff)/(p1\mass + p2\mass) //Uusi nopeus laskettuna liikemäärän säilymislain ja restituutiokertoimen avulla
						vn2# = (p1\mass*v1 + p2\mass*v2 + p1\mass*cr*vdiff)/(p1\mass + p2\mass)
						
						unitX# = x12/cLen //Yhdysjanan suuntainen yksikkövektori
						unitY# = y12/cLen
						v1diff# = vn1 - v1 //Noepuksien erotus ennen ja jälkeen törmäyksen (skalaari)
						v2diff# = vn2 - v2
						v1dx# = (v1diff)*unitX //Pallojen nopeuksien muutokset (vektori)
						v1dy# = (v1diff)*unitY
						v2dx# = (v2diff)*unitX
						v2dy# = (v2diff)*unitY
						
						p1\velX = p1\velX + v1dx //Pivitetään pallojen nopeudet
						p1\velY = p1\velY + v1dy
						p2\velX = p2\velX + v2dx
						p2\velY = p2\velY + v2dy
					EndIf
				EndIf
			EndIf
		Next p2
	Next p1
	
	//Piirretään objektit, että teksti näkyy
	DrawGame
	
	//Tulostetaan vähän infoa
	Color 150, 0, 0
	Text 5, 5, "Systeemin kokonaisliike-energia: " + kEnergia
	Text 5, 20, "Törmäystarkistuksia: " + testeja
	Text 5, 35, "Päällekkäisiä palloja: " + torm1
	Text 5, 50, "Törmääviä palloja: " + torm2
	
	DrawScreen
	SetWindow Str(FPS())
	ftc = LimitFPS(ftc)
Forever

//Rajoittaa Pelin pyörimisnopeutta ja lepuuttaa prosessoria yli jäävän ajan
Function LimitFPS(FrameTime%)
    If Timer()-FrameTime<1000/FPSLIMIT Then Wait 1000/FPSLIMIT-(Timer()-FrameTime)
    Return Timer()
EndFunction
EDIT:

Jos jotakuta kiinnostaa itse fysiikka koodin ja vektorimatematiikan takana, kannattaa tsekata tämä Wikipedia-artikkeli.

CoolBasic henkilökuntaa
Tech-kehittäjä
CoolBasic Classic, Cool VES

CoolPhysicsEngine | MissileSystem | Jana-ympyrä -törmäys | cbSimpleTexture | CoolCPLX
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: Fysiikkamallinnuksia

Post by MaGetzUb »

Oli kyllä hieno tuo biljardi jutska, täytyy myöntää, ehkä nopeudet vaan tuntuivat epärealistislita.

Btw, mites SPuntte tuo Advanced Character Physics sivuilla tuo törmäyshomma toimii, en oikein saa tuosta kaavasta selvää, johna tuo linja/kolmio törmää tuohon terävään osaan tuola ns. häkissäänsä(figure 3a). Ja miten yleensä ko. linja käydään läpi, kun tarkistetaan monen objektin leikkaus?
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.
SPuntte
Tech Developer
Tech Developer
Posts: 650
Joined: Mon Aug 27, 2007 9:51 pm
Location: Helsinki, Finland
Contact:

Re: Fysiikkamallinnuksia

Post by SPuntte »

MaGetzUb wrote:Oli kyllä hieno tuo biljardi jutska, täytyy myöntää, ehkä nopeudet vaan tuntuivat epärealistislita.
Toki ilmanvastus ja muu kitka puuttuu, mutta muuten nopeudet ovat ihan realistisia. Fysiikka kertoo, miksi:
muista, että liikemäärä (massan ja nopeuden tulo) säilyy, eli törmäyksessä kappaleine liikemäärä muuttu tasan saman verran. Jos kappaleen A massa on kymmenkertainen B:n massaan verrattuna, muuttu kappaleen B nopeus törmäyksessä kymmenketaisesti A:n nopeuden muutoksen verran. Esimerkissäni massa ~ pallon säteen kuutio, joten esimerkiksi pallon törmätessä siihen verrattuna kaksi kertaa suurempaan. palloon, muuttuu pienemmän pallon nopeus kahdeksankertaisesti verrattuna suurempaan palloon.

Alussa arvotaan kappaleiden nopeudet, ei liikemärät, joten liikemääräjakauma on eätasainen. Kun pallot törmäilevät, se tasoittuu, jolloin keskimääräistä suuremmat pallot tilastollisesti hidastuvat ja pienemmät nopeutuvat.
MaGetzUb wrote:Btw, mites SPuntte tuo Advanced Character Physics sivuilla tuo törmäyshomma toimii, en oikein saa tuosta kaavasta selvää, johna tuo linja/kolmio törmää tuohon terävään osaan tuola ns. häkissäänsä(figure 3a). Ja miten yleensä ko. linja käydään läpi, kun tarkistetaan monen objektin leikkaus?
Ensinnäkin kannattaa huomioida, että sivulla mainitaan seuraavaa:
Thomas Jakobsen @ Advanced Character Physics wrote:We won’t go into the intricacies of constructing a collision detection engine since this is a science in itself. Instead we assume that there is a subsystem available which allows us to detect the collision. Furthermore we assume that the subsystem can reveal to us the penetration depth and identify the penetration points on each of the two colliding objects.
eli kysessä on vain törmäysvaste tietyn datan perusteella, ei törmäystarkistus. Kaava suorittaa yksinkertaisen projisoinnin siten, että pisteiden p1 ja p2 välinen jana ei leikkaa määriteltyä polygonia.
CoolBasic henkilökuntaa
Tech-kehittäjä
CoolBasic Classic, Cool VES

CoolPhysicsEngine | MissileSystem | Jana-ympyrä -törmäys | cbSimpleTexture | CoolCPLX
hybrid
Newcomer
Posts: 18
Joined: Sun Apr 18, 2010 5:24 pm

Re: Fysiikkamallinnuksia

Post by hybrid »

SPuntte wrote:Taisin kirjoittaa tämän DJ-Nerdille, kun hän kysyi apua biljardipelinsä kanssa, mutta tämähän on loistava paikka kontribuoida koko yhteisön hyväksi. Siis tällainen typerä biljardifysiikkaesimerkki, joka käyttää bruteforce-törmäystarkistusta. Tämä tarkoittaa, että algoritmin kompleksisuus on luokkaa O(n² - n), eli kauhean montaa palloa se ei jaksa pyörittää tuollaisenaan. Spatial hashing -tekniikalla algoritmin saisi varmasti kantamaan satoja ellei tuhansia palloja reaaliajassa.

Koodia on vähän kommentoitu, mutta kyselkää, jos jotain outoa ilmenee:

Code: Select all

			If p1 <> p2 Then
EDIT:

Jos jotakuta kiinnostaa itse fysiikka koodin ja vektorimatematiikan takana, kannattaa tsekata tämä Wikipedia-artikkeli.

Hieno fysiikanmallinnus. Raskaasti modattuna ujutin tuon avaruus aiheiseen projektiini(kiitos mallista, projektista lisää myöhemmin) ja ihmettelin miksi kaikki törmäykset tarkistetaan kahteen kertaan. Kompleksisuus luokan saa siis pudotettua puoleen jos muuttaa tuon koodirivin muotoon.

Code: Select all

If p1 < p2 Then
Kombinaatio kaavan avulla voi laskea että törmäystarkistuksia on nyt minimi määrä brute forcelle.
http://fi.wikipedia.org/wiki/Kombinaatio
Post Reply