HyperTransformSprite & Sprite Drehung

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Ara
Beiträge: 32
Registriert: 29.08.2004 13:40

HyperTransformSprite & Sprite Drehung

Beitrag von Ara »

Der Code stammt von STARGÅTE und ist von hier:
https://www.purebasic.fr/english/viewto ... 87#p572387

Die Funktion ist meiner Meinung sehr gut, ich habe aber ein Problem.
In dem unteren Beispiel bei der rechten Karte sieht man, was ich meine.

Die Karte sollte sich der Länge nach drehen wie die linke Karte.
Ich glaube aber, das ich hier vielleicht zu dumm bin um es zu lösen.

Für jede Hilfe bin ich dankbar.

Code: Alles auswählen

;- Slider inlcude by STARGÅTE

Prototype.f SliderFunction(Time.f)

Structure Slider
	Number.i
	Function.SliderFunction
	OldValue.f
	NewValue.f
	OldTime.i
	NewTime.i
EndStructure

Structure SliderInclude
	List		Slider.Slider()
	Array		*SliderID.Slider(0)
EndStructure

Global SliderInclude.SliderInclude

Procedure.i SliderID(Slider.i)
	If Slider & ~$FFFF
		ProcedureReturn Slider
	Else
		ProcedureReturn SliderInclude\SliderID(Slider)
	EndIf
EndProcedure

Procedure.i IsSlider(Slider.i)
	ForEach SliderInclude\Slider()
		If SliderInclude\Slider()\Number = Slider Or @SliderInclude\Slider() = Slider
			ProcedureReturn @SliderInclude\Slider()
		EndIf
	Next
EndProcedure

Procedure.i FreeSlider(Slider.i)
	Protected *Slider.Slider = SliderID(Slider)
	With *Slider
		If Not \Number & ~$FFFF
			SliderInclude\SliderID(\Number) = #Null
		EndIf
		ChangeCurrentElement(SliderInclude\Slider(), *Slider)
		DeleteElement(SliderInclude\Slider())
	EndWith
EndProcedure

