hytopia-physics
4
总安装量
2
周安装量
#53495
全站排名
安装命令
npx skills add https://github.com/abstrucked/hytopia-skills --skill hytopia-physics
Agent 安装分布
opencode
2
claude-code
2
mcpjam
1
openhands
1
zencoder
1
crush
1
Skill 文档
HYTOPIA Physics & Collision
This skill helps you implement physics and collision in HYTOPIA SDK games.
Documentation: https://dev.hytopia.com/sdk-guides/physics
When to Use This Skill
Use this skill when the user:
- Wants to add physics to entities (gravity, velocity, forces)
- Needs collision detection between objects
- Asks about raycasting for hit detection
- Wants to create physics-based gameplay (projectiles, explosions)
- Needs to configure colliders (boxes, spheres, meshes)
- Asks about physics materials (friction, bounciness)
Core Physics Concepts
Adding Physics to Entity
import { Entity, PhysicsComponent, BoxCollider } from 'hytopia';
class PhysicsEntity extends Entity {
constructor() {
super();
this.addComponent(new PhysicsComponent({
mass: 1.0, // Kilograms
gravity: { x: 0, y: -9.81, z: 0 },
linearDamping: 0.1, // Air resistance
angularDamping: 0.1,
useGravity: true
}));
// Add collision shape
this.addComponent(new BoxCollider({
size: { x: 1, y: 1, z: 1 },
offset: { x: 0, y: 0.5, z: 0 }
}));
}
}
Collider Types
import { BoxCollider, SphereCollider, MeshCollider } from 'hytopia';
// Box collider
const box = new BoxCollider({
size: { x: 2, y: 1, z: 0.5 },
offset: { x: 0, y: 0, z: 0 }
});
// Sphere collider
const sphere = new SphereCollider({
radius: 0.5,
offset: { x: 0, y: 0.5, z: 0 }
});
// Mesh collider (from model)
const mesh = new MeshCollider({
modelUri: 'models/terrain.gltf',
convex: false // false = exact mesh, true = convex hull (faster)
});
Applying Forces
import { Entity, PhysicsComponent } from 'hytopia';
class Projectile extends Entity {
physics: PhysicsComponent;
constructor() {
super();
this.physics = new PhysicsComponent({
mass: 0.1,
useGravity: true
});
this.addComponent(this.physics);
}
launch(direction: Vector3, force: number) {
// Apply impulse (instant force)
this.physics.applyImpulse(direction.multiply(force));
// Or apply continuous force
this.physics.applyForce(direction.multiply(force));
// Apply torque (rotation)
this.physics.applyTorque({ x: 0, y: 100, z: 0 });
}
}
Raycasting
Basic Raycast
import { World } from 'hytopia';
// Raycast from point in direction
const result = world.raycast(
{ x: 0, y: 10, z: 0 }, // Origin
{ x: 0, y: -1, z: 0 }, // Direction (normalized)
100 // Max distance
);
if (result.hit) {
console.log('Hit at:', result.position);
console.log('Hit entity:', result.entity);
console.log('Hit normal:', result.normal);
console.log('Hit distance:', result.distance);
}
Player Look Raycast
// What is player looking at?
const raycast = world.raycast(
player.position,
player.lookDirection,
5 // Reach distance
);
if (raycast.hit) {
if (raycast.block) {
// Looking at a block
console.log('Block:', raycast.block.type);
}
if (raycast.entity) {
// Looking at an entity
console.log('Entity:', raycast.entity.id);
}
}
Collision Detection
Collision Events
import { Entity, CollisionComponent } from 'hytopia';
class CollidableEntity extends Entity {
constructor() {
super();
const collision = new CollisionComponent();
collision.onCollisionEnter = (other) => {
console.log('Started colliding with:', other.id);
if (other instanceof Projectile) {
this.takeDamage(10);
}
};
collision.onCollisionExit = (other) => {
console.log('Stopped colliding with:', other.id);
};
collision.onCollisionStay = (other) => {
// Called every frame while colliding
};
this.addComponent(collision);
}
}
Collision Layers
import { PhysicsComponent, CollisionLayer } from 'hytopia';
// Define what collides with what
const physics = new PhysicsComponent({
mass: 1,
collisionLayer: CollisionLayer.DEFAULT,
collisionMask: CollisionLayer.DEFAULT | CollisionLayer.PLAYER
});
// Layers: DEFAULT, PLAYER, ENEMY, PROJECTILE, TRIGGER, etc.
// Player doesn't collide with other players but collides with enemies
const playerPhysics = new PhysicsComponent({
collisionLayer: CollisionLayer.PLAYER,
collisionMask: CollisionLayer.DEFAULT | CollisionLayer.ENEMY | CollisionLayer.PROJECTILE
});
Physics Materials
import { PhysicsMaterial } from 'hytopia';
const bouncyMaterial = new PhysicsMaterial({
friction: 0.5, // 0 = slippery, 1 = rough
restitution: 0.8, // 0 = no bounce, 1 = perfect bounce
density: 1.0 // Affects mass calculation
});
const iceMaterial = new PhysicsMaterial({
friction: 0.1,
restitution: 0.1
});
// Apply to collider
const collider = new BoxCollider({
size: { x: 1, y: 1, z: 1 },
material: bouncyMaterial
});
Best Practices
- Use simple colliders – Box/Sphere are faster than Mesh
- Set appropriate mass – Realistic values (kg) work best
- Use layers wisely – Filter collisions to improve performance
- Raycast before spawning – Check if space is clear
- Sleep inactive bodies – Saves CPU for stationary objects
Common Patterns
Ground Check
function isGrounded(entity: Entity): boolean {
const raycast = world.raycast(
entity.position,
{ x: 0, y: -1, z: 0 },
0.1 // Small distance below entity
);
return raycast.hit && raycast.distance < 0.05;
}
// Usage
if (isGrounded(player) && input.isPressed('space')) {
player.physics.applyImpulse({ x: 0, y: 10, z: 0 });
}
Explosion Force
function applyExplosion(center: Vector3, radius: number, force: number) {
// Get all entities in radius
const entities = world.getEntitiesInRadius(center, radius);
for (const entity of entities) {
const direction = entity.position.subtract(center).normalize();
const distance = entity.position.distance(center);
const falloff = 1 - (distance / radius); // Stronger closer to center
if (entity.physics) {
entity.physics.applyImpulse(
direction.multiply(force * falloff)
);
}
}
}