-- A physics mixin. Responsible for turning the game object it's attached to into a full fledged physics object.
-- Currently the only default way to add collision to objects is via this mixin.
-- In the future I want to create a way that doesn't make use of box2d for simpler games, but that also uses roughly the same API so that gameplay code doesn't have to be different regardless of which one you're using.
-- Using any of the "set_as" init functions requires the game object to have a group attached to it.
Physics=Object:extend()
-- Sets this object as a physics rectangle.
-- Its body_type can be either 'static', 'dynamic' or 'kinematic' (see box2d for more info) and its tag has to have been created in group:set_as_physics_world.
-- Its .shape variable is set to a Rectangle instance and this instance is updated to be in sync with the physics body every frame.
-- Its body_type can be either 'static', 'dynamic' or 'kinematic' (see box2d for more info) and its tag has to have been created in group:set_as_physics_world.
-- Its .shape variable is set to a Line instance and this instance is updated to be in sync with the physics body every frame.
-- Sets this object as a physics chain (a collection of edges)
-- Its body_type can be either 'static', 'dynamic' or 'kinematic' (see box2d for more info) and its tag has to have been created in group:set_as_physics_world.
-- If loop is set to true, then the collection of edges will be closed, forming a polygon. Otherwise it will be open.
-- Its .shape variable is set to a Chain instance and this instance is updated to be in sync with the physics body every frame.
-- Its body_type can be either 'static', 'dynamic' or 'kinematic' (see box2d for more info) and its tag has to have been created in group:set_as_physics_world.
-- Its .shape variable is set to a Polygon instance and this instance is updated to be in sync with the physics body every frame.
-- Its body_type can be either 'static', 'dynamic' or 'kinematic' (see box2d for more info) and its tag has to have been created in group:set_as_physics_world.
-- Its .shape variable is set to a Circle instance and this instance is updated to be in sync with the physics body every frame.
functionPhysics:set_as_circle(rs,body_type,tag)
ifnotself.groupthenerror("The GameObject must have a group defined for the Physics mixin to function")end
-- Its body_type can be either 'static', 'dynamic' or 'kinematic' (see box2d for more info) and its tag has to have been created in group:set_as_physics_world.
-- Its .shape variable is set to a Triangle instance and this instance is updated to be in sync with the physics body every frame.
-- Exactly the same as group:get_objects_in_shape, except additionally it automatically removes this object from the results.
-- self:get_objects_in_shape(Circle(self.x, self.y, 100), {Enemy1, Enemy2, Enemy3}) -> all objects of class Enemy1, Enemy2 and Enemy3 in a circle of radius 100 around this object
-- Returns the closest object to this object in the given shape, optionally excluding objects in the exclude list passed in.
-- self:get_closest_object_in_shape(Circle(self.x, self.y, 100), {Enemy1, Enemy2, Enemy3}) -> closest object of class Enemy1, Enemy2 or Enemy3 in a circle of radius 100 around this object
-- self:get_closest_object_in_shape(Circle(self.x, self.y, 100), {Enemy1, Enemy2, Enemy3}, {object_1, object_2}) -> same as above except excluding object instances object_1 and object_2
-- Returns a random object in the given shape, excluding this object and also optionally excluding objects in the exclude list passed in.
-- self:get_random_object_in_shape(Circle(self.x, self.y, 100), {Enemy1, Enemy2, Enemy3}) -> random object of class Enemy1, Enemy2 or Enemy3 in a circle of radius 100 around this object
-- self:get_random_object_in_shape(Circle(self.x, self.y, 100), {Enemy1, Enemy2, Enemy3}, {object_1, object_2}) -> same as above except excluding object instances object_1 and object_2
-- Sets the object's position directly, avoid using if you need velocity/acceleration calculations to make sense and be accurate, as teleporting the object around messes up its physics
-- self:set_position(100, 100)
functionPhysics:set_position(x,y)
ifself.bodythenself.body:setPosition(x,y)end
returnself:update_position()
end
-- Returns the object's position as two values
-- x, y = self:get_position()
functionPhysics:get_position()
self:update_position()
ifself.bodythenreturnself.body:getPosition()end
end
-- Sets the object as a bullet
-- Bullets will collide and generate proper collision responses regardless of their velocity, despite being more expensive to calculate
-- self:set_bullet(true)
functionPhysics:set_bullet(v)
ifself.bodythenself.body:setBullet(v)end
returnself
end
-- Sets the object to have fixed rotation
-- When box2d objects don't have fixed rotation, whenever they collide with other objects they will rotate around depending on where the collision happened
-- Setting this to true prevents that from happening, useful for every type of game where you don't need accurate physics responses in terms of the characters rotation
-- The higher this value, the more the object will resist movement and the faster it will stop moving after forces are applied to it
-- self:set_damping(10)
functionPhysics:set_damping(v)
ifself.bodythenself.body:setLinearDamping(v)end
returnself
end
-- Sets the object's angular velocity
-- If set_fixed_rotation is set to true then this will do nothing
-- self:set_angular_velocity(math.pi/4)
functionPhysics:set_angular_velocity(v)
ifself.bodythenself.body:setAngularVelocity(v)end
returnself
end
-- Sets the object's angular damping
-- The higher this value, the more the object will resist rotation and the faster it will stop rotating after angular forces are applied to it
-- self:set_angular_damping(10)
functionPhysics:set_angular_damping(v)
ifself.bodythenself.body:setAngularDamping(v)end
returnself
end
-- Returns the object's angle
-- r = self:get_angle()
functionPhysics:get_angle()
ifself.bodythenreturnself.body:getAngle()end
end
-- Sets the object's angle
-- If set_fixed_rotation is set to true then this will do nothing
-- self:set_angle(math.pi/8)
functionPhysics:set_angle(v)
ifself.bodythenself.body:setAngle(v)end
returnself
end
-- Sets the object's restitution
-- This is a value from 0 to 1 and the higher it is the more energy the object will conserve when bouncing off other objects
-- At 1, it will bounce perfectly and not lose any velocity
-- At 0, it will not bounce at all
-- self:set_restitution(0.75)
functionPhysics:set_restitution(v)
ifself.fixturethen
self.fixture:setRestitution(v)
elseifself.fixturesthen
for_,fixtureinipairs(self.fixtures)do
fixture:setRestitution(v)
end
end
returnself
end
-- Sets the object's friction
-- This is a value from 0 to infinity, but generally between 0 and 1, the higher it is the more friction there will be when this object slides with another
-- At 0 friction is turned off and the object will slide with no resistance
-- The friction calculation takes into account the friction of both objects sliding on one another, so if one object has friction set to 0 then it will treat the interaction as if there's no friction
-- self:set_friction(1)
functionPhysics:set_friction(v)
ifself.fixturethen
self.fixture:setFriction(v)
elseifself.fixturesthen
for_,fixtureinipairs(self.fixtures)do
fixture:setFriction(v)
end
end
returnself
end
-- Applies an instantaneous amount of force to the object
-- Other than the object, the 3 arguments available are:
-- max_speed - the maximum speed the object can have in this acceleration
-- deceleration - how fast the object will decelerate once it gets closer to the target, higher values will make the deceleration more abrupt, do not make this value 0
-- turn_coefficient - how strong is the turning force for this object, higher values will make it turn faster
-- Keeps this object separated from other objects of specific classes according to the radius passed in
-- What this function does is simply look at all nearby objects and apply forces to this object such that it remains separated from them
-- self:separate(40, {Enemy}) -> when this is called every frame, this applies forces to this object to keep it separated from other Enemy instances by 40 units at all times