Procedure.i CreateSlider(Slider.i, Function.SliderFunction=#Null, Value.f=0.0)
	Protected *Slider.Slider
	If Slider = #PB_Any
		*Slider.Slider = AddElement(SliderInclude\Slider())
		*Slider\Number = *Slider
	ElseIf Not Slider & ~$FFFF
		*Slider.Slider = AddElement(SliderInclude\Slider())
		*Slider\Number = Slider
		If ArraySize(SliderInclude\SliderID()) < Slider 
			ReDim SliderInclude\SliderID(Slider)
		ElseIf SliderInclude\SliderID(Slider)
			FreeSlider(SliderInclude\SliderID(Slider))
		EndIf
		SliderInclude\SliderID(Slider) = *Slider
	Else
		ProcedureReturn #Null
	EndIf
	With *Slider
		\Function = Function
		\OldValue = Value
		\NewValue = Value
	EndWith
	ProcedureReturn *Slider
EndProcedure

Procedure.f SliderValue(Slider.i)
	Protected *Slider.Slider = SliderID(Slider)
	Protected Timestamp.i = ElapsedMilliseconds()
	With *Slider
		If Timestamp >= \NewTime
			ProcedureReturn \NewValue
		ElseIf Timestamp >= \OldTime
			If \Function
				ProcedureReturn \OldValue + \Function((Timestamp-\OldTime)/(\NewTime-\OldTime))*(\NewValue-\OldValue)
			Else
				ProcedureReturn \OldValue + (Timestamp-\OldTime)/(\NewTime-\OldTime)*(\NewValue-\OldValue)
			EndIf
		Else
			ProcedureReturn \OldValue
		EndIf
	EndWith
EndProcedure

Procedure.f SliderTargetValue(Slider.i)
	Protected *Slider.Slider = SliderID(Slider)
	ProcedureReturn *Slider\NewValue
EndProcedure

Procedure.i ChangeSlider(Slider.i, Value.f, Time.f=0.0, Function.SliderFunction=#Null, Delay.f=0.0)
	Protected *Slider.Slider = SliderID(Slider)
	Protected Timestamp.i = ElapsedMilliseconds()
	With *Slider
		If Value <> \NewValue
			If Function
				\Function = Function
			EndIf
			\OldValue = SliderValue(Slider)
			\NewValue = Value
			\OldTime  = Delay*1000 + Timestamp
			\NewTime  = Delay*1000 + Timestamp + Time * 1000
		EndIf
	EndWith
EndProcedure



;- Example: flipping a card

Procedure HyperTransformSprite(Sprite.i, Width.f, Height.f, Depth.f, Roll.f, Yaw.f, Pitch.f, AlignX.f=0.5, AlignY.f=0.5)
	
	Protected CosZ.f = Cos(Radian(Roll)), CosY.f = Cos(Radian(Yaw)), CosX.f = Cos(Radian(Pitch))
	Protected SinZ.f = Sin(Radian(Roll)), SinY.f = Sin(Radian(Yaw)), SinX.f = Sin(Radian(Pitch))
	
	Protected A11.f =  CosY*CosZ,                A12.f = -CosY*SinZ,                A13.f =  SinY
	Protected A21.f =  SinX*SinY*CosZ+CosX*SinZ, A22.f = -SinX*SinY*SinZ+CosX*CosZ, A23.f = -SinX*CosY
	Protected A31.f = -CosX*SinY*CosZ+SinX*SinZ, A32.f =  CosX*SinY*SinZ+SinX*CosZ, A33.f =  CosX*CosY
	
	Protected U0.f = -AlignX*Width,  U1.f = (1-AlignX)*Width
	Protected V0.f = -AlignY*Height, V1.f = (1-AlignY)*Height
	
	Protected Z1.f = U0*A31 + V0*A32 + Depth
	Protected Y1.f = ( U0*A21 + V0*A22 ) * Depth / Z1
	Protected X1.f = ( U0*A11 + V0*A12 ) * Depth / Z1
	Protected Z2.f = U1*A31 + V0*A32 + Depth
	Protected Y2.f = ( U1*A21 + V0*A22 ) * Depth / Z2
	Protected X2.f = ( U1*A11 + V0*A12 ) * Depth / Z2
	Protected Z3.f = U1*A31 + V1*A32 + Depth
	Protected Y3.f = ( U1*A21 + V1*A22 ) * Depth / Z3
	Protected X3.f = ( U1*A11 + V1*A12 ) * Depth / Z3
	Protected Z4.f = U0*A31 + V1*A32 + Depth
	Protected Y4.f = ( U0*A21 + V1*A22 ) * Depth / Z4
	Protected X4.f = ( U0*A11 + V1*A12 ) * Depth / Z4
	
	TransformSprite(Sprite, X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, X4, Y4, Z4)
	
EndProcedure

InitSprite()

UsePNGImageDecoder()

Enumeration
	#Window
	#SpriteFront
	#SpriteBack
	#Slider
EndEnumeration

OpenWindow(#Window, 0, 0, 600, 400, "ScreenTitle", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(#Window), 0, 0, WindowWidth(#Window), WindowHeight(#Window), 0, 0, 0)

SpriteQuality(#PB_Sprite_BilinearFiltering)

CatchSprite(#SpriteFront, ReceiveHTTPMemory("http://data.unionbytes.de/10.png"), #PB_Sprite_AlphaBlending)
CatchSprite(#SpriteBack, ReceiveHTTPMemory("http://data.unionbytes.de/Deck.png"), #PB_Sprite_AlphaBlending)


Procedure.f MySlider(Time.f) ; This is an optional definition for the slider behavior. It defines how the value (0.0-1.0) has to change during the time (0.0-1.0).
	ProcedureReturn 0.5-Cos(Time*#PI)*0.5
EndProcedure

CreateSlider(#Slider) ; Create a slider with linear behavior, it is like other PB functions
; CreateSlider(#Slider, @MySlider()) ; Try it, for soft behavior

Repeat
	
	Repeat
		
		Select WindowEvent()
			Case #PB_Event_CloseWindow
				End
			Case #PB_Event_LeftClick
				If SliderTargetValue(#Slider) = 0.0 ; If the new target value is 0.0, flip to 180.0 in 1.0 seconds
					ChangeSlider(#Slider, 180.0, 1.0) 
				Else
					ChangeSlider(#Slider, 0.0, 1.0) ; If the new target value is not 0.0, flip to 0.0 in 1.0 seconds
				EndIf
			Case #Null
				Break
		EndSelect
		
	ForEver
	
	ClearScreen(0)
	
	HyperTransformSprite(#SpriteFront, 160, 220, 500, 0, 0, SliderValue(#Slider)+180) ; this sprite is rotated 180° more
	HyperTransformSprite(#SpriteBack, 160, 220, 500, 0, 0, SliderValue(#Slider))
	
	If SliderValue(#Slider) <= 90 Or SliderValue(#Slider) >= 270
	  DisplayTransparentSprite(#SpriteBack, 180, 150)
	Else
	  DisplayTransparentSprite(#SpriteFront, 180, 150) ; display both sprites
	EndIf
	
	HyperTransformSprite(#SpriteFront, 160, 220, 500, 45, 0, SliderValue(#Slider)+180) ; this sprite is rotated 180° more
	HyperTransformSprite(#SpriteBack, 160, 220, 500, 45, 0, SliderValue(#Slider))
	
	If SliderValue(#Slider) <= 90 Or SliderValue(#Slider) >= 270
	  DisplayTransparentSprite(#SpriteBack, 420, 150)
	Else
	  DisplayTransparentSprite(#SpriteFront, 420, 150) ; display both sprites
	EndIf
	
	FlipBuffers()
	
ForEver
Viele Grüße
Thomas
Win10 Pro
PureBasic 6.01 LTS
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: HyperTransformSprite & Sprite Drehung

Beitrag von STARGÅTE »

Hallo Ara,

bei HyperTransformSprite gibst du zwar die drei Winkel an kannst aber leider nicht entscheiden, wie die Reihenfolge der Anwendung ist. In meinem Fall ist die Ausführungsreihenfolge: Roll, Yaw, Pitch, also wie die Argument-Reihenfolge auch ist.
Du willst die Karte aber erst "flippen" und dann um sich drehen lassen, also Pitch, Yaw, Roll.

Ich habe bei HyperTransformSprite einen entsprechenden Flag hinzugefügt um die Reihenfolge zu definieren:

Code: Alles auswählen

#Euler_RollYawPitch = 1
#Euler_PitchYawRoll = 2

Procedure HyperTransformSprite(Sprite.i, Width.f, Height.f, Depth.f, Roll.f, Yaw.f, Pitch.f, AlignX.f=0.5, AlignY.f=0.5, Sequence.i=#Euler_RollYawPitch)
	
	Protected CosZ.f = Cos(Radian(Roll)), CosY.f = Cos(Radian(Yaw)), CosX.f = Cos(Radian(Pitch))
	Protected SinZ.f = Sin(Radian(Roll)), SinY.f = Sin(Radian(Yaw)), SinX.f = Sin(Radian(Pitch))
	
	Protected A11.f, A12.f, A13.f, A21.f, A22.f, A23.f, A31.f, A32.f, A33.f
	
	If Sequence = #Euler_PitchYawRoll
		A11 =  CosY*CosZ                : A12 = SinX*SinY*CosZ-CosX*SinZ  : A13 =  CosX*SinY*CosZ+SinX*SinZ
		A21 =  CosY*SinZ                : A22 = SinX*SinY*SinZ+CosX*CosZ  : A23 =  CosX*SinY*SinZ-SinX*CosZ
		A31 = -SinY                     : A32 = SinX*CosY                 : A33 =  CosX*CosY
	Else
		A11 =  CosY*CosZ                : A12 = -CosY*SinZ                : A13 =  SinY
		A21 =  SinX*SinY*CosZ+CosX*SinZ : A22 = -SinX*SinY*SinZ+CosX*CosZ : A23 = -SinX*CosY
		A31 = -CosX*SinY*CosZ+SinX*SinZ : A32 =  CosX*SinY*SinZ+SinX*CosZ : A33 =  CosX*CosY
	EndIf
	
	Protected U0.f = -AlignX*Width,  U1.f = (1-AlignX)*Width
	Protected V0.f = -AlignY*Height, V1.f = (1-AlignY)*Height
	
	Protected Z1.f = U0*A31 + V0*A32 + Depth
	Protected Y1.f = ( U0*A21 + V0*A22 ) * Depth / Z1
	Protected X1.f = ( U0*A11 + V0*A12 ) * Depth / Z1
	Protected Z2.f = U1*A31 + V0*A32 + Depth
	Protected Y2.f = ( U1*A21 + V0*A22 ) * Depth / Z2
	Protected X2.f = ( U1*A11 + V0*A12 ) * Depth / Z2
	Protected Z3.f = U1*A31 + V1*A32 + Depth
	Protected Y3.f = ( U1*A21 + V1*A22 ) * Depth / Z3
	Protected X3.f = ( U1*A11 + V1*A12 ) * Depth / Z3
	Protected Z4.f = U0*A31 + V1*A32 + Depth
	Protected Y4.f = ( U0*A21 + V1*A22 ) * Depth / Z4
	Protected X4.f = ( U0*A11 + V1*A12 ) * Depth / Z4
	
	TransformSprite(Sprite, X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, X4, Y4, Z4)
	
EndProcedure
Entsprechend dann unten im Code:

Code: Alles auswählen

	HyperTransformSprite(#SpriteFront, 160, 220, 500, 45, 0, SliderValue(#Slider)+180, 0.5, 0.5, #Euler_PitchYawRoll) ; this sprite is rotated 180° more
	HyperTransformSprite(#SpriteBack, 160, 220, 500, 45, 0, SliderValue(#Slider), 0.5, 0.5, #Euler_PitchYawRoll)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Ara
Beiträge: 32
Registriert: 29.08.2004 13:40

Re: HyperTransformSprite & Sprite Drehung

Beitrag von Ara »

Vielen vielen Dank für die schnelle Hilfe.
Win10 Pro
PureBasic 6.01 LTS
Antworten