Hi everyone. I’m trying to implement a small game here, and I hope to add a collider to my bowl model. I want the collider to be exact same shape with the bowl, so that it can holds other objects. Is it possible to do that? Thank you!
Hello @HelpAR_Inc what physics engine are you using? Is this A-frame? More information would be helpful.
Hi Ian, thanks for getting back. I’m using A-frame. I’m pasting my code here. I’m having trouble applying a correct collider for the ‘bowl’ model (code at bottom part). Any advice will be greatly appreciated!
export const shootCerealComponent = () => ({
init() {
const camera = document.getElementById('camera')
this.modelPlaced = false
this.el.sceneEl.addEventListener('touchstart', (event) => {
const position = this.calculatePlacementPosition(camera)
if (!this.modelPlaced) {
this.createAndPlaceModel(position)
this.modelPlaced = true
}
if (this.modelPlaced) {
const cereal = document.createElement('a-entity')
cereal.setAttribute('position', camera.object3D.position)
cereal.setAttribute('scale', '0.5 0.5 0.5')
cereal.setAttribute('gltf-model', '#cerealModel')
const randomRotation = {x: -90 + Math.random() * 30, y: Math.random() * 360, z: 0}
cereal.setAttribute('rotation', randomRotation)
const velocity = new THREE.Vector3(0, 0, -10)
velocity.applyQuaternion(camera.object3D.quaternion)
cereal.setAttribute('velocity', velocity)
cereal.setAttribute('body', {
type: 'dynamic',
sphereRadius: 0.35,
shape: 'sphere',
})
cereal.setAttribute('shadow', {
receive: false,
})
this.el.sceneEl.appendChild(cereal)
let didCollide = false
cereal.addEventListener('collide', (e) => {
if (didCollide || e.detail.body.el.id !== 'ground') {
return
}
didCollide = true
})
}
})
},
calculatePlacementPosition(camera) {
const position = camera.getAttribute('position')
const rotation = camera.getAttribute('rotation')
const distance = 10
const x = position.x - distance * Math.sin(rotation.y * Math.PI / 180)
const z = position.z - distance * Math.cos(rotation.y * Math.PI / 180)
const y = 0
return {x, y, z}
},
createAndPlaceModel(position) {
const model = document.createElement('a-entity')
model.setAttribute('position', position)
model.setAttribute('gltf-model', '#bowlModel')
model.setAttribute('shadow', {
receive: false,
})
model.setAttribute('material', {
color: '#FFC0CB',
})
model.setAttribute('body', {
type: 'static',
sphereRadius: 2,
shape: 'sphere',
})
this.el.sceneEl.appendChild(model)
model.addEventListener('model-loaded', () => {
model.setAttribute('visible', 'true')
model.setAttribute('animation', {
property: 'scale',
to: '2 2 2',
easing: 'easeOutElastic',
dur: 800,
})
})
},
})
Hello @HelpAR_Inc it looks like you are using CANNON.js physics engine. This question would probably be better suite for the A-frame slack channel rather than 8th Wall sepcficially.
You can find the Slack channel here: Community – A-Frame
That being said some things to keep it is suggested to use AMMO.js as CANNON.js may be depricated in the future. As stated here:
If you decide to move forward with AMMO.js you can reference our sample project here:
specifically our glb-physics-object.js file which allows you to add a physics collider to .glb models.
Thank you so much for your amazing help Ian! I switched to AMMO.js and successfully apply the collider. However, the velocity doesn’t seem to be applied to the cereal as I tap the screen, it just drops down instead of being tossed forward. Could you please help with any insights? Thank you so much!
const tossComponent = {
init() {
const camera = document.getElementById(‘camera’)
this.tossAnimation = () => {
const cereal = document.createElement(‘a-entity’)
cereal.setAttribute(‘position’, camera.object3D.position)
cereal.setAttribute(‘scale’, ‘0.5 0.5 0.5’)
cereal.setAttribute(‘gltf-model’, ‘#cereal’)
const randomRotation = {x: -90 + Math.random() * 30, y: Math.random() * 360, z: 0}
cereal.setAttribute('rotation', randomRotation)
const velocity = new THREE.Vector3(0, 0, -10)
velocity.applyQuaternion(camera.object3D.quaternion)
cereal.setAttribute('velocity', velocity)
cereal.setAttribute('ammo-body', {
type: 'dynamic',
shape: 'hull',
mass: 1,
})
cereal.setAttribute('shadow', {
receive: false,
})
this.el.sceneEl.appendChild(cereal)
}
this.el.sceneEl.addEventListener('click', this.tossAnimation)
},
}
export {tossComponent}
This might be a better component
AFRAME.registerComponent('toss-component', {
init() {
const camera = document.getElementById('camera'); // Ensure this ID matches your camera entity
this.tossAnimation = () => {
const cereal = document.createElement('a-entity');
cereal.setAttribute('position', camera.object3D.position);
cereal.setAttribute('scale', '0.5 0.5 0.5');
cereal.setAttribute('gltf-model', '#cereal');
const randomRotation = {x: -90 + Math.random() * 30, y: Math.random() * 360, z: 0};
cereal.setAttribute('rotation', `${randomRotation.x} ${randomRotation.y} ${randomRotation.z}`);
cereal.setAttribute('ammo-body', 'type: dynamic; shape: hull; mass: 1');
cereal.setAttribute('shadow', 'receive: false');
// Append to scene
this.el.sceneEl.appendChild(cereal);
cereal.addEventListener('body-loaded', () => {
const velocity = new THREE.Vector3(0, 0, -10);
velocity.applyQuaternion(camera.object3D.quaternion);
const ammoVelocity = new Ammo.btVector3(velocity.x, velocity.y, velocity.z);
cereal.components['ammo-body'].body.setLinearVelocity(ammoVelocity);
Ammo.destroy(ammoVelocity); // Prevent memory leaks by cleaning up
// Optionally, remove the cereal entity after some time
setTimeout(() => {
if (cereal.parentNode) {
cereal.parentNode.removeChild(cereal);
}
}, 5000); // Adjust the time as needed
});
};
this.el.sceneEl.addEventListener('click', this.tossAnimation);
},
});
Key Changes and Notes:
Position and Scale: These are set similarly to your original component, aligning the cereal’s starting position with the camera’s position.
Rotation: Randomized as before, but ensure you’re setting the attribute correctly.
Physics and Velocity: The handling of physics and velocity now waits for the body-loaded event, ensuring the physics body is fully loaded before attempting to set the velocity. The velocity application now properly creates an Ammo.btVector3 object for use with Ammo.js physics.
Cleanup: I’ve included an optional timeout to remove the cereal entity from the scene after a certain time to prevent clutter and potential performance issues.
Make sure to replace ‘camera’ and ‘#cereal’ with the correct IDs or selectors matching your actual camera and cereal model entities in your A-Frame scene.