excaliburjs / Excalibur

🎮 Your friendly TypeScript 2D game engine for the web 🗡️
https://excaliburjs.com
BSD 2-Clause "Simplified" License
1.83k stars 193 forks source link

Create a Swipe Tracker #1123

Open justjoeyuk opened 5 years ago

justjoeyuk commented 5 years ago

I made this same issue previously, but on an alternate account where I would not be subscribed properly to this issue. I've remade it.

It would be useful to have a feature that allows you to track swipes on a mobile device. I've created my own using Excaliburs' current features. I'm not sure if it's suitable for the engines' scope, however. The code is below for reference, but I believe that a utility for swipe gestures would be handy.

The math isn't fantastic in this Swipe Tracker either. I'm still playing around with it.

import { Vector, Class, Engine, GameEvent } from "excalibur";
import { PointerDownEvent, PointerMoveEvent, PointerUpEvent } from "excalibur/dist/Input";

export enum STSensitivity {
    High,
    Medium,
    Low
}

export enum SwipeDirection {
    NONE,
    UP,
    RIGHT,
    DOWN,
    LEFT
}

export class SwipeEvent extends GameEvent<any> {
    constructor(public direction: SwipeDirection) {
      super();
    }
}

export default class SwipeTracker extends Class {    

    public sensitivity: STSensitivity;

    get swipeTimeDelay(): number { 
        return this.sensitivity == STSensitivity.High ? 50 : STSensitivity.Medium ? 100 :  200;
    }

    get swipePositionThreshold(): number { 
        return this.sensitivity == STSensitivity.High ? 80 : STSensitivity.Medium ? 120 :  180;
    }

    private _timerComplete: Boolean;
    private _initialPointerPosition: Vector;
    private _swipeEventEmitted: Boolean;

    constructor(_engine : Engine) {
        super();
        this.sensitivity = STSensitivity.High;

        _engine.input.pointers.primary.on('down', (pe) => {
            let castPE = pe as PointerDownEvent;
            this._initialPointerPosition = new Vector(castPE.screenPos.x, castPE.screenPos.x);
            this._swipeEventEmitted = false;
            this._timerComplete = false;

            setTimeout(() => {
                this._timerComplete = true
            }, this.swipeTimeDelay);
        });

        _engine.input.pointers.primary.on('move', (pe) => {
            let castPE = pe as PointerMoveEvent;
            this.emitSwipeIfNecessary(castPE);
        });

        _engine.input.pointers.primary.on('up', (pe) => {
            let castPE = pe as PointerMoveEvent;
            this.emitSwipeIfNecessary(castPE);
        });
    }

    private emitSwipeIfNecessary( pe: PointerMoveEvent | PointerUpEvent) {
        let swipeDirection = SwipeDirection.NONE;

        if (this._timerComplete && !this._swipeEventEmitted) {
            if (pe.screenPos.x > this._initialPointerPosition.x + this.swipePositionThreshold) {
                swipeDirection = SwipeDirection.RIGHT;
            } else if (pe.screenPos.x < this._initialPointerPosition.x - this.swipePositionThreshold) {
                swipeDirection = SwipeDirection.LEFT;
            } else if (pe.screenPos.y > this._initialPointerPosition.y + this.swipePositionThreshold) {
                swipeDirection = SwipeDirection.DOWN;
            } else if (pe.screenPos.y < this._initialPointerPosition.y - this.swipePositionThreshold) {
                swipeDirection = SwipeDirection.UP;
            }

            if (swipeDirection != undefined) {
                this.emit('swipe', new SwipeEvent(swipeDirection));
                this._swipeEventEmitted = true;
            }
        }
    }
}

Usage:

let tracker = new SwipeTracker(_engine);
tracker.on('swipe', (sw: SwipeEvent) => { console.log(sw.direction) })
eonarheim commented 5 years ago

@justjoeyuk This is excellent! 100% want this in core excalibur.

The team has talked about implementing some form of gesture api like this #475, this would be an excellent start to this.

justjoeyuk commented 5 years ago

@eonarheim That's brilliant to hear. However, I've began adding a "enableKeyboard" for the SwipeTracker (mainly to debug on Desktop). I've encountered an error with the imports and now it won't compile. When I add import {KeyEvent, Keys } from "excalibur/dist/Input";

I get the following compiler warnings:

WARNING in ./node_modules/excalibur/dist/Input/Index.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* C:\Users\Buxbo\Desktop\Games\Meteor\node_modules\excalibur\dist\Input\Index.js
    Used by 10 module(s), i. e.
    C:\Users\Buxbo\Desktop\Games\Meteor\node_modules\excalibur\dist\Engine.js
* C:\Users\Buxbo\Desktop\Games\Meteor\node_modules\excalibur\dist\Input\index.js
    Used by 1 module(s), i. e.

It builds but refuses to run now. Any ideas?

eonarheim commented 5 years ago

@justjoeyuk Sadly, loading individual types like Import {KeyEvent, Keys } from "excalibur/dist/Input from files isn't super friendly at the moment for excalibur and doesn't provide a lot of tree shaking benefits yet (we need more discipline in our imports in the core library).

It's concerning that there appears to be 2 index files Index.js and index.js in the node module Input directory. I don't see it in a fresh install of latest excalibur though? What does your file system show? image

justjoeyuk commented 5 years ago

Hey @eonarheim ,

I added the CSS file loader and that's fine, that error is gone. I'll start to use the imports as you described now.

However, I'm interested in contributing to this project and would like more information about how to do so whilst building a project I'm working on. Do you have Discord or anything along those lines? I'd love to be able to modify the engine directly whilst working on my current project.

Regards

justjoeyuk commented 5 years ago

@eonarheim The directory only contains "Index.ts" but it looks like by default, import x from y looks for index.ts which seems accurate from my experience.

justjoeyuk commented 5 years ago

@eonarheim It works now, I used import * as ex from 'excalibur'; instead. However, I do believe that all Index.ts should be index.ts which is the conventional way for module resolves to be handled. It can alternative partially fixed by doing import {PointerEvent} from 'excalibur/dist/Input/Index' but then you get compiler errors saying that Document isn't a property of undefined on PointerScope for whatever reason.

eonarheim commented 5 years ago

@justjoeyuk Hmm good point, we should definitely open a bug on the capitalization of the Index.ts barrels. That import looks pretty un-ideal.

It may be a bigger question for the team, should we open an additional issue switch to all lowercase files in excalibur to match closer to node @excaliburjs/core-contributors?

eonarheim commented 5 years ago

@justjoeyuk As for working on the engine while building a game I've done a couple approaches

I'll make an issue later to update our readme to include this in our documentation 👍

github-actions[bot] commented 3 years ago

This issue hasn't had any recent activity lately and is being marked as stale automatically.

github-actions[bot] commented 1 month ago

This issue hasn't had any recent activity lately and is being marked as stale automatically.