2dRayCast: Pikselin tarkka törmäys.

Oletko tehnyt jotain, mistä muut voisivat hyötyä. Postita vinkit tänne.
Post Reply
JATothrim
Tech Developer
Tech Developer
Posts: 606
Joined: Tue Aug 28, 2007 6:46 pm
Location: Kuopio

2dRayCast: Pikselin tarkka törmäys.

Post by JATothrim »

Tämmösen virittelin: kuvan sisällä raycastingillä toimivat törmäykset. Jahka kehitän kirjastoa pidemmälle niin funktioiden hyödyllisyys ja määrä paranevat.
Esimerkkinä on kuinka kirjastolla voidaan tehdä sulavasti maanpinnalla kulkeva pallo. Raycast on ehkä paras tapa välttää "tunneloituminen" tämän tyyppisessä törmäys moottorissa, sillä esine kulkee yleensä todella nopeasti.
Nykyiset funktiot:
CheckPlotCollision() - epätarkka ehkä jopa hyödytön reunan etsintä tapa.
RayPlotCollision() - paras, nopein ja tarkin raycaster mitä cb:llä voi tehdä getpixel2() funktioon perustuen. (jos on vieläkin nopeampi, niin kertokaa ihmeessä)
CheckPlotAngleCollision() - maaston normaali CheckPlotCollision():lla. arvaa tarkuus...
RayPlotAngleCollision() - maaston normaali, toimiva ja kätevä.
RayPlotEnvCollision() - maaston normaali hitaille jutuille.
Funktiot:

Code: Select all

// Pixel-Perfect Collision, Edge Detector(s)!

Const COLLISION_PIXEL = -16777216
' Cords are in image cordinates, (0,0) is the left top corner. :
Global CPC_PlotX As Float
Global CPC_PlotY As Float

