• Dear Cerberus X User!

    As we prepare to transition the forum ownership from Mike to Phil (TripleHead GmbH), we need your explicit consent to transfer your user data in accordance with our amended Terms and Rules in order to be compliant with data protection laws.

    Important: If you accept the amended Terms and Rules, you agree to the transfer of your user data to the future forum owner!

    Please read the new Terms and Rules below, check the box to agree, and click "Accept" to continue enjoying your Cerberus X Forum experience. The deadline for consent is April 5, 2024.

    Do not accept the amended Terms and Rules if you do not wish your personal data to be transferred to the future forum owner!

    Accepting ensures:

    - Continued access to your account with a short break for the actual transfer.

    - Retention of your data under the same terms.

    Without consent:

    - You don't have further access to your forum user account.

    - Your account and personal data will be deleted after April 5, 2024.

    - Public posts remain, but usernames indicating real identity will be anonymized. If you disagree with a fictitious name you have the option to contact us so we can find a name that is acceptable to you.

    We hope to keep you in our community and see you on the forum soon!

    All the best

    Your Cerberus X Team

Snippet Matrix useful for physics, collision and loads more

Wingnut

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,414
Cerberus:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=False

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field myRect : Rectangle
    Field origin : Point
    Field debugOn : Bool = False
    Field canvas : Canvas

    Method OnCreate()
        canvas = New Canvas
         ' Vertical blanking
        SetSwapInterval 1 ; SetUpdateRate 0   
        ' Creates a new identity matrix
        myMatrix = New Matrix()
        ' Creates a new point
        myPoint = New Point()
        ' Creates a rectangle
        myRect = New Rectangle(-100,-100,200,200)
        ' Stores origin
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
    End Method
   
    Method OnUpdate()
        canvas.Clear 0,0,0   
       
        ' Translate matrix
        If KeyDown(KEY_UP) Then myMatrix.translateBy(0,-1)
        If KeyDown(KEY_DOWN) THen myMatrix.translateBy(0,1)   
        If KeyDown(KEY_LEFT) Then myMatrix.translateBy(-1,0)
        If KeyDown(KEY_RIGHT) Then myMatrix.translateBy(1,0)

        ' Scale matrix
        If KeyDown(KEY_N) Then myMatrix.scaleBy(1.01,1.01)
        If KeyDown(KEY_M) Then myMatrix.scaleBy(0.99,0.99)
       
        ' Scale matrix (free dimensions)
        If KeyDown(KEY_W) Then myMatrix.scaleBy(1,1.1)
        If KeyDown(KEY_S) Then myMatrix.scaleBy(1,0.9)
        If KeyDown(KEY_A) Then myMatrix.scaleBy(1.1,1)
        If KeyDown(KEY_D) Then myMatrix.scaleBy(0.9,1)

        ' Rotate matrix
        If KeyDown(KEY_Z) Then myMatrix.rotateBy(-1)
        If KeyDown(KEY_X) Then myMatrix.rotateBy(1)   
       
        ' Shear matrix
        If KeyDown(KEY_1) Then myMatrix.shearBy(0.1,0)
        If KeyDown(KEY_2) Then myMatrix.shearBy(-0.1,0)
        If KeyDown(KEY_3) Then myMatrix.shearBy(0,0.1)
        If KeyDown(KEY_4) Then myMatrix.shearBy(0,-0.1)
       
    End Method
   
    Method OnRender()
        canvas.Clear 0,0,0
        canvas.PushMatrix
        canvas.Translate origin.mX,origin.mY
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy
        canvas.Translate  -origin.mX,-origin.mY
        canvas.SetColor 1,1,1
        canvas.DrawRect origin.mX + myRect.mX,origin.mY + myRect.mY,myRect.mWidth,myRect.mHeight
        canvas.PopMatrix
        myPoint.mX = TouchX() - origin.mX
        myPoint.mY = TouchY() - origin.mY
       
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
               
        ' Transforms point
        Local testPoint : Point = invMatrix.transformPoint(myPoint)

        ' Draws debug stuff
        If debugOn = True

            ' Draws original outline rectangle shape
            canvas.SetColor 0,0,1
            canvas.DrawLine origin.mX + myRect.mX,origin.mY + myRect.mY,origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mY
            canvas.DrawLine origin.mX + myRect.mX,origin.mY + myRect.mHeight / 2.0,origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mHeight / 2.0
            canvas.DrawLine origin.mX + myRect.mX,origin.mY + myRect.mY,origin.mX + myRect.mX,origin.mY + myRect.mHeight / 2.0
            canvas.DrawLine origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mY,origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mHeight / 2.0
            canvas.SetColor 1,1,1
            canvas.DrawText testPoint.mX + "," + testPoint.mY,0,0

            ' Draws test marker
            canvas.SetColor 1,0,0
            canvas.DrawOval origin.mX + testPoint.mX - 4,origin.mY + testPoint.mY - 4,8,8
        Endif

        ' Checks if touching inside the shape
        If TouchDown(0)
            ' Simple rectangle check as the point has been transformed
            If myRect.containsPoint(testPoint) Then canvas.SetColor 1,0,0 ; canvas.DrawText "Point Inside Rect!",origin.mX,50,0.5,0.5
        Endif
        canvas.Flush
    End Method
   
