Share My Creation LittleSquare Physics Demo

Here's a little physics demo I wrote to kill some time at work... Enjoy. :)
Open the attached JAR file and/or download the source code.

demo.png


PhysiX.b4j
B4X:
#Region  Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 400
#End Region

Sub Process_Globals
    'Custom Types
        Type PhysicalObject2D(posX As Double, posY As Double, sizeX As Double, sizeY As Double, Velocity As Vector, Gravity As Vector)
        Type Line2D(aX As Double, aY As Double, bX As Double, bY As Double, Active As Boolean)
        Type PerformanceMeasurement(Interval As Double, TimeStamp As Long)

    'MainForm
        Private fx                             As JFX
        Private MainForm                       As Form
        Dim cvs As Canvas

    'Main Cycle
        Dim DeltaTime                          As PerformanceMeasurement
        Dim MainCycle                          As Timer

    'Physical Elements
        Dim LittleSquare                       As PhysicalObject2D
        Dim Platform                           As PhysicalObject2D
        Dim World                              As PhysicalObject2D

    'Temporary Variables
        Dim tempVelocity                       As Vector
        Dim tempGravity                        As Vector

    'Constants
        Dim EarthMass = 5.972 * Power(10, 24)  As Double

    'User Input
        Dim LaunchVisual                       As Line2D
        Dim UserInput                          As Pane
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    'MainForm Settings
        MainForm           =  Form1
        MainForm.Resizable =  False
        MainForm.Title     =  "LittleSquare Physics Demo - Bruno Silva 2015"
        MainForm.SetFormStyle("UNIFIED")
        MainForm.Show

    'Canvas
        cvs.Initialize("cvs")
        MainForm.RootPane.AddNode(cvs, 0, 0, MainForm.Width, MainForm.Height)

    'User Input
        UserInput.Initialize("UserInput")
        MainForm.RootPane.AddNode(UserInput, 0, 0, MainForm.Width, MainForm.Height)

    'World Gravity
        tempGravity.setAngleAndMagnitudeD(90, 1600)
        World.Gravity = tempGravity

    'Player
        LittleSquare.sizeX = 15
        LittleSquare.sizeY = 15
        LittleSquare.posX  = Rnd(0, cvs.Width - LittleSquare.sizeX)
        LittleSquare.posY  = 0

    'Player Velocity
        tempVelocity.setAngleAndMagnitudeD(Rnd(0,360), 300)
        LittleSquare.Velocity = tempVelocity

    'Stage
        Platform.sizeX = cvs.Width
        Platform.sizeY = 100
        Platform.posX  = 0
        Platform.posY  = cvs.Height - Platform.sizeY

    'Main Cycle
        DeltaTime.Interval = (1 / 60)
        MainCycle.Initialize("MainCycle", 16) 'DeltaTime.Interval * 1000)
        MainCycle.Enabled = True
End Sub

Sub MainCycle_Tick
    'Calculate DeltaTime Interval
        If Not(DeltaTime.TimeStamp = 0) Then DeltaTime.Interval = (Max(1, DateTime.Now - DeltaTime.TimeStamp) / 1000)
        DeltaTime.TimeStamp = DateTime.Now

    'Clear Screen
        cvs.ClearRect(0, 0, cvs.Width, cvs.Height)

    'Apply Gravity Physics
        tempVelocity.dirY  = LittleSquare.Velocity.dirY + (World.Gravity.dirY * DeltaTime.Interval)
        LittleSquare.Velocity = tempVelocity

    'Collision Detection: Platform
        If LittleSquare.posY + LittleSquare.sizeY >= Platform.posY Then  
            If LittleSquare.posY + LittleSquare.sizeY > Platform.posY And LittleSquare.Velocity.AngleD <= 180 Then
                tempVelocity.dirY  = PostCollisionVelocity(LittleSquare.Velocity.dirY, 0, 10, EarthMass, 0.6)
                LittleSquare.Velocity = tempVelocity
            End If
            If Abs(LittleSquare.Velocity.dirY) < Abs(0.05 * World.Gravity.dirY) Then
                tempVelocity.dirY = 0
                LittleSquare.Velocity = tempVelocity
            End If
            LittleSquare.posY = Platform.posY - LittleSquare.sizeY
        End If

    'Collision Detection: Top
        If LittleSquare.posY < 0 Then
            LittleSquare.posY = 0
            tempVelocity.dirY  = PostCollisionVelocity(LittleSquare.Velocity.dirY, 0, 10, EarthMass, 0.6)
            LittleSquare.Velocity = tempVelocity
        End If

    'Collision Detection: Walls
        If LittleSquare.posX + LittleSquare.sizeX > cvs.Width Then
            LittleSquare.posX = cvs.Width - LittleSquare.sizeX
            tempVelocity.dirX  = PostCollisionVelocity(LittleSquare.Velocity.dirX, 0, 10, EarthMass, 0.6)
            LittleSquare.Velocity = tempVelocity
        Else If LittleSquare.posX < 0 Then
            LittleSquare.posX = 0
            tempVelocity.dirX  = PostCollisionVelocity(LittleSquare.Velocity.dirX, 0, 10, EarthMass, 0.6)
            LittleSquare.Velocity = tempVelocity
        End If

    'Friction
        If LittleSquare.posY + LittleSquare.sizeY >= Platform.posY Then
            tempVelocity.dirX  = LittleSquare.Velocity.dirX * 0.8
            LittleSquare.Velocity = tempVelocity
        End If

    'Backup Coords
        Dim oX = LittleSquare.posX As Double
        Dim oY = LittleSquare.posY As Double

    'Update Position
        LittleSquare.posX = LittleSquare.posX + (LittleSquare.Velocity.dirX * DeltaTime.Interval)
        LittleSquare.posY = LittleSquare.posY + (LittleSquare.Velocity.dirY * DeltaTime.Interval)

    'Calculate the Velocity Angle
        tempVelocity.AngleD = CalcAngleD(oX, oY, LittleSquare.posX, LittleSquare.posY)
        LittleSquare.Velocity  = tempVelocity

    'Render on Screen
        DrawShape(LittleSquare, fx.Colors.Blue)
        DrawShape(Platform, fx.Colors.Green)
        If LaunchVisual.Active Then
            LaunchVisual.aX = LittleSquare.posX + (LittleSquare.sizeX / 2)
            LaunchVisual.aY = LittleSquare.posY + (LittleSquare.sizeY / 2)
            DrawLine(LaunchVisual, fx.Colors.Red, 2)
        End If

    'Debug
        'Log(DeltaTime.Interval)
