hitbox offsets
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-08-13 12:39:53 -04:00
parent 902680ad16
commit 06b068643e
10 changed files with 227 additions and 254 deletions

View File

@ -46,7 +46,8 @@
{ {
"type": "hurt", "type": "hurt",
"bone": "Head", "bone": "Head",
"radius": 0.06 "radius": 0.06,
"offset": [0.0,3.0,0.0]
} }
], ],
"tokens" : [ "tokens" : [

View File

@ -72,7 +72,8 @@
{ {
"type": "hit_connected", "type": "hit_connected",
"bone": "Blade3", "bone": "Blade3",
"radius": 0.04 "radius": 0.04,
"offset": [0, 0, 0.15]
} }
] ]
}, },

View File

@ -5,4 +5,5 @@
- @subpage largelocationideas - @subpage largelocationideas
- @subpage macrolocationideas - @subpage macrolocationideas
- @subpage smalllocations - @subpage smalllocations
- @subpage minidungeons - @subpage minidungeons
- @subpage zones

View File

@ -0,0 +1 @@
@page zones Zones

View File

@ -549,6 +549,9 @@ Always upright tree
Fix upright tree clearing linear force/velocity Fix upright tree clearing linear force/velocity
Movement tweaks Movement tweaks
(08/13/2024)
Hitbox support offsets now
# TODO # TODO

View File