// Divide & Test Raycaster. What smaller acc# is that better is the result.
// Note that this algorithm can "skip" pixels pretty easily, so use it for
// a thick walls and when new-coordinates are inside the wall!
// Returns: -2 if coordinates are out of image bonds.
// 			false if there is no collision.
// 			true if there (may be) is collision.
// 			Solution is placed in globals CPC_PlotX and CPC_PlotY.
Function CheckPlotCollision(img%, oldx#, oldy#, newx#, newy#, acc# = 10)
	
	'Check out of bounds:
	xb% = ImageWidth(img)
	yb% = ImageHeight(img)
	If (oldx < 0  Or oldy < 0 Or oldx > xb  Or oldy > yb) Or (newx < 0 Or newy < 0 Or newx > xb Or newy > yb)
		Return -2
	EndIf
	
	'Check the collision
	buffer% = Image(img)
	Lock Image(img)
	
	//New coordinates *must* bus be in side the wall
	If GetPixel2(newx, newy, buffer) = COLLISION_PIXEL
		Unlock buffer
		Return 0
	EndIf
	
	'FIND the edge by divinding coordinates Step by Step.
	to_new_x# = newx
	to_new_y# = newy
	to_old_x# = oldx
	to_old_y# = oldy
	to_x# = oldx
	to_y# = oldy
	current_x# = newx
	current_y# = newy
	While Distance(to_x, to_y, current_x, current_y) > acc
		
		movx# = (current_x + to_x) / 2.0
		movy# = (current_y + to_y) / 2.0
		
		If GetPixel2(Int(current_x), Int(current_y), buffer) <> COLLISION_PIXEL
			to_new_x = current_x
			to_new_y = current_y
			to_x = to_old_x#
			to_y = to_old_y#
		Else
			to_old_x# = current_x
			to_old_y# = current_y
			to_x = to_new_x
			to_y = to_new_y
		EndIf
		current_x = movx
		current_y = movy
		'Circle current_x-2,current_y-2,4 'For algorithm testing purpose..
	Wend
	Unlock buffer
	CPC_PlotX = (current_x + to_x) / 2.0
	CPC_PlotY = (current_y + to_y) / 2.0
	Return 1
EndFunction

// Full Raycaster.
// Returns: -2 if coordinates are out of image bonds.
// 			false when there is no collision.
//			true if there is an collision.
Function RayPlotCollision(img%, x1%, y1%, x2%, y2%)
	'Check out of bounds:
	xb% = ImageWidth(img)
	yb% = ImageHeight(img)
	If (x1 < 0  Or y1 < 0 Or x1 > xb  Or y1 > yb) Or (x2 < 0 Or y2 < 0 Or x2 > xb Or y2 > yb)
		Return -2
	EndIf
	
	'Check the collision
	buffer% = Image(img)
	Lock buffer
	
	dx% = Abs(x2 - x1)
	dy% = Abs(y2 - y1)
	y% = y1
	x% = x1
	error% = 0
	If dx > dy
		add% = 1 - (y2 < y1) Shl 1
		If x1 < x2
			While x <= x2
				If GetPixel2(x, y, buffer) <> COLLISION_PIXEL
					CPC_PlotX = x - 1
					CPC_PlotY = y
					Unlock buffer
					Return 1
				EndIf
				error = error + dy
				If error Shl 1 >= dx
					y = y + add
					error = error - dx
				EndIf
				x = x + 1
			Wend
		Else
			While x >= x2
				If GetPixel2(x, y, buffer) <> COLLISION_PIXEL
					CPC_PlotX = x + 1
					CPC_PlotY = y
					Unlock buffer
					Return 1
				EndIf
				error = error + dy
				If error Shl 1 >= dx
					y = y + add
					error = error - dx
				EndIf
				x = x - 1
			Wend
		EndIf
	Else
		add% = 1 - (x2 < x1) Shl 1
		If y1 < y2
			While y <= y2
				If GetPixel2(x, y, buffer) <> COLLISION_PIXEL
					CPC_PlotX = x
					CPC_PlotY = y - 1
					Unlock buffer
					Return 1
				EndIf
				error = error + dx
				If error Shl 1 >= dy
					x = x + add
					error = error - dy
				EndIf
				y = y + 1
			Wend
		Else
			While y >= y2
				If GetPixel2(x, y, buffer) <> COLLISION_PIXEL
					CPC_PlotX = x
					CPC_PlotY = y + 1
					Unlock buffer
					Return 1
				EndIf
				error = error + dx
				If error Shl 1 >= dy
					x = x + add
					error = error - dy
				EndIf
				y = y - 1
			Wend
		EndIf
	EndIf
	
	Unlock buffer
	Return 0
EndFunction

// Finds the collision normal of ray. (if there is an collision)
// Uses CheckPlotCollision to detect the edge. acc# is the accuary and
// wide# (pixels) is how far away two other rays are casted from
// orginal ray to calculate the angle. 
// Returns: -2 if coordinates are out of image bonds.
// 			-1 if there is no collision.
//			0.0-360.0 if there is an collison. Collision point is
//			placed in globals CPC_PlotX and CPC_PlotY
Function CheckPlotAngleCollision(img%, oldx#, oldy#, newx#, newy#, wide# = 4, acc# = 5)
	If CheckPlotCollision(img, oldx, oldy, newx, newy, acc) = 0 Then Return -1
	cx# = CPC_PlotX
	cy# = CPC_PlotY
	// "Left side"
	angle# = GetAngle(oldx, oldy, newx, newy)
	_addx# = Cos(angle + 90) * wide
	_addy# = -Sin(angle + 90) * wide
	If CheckPlotCollision(img, oldx + _addx, oldy + _addy, newx + _addx, newy + _addy, acc) = 0 Then Return -1
	lx# = CPC_PlotX
	ly# = CPC_PlotY
	'Line oldx + _addx, oldy + _addy, lx, ly
	// "Right side"
	_addx# = Cos(angle - 90) * wide
	_addy# = -Sin(angle - 90) * wide
	If CheckPlotCollision(img, oldx + _addx, oldy + _addy, newx + _addx, newy + _addy, acc) = 0 Then Return -1
	rx# = CPC_PlotX
	ry# = CPC_PlotY
	CPC_PlotX = cx
	CPC_PlotY = cy
	'Line oldx + _addx, oldy + _addy, rx, ry
	//Calculate the angle:
	ang_to_l# = GetAngle(cx, cy, lx, ly)
	ang_to_r# = GetAngle(cx, cy, rx, ry)
	pnormal1# = (((ang_to_l + 180) + ang_to_r) / 2.0)
	pnormal2# = (((ang_to_r - 180) + ang_to_l) / 2.0)
	normal# = (pnormal1 + pnormal2) / 2.0
	// correct, If normal is upside-down:
	angle + 180
	_addx = Cos(angle)
	_addy = Sin(angle)
	If Distance(_addx,_addy,Cos(normal),Sin(normal)) < Distance(_addx,_addy,Cos(normal + 180),Sin(normal + 180))
		Return normal
	Else
		Return WrapAngle(normal + 180)
	EndIf
EndFunction

// Finds the collision normal of ray. (if there is an collision)
// Uses RayPlotCollision to detect the edge.
// wide# (pixels) is how far away two other rays are casted from
// orginal ray to calculate the angle. Actually this casts always
// tree rays at same time!
// Returns:	-1 if there is no collision.
//			0.0-360.0 if there is an collison (the normal angle). 
//			Collision point is placed in globals CPC_PlotX and CPC_PlotY
Function RayPlotAngleCollision(img%, oldx#, oldy#, newx#, newy#, wide# = 4)
	// "main ray"
	If RayPlotCollision(img, oldx, oldy, newx, newy) < 1 Then Return -1
	cx# = CPC_PlotX
	cy# = CPC_PlotY
	// "Left side"
	angle# = GetAngle(oldx, oldy, newx, newy)
	_addx# = Cos(angle + 90) * wide
	_addy# = -Sin(angle + 90) * wide
	If RayPlotCollision(img, oldx + _addx, oldy + _addy, newx + _addx, newy + _addy) < 1 Then Return -1
	lx# = CPC_PlotX
	ly# = CPC_PlotY
	'Line oldx + _addx, oldy + _addy, lx, ly
	// "Right side"
	_addx# = Cos(angle - 90) * wide
	_addy# = -Sin(angle - 90) * wide
	If RayPlotCollision(img, oldx + _addx, oldy + _addy, newx + _addx, newy + _addy) < 1 Then Return -1
	rx# = CPC_PlotX
	ry# = CPC_PlotY
	CPC_PlotX = cx
	CPC_PlotY = cy
	'Line oldx + _addx, oldy + _addy, rx, ry
	//Calculate the angle:
	ang_to_l# = GetAngle(cx, cy, lx, ly)
	ang_to_r# = GetAngle(cx, cy, rx, ry)
	pnormal1# = (((ang_to_l + 180) + ang_to_r) / 2.0)
	pnormal2# = (((ang_to_r - 180) + ang_to_l) / 2.0)
	normal# = (pnormal1 + pnormal2) / 2.0
	// correct, If normal is upside-down:
	angle + 180
	If Distance(Cos(angle),Sin(angle),Cos(normal),Sin(normal)) < Distance(Cos(angle),Sin(angle),Cos(normal + 180),Sin(normal + 180))
		Return normal
	Else
		Return WrapAngle(normal + 180)
	EndIf
EndFunction

// Gains useful data around position (org_x#, org_y#)
// Function casts total amount of ray_count%, range# lenght rays.
// #1:	Finds the ray, that collide point is nearest to (org_x#, org_y#)
//		Solution is placed to globals CPC_NEAR_ENV_X and CPC_NEAR_ENV_Y
// #2:	Finds the ray, that collide point is furthest to (org_x#, org_y#)
//		Solution is placed to globals CPC_FAR_ENV_X and CPC_FAR_ENV_Y
// Uses RayPlotCollision to detect the edge.
// Returns:	false when there is no collision.
//			true if there is a collision.

Global CPC_NEAR_ENV_X As Float, CPC_NEAR_ENV_Y As Float
Global CPC_FAR_ENV_X As Float, CPC_FAR_ENV_Y As Float

Function RayPlotEnvCollision(img%, org_x#, org_y#, range#, ray_count%)
	i% = 0
	near_dist# = -1
	far_dist# = 0
	collied% = False
	While i < ray_count
		cast_angle# = (360.0 / ray_count) * i
		cast_x# = org_x + Cos(cast_angle) * range
		cast_y# = org_y - Sin(cast_angle) * range
		
		If RayPlotCollision(img, org_x, org_y, cast_x, cast_y)
			dist# = Distance(org_x, org_y, CPC_PlotX, CPC_PlotY)
			If dist > far_dist
				far_dist = dist
				CPC_FAR_ENV_X = CPC_PlotX
				CPC_FAR_ENV_Y = CPC_PlotY
			EndIf
			If dist < near_dist Or near_dist = -1
				near_dist = dist
				CPC_NEAR_ENV_X = CPC_PlotX
				CPC_NEAR_ENV_Y = CPC_PlotY
			EndIf
			collied = True
		EndIf
		i + 1
	Wend
	Return collied
EndFunction

// ###############################
// Sub library: BoolCollisionMaps
// ###############################

//	Scans img and returns memblock containing the collision able areas.
Function CreateCollisionMap(img%, hit_color% = -16777216)
EndFunction

// "Draws"  collision src% to dst% in (x%, y%)
Function ApplyCollisionMapTo(src%, dst%, x%, y%)
EndFunction

// "ImagesCollide" routine.
// Returns: true when there is a collision.
Function CollisionTest(test1%, x1%, y1%, test2%, x2%, y2%)
EndFunction

// Like the CollisionTest expect, is it ultimately more useful!
Function CollisionTestAdv(test1%, x1%, y1%, test2%, x2%, y2%, hx%, hy%, pass% = -1)
EndFunction
Ultimate Esimerkki: Napit w,d kiihdyttää palloa. Nuolinapit oikelle,vasemmalle liikuttavat palloa. Hiiren vasen nappi tiputtaa pallon kursorin kohdalta ja oikea pirtää. rulla säätää siveltimen ja pallon kokoa. r-nappi yrittää _liikuttaa_ pallon kursorin kohdalle. NOTE:Koodi mav:aa jostain syystä herkästi jos pallo menee ruudun ulkopuolelle.

Code: Select all

SCREEN 800, 600
'Include "PixelCollisionLib.cb"

// (lähes nopeuden säilyttävä) varustettu maata myöten liukuva pallo
// pikselin tarkalla törmäystunnistuksella!
Global img As integer
Global mouse_scroll As Float

img = MakeImage(800,600)

DrawToImage img
Color cbblue
Circle 100, 100, 200, 1
Circle 400, 200, 200, 1
Color cbblack
Circle 105, 105, 190, 1
DrawToScreen
Color cbwhite

Const gravitation = 0.1
Const push_out = 0.5
plot_prev_x# = 0
plot_prev_y# = 0
plot_x# = 0
plot_y# = 0
plot_speedx# = 0
plot_speedy# = 0
plot_accelx# = 0
plot_accely# = 0
mouse_scroll = 10
Repeat
	If MouseHit(1)
		plot_x = MouseX()
		plot_y = MouseY()
		plot_speedx = 0
		plot_speedy = 0
		test = ON
	EndIf
	
	If MouseDown(2)
		DrawToImage img
		Color cbblue
		Circle MouseX(),MouseY(),mouse_scroll,1
		DrawToScreen
	EndIf
	
	old = mouse_scroll
	mouse_scroll = mouse_scroll + MouseMoveZ()
	DrawImage img,0,0
	Color 0,255,0
	Circle plot_x - mouse_scroll / 2, plot_y - mouse_scroll / 2, mouse_scroll, OFF
	If old <> mouse_scroll
		Color cbblue
		Circle MouseX(),MouseY(),mouse_scroll,0
	EndIf
	
	If test Then Gosub DoSimulation
	If (plot_x < 1  Or plot_y < 1 Or plot_x > ScreenWidth()-1  Or plot_y > ScreenHeight())
		test = OFF
	EndIf
	DrawScreen
Forever
End

DoSimulation:
	
	
	plot_prev_x = plot_x
	plot_prev_y = plot_y
	// Vaihe 1: Korjataan paikkaa & Liu'utetaan pistettä.
	normal# = -1
	If RayPlotEnvCollision(img, plot_x, plot_y, mouse_scroll/2, 36)
		normal# = GetAngle(CPC_NEAR_ENV_X, CPC_NEAR_ENV_Y, plot_x, plot_y)
		dist# = Max(mouse_scroll/2 - Distance(CPC_NEAR_ENV_X, CPC_NEAR_ENV_Y, plot_x, plot_y), 0)
		plot_x = plot_x + Cos(normal) * dist
		plot_y = plot_y - Sin(normal) * dist

		plot_speedx = plot_speedx + Cos(normal) * push_out
		plot_speedy = plot_speedy - Sin(normal) * push_out
	EndIf
	// Vaihe 2: siirretään pistettä käyttäjän mukaan.
	plot_accely = gravitation
	plot_accelx = 0
	
	//Kiihtyvyys:
	If KeyDown(cbkeya) then plot_accelx = -0.3
	If KeyDown(cbkeyd) then plot_accelx = 0.3
	//Nopeus:
	If KeyDown(cbkeyright) Then plot_speedx = 2
	If KeyDown(cbkeyleft) Then plot_speedx = -2
	//Hyppy:
	If KeyHit(cbkeyspace) Then plot_speedy = -5
	
	plot_speedy = plot_speedy + plot_accely
	plot_speedx = plot_speedx + plot_accelx
	plot_x = plot_x + plot_speedx
	plot_y = plot_y + plot_speedy
	
	// ExtremE nopea liike:
	If KeyHit(cbkeyr)
		plot_x = MouseX()
		plot_y = MouseY()
	EndIf
	
	// Vaihe 3: Korjataan pahasti tapahtunut uppoaminen.
	If RayPlotCollision(img, plot_prev_x, plot_prev_y, plot_x, plot_y)
		plot_x = CPC_PlotX*0.8 + plot_prev_x*0.2
		plot_y = CPC_PlotY*0.8 + plot_prev_y*0.2
		plot_speedx = 0
		plot_speedy = 0
	EndIf
	
Return
Pahoittelen mahdollisita typoista/kielioppivirheistä mitä kirjaston kommenteissa saattaa olla. :D
-On selkeästi impulsiivinen koodaaja joka...
ohjelmoi C++:lla rekursiivisesti instantioidun templaten, jonka jokainen instantiaatio instantioi sekundäärisen singleton-template-luokan, jonka jokainen instanssi käynistää säikeen tulostakseen 'jea'.
SPuntte
Tech Developer
Tech Developer
Posts: 650
Joined: Mon Aug 27, 2007 9:51 pm
Location: Helsinki, Finland
Contact:

Re: 2dRayCast: Pikselin tarkka törmäys.

Post by SPuntte »

JATothrim wrote:NOTE:Koodi mav:aa jostain syystä herkästi jos pallo menee ruudun ulkopuolelle.
GetPixel2() ja PutPixel2() aiheuttavat MAVeja, jos pikseli sijaitsee ohjelman ikkunan ulkopuolella. Kannattaa lisäksi muistaa, että sallitut arvot ovat x ∊ [0, ScreenWidth()-1] ja y ∊ [0, ScreenHeight()-1]
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: 2dRayCast: Pikselin tarkka törmäys.

Post by MaGetzUb »

Oletko tehnyt tämän koodin ihan hatusta vetämällä vai jostain löytänyt kaavoja? Jos kaavoja olet löytynyt nii kerrohan toki mistä? :) Tuo koodi saisi vielä laskea, kuinka paljon pallo on maan sisällä ja nostaa sitä sen verran ylöspäin. ;)
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.
JATothrim
Tech Developer
Tech Developer
Posts: 606
Joined: Tue Aug 28, 2007 6:46 pm
Location: Kuopio

Re: 2dRayCast: Pikselin tarkka törmäys.

Post by JATothrim »

SPuntte wrote:
JATothrim wrote:NOTE:Koodi mav:aa jostain syystä herkästi jos pallo menee ruudun ulkopuolelle.
GetPixel2() ja PutPixel2() aiheuttavat MAVeja, jos pikseli sijaitsee ohjelman ikkunan ulkopuolella. Kannattaa lisäksi muistaa, että sallitut arvot ovat x ∊ [0, ScreenWidth()-1] ja y ∊ [0, ScreenHeight()-1]
Asia on harvinaisen selvä minulle, mutta ohjelman pitäisi estää pallon pääsy ruudun ulkopuolelle, koska tälle on tarkistus: itse esimerkissä ja itse RayPlotCollisionissa!
MaGetzUb wrote:Oletko tehnyt tämän koodin ihan hatusta vetämällä vai jostain löytänyt kaavoja? Jos kaavoja olet löytynyt nii kerrohan toki mistä? :) Tuo koodi saisi vielä laskea, kuinka paljon pallo on maan sisällä ja nostaa sitä sen verran ylöspäin. ;)
90% Hatusta, sillä RayPlotCollisioniin otin helppiä wikipediasta jotta sain homman toimimaan pelkästään kokonaisluvuilla, aijempi liukuluku versio oli tosin vedetty hatusta. :roll: Ja uppoamisen saa laskettua ihan cb:n Distance() funkkarilla. ;) Kokeileppas tehdä biljardipeli näin: pelialustana toimii kuva. Törmäykset tarkistettaisiin RayPlotAngleCollisionilla: #luot tyhjän pelialustan kokoisen kuvan. #piirrät tyhjään kuvaan alustan ja pallot, mutta et sitä palloa jonka törmäystä tarkistat. #Cast tarkistettavan pallon kohdalta ja suuntaan: viola' homma toimii.
-On selkeästi impulsiivinen koodaaja joka...
ohjelmoi C++:lla rekursiivisesti instantioidun templaten, jonka jokainen instantiaatio instantioi sekundäärisen singleton-template-luokan, jonka jokainen instanssi käynistää säikeen tulostakseen 'jea'.
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: 2dRayCast: Pikselin tarkka törmäys.