End Sub

'Given the Conservation of Momentum formula (m1*u1)+(m2*u2) = (m1*v1)+(m2*v2),
'we're able to calculate an object's post collision velocity.
'
'u1: ObjectA pre-collision velocity, u2: ObjectB pre-collision velocity, m1: ObjectA mass in kg, m2: ObjectB mass in kg.
'CoR: Coefficient of Restitution, a value between 0.00(0) and 1.00(0) where 1 represents a perfectly elastic collision.
Sub PostCollisionVelocity(u1 As Double, u2 As Double, m1 As Double, m2 As Double, CoR As Double) As Double
    Dim v1 = ((u1 * (m1 - m2)) + (2 * m2 * u2)) / (m1 + m2) As Double
    Return v1 * CoR
End Sub

Sub Userinput_MousePressed (EventData As MouseEvent)
    Dim dist, aX, aY, bX, bY As Double
    aX    = (LittleSquare.posX + LittleSquare.sizeX / 2)
    aY    = (LittleSquare.posY + LittleSquare.sizeY / 2)
    bX    = (EventData.X)
    bY    = (EventData.Y)
    dist  = Sqrt(Power((bX-aX),2) + Power((bY-aY),2))
    If dist <= LittleSquare.sizeX Then
        LaunchVisual.aX     = aX
        LaunchVisual.aY     = aY
        LaunchVisual.bX     = aX
        LaunchVisual.bY     = aY
        LaunchVisual.Active = True
    End If
End Sub

Sub Userinput_MouseDragged (EventData As MouseEvent)
    Dim aX, aY, bX, bY As Double
    aX    = (LittleSquare.posX + LittleSquare.sizeX / 2)
    aY    = (LittleSquare.posY + LittleSquare.sizeY / 2)
    bX    = (EventData.X)
    bY    = (EventData.Y)
    If LaunchVisual.Active Then
        LaunchVisual.aX = aX
        LaunchVisual.aY = aY
        LaunchVisual.bX = bX
        LaunchVisual.bY = bY
    End If
End Sub

Sub Userinput_MouseReleased (EventData As MouseEvent)
    Dim angle, dist, aX, aY, bX, bY As Double
    aX    = (LittleSquare.posX + LittleSquare.sizeX / 2)
    aY    = (LittleSquare.posY + LittleSquare.sizeY / 2)
    bX    = (EventData.X)
    bY    = (EventData.Y)
    angle = CalcAngleD(aX, aY, bX, bY)
    dist  = Sqrt(Power((bX-aX),2) + Power((bY-aY),2))
    If LaunchVisual.active Then
        LaunchVisual.bX = bX
        LaunchVisual.bY = bY
        Dim tempVelocity As Vector
        tempVelocity.setAngleAndMagnitudeD(angle, dist * 5)
        LittleSquare.Velocity = tempVelocity
    End If
    LaunchVisual.Active = False
    LaunchVisual.aX     = 0
    LaunchVisual.aY     = 0
    LaunchVisual.bX     = 0
    LaunchVisual.bY     = 0