@ -3,16 +3,13 @@ package electrosphere.collision.hitbox;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState; import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState; import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxType; import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxType;
import electrosphere.game.data.collidable.HitboxData; import electrosphere.game.data.collidable.HitboxData;
import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.ode.DContactGeom; import org.ode4j.ode.DContactGeom;
import org.ode4j.ode.DGeom; import org.ode4j.ode.DGeom;
@ -21,211 +18,6 @@ import org.ode4j.ode.DGeom;
*/ */
public class HitboxUtils { public class HitboxUtils {
// /**
// * Spawns a hitbox entity on the client
// * @param parent The parent entity to attach the hitbox to
// * @param bone The bone on the parent to attach to
// * @param size The radius of the hitsphere
// * @return The hitbox entity
// */
// public static Entity clientSpawnRegularHitbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(false);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
// /**
// * Spawns a hitbox entity on the server
// * @param parent The parent entity to attach the hitbox to
// * @param bone The bone to attach to the hitbox to
// * @param size The radius of the hitsphere
// * @return The hitbox entity
// */
// public static Entity serverSpawnRegularHitbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(false);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
// /**
// * Spawns a hurtbox on the client
// * @param parent The parent entity of the hurtbox
// * @param bone The bone on the parent to attach the hurtbox to
// * @param size The radius of the hurtsphere
// * @return The hurtbox entity
// */
// public static Entity clientSpawnRegularHurtbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
// /**
// * Spawns a hurtbox on the server
// * @param parent The parent entity of the hurtbox
// * @param bone The bone on the parent to attach the hurtbox to
// * @param size The radius of the hurtsphere
// * @return The hurtbox entity
// */
// public static Entity serverSpawnRegularHurtbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
// /**
// * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
// * @param parent The parent entity of the hitbox
// * @param positionCallback The position callback for keeping hitbox entity position up to date
// * @param size The size of the hitbox
// * @param hurtbox If true, it will instead be a hurtbox
// * @param filter an optional list of parent entities to not colide with
// * @return The hitbox entity
// */
// public static Entity clientSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setPositionCallback(positionCallback);
// data.setRadius(size);
// data.setEntityFilter(filter);
// if(hurtbox){
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// } else {
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// }
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
// /**
// * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
// * @param parent The parent entity of the hitbox
// * @param positionCallback The position callback for keeping hitbox entity position up to date
// * @param size The size of the hitbox
// * @param hurtbox If true, it will instead be a hurtbox
// * @param filter an optional list of parent entities to not colide with
// * @return The hitbox entity
// */
// public static Entity serverSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setPositionCallback(positionCallback);
// data.setRadius(size);
// data.setEntityFilter(filter);
// if(hurtbox){
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// } else {
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// }
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
public static void clientUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
HitboxData hitboxData = getHitboxData(hitbox);
String boneName = hitboxData.getBone();
if(boneName != null){
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
EntityUtils.getPosition(hitbox).set(worldPosition);
} else {
HitboxPositionCallback positionCallback = hitboxData.getPositionCallback();
EntityUtils.getPosition(hitbox).set(positionCallback.getPosition());
}
}
/**
* Updates the position of a hitbox
* @param hitbox the hitbox to update
*/
public static void serverUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
HitboxData hitboxData = getHitboxData(hitbox);
String boneName = hitboxData.getBone();
if(boneName != null){
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3d(parentPos.x,parentPos.y,parentPos.z));
EntityUtils.getPosition(hitbox).set(worldPosition);
} else {
HitboxPositionCallback positionCallback = hitboxData.getPositionCallback();
EntityUtils.getPosition(hitbox).set(positionCallback.getPosition());
}
}
/** /**
* Handles a damage collision on the client * Handles a damage collision on the client

View File

@ -23,7 +23,9 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState.HitboxShapeType; import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState.HitboxShapeType;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.game.data.collidable.HitboxData; import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.utils.DataFormatUtil;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.util.math.MathUtils; import electrosphere.util.math.MathUtils;
@ -235,10 +237,10 @@ public class HitboxCollectionState {
HitboxState shapeStatus = this.geomStateMap.get(geom); HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){ switch(shapeStatus.shapeType){
case SPHERE: { case SPHERE: {
this.updateSphereShapePosition(collisionEngine,boneName,bonePosition); this.updateSphereShapePosition(collisionEngine,boneName,shapeStatus,bonePosition);
} break; } break;
case CAPSULE: { case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,boneName,bonePosition); this.updateCapsuleShapePosition(collisionEngine,boneName,shapeStatus,bonePosition);
} break; } break;
case STATIC_CAPSULE: { case STATIC_CAPSULE: {
} break; } break;
@ -261,10 +263,10 @@ public class HitboxCollectionState {
HitboxState shapeStatus = this.geomStateMap.get(geom); HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){ switch(shapeStatus.shapeType){
case SPHERE: { case SPHERE: {
this.updateSphereShapePosition(collisionEngine,boneName,bonePosition); this.updateSphereShapePosition(collisionEngine,boneName,shapeStatus,bonePosition);
} break; } break;
case CAPSULE: { case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,boneName,bonePosition); this.updateCapsuleShapePosition(collisionEngine,boneName,shapeStatus,bonePosition);
} break; } break;
case STATIC_CAPSULE: { case STATIC_CAPSULE: {
} break; } break;
@ -310,21 +312,27 @@ public class HitboxCollectionState {
* @param boneName The name of the bone * @param boneName The name of the bone
* @param bonePosition the position of the bone * @param bonePosition the position of the bone
*/ */
private void updateSphereShapePosition(CollisionEngine collisionEngine, String boneName, Vector3f bonePosition){ private void updateSphereShapePosition(CollisionEngine collisionEngine, String boneName, HitboxState hitboxState, Vector3f bonePosition){
DGeom geom = this.hitboxGeomMap.get(boneName); DGeom geom = this.hitboxGeomMap.get(boneName);
//get offset's transform
Vector3d offsetPosition = DataFormatUtil.getDoubleListAsVector(hitboxState.getHitboxData().getOffset());
Quaterniond offsetRotation = new Quaterniond();
//the bone's transform
Vector3d bonePositionD = new Vector3d(bonePosition);
Quaterniond boneRotation = new Quaterniond();
//the parent's transform
Vector3d parentPosition = EntityUtils.getPosition(parent);
Quaterniond parentRotation = EntityUtils.getRotation(parent); Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent); Vector3d parentScale = new Vector3d(EntityUtils.getScale(parent));
Vector3d worldPosition = new Vector3d();
Vector3d parentPos = EntityUtils.getPosition(parent);
Quaterniond rotation = new Quaterniond(parentRotation);
//calculate new world pos //calculate
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z); Vector3d hitboxPos = AttachUtils.calculateBoneAttachmentPosition(offsetPosition, offsetRotation, bonePositionD, boneRotation, parentPosition, parentRotation, parentScale);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, hitboxPos, new Quaterniond());
} }
/** /**
@ -333,23 +341,30 @@ public class HitboxCollectionState {
* @param boneName * @param boneName
* @param bonePosition * @param bonePosition
*/ */
private void updateCapsuleShapePosition(CollisionEngine collisionEngine, String boneName, Vector3f bonePosition){ private void updateCapsuleShapePosition(CollisionEngine collisionEngine, String boneName, HitboxState hitboxState, Vector3f bonePosition){
DGeom geom = this.hitboxGeomMap.get(boneName);
HitboxState shapeStatus = this.geomStateMap.get(geom);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3d parentPos = EntityUtils.getPosition(parent);
Quaterniond rotation = new Quaterniond(parentRotation);
Vector3d previousWorldPos = shapeStatus.getPreviousWorldPos();
//calculate new world pos //get data about the hitbox
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z); DGeom geom = this.hitboxGeomMap.get(boneName);
worldPosition = worldPosition.mul(positionScale); Vector3d previousWorldPos = hitboxState.getPreviousWorldPos();
worldPosition = worldPosition.rotate(rotation); double length = hitboxState.getHitboxData().getRadius();
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
double length = shapeStatus.getHitboxData().getRadius();
// double radius = shapeStatus.getHitboxData().getRadius(); //get offset's transform
Vector3d offsetPosition = DataFormatUtil.getDoubleListAsVector(hitboxState.getHitboxData().getOffset());
Quaterniond offsetRotation = new Quaterniond();
//the bone's transform
Vector3d bonePositionD = new Vector3d(bonePosition);
Quaterniond boneRotation = new Quaterniond();
//the parent's transform
Vector3d parentPosition = EntityUtils.getPosition(parent);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3d parentScale = new Vector3d(EntityUtils.getScale(parent));
//calculate
Vector3d worldPosition = AttachUtils.calculateBoneAttachmentPosition(offsetPosition, offsetRotation, bonePositionD, boneRotation, parentPosition, parentRotation, parentScale);
Quaterniond worldRotation = new Quaterniond();
if(previousWorldPos != null){ if(previousWorldPos != null){
//called all subsequent updates to hitbox position //called all subsequent updates to hitbox position
@ -366,7 +381,7 @@ public class HitboxCollectionState {
//the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space //the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space
//ode is Z-axis-up //ode is Z-axis-up
if(previousWorldPos.distance(worldPosition) > 0.0){ if(previousWorldPos.distance(worldPosition) > 0.0){
rotation = MathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0.707,0,0.707)); worldRotation = MathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0.707,0,0.707));
} }
//create new capsule //create new capsule
@ -389,9 +404,9 @@ public class HitboxCollectionState {
} }
length = 0.1; length = 0.1;
} }
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), shapeStatus.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT); geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), hitboxState.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT);
CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom); CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, bodyPosition, rotation); PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, bodyPosition, worldRotation);
} else { } else {
//called first time the hitbox updates position //called first time the hitbox updates position
this.geomStateMap.remove(geom); this.geomStateMap.remove(geom);
@ -399,14 +414,14 @@ public class HitboxCollectionState {
CollisionBodyCreation.destroyShape(collisionEngine, geom); CollisionBodyCreation.destroyShape(collisionEngine, geom);
//create new capsule //create new capsule
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), shapeStatus.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT); geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), hitboxState.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT);
CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom); CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom);
} }
//update maps and other variables for next frame //update maps and other variables for next frame
this.hitboxGeomMap.put(boneName,geom); this.hitboxGeomMap.put(boneName,geom);
this.geomStateMap.put(geom,shapeStatus); this.geomStateMap.put(geom,hitboxState);
this.geoms.add(geom); this.geoms.add(geom);
shapeStatus.setPreviousWorldPos(worldPosition); hitboxState.setPreviousWorldPos(worldPosition);
} }
/** /**

View File

@ -289,6 +289,58 @@ public class AttachUtils {
Vector3d bonePosition, Vector3d bonePosition,
Quaterniond boneRotation, Quaterniond boneRotation,
//parent transforms
Vector3d parentPosition,
Quaterniond parentRotation,
Vector3d parentScale
){
//transform bone space
Vector3d position = AttachUtils.calculateBoneAttachmentPosition(
offsetVector,
offsetRotation,
bonePosition,
boneRotation,
parentPosition,
parentRotation,
parentScale
);
//set
EntityUtils.getPosition(child).set(position);
//calculate and apply rotation
Quaterniond rotation = AttachUtils.calculateBoneAttachmentRotation(
offsetVector,
offsetRotation,
bonePosition,
boneRotation,
parentPosition,
parentRotation,
parentScale
);
EntityUtils.getRotation(child).set(rotation);
}
/**
* Calculates the position of an entity attached to a bone
* @param offsetVector The offset position
* @param offsetRotation The offset rotation
* @param bonePosition The bone's position
* @param boneRotation The bone's rotation
* @param parentPosition The parent's position
* @param parentRotation The parent's rotation
* @param parentScale The parent's scale
* @return The position of the attached/child entity
*/
public static Vector3d calculateBoneAttachmentPosition(
//optional offsets
Vector3d offsetVector,
Quaterniond offsetRotation,
//current bone transform
Vector3d bonePosition,
Quaterniond boneRotation,
//parent transforms //parent transforms
Vector3d parentPosition, Vector3d parentPosition,
Quaterniond parentRotation, Quaterniond parentRotation,
@ -302,11 +354,36 @@ public class AttachUtils {
position = position.rotate(new Quaterniond(parentRotation)); position = position.rotate(new Quaterniond(parentRotation));
//transform worldspace //transform worldspace
position.add(parentPosition); position.add(parentPosition);
//set
EntityUtils.getPosition(child).set(position); return position;
//calculate rotation of model }
EntityUtils.getRotation(child)
.identity() /**
* Calculates the rotation of a child that is attached to a bone on an entity
* @param offsetVector The offset vector
* @param offsetRotation The offset rotation
* @param bonePosition The position of the bone
* @param boneRotation The rotation of the bone
* @param parentPosition The position of the parent
* @param parentRotation The rotation of the parent
* @param parentScale The scale of the parent
* @return The rotation of the child
*/
public static Quaterniond calculateBoneAttachmentRotation(
//optional offsets
Vector3d offsetVector,
Quaterniond offsetRotation,
//current bone transform
Vector3d bonePosition,
Quaterniond boneRotation,
//parent transforms
Vector3d parentPosition,
Quaterniond parentRotation,
Vector3d parentScale
){
return new Quaterniond()
.mul(parentRotation) .mul(parentRotation)
.mul(boneRotation) .mul(boneRotation)
.mul(offsetRotation) .mul(offsetRotation)
@ -649,7 +726,6 @@ public class AttachUtils {
* @param parentEntity * @param parentEntity
* @return The list of entities that are attached to this parent entity, or null if undefined * @return The list of entities that are attached to this parent entity, or null if undefined
*/ */
@SuppressWarnings("unchecked") //as long as we only ever access this value via the getters and setters in this class, this assumption should always be correct
public static List<Entity> getChildrenList(Entity parentEntity){ public static List<Entity> getChildrenList(Entity parentEntity){
return (List<Entity>)parentEntity.getData(EntityDataStrings.ATTACH_CHILDREN_LIST); return (List<Entity>)parentEntity.getData(EntityDataStrings.ATTACH_CHILDREN_LIST);
} }

View File

@ -59,6 +59,9 @@ public class HitboxData {
//used to filter this hitbox to hitting only certain parent entities //used to filter this hitbox to hitting only certain parent entities
List<Entity> filter; List<Entity> filter;
//The offset from the bone
List<Double> offset;
/** /**
* Gets the type of hitbox * Gets the type of hitbox
* @return the type of hitbox * @return the type of hitbox
@ -194,6 +197,22 @@ public class HitboxData {
public List<Entity> getEntityFilter(){ public List<Entity> getEntityFilter(){
return filter; return filter;
} }
/**
* Gets the offset for the hitbox
* @return The offset
*/
public List<Double> getOffset(){
return this.offset;
}
/**
* Sets the offset for the hitbox
* @param offset The offset
*/
public void setOffset(List<Double> offset){
this.offset = offset;
}
} }

View File

@ -0,0 +1,64 @@
package electrosphere.game.data.utils;
import java.util.Arrays;
import java.util.List;
import org.joml.Quaterniond;
import org.joml.Vector3d;
/**
* Converts data structures between formats saved to disk vs formats used in engine
*/
public class DataFormatUtil {
/**
* Gets the rotation in quaterniond form
* @param values The list of raw float values
* @return The quaterniond containing those values or an identity quaterniond if no such values exist
*/
public static Quaterniond getDoubleListAsQuaternion(List<Double> values){
if(values == null){
return new Quaterniond();
}
if(values.size() > 0){
return new Quaterniond(values.get(0),values.get(1),values.get(2),values.get(3));
} else {
return new Quaterniond();
}
}
/**
* Gets a quaterniond as a list of doubles
* @param quat The quaternion
* @return The list of doubles
*/
public static List<Double> getQuatAsDoubleList(Quaterniond quat){
return Arrays.asList((Double)quat.x,(Double)quat.y,(Double)quat.z,(Double)quat.w);
}
/**
* Gets the vector in vector3d form
* @param values The list of raw float values
* @return The vector containing those values or an identity vector if no such values exist
*/
public static Vector3d getDoubleListAsVector(List<Double> values){
if(values == null){
return new Vector3d();
}
if(values.size() > 0){
return new Vector3d(values.get(0),values.get(1),values.get(2));
} else {
return new Vector3d();
}
}
/**
* Gets a vector as a list of doubles
* @param vec The vector
* @return The list of doubles
*/
public static List<Double> getVectorAsDoubleList(Vector3d vec){
return Arrays.asList((Double)vec.x,(Double)vec.y,(Double)vec.z);
}
}