Post by MaGetzUb »

Tarkistatko osumat edes Pseudokoodilla? Tuntuu, että pallo jää todella helposti seinän sisään. Eli vaikka:

Code: Select all

For i# = 0 to Speed# 
koordinaati = koordinaati + speed / i 
Tarkistatörmäys()
Next i 
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.
JATothrim
Tech Developer
Tech Developer
Posts: 606
Joined: Tue Aug 28, 2007 6:46 pm
Location: Kuopio

Re: 2dRayCast: Pikselin tarkka törmäys.

Post by JATothrim »

En. Pallo jää useimmiten sen takia maahan kiinni koska vanhat koordinaatit kerkeävät pävittyä "maahan kiinni" tällöin kaikki raycastit lähtevät maan sisältä, ja tästä systeemi ei tykkää. Pitäisi tallettaa koordinatti joka oli edellisellä kierroksella takuuvarmasti tyhjässä. Mikäli havaitaan että vanhat koordinaatit ovat maan sisässä nollataan pallon paikka talletetuihin koordinaatteihin. Ja Kyseessähän on vain köökkä esimerkki. ;) Laita koodia jos keksit paremman li'uttamis tavan.
EDIT:

Tein paremman version, pallo ei ole kertaakaan jäänyt jumiin (paitsi yhden pikselin kokoisena :D ) Valitettavasti liukuminen monimutkaistui..

