PHYSICS.INC
Introduction
Hello gamers, I have to be honest, I'm not touching anything SA-MP related from more than 2 years, but today I've got a bit nostalgic and just?discovered the?Open-MP project.
This physics.inc (or Objects Physics) library is a project I worked to in 2013, and it would be nice for someone to revive that, if Open-MP developers can help mitigate?the network?problems (too many acks)?that a constantly updating physics simulation gives. As you can notice, it's been a lot of years since I worked on this project, so forgive me if I'll not be detailed enough or write something incorrect. Also,
Physics.inc is a very basic implementation of projectile physics in SA-MP, allowing to handle the 2D or 3D movement of objects (ideally, balls), collisions, or even interacting with the San Andreas world, thanks to the?ColAndreas plugin.
Github
https://github.com/uPeppe/physics.inc
Library dependencies
modelsizes.inc
foreach.inc?
ColAndreas (not mandatory)
zcmd (only for pool, but it's easy to switch to another command processor)
Documentation
Code:
PHY_InitObject(objectid, modelid = 0, Float:mass = 1.0, Float:size = FLOAT_NAN, mode = PHY_MODE_3D)
/*Starts using physics for objectid.
modelid - object's modelid, used to get its size with modelsizes include.
mass - object's mass, it is like its weight and is used in collisions.
size - object's sphere radius, taken from modelsizes.inc by default.
mode - PHY_MODE_3D or PHY_MODE_2D.*/
PHY_GetObjectMode(objectid)
PHY_DeleteObject(objectid)
/*Stops using physics for objectid (doesn't destroy it).*/
PHY_SetObjectVelocity(objectid, Float:vx, Float:vy, Float:vz = 0.0)
/*Moves the object with vx, vy, vz velocities.*/
PHY_GetObjectVelocity(objectid, &Float:vx, &Float:vy, &Float:vz)
PHY_IsObjectMoving(objectid)
PHY_SetObjectAcceleration(objectid, Float:ax, Float:ay, Float:az = 0.0)
/*Sets the object's acceleration.*/
PHY_GetObjectAcceleration(objectid, &Float:ax, &Float:ay, &Float:az)
PHY_GetObjectSpeed(objectid, &Float:speed, _3D = 0)
PHY_GetObjectMoveAngle(objectid, &Float:moveangle)
stock PHY_RollObject(objectid, toggle = 1, rollingmode = PHY_ROLLING_MODE_DEFAULT)
/* Starts rolling the object when it moves of toggle = 1 or stops if toggle = 0.
rollingmode = PHY_ROLLING_MODE_DEFAULT (Euler angles) or PHY_ROLLING_MODE_ADVANCED (Quaternions)
When using advanced rolling mode, if you manually use SetObjectRot in your script, it is adviced to
call PHY_RollObject again, in order to recalculate its quaternion angles.*/
PHY_IsObjectRolling(objectid)
PHY_SetObjectFriction(objectid, Float:friction)
/*Applies friction to the object when it moves on the floor (at its lowest Z). If friction is applied, the object gradually slows down.*/
Float:PHY_GetObjectFriction(objectid)
PHY_SetObjectAirResistance(objectid, Float:resistance)
/*Applies air resistance to the object when it moves. The difference between friction and air resistance is that the former works only if the object is on the floor and the letter is also slows down the object proportionally to its velocity.*/
Float:PHY_GetObjectAirResistance(objectid)
PHY_SetObjectZBound(objectid, Float:low = FLOAT_NAN, Float:high = FLOAT_NAN, Float:constant = 0.0)
/*Limits the object's Z position.
low - The lowest Z that the object can have (you can use FLOAT_NEG_INFINITY). If it is set to NaN it doesn't change.
high - The highest Z that the object can have (you can use FLOAT_INFINITY). If it is set to NaN it doesn't change.
(When you use PHY_InitObject lowest Z is set to the current object's Z and highest Z to FLOAT_INFINITY.
constant - It should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
if it is 0.0 the object stops when it bounces. It could be a middle ground.*/
PHY_SetObjectGravity(objectid, Float:gravity)
/*Sets the gravity's acceleration that the object is subjected to.*/
Float:PHY_GetObjectGravity(objectid)
PHY_SetObjectWorld(objectid, world)
/*Object and walls collide only if the are in the same world or one of them is in the world 0 (default).*/
PHY_ToggleObjectPlayerColls(objectid, toggle = 1, Float:constant = 1.0, Float:distoffset = 0.8, Float:zoffsetlow = 1.0, Float:zoffsethigh = 1.0)
/*Toggles object's collisions with players.
- constant - It should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
if it is 0.0 the object stops when it bounces. It could be a middle ground.
- distoffset - The distance at which the object collides with the player.
- zoffsetlow/zoffsethigh - The max Z distance (downward/upward) at which the object collides with the player.*/
PHY_ApplyRotation(objectid, Float:speed, Float:moveangle)
/*Function used internally to rotate the objects.*/
PHY_CreateWall(Float:x1, Float:y1, Float:x2, Float:y2, Float:constant = 1.0, Float:low = FLOAT_NEG_INFINITY, Float:high = FLOAT_INFINITY)
/*Creates a collision wall (straight line) from A(x1, y1) to B(x2, y2).
constant should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
if it is 0.0 the object stops when it collides.
low is the lowest wall's Z, high is the highest. If they're set to default the wall is like infinitely high. */
PHY_CreateArea(Float:minX, Float:minY, Float:maxX, Float:maxY, Float:constant = 1.0, Float:low = FLOAT_NEG_INFINITY, Float:high = FLOAT_INFINITY)
/*Creates four walls that form an area. Works like IsPlayerInArea.*/
PHY_DestroyWall(wallid)
PHY_SetWallWorld(wallid, world)
PHY_CreateCylinder(Float:x, Float:y, Float:size, Float:constant = 1.0, Float:low = FLOAT_NEG_INFINITY, Float:high = FLOAT_INFINITY)
/*Creates a collision cylinder at position x, y.
constant should be from 0.0 to 1.0. If it is 1.0 the object doesn't lose velocity,
if it is 0.0 the object stops when it collides.
low is the lowest cylinder's Z, high is the highest. If they're set to default the cylinder is like infinitely high.*/
PHY_DestroyCylinder(cylinderid)
PHY_SetCylinderWorld(cylinderid, world)
PHY_SetPlayerWorld(playerid, world)
PHY_UseColAndreas(objectid, mode = 1)
/* Sets ColAndreas mode for the object. Modes: 0 none, 1 collisions z bounds, 2 collisions only, 3 z bounds only */
/* Callbacks */
forward PHY_OnObjectUpdate(objectid);
forward PHY_OnObjectCollideWithObject(object1, object2);
forward PHY_OnObjectCollideWithZBound(objectid, lowhigh); // low bound = 0, high bound = 1
forward PHY_OnObjectCollideWithSAWorld(objectid, Float:cx, Float:cy, Float:cz); // Only with ColAndreas
forward PHY_OnObjectCollideWithWall(objectid, wallid);
forward PHY_OnObjectCollideWithCylinder(objectid, cylinderid);
forward PHY_OnObjectCollideWithPlayer(objectid, playerid);
ColAndreas support
ColAndreas plugin by Pottus and Crayder allows to calculate collisions with every object in San Andreas map and to constantly update the low and high Z bound of the object that uses physics.?
If you want to use ColAndreas features (PHY_UseColAndreas and PHY_OnObjectCollideWithSAWorld), put "#define COLANDREAS" before including "physics.inc".
Warning: the interaction between this library and ColAndreas might be inefficient and very code-time consuming!?
Examples
In gamemodes folder of the Github repository, you can find some examples of what you can do with this library.
- Pool. It's the perfect example of 2D Physics, with balls that can collide between themselves or?with walls.?Press LMB to hold the ball.Press RMB to shot/pass the ball. Press ALT to lob the ball. Press F to make a cross/high shot.?Hit the ball (press RMB/ALT/F) when it is at head height to make a header. Power bar when you are holding RMB/ALT/F.
[Video: https://www.youtube.com/watch?v=yOtlNQvgJ6Q]
- Soccer. Here physics are 3D (z-axis is used). This script also uses the "collision cylinder" feature, for the goal post.
[Video: https://www.youtube.com/watch?v=ISTebVTMYog]
- Throw an object. A more simple example of of 3D physics, with a command to just throw a Deagle in the air.
Code:command(launch, playerid, params[])
{
#define SPEED (10.0)
#define Z_SPEED (4.0)
#define GRAVITY (13.0)
? ? ? ? new modelid = 348; // Deagle Model ID
new Float:x, Float:y, Float:z, Float:ang;
GetPlayerPos(playerid, x, y, z);
GetPlayerFacingAngle(playerid, ang);
new obj = CreateObject(modelid, x, y - 0.5 * floatcos(-(ang 90.0), degrees), z, 93.7, 120.0, ang 60.0);
? PHY_InitObject(obj);
PHY_SetObjectVelocity(obj, SPEED * floatsin(-ang, degrees), SPEED * floatcos(-ang, degrees), Z_SPEED);
PHY_SetObjectFriction(obj, 100); // This will stop the object when it touchs the ground.
PHY_SetObjectGravity(obj, GRAVITY);
PHY_SetObjectZBound(obj, z - 1.0, _, 0.0);
ApplyAnimation(playerid,"GRENADE","WEAPON_throwu",3.0,0,0,0,0,0);
return 1;
}
- ColAndreas testing.
[Video: https://www.youtube.com/watch?v=QKHDK_vogYE]
Appreciated contributions?
I don't even have GTA San Andreas on my computer, so it would be hard for me to update this library. I have a list of things that are very easy to do:
- Update physics.inc with the latest library dependencies versions (but still keeping compatibility with the older ones).
The code is very old, so I used old version of the libraries modelsizes, foreach and ColAndreas. For example, I think no one uses foreach now, but use instead?Y_Iterate. Also, I don't know if the current ColAndreas version works well with the include, because at the time I used one of the first versions.
- Implement a more advanced object rolling.?DONE
With the way the actual code works, the rolling of a ball is not so realistic, because, when an object changes its direction of movement,?the RZ angle is instantly changed to match that direction.A more realistic way to roll objects should use operations on quaternions, instead of Euler angles. In the past, I try to use that, but it didn't work. In 2016, a chinese guy on SA-MP forum managed to fix that and here's the code: https://mega.nz/#!38QlGaLb!uinmaqDDaTjha...WkP3ubLLYI (version of physics.inc that rolls objects using quaternions). It would be nice if you implement part of his code, in order to have two options of rolling objects, with a function like PHY_SetObjectRollingMode: ROLLING_MODE_DEFAULT for the more simple one I wrote and ROLLING_MODE_ADVANCED?for the quaternions one. In order to do that, you modify the?PHY_ApplyRotation function.This is how the ROLLING_MODE_DEFAULT should look: https://www.youtube.com/watch?v=Kbkm4fXaB7Q. This is how the ROLLING_MODE_ADVANCED should look: https://www.youtube.com/watch?v=xl5Vbd2tfwM. As you can see, the problem of the first one is the sudden change of rotation when two balls collide and thus change their direction of movement.