Skip to content

Commit

Permalink
materials, auto mass calcs, improved mass integs
Browse files Browse the repository at this point in the history
  • Loading branch information
AustinEast committed Feb 20, 2022
1 parent 178a60a commit c874466
Show file tree
Hide file tree
Showing 24 changed files with 245 additions and 99 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,20 @@ class Main {
// Create a Body with a Circle Collider and add it to the World
var a = world.make({
elasticity: 0.2,
material: {elasticity: 0.2},
shape: {
type: CIRCLE,
radius: 16,
}
});
// Create a Body with a Rectangle collider and add it to the World
// This Body will have a Mass of zero, rendering it as unmovable
// This Body will be static (ie have a Mass of `0`), rendering it as unmovable
// This is useful for things like platforms or walls.
var b = world.make({
mass: 0, // Setting this to zero makes the body unmovable by forces and collisions
mass: STATIC, // Setting this to Static/`0` makes the body unmovable by forces and collisions
y: 48, // Set the object's Y position below the Circle, so that gravity makes them collide
elasticity: 0.2,
material: {elasticity: 0.2},
shape: {
type: RECT,
width: 10,
Expand Down
93 changes: 77 additions & 16 deletions echo/Body.hx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
*/
public static var defaults(get, null):BodyOptions;

public static final minimum_mass = 0.0001;

static var ids:Int = 0;
/**
* Unique id of the Body.
Expand Down Expand Up @@ -66,16 +68,18 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
*/
public var kinematic:Bool;
/**
* Body's mass. Affects how the Body reacts to Collisions and Velocity.
*
* The higher a Body's mass, the more resistant it is to those forces.
* The Body's mass. Affects how the Body reacts to Collisions and Acceleration Forces. The higher a Body's mass, the more resistant it is to those forces.
*
* If a Body's mass is set to `0`, it becomes static - unmovable by forces and collisions.
*/
public var mass(default, set):Float;

public var material:Material = Material.global;
/**
* Value to determine how much of a Body's `velocity` should be retained during collisions (or how much should the `Body` "bounce", in other words).
*/
public var elasticity:Float;
@:deprecated('Elasticity Value has been moved into the Material object. Use `body.material.elasticity instead.')
public var elasticity(get, set):Float;
/**
* The units/second that a `Body` moves.
*/
Expand All @@ -90,6 +94,12 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
* The units/second that a `Body` will rotate.
*/
public var rotational_velocity:Float;
/**
* A measure of how fast a `Body` will change it's rotational velocity.
*
* Can be thought of the sum of all external rotation forces on an object during a step.
*/
public var rotational_acceleration:Float = 0;
/**
* The maximum values a Body's velocity's x and y components can be. If set to 0, the Body has no restrictions on how fast it can move.
*
Expand Down Expand Up @@ -127,7 +137,8 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
/**
* Percentage value that represents how much a World's gravity affects the Body.
*/
public var gravity_scale:Float;
@:deprecated('Gravity Value has been moved into the Material object. Use `body.material.gravity_scale instead.')
public var gravity_scale(get, set):Float;
/**
* Cached value of 1 divided by the Body's mass. Used in Internal calculations.
*/
Expand Down Expand Up @@ -227,8 +238,17 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
scale_x = options.scale_x;
scale_y = options.scale_y;
kinematic = options.kinematic;
mass = options.mass;
elasticity = options.elasticity;

if (options.material != null) material = options.material;
else if (options.gravity_scale != null || options.elasticity != null) {
// Temp: Support deprecated values
material = {
elasticity: options.elasticity,
gravity_scale: options.gravity_scale
}
}
else material = Material.global;

velocity.set(options.velocity_x, options.velocity_y);
rotational_velocity = options.rotational_velocity;
max_velocity.set(options.max_velocity_x, options.max_velocity_y);
Expand All @@ -237,7 +257,6 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
drag.set(options.drag_x, options.drag_y);
drag_length = options.drag_length;
rotational_drag = options.rotational_drag;
gravity_scale = options.gravity_scale;
last_x = Math.NaN;
last_y = Math.NaN;
last_rotation = Math.NaN;
Expand All @@ -246,6 +265,15 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
if (options.shapes != null) for (shape in options.shapes) create_shape(shape);
if (options.shape_instance != null) add_shape(options.shape_instance);
if (options.shape_instances != null) for (shape in options.shape_instances) add_shape(shape);

switch (options.mass) {
case AUTO:
calculate_mass();
case STATIC:
mass = STATIC;
default:
mass = options.mass;
}
}

public function clone():Body {
Expand All @@ -255,9 +283,9 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
b.rotation = rotation;
b.scale_x = scale_x;
b.scale_y = scale_y;
b.material = material;
b.kinematic = kinematic;
b.mass = mass;
b.elasticity = elasticity;
b.velocity.set(velocity.x, velocity.y);
b.rotational_velocity = rotational_velocity;
b.max_velocity.set(max_velocity.x, max_velocity.y);
Expand All @@ -266,7 +294,6 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
b.drag.set(drag.x, drag.y);
b.drag_length = drag_length;
b.rotational_drag = rotational_drag;
b.gravity_scale = gravity_scale;
b.last_x = last_x;
b.last_y = last_y;
b.last_rotation = last_rotation;
Expand All @@ -279,7 +306,9 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
return b;
}
/**
* Adds a new `Shape` to the Body based on the `ShapeOptions` passed in.
* Adds a new `Shape` to the Body based on the `ShapeOptions` passed in.
*
* If `mass` has not been manually set, It's recommended to call `calculate_mass()` after adding/removing a Body's shapes.
* @param options
* @param position The position in the Body's `shapes` array the Shape will be added to. If set to -1, the Shape is pushed to the end.
* @return The newly created `Shape`.
Expand All @@ -290,6 +319,8 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
}
/**
* Adds a `Shape` to the Body.
*
* If `mass` has not been manually set, It's recommended to call `calculate_mass()` after adding/removing a Body's shapes.
* @param shape
* @param position The position in the Body's `shapes` array the Shape will be added to. If set to -1, the Shape is pushed to the end.
* @return The added `Shape`.
Expand All @@ -304,7 +335,13 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
}
return shape;
}

/**
* Removes a `Shape` from the Body.
*
* If `mass` has not been manually set, It's recommended to call `calculate_mass()` after adding/removing a Body's shapes.
* @param shape The `Shape` to remove.
* @return Shape The removed `Shape`.
*/
public inline function remove_shape(shape:Shape):Shape {
if (shapes.remove(shape)) {
shape.set_parent();
Expand All @@ -315,6 +352,8 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
}
/**
* Clears all Shapes from the Body, releasing them to their respective pools.
*
* If `mass` has not been manually set, It's recommended to call `calculate_mass()` after adding/removing a Body's shapes.
*/
public inline function clear_shapes() {
for (shape in shapes) shape.put();
Expand Down Expand Up @@ -404,6 +443,18 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
world.static_quadtree.update(quadtree_data);
}
}
/**
* Calculates the Body's mass based on the volume of it's shapes and the `density` defined in it's `Material`.
*
* This should be called whenever a Body's overall shape is changed, such as in cases of changing the Body's scale - or if an individual shape on the Body has been added, removed, moved, rotated, or scaled.
*/
public inline function calculate_mass() {
var sum = 0.;
for (shape in shapes) {
sum += shape.volume() * material.density;
}
mass = sum;
}
/**
* Returns true if the Body has moved since the last `Physics.step()`.
*/
Expand Down Expand Up @@ -445,6 +496,10 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {

inline function get_shape() return shapes[0];

inline function get_elasticity() return material.elasticity;

inline function get_gravity_scale() return material.gravity_scale;

// setters
inline function set_x(value:Float):Float {
transform.local_x = value;
Expand Down Expand Up @@ -485,7 +540,7 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
}

inline function set_mass(value:Float):Float {
if (value < 0.0001) {
if (value < minimum_mass) {
mass = inverse_mass = 0;
update_static_bounds();
}
Expand All @@ -500,15 +555,22 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
return mass;
}

inline function set_elasticity(value:Float) {
return material.elasticity = value;
}

inline function set_gravity_scale(value:Float) {
return material.gravity_scale = value;
}

static function get_defaults():BodyOptions return {
kinematic: false,
mass: 1,
mass: AUTO,
x: 0,
y: 0,
rotation: 0,
scale_x: 1,
scale_y: 1,
elasticity: 0,
velocity_x: 0,
velocity_y: 0,
rotational_velocity: 0,
Expand All @@ -520,6 +582,5 @@ class Body implements IDisposable #if cog implements cog.IComponent #end {
drag_y: 0,
drag_length: 0,
rotational_drag: 0,
gravity_scale: 1
}
}
4 changes: 3 additions & 1 deletion echo/Echo.hx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Echo {
/**
* Cache'd `Body` to help with memory management.
*/
static final cached_body:Body = new Body();
static final cached_body:Body = new Body({mass: 1});
/**
* Shortcut for creating a new `World`
* @param options Options for the new `World`
Expand Down Expand Up @@ -214,6 +214,7 @@ class Echo {
}
else temp.put();
}
cached_body.shape.put();
}
}
lb.put();
Expand Down Expand Up @@ -277,6 +278,7 @@ class Echo {
if (temp.data.length > 0) intersections.push(temp);
else temp.put();
}
cached_body.shape.put();
}
}
lb.put();
Expand Down
27 changes: 27 additions & 0 deletions echo/Material.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package echo;

import echo.math.Vector2;
import echo.util.BitMask;
/**
* A Structure that describes the physical properties of a `Body`.
*/
@:structInit
class Material {
public static var global:Material = {};
/**
* Value to determine how much of a Body's `velocity` should be retained during collisions (or how much should the `Body` "bounce" in other words).
*/
public var elasticity:Float = 0;

public var density:Float = 1;

// TODO
public var friction:Float = 0;

// TODO
public var static_friction:Float = 0;
/**
* Percentage value that represents how much a World's gravity affects the Body.
*/
public var gravity_scale:Float = 1;
}
Loading

0 comments on commit c874466

Please sign in to comment.