End Class

' The Point Class describes a two dimensional point Or vector.

Class Point

    Field mX : Float
    Field mY : Float

    ' Initializes a point with its x And y components. _Designated Initializer_.
    Method New(x : Float,y : Float)
        Self.mX = x
        Self.mY = y
    End Method

    Function pointWithPolarLength : Point(length : Float,angle : Float)
        Return New Point(Cos(angle) * length,Sin(angle) * length)
    End Function

    Function pointWithXY : Point(x : Float,y : Float)
        Return New Point(x,y)
    End Function

    Function pointZero : Point()
        Return New Point(0,0)
    End Function
   
    ' Calculates the distance between two points.
    Function distanceFromPoint : Float(p1 : Point,p2 : Point)
        Local diff : Point = p1.subtractPoint(p2)
        Return Sqr((diff.mX * diff.mX) + (diff.mY * diff.mY))
    End Function
   
    ' Determines a point between two specified points. `ratio = 0 -> p1,ratio = 1 -> p2
    Function interpolateFromPoint : Point(p1 : Point,p2 : Point,ratio : Float)
        Local invRation = 1.0 - ratio
        Local x : Float = (invRatio * p1.mX) + (ratio * p2.mX)
        Local y : Float = (invRatio * p1.mY) + (ratio * p2.mY)
        Return New Point(x,y)
    End Function
   
    ' Clones point
    Method clone : Point()
        Return New Point(Self.mX,Self.mY)
    End Method

    ' Length of vector
    Method length : Float()
        Return Sqr((Self.mX * Self.mX) + (Self.mY * Self.mY))
    End Method

    ' Angle of vector
    Method angle : Float()
            Return ATan2(Self.mY,Self.mX)
    End Method
   
    ' Adds a point To the current point And returns the resulting point.
    Method addPoint : Point(point : Point)
        Return New Point(point.mX + Self.mY,point.mY + Self.mY)
    End Method

    ' Substracts a point from the current point And returns the resulting point.
    Method subtractPoint : Point(point : Point)
        Return New Point(point.mX - Self.mX,point.mY - Self.mY)
    End Method

    ' Scales the point by a certain factor And returns the resulting point.
    Method scaleBy : Point(scalar : Float)
        Return New Point(Self.mX * scalar,Self.mY * scalar)
    End Method
   
    ' Scales the line segment between the origin And the current point To one.
    Method normalize : Point()
        If Self.mX = 0 And Self.mY = 0
            Error("Cannot mormalize a point in the origin")
        Else
            Local inverseLength : Float = 1.0 / Self.length()
            Return New Point(Self.mX * inverseLength,Self.mY * inverseLength)
        Endif
    End Method
   
    ' Compares two points.
    Method isEqual : Bool(other : Point)
            If other = Self Then Return True
        Return (Self.mX = point.mX) And (Self.mY = point.mY)   
     End Method

    ' Calculates the distance between two points.
    Method distanceFromPoint : Float(point : Point)
        Local diff : Point = Self.subtractPoint(point)
        Return Sqr((diff.mX * diff.mX) + (diff.mY * diff.mY))
    End Method

    ' Determines a point between two specified points. `ratio = 0 -> self,ratio = 1 -> point
    Method interpolateFromPoint : Point(point : Point,ratio : Float)
        Local invRation = 1.0 - ratio
        Local x : Float = (invRatio * Self.mX) + (ratio * point.mX)
        Local y : Float = (invRatio * Self.mY) + (ratio * point.mY)
        Return New Point(x,y)
    End Method

    ' Returns a string containing the components of the point
    Method description : String()
        Return "(x: " + Self.mX + ",y: " + Self.mY + ")"
    End Method
   
