pmndrs / react-three-fiber

🇨🇭 A React renderer for Three.js
https://docs.pmnd.rs/react-three-fiber
MIT License
27.57k stars 1.59k forks source link

Question about integration with yuka #331

Closed windkomo closed 4 years ago

windkomo commented 4 years ago

Hi, I'm trying to use yuka (https://github.com/Mugen87/yuka) to implement some kind of basic game AI and I'm having trouble figuring out where to put the imperative code. I want to implement this example: demo: https://mugen87.github.io/yuka/examples/steering/seek/ code: https://github.com/Mugen87/yuka/blob/master/examples/steering/seek/index.html

What I want to do it make a vehicle steer towards a target, Basically, the imperative code looks like this:

const vehicleGeometry = new THREE.ConeBufferGeometry( 0.1, 0.5, 8 );
vehicleGeometry.rotateX( Math.PI * 0.5 );
const vehicleMaterial = new THREE.MeshNormalMaterial();
const vehicleMesh = new THREE.Mesh( vehicleGeometry, vehicleMaterial );
vehicleMesh.matrixAutoUpdate = false;
scene.add( vehicleMesh );

const targetGeometry = new THREE.SphereBufferGeometry( 0.05 );
const targetMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const targetMesh = new THREE.Mesh( targetGeometry, targetMaterial );
targetMesh.matrixAutoUpdate = false;
scene.add( targetMesh );

entityManager = new YUKA.EntityManager();
time = new YUKA.Time();

target = new YUKA.GameEntity();
target.setRenderComponent( targetMesh, sync );

vehicle = new YUKA.Vehicle();
vehicle.setRenderComponent( vehicleMesh, sync );

const seekBehavior = new YUKA.SeekBehavior( target.position );
vehicle.steering.add( seekBehavior );

entityManager.add( target );
entityManager.add( vehicle );

function sync( entity, renderComponent ) {
    renderComponent.matrix.copy( entity.worldMatrix );
}

So what I am doing is storing a reference to the target mesh in a global store, and use a React ref to a group as a vehicle. I am using seMemo hook to store class instances like entityManager and vehicle inside a component, and set stuff like seekBehavior inside a useEffect hook. In a useFrame hook, I am updating the entityManager with the time delta. Anything I am missing here?

windkomo commented 4 years ago

I set up a codesandbox showing my issue : https://codesandbox.io/s/agitated-vaughan-n5zid The sphere should steer towards the box.

drcmda commented 4 years ago

this is very similar to https://github.com/react-spring/use-cannon

there are a few mistakes you made.

  1. you set position on the mesh, but it has to be set in the entity, otherwise the gamemanager doesn't know it. for the manager the vehicle was already at 0/0/0 that's why nothing moved

  2. you forgot to set matrixAutoUpdate. you need that if you set the matrix yourself. otherwise change the code in setRenderComponent and set position/rotate/scale directly

  3. with react you have the chance to clean up the imperative mess. try to see the concerns: you have a player, a vehicle and a manager. the manager is the parent to the entities, so it should control the logic.

here's a working draft: https://codesandbox.io/s/interesting-tree-f0rqo

drcmda commented 4 years ago

ps, i didn't know yuka, but if you do something cool with it, let me know - would love to retweet so others can learn from this.

windkomo commented 4 years ago

That makes sense, thanks for taking time to explain this!