mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 13:47:18 +02:00
[WL21389] Collision Shapes need to be updated (details below).
Revised approach involves creating a helper function within ShapeFactory to aid in devising the ShapeType to be used by an ShapeEntityItem for collision. The ShapeFactory is currently doing this for creating the actual Bullet Library collision shapes. ShapeEntityItem overrides its virtually inherited computeShapeInfo which in turn calls the new ShapeFactory helper function. ShapeEntityItem has a new memvar _collisionShapeType to cache its actual ShapeType used by the physics system. This memvar is returned via the getShapeType accessor which is expected to return an object's ShapeType. Note(s): This is similar to the original approach save translation between entity::Shape and ShapeType isn't tied to the EntityItemProperties shapeTypeNames or shapeType. This approach more directly solves the issue of getting the actual ShapeType used by the time it's needed to determine the bullet collision object type created when initializing the physic information. Translation of the ShapeEntityItem's entity::Shape to its ShapeType is handled by ShapeFactory which handles creating the bullet collision objects when setting up physics on the ShapeEntityItems. Known Issue(s): This doesn't compile. It appears that the Entity Library needs to know about the Physics Library. The naive attempt at providing that link failed to resolve all compilation issues. Current Error: C1083: Cannot open include file: btBulletDynamicsCommon.h: No such file or directory (C:\projects\cusack\libraries\entities\src\ShapeEntityItem.cpp) C:\projects\cusack\libraries\physics\src\ShapeFactory.h 15 1 entities modified: libraries/entities-renderer/src/RenderableShapeEntityItem.cpp modified: libraries/entities/CMakeLists.txt modified: libraries/entities/src/ShapeEntityItem.cpp modified: libraries/entities/src/ShapeEntityItem.h modified: libraries/physics/src/ShapeFactory.cpp modified: libraries/physics/src/ShapeFactory.h modified: libraries/physics/src/ShapeInfo.cpp modified: scripts/developer/tests/basicEntityTest/entitySpawner.js new file: scripts/developer/tests/basicEntityTest/shapeSpawner.js
This commit is contained in:
parent
1cb030992f
commit
5bc38bd7f0
9 changed files with 286 additions and 33 deletions
libraries
entities-renderer/src
entities
physics/src
shared/src
scripts/developer/tests/basicEntityTest
|
@ -48,18 +48,22 @@ RenderableShapeEntityItem::Pointer RenderableShapeEntityItem::baseFactory(const
|
|||
}
|
||||
|
||||
EntityItemPointer RenderableShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return baseFactory(entityID, properties);
|
||||
auto result = baseFactory(entityID, properties);
|
||||
|
||||
qCDebug(entities) << "Creating RenderableShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EntityItemPointer RenderableShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
auto result = baseFactory(entityID, properties);
|
||||
result->setShape(entity::Cube);
|
||||
result->setShape(entity::Shape::Cube);
|
||||
return result;
|
||||
}
|
||||
|
||||
EntityItemPointer RenderableShapeEntityItem::sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
auto result = baseFactory(entityID, properties);
|
||||
result->setShape(entity::Sphere);
|
||||
result->setShape(entity::Shape::Sphere);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
set(TARGET_NAME entities)
|
||||
setup_hifi_library(Network Script)
|
||||
link_hifi_libraries(shared networking octree avatars)
|
||||
link_hifi_libraries(shared networking octree avatars physics)
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <QtCore/QDebug>
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <ShapeFactory.h>
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityItemProperties.h"
|
||||
|
@ -58,7 +59,11 @@ ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entity
|
|||
}
|
||||
|
||||
EntityItemPointer ShapeEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return baseFactory(entityID, properties);
|
||||
auto result = baseFactory(entityID, properties);
|
||||
|
||||
qCDebug(entities) << "Creating ShapeEntityItem( " << result->_name << " ): " << result.get() << " ID: " << result->_id;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
EntityItemPointer ShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
|
@ -101,6 +106,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) {
|
|||
}
|
||||
}
|
||||
|
||||
//TODO_CUSACK: Move back to header prior to PN
|
||||
void ShapeEntityItem::setShape( const QString &shape ) {
|
||||
setShape(entity::shapeFromString(shape));
|
||||
}
|
||||
|
||||
bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
|
@ -160,10 +170,46 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
|
||||
}
|
||||
|
||||
void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||
|
||||
if ( _collisionShapeType == ShapeType::SHAPE_TYPE_NONE ) {
|
||||
if (_shape == entity::Shape::NUM_SHAPES)
|
||||
{
|
||||
EntityItem::computeShapeInfo(info);
|
||||
|
||||
//--EARLY EXIT--( allow default handling to process )
|
||||
return;
|
||||
}
|
||||
|
||||
_collisionShapeType = ShapeFactory::computeShapeType(getShape(), getDimensions());
|
||||
}
|
||||
|
||||
return EntityItem::computeShapeInfo(info);
|
||||
}
|
||||
|
||||
// This value specifes how the shape should be treated by physics calculations.
|
||||
// For now, all polys will act as spheres
|
||||
ShapeType ShapeEntityItem::getShapeType() const {
|
||||
return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID;
|
||||
//TODO_CUSACK: This needs to be retrieved from properties if possible
|
||||
// or stored within a new member and set during parsing of
|
||||
// the properties like setShape via set/get/readEntityProperties.
|
||||
// Perhaps if the _actual_ collisionShapeType is needed (the version that's in use
|
||||
// based on analysis of the shape's halfExtents when BulletLibrary collision shape was
|
||||
// created as opposed to the desired ShapeType is it possible to retrieve that information)?
|
||||
//if (_shape == entity::Shape::Cylinder) {
|
||||
// return SHAPE_TYPE_CYLINDER_Y;
|
||||
//}
|
||||
|
||||
//// Original functionality: Everything not a cube, is treated like an ellipsoid/sphere
|
||||
//return (_shape == entity::Shape::Cube) ? SHAPE_TYPE_BOX : SHAPE_TYPE_ELLIPSOID;
|
||||
|
||||
if (_collisionShapeType == ShapeType::SHAPE_TYPE_NONE)
|
||||
{
|
||||
//--EARLY EXIT--( Maintain previous behavior of treating invalid as Ellipsoid/Sphere )
|
||||
return SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
|
||||
return _collisionShapeType;
|
||||
}
|
||||
|
||||
void ShapeEntityItem::setColor(const rgbColor& value) {
|
||||
|
@ -223,10 +269,12 @@ bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
|
|||
void ShapeEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " shape:" << stringFromShape(_shape);
|
||||
qCDebug(entities) << " name:" << _name;
|
||||
qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )";
|
||||
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
|
||||
entity::Shape getShape() const { return _shape; }
|
||||
void setShape(const entity::Shape& shape);
|
||||
void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); }
|
||||
void setShape(const QString& shape);
|
||||
|
||||
float getAlpha() const { return _alpha; };
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
|
@ -84,6 +84,7 @@ public:
|
|||
QColor getQColor() const;
|
||||
void setColor(const QColor& value);
|
||||
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
ShapeType getShapeType() const override;
|
||||
bool shouldBePhysical() const override { return !isDead(); }
|
||||
|
||||
|
@ -100,6 +101,7 @@ protected:
|
|||
float _alpha { 1 };
|
||||
rgbColor _color;
|
||||
entity::Shape _shape { entity::Shape::Sphere };
|
||||
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_NONE };
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeEntityItem_h
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "BulletUtil.h"
|
||||
|
||||
// These are the same normalized directions used by the btShapeHull class.
|
||||
// 12 points for the face centers of a duodecohedron plus another 30 points
|
||||
// 12 points for the face centers of a dodecahedron plus another 30 points
|
||||
// for the midpoints the edges, for a total of 42.
|
||||
const uint32_t NUM_UNIT_SPHERE_DIRECTIONS = 42;
|
||||
static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = {
|
||||
|
@ -247,6 +247,124 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) {
|
|||
delete dataArray;
|
||||
}
|
||||
|
||||
ShapeType validateShapeType(ShapeType type, const glm::vec3 &halfExtents, btCollisionShape *outCollisionShape = nullptr)
|
||||
{
|
||||
if ((type == SHAPE_TYPE_SPHERE) || (type == SHAPE_TYPE_ELLIPSOID))
|
||||
{
|
||||
float radius = halfExtents.x;
|
||||
const float MIN_RADIUS = 0.001f;
|
||||
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
if (radius > MIN_RADIUS
|
||||
&& fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR
|
||||
&& fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
// close enough to true sphere
|
||||
if (outCollisionShape) {
|
||||
outCollisionShape = new btSphereShape(radius);
|
||||
}
|
||||
|
||||
return SHAPE_TYPE_SPHERE;
|
||||
}
|
||||
else {
|
||||
ShapeInfo::PointList points;
|
||||
points.reserve(NUM_UNIT_SPHERE_DIRECTIONS);
|
||||
for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) {
|
||||
points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents);
|
||||
}
|
||||
if (outCollisionShape) {
|
||||
outCollisionShape = createConvexHull(points);
|
||||
}
|
||||
|
||||
return SHAPE_TYPE_ELLIPSOID;
|
||||
}
|
||||
}
|
||||
else if ((type == SHAPE_TYPE_CYLINDER_X) || (type == SHAPE_TYPE_CYLINDER_Y) || (type == SHAPE_TYPE_CYLINDER_Z))
|
||||
{
|
||||
const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);
|
||||
if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) {
|
||||
if (outCollisionShape) {
|
||||
outCollisionShape = new btCylinderShape(btHalfExtents);
|
||||
}
|
||||
|
||||
return SHAPE_TYPE_CYLINDER_Y;
|
||||
}
|
||||
else if (halfExtents.x > halfExtents.z) {
|
||||
if (outCollisionShape) {
|
||||
outCollisionShape = new btCylinderShapeX(btHalfExtents);
|
||||
}
|
||||
|
||||
return SHAPE_TYPE_CYLINDER_X;
|
||||
}
|
||||
else if (halfExtents.z > halfExtents.x) {
|
||||
if (outCollisionShape) {
|
||||
outCollisionShape = new btCylinderShapeZ(btHalfExtents);
|
||||
}
|
||||
|
||||
return SHAPE_TYPE_CYLINDER_Z;
|
||||
}
|
||||
else //...there was no major axis, treat as a sphere
|
||||
{
|
||||
ShapeType cylinderFallback = validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, outCollisionShape);
|
||||
return cylinderFallback;
|
||||
}
|
||||
}
|
||||
|
||||
//Got here, then you are what you are along with outCollisionShape
|
||||
return type;
|
||||
}
|
||||
|
||||
ShapeType ShapeFactory::computeShapeType(entity::Shape shape, const glm::vec3 &entityDimensions) {
|
||||
if ( shape == entity::Shape::NUM_SHAPES ) {
|
||||
//--EARLY EXIT--
|
||||
return SHAPE_TYPE_NONE;
|
||||
}
|
||||
|
||||
const glm::vec3 halfExtents = entityDimensions * 0.5f;
|
||||
switch (shape){
|
||||
case entity::Shape::Triangle: {
|
||||
//TODO_CUSACK: Implement this
|
||||
return validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents);
|
||||
}
|
||||
|
||||
//Note: Intentional Fallthrough from Quad to Cube
|
||||
case entity::Shape::Quad:
|
||||
case entity::Shape::Cube: {
|
||||
return SHAPE_TYPE_BOX;
|
||||
}
|
||||
|
||||
//Note: Intentional Fallthrough from Hexagon to Sphere
|
||||
case entity::Shape::Hexagon:
|
||||
case entity::Shape::Octagon:
|
||||
case entity::Shape::Circle:
|
||||
case entity::Shape::Sphere: {
|
||||
return validateShapeType(SHAPE_TYPE_SPHERE, halfExtents);
|
||||
}
|
||||
|
||||
case entity::Shape::Cylinder: {
|
||||
return validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents);
|
||||
}
|
||||
|
||||
//Note: Intentional Fallthrough from Tetrahedron to Icosahedron
|
||||
case entity::Shape::Tetrahedron:
|
||||
case entity::Shape::Octahedron:
|
||||
case entity::Shape::Dodecahedron:
|
||||
case entity::Shape::Icosahedron: {
|
||||
|
||||
//TODO_CUSACK: Implement the hedrons
|
||||
return validateShapeType( SHAPE_TYPE_ELLIPSOID, halfExtents );
|
||||
}
|
||||
|
||||
//Note: Intentional Fallthrough from Torus to default.
|
||||
case entity::Shape::Torus:
|
||||
case entity::Shape::Cone: {
|
||||
|
||||
// These types are currently unsupported
|
||||
}
|
||||
default:
|
||||
return SHAPE_TYPE_NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
|
||||
btCollisionShape* shape = NULL;
|
||||
int type = info.getType();
|
||||
|
@ -255,30 +373,33 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
|||
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z));
|
||||
shape = new btSphereShape(radius);
|
||||
}
|
||||
break;
|
||||
//case SHAPE_TYPE_SPHERE: {
|
||||
// glm::vec3 halfExtents = info.getHalfExtents();
|
||||
// float radius = glm::max(halfExtents.x, glm::max(halfExtents.y, halfExtents.z));
|
||||
// shape = new btSphereShape(radius);
|
||||
//}
|
||||
//break;
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
case SHAPE_TYPE_ELLIPSOID: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = halfExtents.x;
|
||||
const float MIN_RADIUS = 0.001f;
|
||||
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
if (radius > MIN_RADIUS
|
||||
&& fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR
|
||||
&& fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
// close enough to true sphere
|
||||
shape = new btSphereShape(radius);
|
||||
} else {
|
||||
ShapeInfo::PointList points;
|
||||
points.reserve(NUM_UNIT_SPHERE_DIRECTIONS);
|
||||
for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) {
|
||||
points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents);
|
||||
}
|
||||
shape = createConvexHull(points);
|
||||
}
|
||||
//float radius = halfExtents.x;
|
||||
//const float MIN_RADIUS = 0.001f;
|
||||
//const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
|
||||
//if (radius > MIN_RADIUS
|
||||
// && fabsf(radius - halfExtents.y) / radius < MIN_RELATIVE_SPHERICAL_ERROR
|
||||
// && fabsf(radius - halfExtents.z) / radius < MIN_RELATIVE_SPHERICAL_ERROR) {
|
||||
// // close enough to true sphere
|
||||
// shape = new btSphereShape(radius);
|
||||
//} else {
|
||||
// ShapeInfo::PointList points;
|
||||
// points.reserve(NUM_UNIT_SPHERE_DIRECTIONS);
|
||||
// for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) {
|
||||
// points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents);
|
||||
// }
|
||||
// shape = createConvexHull(points);
|
||||
//}
|
||||
|
||||
validateShapeType(SHAPE_TYPE_ELLIPSOID, halfExtents, shape);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
|
@ -288,6 +409,42 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
|||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE_X: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = halfExtents.y;
|
||||
float height = 2.0f * halfExtents.x;
|
||||
shape = new btCapsuleShapeX(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE_Z: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = halfExtents.x;
|
||||
float height = 2.0f * halfExtents.z;
|
||||
shape = new btCapsuleShapeZ(radius, height);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER_X:
|
||||
case SHAPE_TYPE_CYLINDER_Z:
|
||||
case SHAPE_TYPE_CYLINDER_Y: {
|
||||
// TODO_CUSACK: Should allow for minor variance along axes.
|
||||
const glm::vec3 halfExtents = info.getHalfExtents();
|
||||
//const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);
|
||||
//if ((halfExtents.y > halfExtents.x) && (halfExtents.y > halfExtents.z)) {
|
||||
// shape = new btCylinderShape(btHalfExtents);
|
||||
//}
|
||||
//else if (halfExtents.x > halfExtents.z) {
|
||||
// shape = new btCylinderShapeX(btHalfExtents);
|
||||
//}
|
||||
//else if (halfExtents.z > halfExtents.x) {
|
||||
// shape = new btCylinderShapeZ(btHalfExtents);
|
||||
//}
|
||||
//else //...there was no major axis, treat as a sphere
|
||||
//{
|
||||
// //TODO_CUSACK: Shunt to ELLIPSOID handling
|
||||
//}
|
||||
validateShapeType(SHAPE_TYPE_CYLINDER_Y, halfExtents, shape);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
case SHAPE_TYPE_SIMPLE_HULL: {
|
||||
const ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
#include <btBulletDynamicsCommon.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <ShapeEntityItem.h> //< Needed for entity::Shape
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
// translates between ShapeInfo and btShape
|
||||
|
||||
namespace ShapeFactory {
|
||||
|
||||
ShapeType computeShapeType( entity::Shape shape, const glm::vec3 &entityDimensions);
|
||||
const btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||
void deleteShape(const btCollisionShape* shape);
|
||||
|
||||
|
|
|
@ -136,7 +136,10 @@ float ShapeInfo::computeVolume() const {
|
|||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f);
|
||||
// Need to offset halfExtents.y by x to account for the system treating
|
||||
// the y extent of the capsule as the cylindrical height + spherical radius.
|
||||
float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x);
|
||||
volume = PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
var SCRIPT_URL = Script.resolvePath("myEntityScript.js")
|
||||
|
||||
var myEntity = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
name: "Cusack_Testing",
|
||||
type: "Shape",
|
||||
shapeType: "Cylinder",
|
||||
color: {
|
||||
red: 200,
|
||||
green: 10,
|
||||
|
|
33
scripts/developer/tests/basicEntityTest/shapeSpawner.js
Normal file
33
scripts/developer/tests/basicEntityTest/shapeSpawner.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
var orientation = Camera.getOrientation();
|
||||
orientation = Quat.safeEulerAngles(orientation);
|
||||
orientation.x = 0;
|
||||
orientation = Quat.fromVec3Degrees(orientation);
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation)));
|
||||
|
||||
// Math.random ensures no caching of script
|
||||
var SCRIPT_URL = Script.resolvePath("myEntityScript.js")
|
||||
|
||||
var myEntity = Entities.addEntity({
|
||||
name: "ShapeSpawnTest",
|
||||
type: "Shape",
|
||||
shape: "Cylinder",
|
||||
color: {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 200
|
||||
},
|
||||
position: center,
|
||||
dimensions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1
|
||||
},
|
||||
script: SCRIPT_URL
|
||||
})
|
||||
|
||||
|
||||
function cleanup() {
|
||||
// Entities.deleteEntity(myEntity);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
Loading…
Reference in a new issue