End Class

' The Rectangle Class describes a rectangle by its top-left corner point (x,y) And by its width And height.

Class Rectangle

    Field mX : Float
    Field mY : Float
    Field mWidth : Float
    Field mHeight : Float

    ' Initializes a rectangle
    Method New()
        Self.mX = 0
        Self.mY = 0
        Self.mWidth = 0
        Self.mHeight = 0
    End Method
   
    ' Initializes a rectangle with the specified components
    Method New(x : Float,y : Float,width : Float,height : Float)
        Self.mX = x
        Self.mY = y
        Self.mWidth = width
        Self.mHeight = height
    End Method
   
    Function rectangleWithValues : Rectangle(x : Float,y : Float,width : Float,height : Float)
        Return New Rectangle(x,y,width,height)
    End Function
   
    ' Clone rectangle
    Method clone : Rectangle()
        Return New Rectangle(Self.mX,Self.mY,Self.mWidth,Self.mHeight)
    End Method

    ' Determines If a point is within the rectangle.
    Method containsXY : Bool(x : Float,y : Float)
        Return (x >= mX) And (y >= mY) And (x <= mX + mWidth) And (y <= mY + mHeight)
    End Method
   
    ' Determines If a point is within the rectangle.
    Method containsPoint : Bool(point : Point)
        Return Self.containsXY(point.mX,point.mY)
    End Method
   
    ' Determines If another rectangle is within the rectangle.
    Method containsRectangle : Bool(rectangle : Rectangle)
        Local rX : Float = rectangle.mX
        Local rY : Float = rectangle.mY
        Local rWidth : Float = rectangle.mWidth
        Local rHeight : Float = rectangle.mHeight
        Return (rX >= Self.mX) And (rX + rWidth <= mX + mWidth) And (rY >= mY) And (rY + rHeight <= mY + mHeight)
    End Method
   
    ' Determines If another rectangle contains Or intersects the rectangle.
    Method intersectsRectangle:Bool(rectangle : Rectangle)
        Local rX : Float = rectangle.mX
        Local rY : Float = rectangle.mY
        Local rWidth : Float = rectangle.mWidth
        Local rHeight : Float = rectangle.mHeight
        Local outside : Bool = (rX <= Self.mX And rX + rWidth <= Self.mX) Or (rX >= Self.mX + Self.mWidth And rX + rWidth >= Self.mX + Self.mWidth) Or (rY <= Self.mY And rY + rHeight <= Self.mY) Or (rY >= Self.mY + Self.mHeight And rY + rHeight >= Self.mY + Self.mHeight)
        Return Not outside
    End Method
   
    ' If the specified rectangle intersects with the rectangle,returns the area of intersection.
    Method intersectionWithRectangle : Rectangle(rectangle : Rectangle)
        Local left : Float = Max(Self.mX,rectangle.mX)
        Local right : Float = Min(Self.mX + Self.mWidth,rectangle.mX + rectangle.mWidth)
        Local top : Float = Max(Self.mY,rectangle.mY)
        Local bottom : Float = Min(Self.mY + Self.mHeight,rectangle.mY + rectangle.mHeight)
        If (left > right Or top > bottom)
            Return New Rectangle(0,0,0,0)
        Else
            Return New Rectangle(left,top,right - left,bottom - top)
        Endif
    End Method
   
    ' Adds two rectangles together To create a New Rectangle Object (by filling in the space between the two rectangles).
    Method uniteWithRectangle : Rectangle(rectangle : Rectangle)
        Local left : Float = Min(Self.mX,rectangle.mX)
        Local right : Float = Max(Self.mX + Self.mWidth,rectangle.mX + rectangle.mWidth)
        Local top : Float = Min(Self.mY,rectangle.mY)
        Local bottom : Float = Max(Self.mY + Self.mHeight,rectangle.mY + rectangle.mHeight)
        Return New Rectangle(left,top,right - left,bottom - top)
    End Method
   
    ' Sets x,y,width And height components To zero.
    Method setEmpty()
        Self.mX = 0
        Self.mY = 0
        Self.mWidth = 0
        Self.mHeight = 0
    End Method

    ' Checks if width or height components are zero.
    Method isEmpty : Bool()
        Return (Self.mWidth = 0) Or (Self.mHeight = 0)
    End Method

    ' Checks if two rectangles are equal
    Method isEqual : Bool(rectangle : Rectangle)
        If rectangle = Self Then Return True
        Return (Self.mX = rectangle.mX) And (Self.mY = rectangle.mY) And (Self.mWidth = rectangle.mWidth) And (Self.mHeight = rectangle.mHeight)          
    End Method
   
    ' Returns a string containing the components of the rectangle
    Method description : String()
        Return "(x: " + Self.mX + ",y: " + Self.mY + " width: " + Self.mWidth + " height: " + Self.mHeight + ")"
    End Method

