2D Vektoren

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

M0rgenstern

Betreff: 2D Vektoren

BeitragMo, Nov 01, 2010 22:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Leute.
Ich habe eine Vektorenklasse gebastelt.
Ich denke einfach, dass man mit Vektoren in Spielen besser arbeiten kann als immer mit X und Y Koordinaten.
Aber auch allgemein ist es vielleicht mal nicht schlecht sowas "im Haus" zu haben.
Also hier ist die Klasse (mit Kommentaren):

BlitzMax: [AUSKLAPPEN]
Type TVector2D 'A Vector Class which can do any Operation on 2D Vectors
Field _fXComponent:Float 'X-Component of the Vector
Field _fYComponent:Float 'Y-Component of the Vector
Field _fAbsoluteValue:Float 'The Absoulte Value (Length) of the Vector

Method Get_X:Float() 'Method to get the X-Component
Return Self._fXComponent
End Method
Method Set_X(px:Float) 'Method to set the X-Component
Self._fXComponent = px
End Method

Method Get_Y:Float() 'Method to get the Y-Component
Return Self._fYComponent
End Method
Method Set_Y(py:Float) 'Method to set the Y-Component
Self._fYComponent = py
End Method

Method Get_Length:Float() 'Method to get the Absolute Value (Length)
Return Self._fAbsoluteValue
End Method
'This Method probably isn't needed and the user shouldn't set a random Length
'because this would be wrong:
'Method Set_Length(plength:Float)
' Self._fAbsoluteValue = plength
'End Method

Method PrintValues()
Print "X-Component: " + Self._fXComponent
Print "Y-Component: " + Self._fYComponent
Print "Absolute Value: " + Self._fAbsoluteValue
End Method

Method GetValuesAsString:String()
Local tmpString:String = ("X/Y: " + Self._fXComponent + " / " + Self._fYComponent + " |vec|: " + Self._fAbsoluteValue)
Return tmpString
End Method

'Constructor of the Class
Function Create:TVector2D(pX:Float, pY:Float)
Local tmpVec2D:TVector2D = New TVector2D
tmpVec2D._fXComponent = pX
tmpVec2D._fYComponent = pY
tmpVec2D._fAbsoluteValue = tmpVec2D.CalcLength()
Return tmpVec2D
End Function

'"Constructor" for a Zero Vector
Function Zero:TVector2D()
Local tmpVec2D:TVector2D = New TVector2D
tmpVec2D = TVector2D.Create(0.0, 0.0) 'Just calls the Constructor with the parameters 0, 0
Return tmpVec2D
End Function

'Calculates the Length of a Vector
Method CalcLength:Float()
Return Sqr((Self._fXComponent * Self._fXComponent) + (Self._fYComponent * Self._fYComponent))
End Method

'Calculates the distance between two Vectors
Function CalcDistance:Float(pVec1:TVector2D, pVec2:TVector2D)
Return Sqr(((pVec1._fXComponent - pVec2._fXComponent) * (pvec1._fXComponent - pvec2._fXComponent)) + ((pvec1._fYComponent - pvec2._fYComponent) * (pvec1._fYComponent - pvec2._fYComponent)))
End Function

'Add two Vectors
Function Add:TVector2D(pVec1:TVector2D, pVec2:TVector2D)
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Create(pVec1._fXComponent + pVec2._fXComponent, pVec1._fYComponent + pVec2._fYComponent)
Return tmpVec
End Function

'Subtract two Vectors (vec1-vec2)
Function Subtract:TVector2D(pVec1:TVector2D, pVec2:TVector2D)
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Create(pVec1._fXComponent - pVec2._fXComponent, pVec1._fYComponent - pVec2._fYComponent)
Return tmpVec
End Function

'Multiplies a Vector with a number (makes the Vector shorter or longer)
Method Multiply:TVector2D(pFactor:Float)
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Create(pFactor * Self._fXComponent, pFactor * Self._fYComponent)
Return tmpVec
End Method

'Calculates the Scalar Product of two Vectors
Function ScalarProduct:Float(pVec1:TVector2D, pVec2:TVector2D)
Return ((pVec1._fXComponent * pVec2._fXComponent) + (pVec1._fYComponent * pVec2._fYComponent))
End Function

'Calculates the angle between two Vectors
Function AngleBetween:Int(pVec1:TVector2D, pVec2:TVector2D)
Local tmpResult:Float
'tmpResult =
tmpResult = ScalarProduct(pVec1, pVec2) / (pVec1._fAbsoluteValue * pVec2._fAbsoluteValue)
If ((tmpResult <= 1) And (tmpResult >= - 1)) Then 'Need to be a number between -1 and 1
Return Floor(ACos(tmpResult) + 0.5)
Else
Return (-1) 'Else it will be -1 (because the result of acos is between 180 and 0)
EndIf
End Function

