bberak / react-game-engine

A lightweight Game Engine for the web (React) 🕹⚡🎮
MIT License
420 stars 25 forks source link

Movement System Ignore other entities. #9

Closed michaelcuneo closed 1 year ago

michaelcuneo commented 4 years ago

I have a resize and drag system on some balls on my screen in the game engine.

I'd have a DragSystem like the following...

import { getSphereBasedOnPositionClicked } from '../Utils/Measurements';

const DragSystem = (entities, { mouseController }) => {
  const { switchHud } = entities;
  const mouseDown = mouseController.left;
  const sphere = getSphereBasedOnPositionClicked(
    entities,
    mouseController.position,
  );

    if (switchHud.data.value && mouseDown && sphere) {
      if (mouseController.position !== mouseController.previous.position) {
        const moveX =
          mouseController.position.x - mouseController.previous.position.x;
        const moveY =
          mouseController.position.y - mouseController.previous.position.y;

        sphere.position.x += moveX;
        sphere.position.y += moveY;
      }
    }

  return entities;
};

export default DragSystem;

I'd like to be able to continue with the one single entity until the mouseController.left becomes false... i.e. the user no longer clicks the mouse button.

So that moving around on the screen doesn't pick up other entities and starrt draging or resizing those as well. But because the system is real time, my mouse pointer can hit other balls and overlap/detect those while resizing/dragging just the one that I started with.

michaelcuneo commented 4 years ago

I tried a few different methods for this... I would need some way of selecting each ball after a click which isn't affected by the real time updating somehow. I wrote a touchSystem that would somehow give me a touched and previously touched, but because it's realtime, it still detects that I'm touching another ball in the layer.

Second attempt was to try and separate the drag system into two or three functions that allowed me to store the state of which ball was touched until the mouseController.left was false, but this also doesn't work because I can't store a fixed value in the DragSystem because it updates in close to real time...

So now I'm not too sure how to go about it.

bberak commented 4 years ago

Hi @michaelcuneo,

I know I have oversimplfied what you're trying to achieve, so apologies.

Of the top of my head, I'd try and create a selection system like this:

  1. Left mouse button is pushed down (to begin drag)
  2. Find all spheres from the entities
  3. Check if any sphere has a focused property equalling true
  4. If not, find closest sphere and set:
sphere.focused = true;
  1. Check for a left mouse button release
  2. If mouse button released, find the focused sphere (if any), and set shere.focused = false;

Here is some pseudo code:

if (leftMouseButtonDown(mouse)) {
   const spheres = getAllSpheres(entities);
   const focusedSphere = findFocusedSphere(spheres)
   if (!focusedSphere) {
      const closest = findClosestSphere(spheres, mouse)  
      closest.focused = true
   }
}

if (leftMouseButtonReleased(mouse)) {
   const spheres = getAllSpheres(entities);
   let focusedSphere = findFocusedSphere(spheres)
   if (focusedSphere)
     focusedSphere.focused = false
}

Perhaps in a separate drag system (for separating concerns):

  1. Find all spheres from the entities
  2. Find the sphere that is currently focused
  3. If there is a focused sphere, update it's position to the mouse position
const spheres = getAllSpheres(entities);
let focusedSphere = findFocusedSphere(spheres)
if (focusedSphere)
     focusedSphere.position = mouse.position