End Sub

Public Sub CalcAngleD(aX As Double, aY As Double, bX As Double, bY As Double) As Double
    Dim dirX = bX - aX As Double
    Dim dirY = bY - aY As Double
    Return ATan2D(dirY, dirX)
End Sub

Sub DrawShape(input As PhysicalObject2D, color As Paint)
    cvs.DrawRect(input.posX, input.posY, input.sizeX, input.sizeY, color, True, 0)
End Sub

Sub DrawLine(line As Line2D, color As Paint, thickness As Int)
    cvs.DrawLine(line.aX, line.aY, line.bX, line.bY, color, thickness)
End Sub

Vector.bas
B4X:
'Class module
Private Sub Class_Globals
    Private fx As JFX
    Dim Description As String
    Dim Units       As String
    Dim Size        As Double
    Dim AngleD      As Double
    Dim AngleR      As Double
    Dim dirX        As Double
    Dim dirY        As Double
End Sub

'Sets this vector's description and units
Public Sub setDescription(Vector_Description As String, Vector_Units As String)
    Description = Vector_Description
    Units       = Vector_Units
End Sub

'Sets this vector's directional components, magnitude and angle from an imaginary line between two points in space, given their X, Y coordinates.
Public Sub setVectorFromLine(aX As Double, aY As Double, bX As Double, bY As Double)
    dirX      = bX - aX
    dirY      = bY - aY
    AngleD    = ATan2D(dirY, dirX)
    AngleR    = ATan2 (dirY, dirX)
    Size      = Sqrt(Power(dirX, 2) + Power(dirY, 2))
End Sub

'Sets this vector's directional components based on the given size and angle in degrees.
Public Sub setAngleAndMagnitudeD(Degrees As Double, Magnitude As Double)
    AngleD    = Degrees
    AngleR    = Degrees * cPI / 180
    Size      = Magnitude
    dirX      = CosD(Degrees) * Magnitude
    dirY      = SinD(Degrees) * Magnitude
End Sub

'Sets this vector's directional components based on the given size and angle in radians.
Public Sub setAngleAndMagnitudeR(Magnitude As Double, Radians As Double)
    AngleD    = Radians * 180 / cPI
    AngleR    = Radians
    Size      = Magnitude
    dirX      = Cos(Radians) * Magnitude
    dirY      = Sin(Radians) * Magnitude
End Sub

'Updates the vector's directional components, magnitude and angle in radians based on the given angle in degrees.
Public Sub setAngleD(Degrees As Double)
    AngleD    = Degrees
    AngleR    = Degrees * cPI / 180
    dirX      = CosD(Degrees) * Size
    dirY      = SinD(Degrees) * Size
End Sub

'Updates the vector's directional components, magnitude and angle in degrees based on the given angle in radians.
Public Sub setAngleR(Radians As Double)
    AngleD    = Radians * 180 / cPI
    AngleR    = Radians
    dirX      = Cos(Radians) * Size
    dirY      = Sin(Radians) * Size
End Sub
 

Attachments

  • PhysiX.jar
    299.7 KB · Views: 488
  • LittleSquare.zip
    3.2 KB · Views: 494
Last edited:

BeneBarros

Active Member
Licensed User
Longtime User
I did exactly as below
Dim Magn As Double = Sqrt((dist * 9.80665) / SinD(2*Abs(Angle)))

but you should have a problem
I had to add a variable to adjust the length
Dim Magn As Double = Sqrt((dist * 9.80665) / SinD(2*Abs(Angle))) * 2.575

see what I'm doing. (Unfinished)
 
Last edited:

BeneBarros

Active Member
Licensed User
Longtime User
B4X:
Dim Const TORADIANS As Double = 0.017453292519943295769236907684886127134428718885417
Dim       Magn      As Double = Sqrt((dist * G) / Sin(2 * Angle * TORADIANS))

Does this work?
does not work...
This equation returns the same result as the above.
I'll keep searching, see if I can find the solution.
Thanks for listening.
 

wonder

Expert
Licensed User
Longtime User
Another remark: Why are you using the real-world Gravity value?
In my source code, the gravity value (magnitude) is 1600:
B4X:
    'World Gravity
        tempGravity.setAngleAndMagnitudeD(90, 1600)
        World.Gravity = tempGravity
 
Last edited:

BeneBarros

Active Member
Licensed User
Longtime User
would it be this?
tempGravity.setAngleAndMagnitudeD(Abs(Angle), 1600)
World.GRAVITY = tempGravity
Dim dist As Double = (cvT.Left + 10 + TbPosX * 38) - GameBall.posX
Dim Force As Double = Sqrt((dist * World.GRAVITY.AngleD) / SinD(2*Abs(Angle)))

Excellent. Now it works perfect.
Thank you very much
 
Top