Code: Select all

SCREEN 800, 600
Include "..\Include\PixelCollisionLib.cb"

// .9 kitka kertoimella (lähes nopeuden säilyttävä) varustettu maata myöten liukuva pallo
// pikselin tarkalla törmäys tunnistuksella!
Global img As integer
Global mouse_scroll As Float

img = MakeImage(800,600)
 
DrawToImage img
Color cbblue
Circle 100, 100, 200, 1
Circle 400, 200, 200, 1
Color cbblack
Circle 105, 105, 190, 1
DrawToScreen
Color cbwhite

//Vakioita pallolle..
Const gravitation = 0.1		'painovoima
Const slide_fact = 0.99		'liukumis kitka
Const slide_start = 0.1		'Cos(normaali) > slide_start toteutuessaan sallii luikumisen.

plot_prev_x2# = 0
plot_prev_y2# = 0
plot_prev_x# = 0
plot_prev_y# = 0
plot_x# = 0
plot_y# = 0
plot_speedx# = 0
plot_speedy# = 0
plot_accelx# = 0
plot_accely# = 0
mouse_scroll = 10
Repeat
	If MouseHit(1)
		plot_x = MouseX()
		plot_y = MouseY()
		plot_prev_x = plot_x
		plot_prev_y = plot_y
		plot_prev_x2 = plot_x
		plot_prev_y2 = plot_y
		plot_speedx = 0
		plot_speedy = 0
		test = ON
	EndIf
	
	If MouseDown(2)
		DrawToImage img
		Color cbblue
		Circle MouseX(),MouseY(),mouse_scroll,1
		DrawToScreen
	EndIf
	
	old = mouse_scroll
	mouse_scroll = mouse_scroll + MouseMoveZ()
	DrawImage img,0,0
	Color 0,255,0
	Circle plot_x - mouse_scroll / 2, plot_y - mouse_scroll / 2, mouse_scroll, OFF
	If old <> mouse_scroll
		Color cbblue
		Circle MouseX(),MouseY(),mouse_scroll,0
	EndIf
	
	If test Then Gosub DoSimulation
	If (plot_x < 1  Or plot_y < 1 Or plot_x > ScreenWidth()-1  Or plot_y > ScreenHeight())
		test = OFF
	EndIf
	DrawScreen