End Class

' ------------------------------------------------------------------------------------------------
'  The Matrix Class describes an affine 2D transformation Matrix. It provides methods To
'  manipulate the matrix in convenient ways, and can be used To transform points.
' 
'  The matrix has the following form:
'      |a c tx|
'      |b d ty|
'      |0 0  1|
' -------------------------------------------------------------------------------------------------

Class Matrix

     Field mA : Float
    Field mB : Float
    Field mC : Float
    Field mD : Float
     Field mTx : Float
    Field mTy : Float

    ' Initializes an identity matrix.
    Method New()
        Self.mA = 1.0
        Self.mB = 0.0
        Self.mC = 0.0
        Self.mD = 1.0
        Self.mTx = 0.0
        Self.mTy = 0.0       
    End Method
   
    ' Initializes a matrix with the specified components.
    Method New(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        Self.mA = a
        Self.mB = b
        Self.mC = c
        Self.mD = d
        Self.mTx = tx
        Self.mTy = ty
    End Method

    Function matrixWithValues : Matrix(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        Return New Matrix(a,b,c,d,tx,ty)
    End Function
   
    Function matrixWithIdentity : Matrix()
        Return New Matrix()
    End Function

    ' Setter
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a
        matrix.mB = b
        matrix.mC = c
        matrix.mD = d
        matrix.mTx = tx
        matrix.mTy = ty
    End Function
   
    ' Compares two matrices.
    Method isEqual : Bool(other : Matrix)
        If other = Self Then Return True
        Return (other.mA = Self.mA) And (other.mB = Self.mB) And (other.mC = Self.mC) And (other.mD = Self.mD) And (other.mTx = Self.mTx) And (other.mTy = Self.mTy)
    End Method

    ' Clone matrix
    Method clone : Matrix()
        Return New Matrix(Self.mA,Self.mB,Self.mC,Self.mD,Self.mTx,Self.mTy)
    End Method
   
    ' Sets a matrix with the with the specified components
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        Self.mA = a
        Self.mB = b
        Self.mC = c
        Self.mD = d
        Self.mTx = tx
        Self.mTy = ty
    End Method

    ' Concatenates a matrix with the current matrix,combining the geometric effects of the two.
    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * Self.mA  + matrix.mC * Self.mB
        Local b : Float = matrix.mB * Self.mA  + matrix.mD * Self.mB
        Local c : Float = matrix.mA * Self.mC  + matrix.mC * Self.mD
        Local d : Float = matrix.mB * Self.mC  + matrix.mD * Self.mD
        Local tx : Float = matrix.mA * Self.mTx + matrix.mC * Self.mTy + matrix.mTx
        Local ty : Float = matrix.mB * Self.mTx + matrix.mD * Self.mTy + matrix.mTy
        Self.setValues(a,b,c,d,tx,ty)
    End Method
   
    ' Determinate of matrix
    Method determinant : Float()
            Return (Self.mA * Self.mD) - (Self.mC * Self.mB)
    End Method
   
    ' Translates the matrix along the x And y axes.
    Method translateBy : Void(dx : Float,dy : Float)
        Self.mTx = Self.mTx + dx
        Self.mTy = Self.mTy + dy
    End Method

    ' Applies a scaling transformation To the matrix.
    Method scaleBy : Void(sx : Float,sy : Float)
        Self.mA = Self.mA * sx
        Self.mB = Self.mB * sy
        Self.mC = Self.mC * sx
        Self.mD = Self.mD * sy
        Self.mTx = Self.mTx * sx
        Self.mTy = Self.mTy * sy
    End Method

    ' Applies a uniform scaling transformation To the matrix.
    Method scaleBy : Void(scale : Float)
        Self.scaleBy(scale,scale)
    End Method

    ' Applies a rotation on the matrix.
    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        Self.concatMatrix(rotMatrix)
    End Method
   
    ' Applies a shearing transformation To the matrix.
    Method shearBy : Void(sx : Float,sy : Float)   
        Self.mC = Self.mC + sx
        Self.mB = Self.mB + sy
    End Method

    ' Applies a uniform shearing transformation To the matrix.
    Method shearBy : Void(shear : Float)   
        Self.mC = Self.mC * shear
        Self.mB = Self.mB * shear
    End Method

    ' Sets each matrix Property To a value that causes a Null transformation.
    Method identity : Void()
        Self.setValues(1.0,0.0,0.0,1.0,0.0,0.0)
    End Method
   
    ' Performs the opposite transformation of the matrix.
    Method invert : Void()
        Local det : Float = Self.determinant()
        Local a : Float = Self.mD / det
        Local b : Float = -Self.mB / det
        Local c : Float = -Self.mC / det
        Local d : Float = Self.mA / det
        Local tx : Float = ((Self.mC * Self.mTy) - (Self.mD * Self.mTx)) / det
        Local ty : Float = ((Self.mB * Self.mTx) - (Self.mA * Self.mTy)) / det
        Self.setValues(a,b,c,d,tx,ty)
    End Method

    ' Applies the geometric transformation represented by the matrix To the specified point.
    Method transformPoint : Point(point : Point)
        Local x : Float = (Self.mA * point.mX) + (Self.mC * point.mY) + Self.mTx
        Local y : Float = (Self.mB * point.mX) + (Self.mD * point.mY) + Self.mTy
        Return New Point(x,y)
    End Method
   
    ' Returns a string containing the components of the matrix
    Method description : String()
        Return "(a = " + Self.mA + "," + "b = " + Self.mB + "," + "c = " + Self.mC + "," + "d = " + Self.mD + "," + "tx = " + Self.mTx + "," + "ty = " + Self.mTy + ")"
    End Method

End Class
 
Last edited:
Back
Top Bottom