Share My Creation LittleSquare Physics Demo

Discussion in 'B4J Share Your Creations' started by wonder, Sep 11, 2015.

  1. wonder

    wonder Expert Licensed User

    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.

    [​IMG]

    PhysiX.b4j
    Code:
    #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(1024)  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, 
    00, MainForm.Width, MainForm.Height)

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

        
    'World Gravity
            tempGravity.setAngleAndMagnitudeD(901600)
            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 = 0Then DeltaTime.Interval = (Max(1DateTime.Now - DeltaTime.TimeStamp) / 1000)
            DeltaTime.TimeStamp = 
    DateTime.Now

        
    'Clear Screen
            cvs.ClearRect(00, 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, 
    010, 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, 
    010, 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, 
    010, EarthMass, 0.6)
                LittleSquare.Velocity = tempVelocity
            
    Else If LittleSquare.posX < 0 Then
                LittleSquare.posX = 
    0
                tempVelocity.dirX  = PostCollisionVelocity(LittleSquare.Velocity.dirX, 
    010, 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, 
    True0)
    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
    Code:
    '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
     

    Attached Files:

    Last edited: Sep 13, 2015
    BeneBarros, jmon, Beja and 3 others like this.
  2. Douglas Farias

    Douglas Farias Expert Licensed User

    Como eu queria ter tempo de estudar isso :( amo jogos
     
    wonder likes this.
  3. Jaames

    Jaames Active Member Licensed User

    Nice , thanks for sharing. One question though, do you manually keep your code that clean? I find your code very easy to read. :)
     
    wonder likes this.
  4. wonder

    wonder Expert Licensed User

    Thanks for commenting! I'm glad you enjoy the demo! :D
    I have to say that I'm extra careful with my public code, but in general yes, I like to keep things tidy and visually appealing. :)
    For me, there's nothing worse than going back to an old project and seeing nothing than spaghetti code.
     
    thedesolatesoul, Jaames and inakigarm like this.
  5. ilan

    ilan Expert Licensed User

    very nice, could you convert it to b4a?

    EDIT: i have tried to use it in b4a but for some reason the little square stays on the top like he has no gravity... :confused:
     
    Last edited: Oct 22, 2015
    wonder likes this.
  6. wonder

    wonder Expert Licensed User

    In B4A, have you done it with Canvas or LibGDX?
     
  7. ilan

    ilan Expert Licensed User

    Canvas
     
  8. wonder

    wonder Expert Licensed User

    As requested, here's the B4A version. :)
    It's pretty much the same, except for a little change in the collision detection (Ctrl+F: "NEW CODE").

    Let me know if it works! :D
     

    Attached Files:

    Beja, Erel and ilan like this.
  9. ilan

    ilan Expert Licensed User

    great, wonder. i have tried it and i am getting an error in activity_create

    this line is the problem: tempGravity.setAngleAndMagnitudeD(90, 1600)

     
  10. wonder

    wonder Expert Licensed User

    @ilan, I'm using B4A 4.00 with Java 8. No issues here... :confused:
    Try this one. I added an Initialize method to Vector.bas.
     

    Attached Files:

    Last edited: Oct 23, 2015
  11. ilan

    ilan Expert Licensed User

    hi wonder,

    if i want the square to jump always the same height so there will not be any friction on axis y how can i do that with your example?

    when i set CoR to 1 the square jumps higher and higher but i would like to have it jump the same distance every time it hits the ground.

    thank you
     
  12. wonder

    wonder Expert Licensed User

    Then you cannot use the PostCollisionVelocity function, since its formula concerns real-world physics and the behavior you're describing kinda breaks the Newton laws of motion.

    That said, for every vertical and downwards collision (where velocity.y > 0 ), you should instruct the object to get just the right amount of vertical upwards velocity. This amount should be a fixed value.

    Code:
    If ObjectHitsTheGround And velocity.y > 0 Then
        velocity.y = -
    300 'For example
    End If
    You'll have to experiment with different values until you get the desired result.

    Remember I'm no physicist, I just like games! :)
     
    ilan likes this.
  13. ilan

    ilan Expert Licensed User

    In some tutorials i saw they said that if you want to have that behaivor were the ball does not change his velocity you need to set the friction of this physic object to 0.

    An object with no friction should keep his velocity also after hitting a wall/ground.
     
  14. wonder

    wonder Expert Licensed User

    There is no vertical friction in my example. Do you mean, perhaps, the "conservation of momentum"?

     
  15. ilan

    ilan Expert Licensed User

    I saw this video, it is very interesting.

    I dont know how to explain it. (I will try)

    When a ball will hit the ground it will never come back to his startpoint because of the friction.

    If there where no friction it will bounce back exactly to the place he started to fall because this is the force he came against the second body.

    You put a variable in your code CoR that is the elastity of the body but when i put to 1 it will bounce higher then the starting point so something is maybe wrong with the formula?

    It should bounce to the same point he started. Or am i wrong?
     
  16. wonder

    wonder Expert Licensed User

    No, no, every time the ball hits the ground, it loses energy. Friction has nothing to do with it.

    [​IMG]
    Source: http://www.gcsescience.com/pen30-energy-ball-bounce.htm

    The in the real-world, the Coefficient of Restitution is something that can only be obtained after the collision happens.

    [​IMG]

    In my LittleSquare Physics demo, we do not have any information regarding the material the object is made of.
    All the computer knows is that it weighs 10 kilos, as seen in the code below:
    Code:
    PostCollisionVelocity(LittleSquare.Velocity.dirY, 010, EarthMass, 0.6)
    Intuitively, we know that a ball made of rubber would bounce really high, but one made of stone would not bounce at all.
    Since computer doesn't have any of this information, a good workaround is to introduce the CoR variable à priori.
    This way we're able to determine what kind of collision we want, in a very inexpensive way.

    Code:
    '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
    It's the conservation of momentum formula, which I think is the correct one for this purpose.
    My source: http://physics.tutorvista.com/momentum/conservation-of-momentum.html
     
    Last edited: Feb 24, 2016
    inakigarm likes this.
  17. wonder

    wonder Expert Licensed User

    Just in case, here's an alternate version of the formula, taken from the Wikipedia page:
    Code:
    Sub PostCollisionVelocity(u1 As Double, u2 As Double, m1 As Double, m2 As Double, CoR As Double) As Double
        
    Return ((m1 * u1) + (m2 * u2) + (m2 * CoR * (u2 - u1))) / (m1 + m2)
    End Sub
    It yields the exact same results, I just tested it. These are indeed the correct formulas. :)
     
  18. ilan

    ilan Expert Licensed User

    thanx wonder, i will use your example to create my next game. i will need to change a little the code, since i will not swing my character like you do but it is a great example to build from it lots of games. :)
     
    wonder likes this.
  19. BeneBarros

    BeneBarros Active Member Licensed User

    Is there any formula for finding the magnitude? Informing degree of tilt and distance from the ball to the goal.
     
  20. wonder

    wonder Expert Licensed User

    Last edited: Aug 23, 2016
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice