/** * Create a prop, add it to the scene with its base at the insertion point, and pick it. Assumes * that the application is in world-building mode. * * @param propType which kind of prop to add (not null) * @param relativeSize the prop's size relative to standard (>0) */ private void addAsPick(String propType, float relativeSize) { assert propType != null; assert relativeSize > 0f : relativeSize; /* * Create the prop. */ Node node = create(propType, relativeSize); /* * The new prop is to be the ONLY picked spatial, so unpick the rest. */ PickablesNode pickables = scene.getWorld().getPickables(); pickables.clearPick(); /* * Add and pick the prop. */ pickables.add(node); SpatialProperties.setPicked(node, true); /* * Initialize the prop's position. */ Cursor3DIndicator cursor3D = scene.getIndicators().getCursor3D(); Vector3f baseLocation = cursor3D.getWorldLocation(); float baseY = MySpatial.getMinY(node); Vector3f centerLocation = baseLocation.add(0f, -baseY, 0f); MySpatial.setWorldLocation(node, centerLocation); }
/** * 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; }
/** * 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; }
/** * Reload a prop and unpick it. * * @param originalProp which prop to reload (not null) */ public void reload(Spatial originalProp) { String name = originalProp.getName(); logger.log(Level.INFO, "reloading prop {0}", MyString.quote(name)); Node reloaded = duplicate(originalProp); scene.deleteSpatial(originalProp); reloaded.setName(name); }
/** * 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; }
/** * Load a prop model without adding it to the scene. * * @param propType which kind of prop to load (not null) */ private Node loadModel(String propType) { assert propType != null; /* * Load the prop model. */ Node node = Assets.loadPropModel(propType); /* * Generate a unique name for the new prop. */ NameGenerator nameGenerator = scene.getNameGenerator(); String name = nameGenerator.unique(propType); node.setName(name); return node; }
/** * Create a prop and add it to the scene. Assumes that the application is in world-building mode. * * @param propType which kind of prop to add (not null) * @param relativeSize the prop's size relative to standard (>0) * @param centerLocation world coordinates for the prop's center (unaffected, not null) * @param orientation initial orientation of the prop (unaffected, unit vector) */ Node add(String propType, float relativeSize, Vector3f centerLocation, Quaternion orientation) { assert propType != null; assert relativeSize > 0f : relativeSize; assert orientation != null; /* * Create the prop and add it to the scene. */ Node node = create(propType, relativeSize); scene.getWorld().getPickables().add(node); /* * Position the prop. */ MySpatial.setWorldOrientation(node, orientation); MySpatial.setWorldLocation(node, centerLocation); return node; }