'Tests if two Vectors are orthogonal (right angled)
Function AreOrthogonal:Int(pVec1:TVector2D, pVec2:TVector2D)
Local tmpValue:Float
tmpValue = ScalarProduct(pVec1, pVec2)
If tmpValue = 0 Then
Return True
Else
Return False
EndIf
End Function

'Calculates the orthogonal projection of Vec1 on Vec2
Function OrthogonalProjection:TVector2D(pVec1:TVector2D, pVec2:TVector2D)
Local tmpValue:Float
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Zero()
tmpValue = ScalarProduct(pVec1, pVec2.Standardise())
tmpVec = pVec2.Standardise().Multiply(tmpValue)
tmpVec.CalcLength()
Return tmpVec
End Function

'Calculates the unit Vector
Method Standardise:TVector2D()
Local tmpVec:TVector2D = New TVector2D
Local tmpValue:Float
tmpValue = 1 / Self._fAbsoluteValue
tmpVec = Self.Multiply(tmpValue)
Return tmpVec
End Method
End Type


Und hier ist ein kleines Testprogramm:

BlitzMax: [AUSKLAPPEN]
SuperStrict
Include "Includes\VectorClass.bmx"

Global Vector1:TVector2D, Vector2:TVector2D, Vector3:TVector2D
Global fValue:Float = 0

Vector1 = TVector2D.Create(-3, 2)
Vector2 = TVector2D.Create(4, 6)
Vector3 = TVector2D.Zero()

Print "----------------"
Print "Vektoren:"
Print "Vektor1: " + Vector1.GetValuesAsString()
Print "Vektor2: " + Vector2.GetValuesAsString()
Print "Vektor3: "
Vector3.PrintValues()
Print "----------------"

fValue = TVector2D.CalcDistance(Vector1, Vector2)
Print "Entfernung 1 und 2: " + fValue

Vector3 = TVector2D.Add(Vector1, Vector2)
Print "1+2: " + Vector3.GetValuesAsString()

Vector3 = TVector2D.Subtract(Vector1, Vector2)
Print "1-2: " + Vector3.GetValuesAsString()

Vector3 = Vector1.Multiply(1.5)
Print "1.5*1: " + Vector3.GetValuesAsString()

fValue = TVector2D.ScalarProduct(Vector1, Vector2)
Print "1*2 (Skalarprodukt): " + fValue

fValue = TVector2D.AngleBetween(Vector1, Vector2)
Print "Winkel zwischen 1 und 2: " + fValue

Print "rechtwinklig zueinander? " + TVector2D.AreOrthogonal(Vector1, Vector2)

Vector3 = TVector2D.OrthogonalProjection(Vector1, Vector2)
Print "orthogonale Prjektion von 1 auf 2: " + Vector3.GetValuesAsString()

Vector3 = Vector1.Standardise()
Print "Vektor1 normiert: " + Vector3.GetValuesAsString()


Über Rückmeldung freu ich mich natürlich.
Ich hoffe, dass es jemand gebrauchen kann.

Lg, M0rgenstern

ComNik

BeitragMo, Nov 01, 2010 23:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Wobei ich anmerken darf das bei so grundsätzlichen Sachen wie einer Vektor Klasse (ich glaube ich hab auch mal eine hier iwo gepostet)
jeder seine eigenen Vorlieben was den Umfang, Zugriff, etc angeht.

Für wirklich rechenintensive Sachen wo jede Millisekunde zählt ist immer noch Float[2] am schnellsten.

Anonsten sollte ein Vektor Objekt so klein wie möglich sein, ich glaube es ist nicht nötig den Betrag mitzuführen.

