How to Make a Physics Engine

Материал из Поле цифровой дидактики

This tutorial shows how to make a simple physics engine where the sprite is not controlled by the arrow keys, as in Platformers, but rather interacts like dropping and pushing the Sprite in real life would.

Make Variables

First make the following Variables 'for this sprite'

(X Velocity)//The velocity of the sprite on the X axis
(Y Velocity)//The velocity of the sprite on the Y axis
(Direction::variables)//The speed at which the sprite is turning
(Slope)//Used for slope detection in collisions

Next make two sprites, one will be the one that uses the physics, and the other will be the one will be the ground that the sprite interacts with. In this tutorial, all the scripts are used in the main sprite and the ground sprite is called 'ground'.

Collision Detection

First, collision detection needs to be made. The collision detection that will be used is similar to ones used in platformers, however, this script does not use any controls to move the player.

define Physics (friction) (stiffness)//Run without screen refresh
if <not<touching (ground v)?>> then
    change [Y velocity v] by (-1)
end
change y by (Y velocity)
if <touching (ground v)?> then
    repeat ([abs v] of ([ceiling v] of (Y velocity)))
        change y by ((([abs v] of (Y velocity))/(Y velocity)) * (-1))
    end
end
set [Y velocity v] to (1)
change x by (X Velocity)
if <touching (ground v)?> then
    set [slope v] to (0)
    repeat until <<(slope) = (-8)> or <not<touching (ground v)?>>
        change [slope v] by (-1)
        change y by (1)
    end
if <(slope) = (-8)> then
    change y by (slope)
    repeat ([abs v] of ([ceiling v] of (X Velocity)))
        change x by ((([abs v] of (X Velocity))/ (x Velocity))*(-1)
    end
    set [X Velocity v] to (0)
end
end

Turning When Hitting a Slope

This script will make the sprite fall toward the ground and not go through it, however, this does not give a realistic physics look because the sprite does not turn or move on slopes. To add turning and sliding down slopes, another custom block needs to be made, called Turn:

define Turn//Run without screen rfefresh
change x by (10)//Move to the right and detect if still touching the ground, if not, turn and slide to the right a little bit.
if <not<touching (ground v)?>> then
    change [Direction v] by (3)
    change [X Velocity v] by (.3)
end
change x by (-20)//-20 this time because it is now needed to undo the movement from moving to the right and then move to the left, so the equivalent of moving to the left twice.
if <not<touching (ground v) ?>> then//Do the opposite this time.
    change [Direction v] by (-3)
    change [X Velocity v] by (-.3)
end
change x by (10)
turn cw (2) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (1)
end
turn ccw (4) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (-1)
end
turn cw (12) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (2)
end
turn ccw (20) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (-2)
end
turn cw (10) degrees

Now that the turning custom block has been created, it needs to be used:

define Physics (friction) (stiffness)//Run without screen refresh
if <not<touching (ground v)?>> then
    change [Y velocity v] by (-1)
end
change y by (Y velocity)
if <touching (ground v)?> then
    repeat ([abs v] of ([ceiling v] of (Y velocity)))
        change y by ((([abs v] of (Y velocity))/(Y velocity)) * (-1))
    end
end
set [Y velocity v] to (1)
change x by (X Velocity)
if <touching (ground v)?> then
    set [slope v] to (0)
    repeat until <<(slope) = (-8)> or <not<touching (ground v)?>>
        change [slope v] by (-1)
        change y by (1)
    end
if <(slope) = (-8)> then
    change y by (slope)
    repeat ([abs v] of ([ceiling v] of (X Velocity)))
        change x by ((([abs v] of (X Velocity))/ (x Velocity))*(-1)
    end
    set [X Velocity v] to (0)
end
end
turn cw (Direction::variables) degrees
set [Direction v] to ((Direction::variables) * (stiffness::custom))
set [X Velocity v] to ((X velocity) * (friction::custom))
Turn::custom

Implementing Code

The turning and collision detection has been created, so the only thing left to do is to use it.

When green flag clicked
go to x: (0) y: (0)//Where the sprite will start (coordinates can be different)
set [Direction v] to [0]//Setting variables to avoid bugs
set [X Velocity v] to [0]
set [Y Velocity v] to [0]
forever//using our code!
    Physics (0.95)(.6)::custom
    ...::grey//Other code can be placed in here for the controls of the sprite, e.g. allow it to be dragged, moved by the arrow keys, etc.
end

Final Code

Шаблон:Note Here is the final code for the physics engine:

define Physics (friction) (stiffness)//Run without screen refresh
if <not<touching (ground v)?>> then
    change [Y velocity v] by (-1)
end
change y by (Y velocity)
if <touching (ground v)?> then
    repeat ([abs v] of ([ceiling v] of (Y velocity)))
        change y by ((([abs v] of (Y velocity))/(Y velocity)) * (-1))
    end
end
set [Y velocity v] to (1)
change x by (X Velocity)
if <touching (ground v)?> then
    set [slope v] to (0)
    repeat until <<(slope) = (-8)> or <not<touching (ground v)?>>
        change [slope v] by (-1)
        change y by (1)
    end
if <(slope) = (-8)> then
    change y by (slope)
    repeat ([abs v] of ([ceiling v] of (X Velocity)))
        change x by ((([abs v] of (X Velocity))/ (x Velocity))*(-1)
    end
    set [X Velocity v] to (0)
end
end
turn cw (Direction::variables) degrees
set [Direction v] to ((Direction::variables) * (stiffness::custom))
set [X Velocity v] to ((X velocity) * (friction::custom))
Turn::custom


define Turn//Run without screen rfefresh
change x by (10)//Move to the right and detect if still touching the ground, if not, turn and slide to the right a little bit.
if <not<touching (ground v)?>> then
    change [Direction v] by (3)
    change [X Velocity v] by (.3)
end
change x by (-20)//-20 this time because it is now needed to undo the movement from moving to the right and then move to the left, so the equivalent of moving to the left twice.
if <not<touching (ground v) ?>> then//Do the opposite this time.
    change [Direction v] by (-3)
    change [X Velocity v] by (-.3)
end
change x by (10)
turn cw (2) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (1)
end
turn ccw (4) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (-1)
end
turn cw (12) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (2)
end
turn ccw (20) degrees
if <not<touching (ground v)?>> then
    change [Direction v] by (-2)
end
turn cw (10) degrees


When green flag clicked
go to x: (0) y: (0)//Where the sprite will start (coordinates can be different)
set [Direction v] to [0]//Setting variables to avoid bugs
set [X Velocity v] to [0]
set [Y Velocity v] to [0]
forever
    Physics (0.95)(.6)::custom
    ...::grey//Other code can be placed in here for the controls of the sprite, e.g. allow it to be dragged, moved by the arrow keys, etc.
end