Forever
End

DoSimulation:
	
	plot_prev_x2 = plot_prev_x
	plot_prev_y2 = plot_prev_y
	plot_prev_x = plot_x
	plot_prev_y = plot_y
	
	plot_accely = gravitation
	plot_accelx = 0
	// Vaihe 1: Korjataan paikkaa & Liu'utetaan pistettä.
	normal# = -1
	If RayPlotEnvCollision(img, plot_x, plot_y, mouse_scroll/2, 36)
		normal# = GetAngle(CPC_NEAR_ENV_X, CPC_NEAR_ENV_Y, plot_x, plot_y)
		dist# = Max(mouse_scroll/2 - Distance(CPC_NEAR_ENV_X, CPC_NEAR_ENV_Y, plot_x, plot_y), 0)
		plot_x = plot_x + Cos(normal) * dist
		plot_y = plot_y - Sin(normal) * dist

		
		If Cos(normal) > slide_start
			plot_speedx = plot_speedx * slide_fact + Cos(normal-90) * plot_accely
			plot_speedy = plot_speedy * slide_fact - Sin(normal-90) * plot_accely
			plot_accelx = Cos(normal-90) * plot_accely
			plot_accely = 0
		ElseIf Cos(normal) < -slide_start
			plot_speedx = plot_speedx * slide_fact + Cos(normal+90) * plot_accely
			plot_speedy = plot_speedy * slide_fact - Sin(normal+90) * plot_accely
			plot_accelx = Cos(normal+90) * plot_accely
			plot_accely = 0
		Else
			// ollaan asetusten mukaan tasamaalla.. nollataan painovoima ja nopeudet.
			plot_speedx = plot_speedx * slide_fact
			plot_speedy = plot_speedy * slide_fact'0
			plot_accely = 0
		EndIf
	EndIf
	// Vaihe 2: siirretään pistettä käyttäjän mukaan.
	
	//Kiihtyvyys:
	If KeyDown(cbkeya) Then plot_accelx = -1.3
	If KeyDown(cbkeyd) Then plot_accelx = 1.3
	//Nopeus:
	If KeyDown(cbkeyright) Then plot_speedx = 2
	If KeyDown(cbkeyleft) Then plot_speedx = -2
	//Hyppy:
	If KeyHit(cbkeyspace) Then plot_speedy = -5
	
	plot_speedy = plot_speedy + plot_accely
	plot_speedx = plot_speedx + plot_accelx
	plot_x = plot_x + plot_speedx
	plot_y = plot_y + plot_speedy
	
	// ExtremE nopea liike:
	If KeyHit(cbkeyr)
		plot_x = MouseX()
		plot_y = MouseY()
	EndIf
	
	// Vaihe 3: Korjataan pahasti tapahtunut uppoaminen.
	cn_plt_x# = (plot_prev_x + plot_prev_x2) /2.0
	cb_plt_y# = (plot_prev_y + plot_prev_y2) /2.0
	If RayPlotCollision(img,  cn_plt_x, cb_plt_y, plot_x, plot_y)
		//kulma jossa upottiin maahan..
		angle# = GetAngle(plot_x, plot_y, cn_plt_x , cb_plt_y)
		plot_x =  CPC_PlotX + Cos(angle) * mouse_scroll/2
		plot_y = CPC_PlotY - Sin(angle) * mouse_scroll/2
		plot_speedx = 0
		plot_speedy = 0
	EndIf
	
Return
[/edit]
-On selkeästi impulsiivinen koodaaja joka...
ohjelmoi C++:lla rekursiivisesti instantioidun templaten, jonka jokainen instantiaatio instantioi sekundäärisen singleton-template-luokan, jonka jokainen instanssi käynistää säikeen tulostakseen 'jea'.
Post Reply