npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hexr-shit-physics

v1.2.0

Published

A Terrible Arcade Physics Subsystem

Downloads

2

Readme

# Hexr Shit Physics

What is it?

A rather crude, hacked together 2D arcade "physics" system designed to work with objects generated by the Hexr engine, which uses Three.JS. Objects can be sprites, or arbitrary rectangles, or collision regions automatically derived from tile maps.

Works like this:

  • Every object involved in collision detection gets a bounding box, a precise SAT polygon and an actually 3D cube mesh. There are helper
  • Each object needs adding with .addObject(). Every frame you call .test() and this returns a list of all the possible collisions in the entire world
  • Pass this list of collisions to every entity interested in collision, and use helper functions to narrow down the list to ones involving the entity itself

Once you have this list you can:

  • test to see if points in space collide with specific types of objects.
  • let the SAT collision detection automatically resolve collisions, if you dare.

You can also:

  • check to see if A can see B (line of sight checks)

Why you shouldn't even think about using this

It's just a hacked together mess of thrown together things with an ill-concieved API. It's adapted from code written during game jams. It's not pretty.

API.

This module is pretty tightly coupled with the hexr engine and the data generated by the hexr editor. It's incredibly opinionated about what sort of data it expects going on and unyielding in its opinion of what should be output. Sorry about that.

That being said, at least for the sake of my own sanity, I'm going to document the API as it currently stands.

Please note:

var shitPhysics = require('hexr-shit-physics');

Adding/Updating bodies

shitPhysics.addShitPhysicsBody (object)

Adds a body to a sprite, which has the following data structure:

{
  meta : {
    position : [x, y],
    size : [x, y],
    collisionVerts : [
      [tl.x, tl.y],
      [bl.x, bl.y],
      [br.x, br.y],
      [tr.x, tr.y]
    ]
  },
  instanceId : 'unique-identifyier-for-me',
  prototypeId : 'what-type-of-thing-am-id'
}

... where collisionVerts are relative to the position of the sprite. The position is fixed to the center of the sprite. size is basically scale. By default Hexr sprites have a size of 1 THREE.JS unit x 1 THREE.JS unit. The size is the size relative to other sprites.

It can add a body to a /box instance/. A box instance is basically just a rectangular object, typically used for making invisible collision triggers etc.

{
  meta : {
    position : [x, y]
    verticies : [
      [tl.x, tl.y],
      [bl.x, bl.y],
      [br.x, br.y],
      [tr.x, tr.y]
    ]
  },
  instanceId : 'etc',
  prototypeId : 'etc'
}

In this case, the position array is meant to be the top left, not the centre. The verticies for the box are in the same order and remain relative to the position.

In both cases it adds the following structure to the object:

{
  meta : { ... },
  body : {
    collider : SAT.Polygon,
    AABB : {
      min[bottomLeftX, bottomLeftY],
      max[topRightX, topRightY]
    },
    rayMesh : THREE.Mesh // box geometry with actual depth so raycasting intersects correctly
  }
}

... and adds this body to the broad phase collision detection

shitPhysics.updatePhysicsBody(object)

An object with a body previously generated with addShitPhysicsBody() can have the raycast mesh, the bounding box and the SAT polygon updated by this helper. For this to work it expects that the object will have a mesh property pointing at a THREE.Mesh object. The position of this mesh is what will be used to update the rest of the body.

You pretty much need to call this function for any object whenever it moves. Eventually it will be possible to pick up changes to rotation and scale but this is out of scope for now. Honestly just switching to Box2D will be a lot easier.

shitPhysics.removeBodyFromWorld(object)

An object that has previously been added to the world with addShitPhysicsBody() or addObject() can be removed from the world (in effect, it is removed from the broad phase collision detection system and therefore will never show up on a list of possible collisions). The body data remains, along with the SAT polygon.

TODO: Should also remove the rayMesh from the list of possible intersections...

shitPhysics.addObject(object)

You can add an object directly to the broad phase collision detection system. As a minimum such an object must be:

{
  body : {
    AABB : {
      min [bottomLeftX, bottomLeftY],
      max [topRightX, topRightY]
  },
  static : true || false
  prototypeId : 'the-type-of-thing',
  instanceId : 'unique-identifier'
}

The broad phase will happily detect possible collisions on objects without prototypeId or instanceId but the helper functions which narrow down the list of possible collisions will not work without them.

shitPhysics.reset()

Empties the broadphase grid and drops the list of raycast meshes. Useful when you switch level in game and you need to start again from scratch.

shitPhysics.makeBodyFromHexrTilemapCollisionBox (object)

Adds a body to "collision boxes" generated by the Hexr level parser. This takes a tilemap and attempts to merge the tiles into the minimum number of collision boxes. They're now just one of many different types of bounding boxes that exist inside this software right now.

{
  tl : {
    x : 0,
    y : 0
  },
  br : {
    x : 1,
    y : 1
  }
}

It adds the following structure to the object:

{
  meta : { ... },
  body : {
    collider : SAT.Polygon,
    AABB : {
      min[bottomLeftX, bottomLeftY],
      max[topRightX, topRightY]
    },
    rayMesh : THREE.Mesh // box geometry with actual depth so raycasting intersects correctly
  }
}

Working with collision pairs

shitPhysics.test()

Returns an array of all possible collisions at this moment. Note that static object->static object collisions will never appear here. You should pass this list of collisions to all entities interested in collision detection.

var possibleCollisionsArray = shitPHysics.test()

shitPhysics.findAandB(possibleCollisionsArray, object, prototypeId)

Okay, so this is a helper function which filters down a full list of collisions down to just collisions that involve object and objects with a matching prototypeId. For example, all objects added via makeBodyFromHexrTilemapCollisionBox() are automatically assigned a prototypeId of 'static-block'.

object must be the same object that you used addShitPhysicsBody or addObject on.

Typical use-case would be

// want to find just the collisions between the player and the environment:
var list = shitPhysics.findAandB( worldCollisions, player, 'static-block');

// right, now I want to just find collisions with chickens..
var list = shitPhysics.findAandB( worldCollisions, player, 'chicken');

shitPhysics.findAnotB(possibleCollisionsArray, object, prototypeId)

Same as findAandB except now you want to exclude collisions involving prototypeId. The idea is that you probably want one list of collisions with the environment and other list of collisions with other entities/objects in the world.

// all collisions involving the player EXCEPT for 'static-block'
var entityCollisions = shitPhysics.findAnotB( worldCollisions, player, 'static-block')

shitPhysics.isPointInBox (collisionsArray, x, y)

Pass this a list of possible collisions and a co-ordinate and this will tell you if the point is inside any of the boxes. Typical usecase for this is figuring out if a player is standing on the ground or touching a wall etc.

shitPhysics.getFinalPosition(collisionsArray, object.body, targetX, targetY)

The SAT stuff has a naive collisions solver which, if you like, you can let loose on your objects after you've applied whatever movement you need to. This gives mostly okay results but it only does one pass so it's not brilliant. Returns a vector with a suggested position.

shitPhysics.canAseeB(objectA, objectB, farDistance)

This abstracts THREE's Raycaster and uses the non-rendered box geometry meshes to test line of sight and returns true or false.

License

MIT

Contributing

Not really expected but obviously this is desperately bad stuff that needs all the help it can get.