RTS Style dragging on android

Hi, I am creating an rts style game on android and i am stuck on the camera controlling. If the user drags drags on the screen the camera should move according to its dragging. I already implemented the following code:

    public void onAnalog(String name, float value, float tpf) {
      
       if(isDragging) {
        
            Vector3f cameraMovement = new Vector3f();
        
            if(name.equals(SCROLL_DOWN)) 
                cameraMovement.z -= value * speed;
            else if(name.equals(SCROLL_UP)) 
                cameraMovement.z += value * speed;
            else if(name.equals(SCROLL_LEFT)) 
                cameraMovement.x -= value * speed;
            else if(name.equals(SCROLL_RIGHT)) 
                cameraMovement.x += value * speed;
        
            cam.setLocation(cam.getLocation().add(cameraMovement));
        }
    }

The problem now is that the camera movement is not correct. For example if the user starts to drag with the mouse/finger starting on some specific point in the map the finger is not on the top of that point later. (Hope you understand my point)

I think the important thing is to set the speed variable for horizontal and vertical movement correct. Could you please tell me how to do this.

Thanks

Where is your finger then
Too far in the direction?
In the wrong direction?

My finger is too far or to close in the right direction, depending on speed

Then set speed between those values?

Well, I think the correct value of speed depends on the zoom and the screen resolution. So the correct value for my device would not work in general. I am looking for an general way to calculate speed.

But you could easily calculate that as well.
If you have your zoom-level and you know the scren resolution you have:

speed * value / zoom

Iā€™m not sure how resolution and value work together (is value in pixels or in units you use in the game or etc)

I would guess that you have something like

speed * value / zoom * (reference_width / actual_width)

in the end

1 Like

Thanks. That is an quite simple but good idea! I created this code, but it is not yet tested for other screen resolutions. It allows you to zoom and scroll the camera with two fingers:

package de.jvhoffbauer.empire.game;

import com.jme3.input.InputManager;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.controls.TouchListener;
import com.jme3.input.controls.TouchTrigger;
import com.jme3.input.event.TouchEvent;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import static de.jvhoffbauer.empire.game.StrategyCameraController.SCROLL_DOWN;
import static de.jvhoffbauer.empire.game.StrategyCameraController.SCROLL_LEFT;
import static de.jvhoffbauer.empire.game.StrategyCameraController.SCROLL_RIGHT;
import static de.jvhoffbauer.empire.game.StrategyCameraController.SCROLL_UP;

/**
 *
 * @author jvh
 */
public class StrategyCameraControllerAndroid extends StrategyCameraController implements TouchListener {

    public static final int REFERENCE_WIDTH = 1920, REFERENCE_HEIGHT = 1080;
    private float widthScale, heightScale;
    private float speed = 0.001f;

    private Vector2f prevPointerPos = new Vector2f();
    private float prevScaleFactor = 0;
    private float zoomSpeed = 1;


    public StrategyCameraControllerAndroid(Camera cam, InputManager inputManager) {
        super(cam, inputManager);

        this.widthScale = cam.getWidth() / REFERENCE_WIDTH;
        this.heightScale = cam.getHeight() / REFERENCE_HEIGHT;
    }
    protected void registerInputs() {

        inputManager.addMapping(TRIGGER_DRAG, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addMapping(SCROLL_DOWN, new MouseAxisTrigger(MouseInput.AXIS_Y, false));
        inputManager.addMapping(SCROLL_UP, new MouseAxisTrigger(MouseInput.AXIS_Y, true));
        inputManager.addMapping(SCROLL_LEFT, new MouseAxisTrigger(MouseInput.AXIS_X, true));
        inputManager.addMapping(SCROLL_RIGHT, new MouseAxisTrigger(MouseInput.AXIS_X, false));

        inputManager.addListener(this, new String[]{TRIGGER_DRAG, SCROLL_DOWN, SCROLL_UP, SCROLL_LEFT,
            SCROLL_RIGHT});

        inputManager.addMapping("Touch", new TouchTrigger(0));
        inputManager.addListener(this, "Touch");
    }

    public void onTouch(String name, TouchEvent event, float tpf) {

        if(event.getType() == TouchEvent.Type.SCALE_START) {
            prevPointerPos = null;
            prevScaleFactor = -1;
        }
        else if(event.getType() == TouchEvent.Type.SCALE_MOVE) {

            if(prevPointerPos == null) {
                prevPointerPos = new Vector2f(event.getX(), event.getY());
                prevScaleFactor = event.getScaleFactor();
            }

            // Move camera
            prevPointerPos.subtractLocal(event.getX(), event.getY()); // prevPointerPos now is delta between prev and current pointer pos
            Vector3f cameraMovement = new Vector3f(prevPointerPos.x, 0, prevPointerPos.y);
            cameraMovement.x *= -speed * cam.getLocation().y * widthScale;
            cameraMovement.z *=  speed * cam.getLocation().y * heightScale;
            cam.setLocation(cam.getLocation().add(cameraMovement));
            prevPointerPos.set(event.getX(), event.getY());

            // Zoom
            float deltaScaleFactor = prevScaleFactor - event.getScaleFactor();
            prevScaleFactor = event.getScaleFactor();
            setToZoom(getZoom() + deltaScaleFactor * zoomSpeed);
        }
    }
}

and:

package de.jvhoffbauer.empire.game;

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.InputManager;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;

/**
 *
 * @author jvh
 */
public abstract class StrategyCameraController extends AbstractAppState {

    public static String 
            TRIGGER_DRAG = "TriggerDrag",
            SCROLL_UP = "ScrollUp",
            SCROLL_DOWN = "ScrollDown",
            SCROLL_LEFT = "ScrollLeft",
            SCROLL_RIGHT = "ScrollRight",
            ZOOM_IN = "ZoomIn",
            ZOOM_OUT = "ZoomOut";

    protected Camera cam;
    protected InputManager inputManager;

    private float zoom = 1;
    private float camMinY = 1.5f, camMaxY = 10;


    public StrategyCameraController(Camera cam, InputManager inputManager) {

        this.cam = cam;
        this.inputManager = inputManager;

    }
    protected abstract void registerInputs();

    @Override
    public void initialize(AppStateManager stateManager, Application app) {

        cam.setLocation(new Vector3f(0, camMaxY, 0));
        cam.lookAt(Vector3f.ZERO, cam.getUp());

        registerInputs();
    }

    /**
     * Zooms the camera to a certaion value, which is in [0; 1].
     */
    protected void setToZoom(float zoom) {

        if(zoom > 1)
            zoom = 1;
        else if(zoom < 0)
            zoom = 0;

        this.zoom = zoom;
        Vector3f camPos = cam.getLocation();
        camPos.y = camMinY + (camMaxY - camMinY) * zoom;
        cam.setLocation(camPos);
    }
    protected float getZoom() {
        return zoom;
    }
}

hmpf; I knew I did it the wrong way