Aber das sind nur Kleinigkeiten (:
WIP: Vorx.Engine

Silver_Knee

BeitragMo, Nov 01, 2010 23:58
Antworten mit Zitat
Benutzer-Profile anzeigen
da machst du schon get und set-methoden und vergisst bei der setx,y den absolutwert neu zu berechnen Wink

Shinkiro1

ehemals "Espada"

BeitragDi, Nov 02, 2010 0:06
Antworten mit Zitat
Benutzer-Profile anzeigen
An dieser Stelle möchte ich mal den Sinn von Gettern und Settern in Frage stellen, wenn diese wirklich nur dazu sind eine Field Variable zurückzugeben.
In BMax sind Fields ja sowieso public ... oder übersehe ich hier einen Punkt?

FireballFlame

BeitragDi, Nov 02, 2010 0:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Aufrüstungen für Threadsicherheit. Und allgemeine Sauberkeit.
PC: Intel Core i7 @ 4x2.93GHz | 6 GB RAM | Nvidia GeForce GT 440 | Desktop 2x1280x1024px | Windows 7 Professional 64bit
Laptop: Intel Core i7 @ 4x2.00GHz | 8 GB RAM | Nvidia GeForce GT 540M | Desktop 1366x768px | Windows 7 Home Premium 64bit

M0rgenstern

BeitragDi, Nov 02, 2010 13:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Das mit Get und Set bin ich so aus anderen Sprachen gewohnt und finde das eigentlich ganz schön, auch wenn es in BMax nicht so viel bringt, da man die Attribute nicht auf Public bzw Protected oder Private setzen kann.

@Silver_Knee: Ups. Werde ich heute Mittag direkt fixen.

@ComNik:
Klar sollte so klein wie möglich sein und für Spiele braucht man den Betrag auch nicht unbedingt aber wenn man mit Vektoren rechnen will, dann find ich das ganz schick.

Gibts sonst noch Anregungen was man hinzufügen/verbessern könnte?

Lg, M0rgenstern

Lastmayday

BeitragDi, Nov 02, 2010 14:49
Antworten mit Zitat
Benutzer-Profile anzeigen
M0rgenstern hat Folgendes geschrieben:
[...]auch wenn es in BMax nicht so viel bringt, da man die Attribute nicht auf Public bzw Protected oder Private setzen kann. [...]


doch kann man.

Code: [AUSKLAPPEN]
Private
Description Private makes a Constant, Global variable or Function only accessible from within the current source file
 

Macintosh

BeitragDi, Nov 02, 2010 16:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Code: [AUSKLAPPEN]
Private
Description Private makes a Constant, Global variable or Function only accessible from within the current source file

within the current source file Es geht ja um Klassen.

M0rgenstern

Betreff: Update

BeitragDi, Nov 02, 2010 19:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Hier ist die gefixte Klasse:

BlitzMax: [AUSKLAPPEN]
Type TVector2D 'A Vector Class which can do any Operation on 2D Vectors
Field _fXComponent:Float 'X-Component of the Vector
Field _fYComponent:Float 'Y-Component of the Vector
Field _fAbsoluteValue:Float 'The Absoulte Value (Length) of the Vector

Method Get_X:Float() 'Method to get the X-Component
Return Self._fXComponent
End Method
Method Set_X(px:Float) 'Method to set the X-Component
Self._fXComponent = px
Self._fAbsoluteValue = Self.CalcLength()
End Method

Method Get_Y:Float() 'Method to get the Y-Component
Return Self._fYComponent
End Method
Method Set_Y(py:Float) 'Method to set the Y-Component
Self._fYComponent = py
Self._fAbsoluteValue = Self.CalcLength()
End Method

Method Get_Length:Float() 'Method to get the Absolute Value (Length)
Return Self._fAbsoluteValue
End Method
'This Method probably isn't needed and the user shouldn't set a random Length
'because this would be wrong:
'Method Set_Length(plength:Float)
' Self._fAbsoluteValue = plength
'End Method

Method PrintValues()
Print "X-Component: " + Self._fXComponent
Print "Y-Component: " + Self._fYComponent
Print "Absolute Value: " + Self._fAbsoluteValue
End Method

Method GetValuesAsString:String()
Local tmpString:String = ("X/Y: " + Self._fXComponent + " / " + Self._fYComponent + " |vec|: " + Self._fAbsoluteValue)
Return tmpString
End Method

'Constructor of the Class
Function Create:TVector2D(pX:Float, pY:Float)
Local tmpVec2D:TVector2D = New TVector2D
tmpVec2D._fXComponent = pX
tmpVec2D._fYComponent = pY
tmpVec2D._fAbsoluteValue = tmpVec2D.CalcLength()
Return tmpVec2D
End Function

'"Constructor" for a Zero Vector
Function Zero:TVector2D()
Local tmpVec2D:TVector2D = New TVector2D
tmpVec2D = TVector2D.Create(0.0, 0.0) 'Just calls the Constructor with the parameters 0, 0
Return tmpVec2D
End Function

'Calculates the Length of a Vector
Method CalcLength:Float()
Return Sqr((Self._fXComponent * Self._fXComponent) + (Self._fYComponent * Self._fYComponent))
End Method

'Calculates the distance between two Vectors
Function CalcDistance:Float(pVec1:TVector2D, pVec2:TVector2D)
Return Sqr(((pVec1._fXComponent - pVec2._fXComponent) * (pvec1._fXComponent - pvec2._fXComponent)) + ((pvec1._fYComponent - pvec2._fYComponent) * (pvec1._fYComponent - pvec2._fYComponent)))
End Function

'Add two Vectors
Function Add:TVector2D(pVec1:TVector2D, pVec2:TVector2D)
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Create(pVec1._fXComponent + pVec2._fXComponent, pVec1._fYComponent + pVec2._fYComponent)
Return tmpVec
End Function

'Subtract two Vectors (vec1-vec2)
Function Subtract:TVector2D(pVec1:TVector2D, pVec2:TVector2D)
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Create(pVec1._fXComponent - pVec2._fXComponent, pVec1._fYComponent - pVec2._fYComponent)
Return tmpVec
End Function

'Multiplies a Vector with a number (makes the Vector shorter or longer)
Method Multiply:TVector2D(pFactor:Float)
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Create(pFactor * Self._fXComponent, pFactor * Self._fYComponent)
Return tmpVec
End Method

'Calculates the Scalar Product of two Vectors
Function ScalarProduct:Float(pVec1:TVector2D, pVec2:TVector2D)
Return ((pVec1._fXComponent * pVec2._fXComponent) + (pVec1._fYComponent * pVec2._fYComponent))
End Function

'Calculates the angle between two Vectors
Function AngleBetween:Int(pVec1:TVector2D, pVec2:TVector2D)
Local tmpResult:Float
'tmpResult =
tmpResult = ScalarProduct(pVec1, pVec2) / (pVec1._fAbsoluteValue * pVec2._fAbsoluteValue)
If ((tmpResult <= 1) And (tmpResult >= - 1)) Then 'Need to be a number between -1 and 1
Return Floor(ACos(tmpResult) + 0.5)
Else
Return (-1) 'Else it will be -1 (because the result of acos is between 180 and 0)
EndIf
End Function

'Tests if two Vectors are orthogonal (right angled)
Function AreOrthogonal:Int(pVec1:TVector2D, pVec2:TVector2D)
Local tmpValue:Float
tmpValue = ScalarProduct(pVec1, pVec2)
If tmpValue = 0 Then
Return True
Else
Return False
EndIf
End Function

'Calculates the orthogonal projection of Vec1 on Vec2
Function OrthogonalProjection:TVector2D(pVec1:TVector2D, pVec2:TVector2D)
Local tmpValue:Float
Local tmpVec:TVector2D = New TVector2D
tmpVec = TVector2D.Zero()
tmpValue = ScalarProduct(pVec1, pVec2.Standardise())
tmpVec = pVec2.Standardise().Multiply(tmpValue)
tmpVec.CalcLength()
Return tmpVec
End Function

'Calculates the unit Vector
Method Standardise:TVector2D()
Local tmpVec:TVector2D = New TVector2D
Local tmpValue:Float
tmpValue = 1 / Self._fAbsoluteValue
tmpVec = Self.Multiply(tmpValue)
Return tmpVec
End Method
End Type


@Macintosh:
Wenn man aber jede Klasse in ne einzelne Datei packt, dann funktioniert das schon^^

Lg, M0rgenstern
 

Macintosh

BeitragDi, Nov 02, 2010 19:59
Antworten mit Zitat
Benutzer-Profile anzeigen
naja, aber das ist unter BMax eher unüblich ^^
 

FWeinb

ehemals "ich"

BeitragDi, Nov 02, 2010 21:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich mache das auch in BlitzMax immer, dass ich jede Klasse (bzw. Type) in eine einzelne Datei schreibe. Es ist erstens schöner, da man die Types dann alle mit einem Import einbinden kann und zweitens ist der Code viel besser wiederverwendbar. Außerdem Programmierst du dann meiner Meinung nach gleich "schöner" da du jeden Type als "einzelnen" Teil des Programms betrachtest.

Gruß,
ich
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs
 

Macintosh

BeitragDi, Nov 02, 2010 22:10
Antworten mit Zitat
Benutzer-Profile anzeigen
habs nur in wenigen projekten so, mit vielen dateien.
weil ich progee mit anderen zusammen, und der mag das garnicht ^^

M0rgenstern

BeitragDi, Nov 02, 2010 22:39
Antworten mit Zitat
Benutzer-Profile anzeigen
@ ich:
Mit Import einbinden? Warum das?
Es ist viel einfacher mit Include einzubinden.
Wenn du nämlich eine Klasse hast die auf eine andere zugreift dann ist das schon sone Sache. Außerdem: Wenn man Klassen ableitet und abhängigkeiten unter Klassen entstehen, dann passierts schnell dass man mit Import zyklisch importieren müsste.
Mit Incldue sieht das anders aus.

Lg, M0rgenstern
 

FWeinb

ehemals "ich"

BeitragMi, Nov 03, 2010 13:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich programmerie die Klasse dann so, das es zu keinen Zyklischen Imports kommt.

Gruß,
Ich
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group