/** * Generate a collision shape for a prop. * * @param propType the type of the prop (not null) * @param relativeSize the prop's size relative to standard (>0) * @param parts (not null) * @return a new instance */ private CollisionShape createShape(String propType, float relativeSize, List<Spatial> parts) { assert propType != null; assert relativeSize > 0f : relativeSize; assert parts != null; assert !parts.isEmpty(); if ("barrel".equals(propType)) { /* * Generate a cylindrical shape aligned with the Y-axis. */ float halfHeight = 0.5f * relativeSize; // meters float radius = 0.472f * relativeSize; // meters Vector3f halfExtents = new Vector3f(radius, halfHeight, radius); float scaleFactor = scene.getScaleFactor(); halfExtents.divideLocal(scaleFactor); CollisionShape shape = new CylinderCollisionShape(halfExtents, PhysicsSpace.AXIS_Y); return shape; } /* * Generate a compound shape composed of GImpact shapes, * one for each geometry. */ CompoundCollisionShape shape = new CompoundCollisionShape(); for (Spatial part : parts) { Geometry geometry = (Geometry) part; Mesh mesh = geometry.getMesh(); CollisionShape partShape = new GImpactCollisionShape(mesh); Vector3f scale = part.getWorldScale(); partShape.setScale(scale); shape.addChildShape(partShape, Vector3f.ZERO); } return shape; }
/** * Get the relative size of a prop. * * @param spatial which prop (not null) * @return the prop's size relative to standard (>0) */ public float getRelativeSize(Spatial spatial) { assert spatial != null; float result = spatial.getWorldScale().x; result *= scene.getScaleFactor(); return result; }
/** * Create a prop without adding it to the scene. * * @param propType which kind of prop to add (not null) * @param relativeSize the prop's size relative to standard (>0) * @return a new node to represent the prop, or null if the model is invalid */ private Node create(String propType, float relativeSize) { assert propType != null; assert relativeSize > 0f : relativeSize; Node propNode = loadModel(propType); Node modelNode = (Node) propNode.getChild(0); List<Spatial> parts = modelNode.getChildren(); /* * Texture each part of the prop and specify its hardness. */ for (Spatial part : parts) { String partName = part.getName(); if (!(part instanceof Geometry)) { logger.log(Level.SEVERE, "Prop part {0} is not a geometry.", MyString.quote(partName)); return null; } String materialName = material(partName); SpatialProperties.setHardness(part, materialName); Material material = Assets.loadBlockMaterial(materialName); part.setMaterial(material); } /* * Set the scale factor. */ float scaleFactor = scene.getScaleFactor(); float modelScale = relativeSize / scaleFactor; propNode.setLocalScale(modelScale); assert getRelativeSize(propNode) == relativeSize : relativeSize; /* * Set other properties. */ propNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); /* * Give the prop a physics control. */ CollisionShape shape = createShape(propType, relativeSize, parts); float mass = calculateMass(propType, relativeSize); RigidBodyControl rigidBodyControl = new RigidBodyControl(shape, mass); propNode.addControl(rigidBodyControl); /* * Configure the physics control. */ rigidBodyControl.setFriction(friction); scene.getWorld().getPhysics().addObject(rigidBodyControl); /* * Give the prop a PickedControl. */ SpatialProperties.setPickType(propNode, pickType); PickedControl pickedControl = new PickedControl(); propNode.addControl(pickedControl); return propNode; }