libgdx中只有水平触摸板

时间:2018-02-21 00:50:57

标签: libgdx

我试图将libgdx触控板类修改为仅水平移动而不是整圆。所以像这样:

enter image description here  但触摸是混乱的,并没有像在圆形版本中那样阻止触摸板边界内的移动。继承我的版本,任何有关我出错的地方的帮助都会受到赞赏:

public class HorizontalTouchpad extends Widget {
    private HorizontalTouchpadStyle style;
    boolean touched;
    boolean resetOnTouchUp = true;
    private float deadzoneWidth;
    private final Rectangle knobBounds = new Rectangle(0, 0, 0,0);
    private final Rectangle touchBounds = new Rectangle(0, 0, 0,0);
    private final Rectangle deadzoneBounds = new Rectangle(0, 0, 0,0);
    private final Vector2 knobPosition = new Vector2();
    private final Vector2 knobPercent = new Vector2();

    /** @param deadzoneWidth The distance in pixels from the center of the touchpad required for the knob to be moved. */
    public HorizontalTouchpad (float deadzoneWidth, Skin skin) {
        this(deadzoneWidth, skin.get(HorizontalTouchpadStyle.class));
    }

    /** @param deadzoneWidth The distance in pixels from the center of the touchpad required for the knob to be moved. */
    public HorizontalTouchpad (float deadzoneWidth, Skin skin, String styleName) {
        this(deadzoneWidth, skin.get(styleName, HorizontalTouchpadStyle.class));
    }

    /** @param deadzoneWidth The distance in pixels from the center of the touchpad required for the knob to be moved. */
    public HorizontalTouchpad (float deadzoneWidth, HorizontalTouchpadStyle style) {
        if (deadzoneWidth < 0) throw new IllegalArgumentException("deadzoneWidth must be > 0");
        this.deadzoneWidth = deadzoneWidth;

        knobPosition.set(getWidth() / 2f, getHeight() / 2f);

        setStyle(style);
        setSize(getPrefWidth(), getPrefHeight());

        addListener(new InputListener() {
            @Override
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                if (touched) return false;
                touched = true;
                calculatePositionAndValue(x, y, false);
                return true;
            }

            @Override
            public void touchDragged (InputEvent event, float x, float y, int pointer) {
                calculatePositionAndValue(x, y, false);
            }

            @Override
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                touched = false;
                calculatePositionAndValue(x, y, resetOnTouchUp);
            }
        });
    }

    void calculatePositionAndValue (float x, float y, boolean isTouchUp) {
        float oldPositionX = knobPosition.x;
        float oldPositionY = knobPosition.y;
        float oldPercentX = knobPercent.x;
        float oldPercentY = knobPercent.y;
        float centerX = knobBounds.x;
        float centerY = knobBounds.y;
        knobPosition.set(centerX, centerY);
        knobPercent.set(0f, 0f);
        if (!isTouchUp) {
            if (!deadzoneBounds.contains(x, y)) {
                knobPercent.set((x - centerX) / (knobBounds.getWidth()/2), 0);
                float length = knobPercent.len();
                if (length > 1) knobPercent.scl(1 / length);
                if (knobBounds.contains(x, y)) {
                    knobPosition.set(x, y);
                } else {
                    knobPosition.set(knobPercent).nor().scl(knobBounds.getWidth()/2,0).add(knobBounds.x, knobBounds.y);
                }
            }
        }
        if (oldPercentX != knobPercent.x || oldPercentY != knobPercent.y) {
            ChangeListener.ChangeEvent changeEvent = Pools.obtain(ChangeListener.ChangeEvent.class);
            if (fire(changeEvent)) {
                knobPercent.set(oldPercentX, oldPercentY);
                knobPosition.set(oldPositionX, oldPositionY);
            }
            Pools.free(changeEvent);
        }
    }

    public void setStyle (HorizontalTouchpadStyle style) {
        if (style == null) throw new IllegalArgumentException("style cannot be null");
        this.style = style;
        invalidateHierarchy();
    }

    /** Returns the touchpad's style. Modifying the returned style may not have an effect until {@link #setStyle(HorizontalTouchpadStyle)} is
     * called. */
    public HorizontalTouchpadStyle getStyle () {
        return style;
    }

    @Override
    public Actor hit (float x, float y, boolean touchable) {
        if (touchable && this.getTouchable() != Touchable.enabled) return null;
        return touchBounds.contains(x, y) ? this : null;
    }

    @Override
    public void layout () {
        // Recalc pad and deadzone bounds
        float halfWidth = getWidth() / 2;
        float halfHeight = getHeight() / 2;
        float radius = Math.min(halfWidth, halfHeight);
        touchBounds.set(halfWidth, halfHeight, getWidth(),getHeight());
        if (style.knob != null) radius -= Math.max(style.knob.getMinWidth(), style.knob.getMinHeight()) / 2;
        knobBounds.set(halfWidth, halfHeight, getWidth(),getHeight());
        deadzoneBounds.set(halfWidth, halfHeight, deadzoneWidth, getHeight());
        // Recalc pad values and knob position
        knobPosition.set(halfWidth, halfHeight);
        knobPercent.set(0, 0);
    }

    @Override
    public void draw (Batch batch, float parentAlpha) {
        validate();

        Color c = getColor();
        batch.setColor(c.r, c.g, c.b, c.a * parentAlpha);

        float x = getX();
        float y = getY();
        float w = getWidth();
        float h = getHeight();

        final Drawable bg = style.background;
        if (bg != null) bg.draw(batch, x, y, w, h);

        final Drawable knob = style.knob;
        if (knob != null) {
            x += knobPosition.x - knob.getMinWidth() / 2f;
            y += knobPosition.y - knob.getMinHeight() / 2f;
            knob.draw(batch, x, y, knob.getMinWidth(), knob.getMinHeight());
        }
    }

    @Override
    public float getPrefWidth () {
        return style.background != null ? style.background.getMinWidth() : 0;
    }

    @Override
    public float getPrefHeight () {
        return style.background != null ? style.background.getMinHeight() : 0;
    }

    public boolean isTouched () {
        return touched;
    }

    public boolean getResetOnTouchUp () {
        return resetOnTouchUp;
    }

    /** @param reset Whether to reset the knob to the center on touch up. */
    public void setResetOnTouchUp (boolean reset) {
        this.resetOnTouchUp = reset;
    }

    /** @param deadzoneWidth The distance in pixels from the center of the touchpad required for the knob to be moved. */
    public void setDeadzone (float deadzoneWidth) {
        if (deadzoneWidth < 0) throw new IllegalArgumentException("deadzoneWidth must be > 0");
        this.deadzoneWidth = deadzoneWidth;
        invalidate();
    }

    /** Returns the x-position of the knob relative to the center of the widget. The positive direction is right. */
    public float getKnobX () {
        return knobPosition.x;
    }

    /** Returns the y-position of the knob relative to the center of the widget. The positive direction is up. */
    public float getKnobY () {
        return knobPosition.y;
    }

    /** Returns the x-position of the knob as a percentage from the center of the touchpad to the edge of the circular movement
     * area. The positive direction is right. */
    public float getKnobPercentX () {
        return knobPercent.x;
    }

    /** Returns the y-position of the knob as a percentage from the center of the touchpad to the edge of the circular movement
     * area. The positive direction is up. */
    public float getKnobPercentY () {
        return knobPercent.y;
    }

    /** The style for a {@link HorizontalTouchpad}.
     * @author Josh Street */
    public static class HorizontalTouchpadStyle {
        /** Stretched in both directions. Optional. */
        public Drawable background;

        /** Optional. */
        public Drawable knob;

        public HorizontalTouchpadStyle () {
        }

        public HorizontalTouchpadStyle (Drawable background, Drawable knob) {
            this.background = background;
            this.knob = knob;
        }

        public HorizontalTouchpadStyle (HorizontalTouchpadStyle style) {
            this.background = style.background;
            this.knob = style.knob;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

如果你只允许水平移动,那么只有x位置才有意义吗?您可以将y-position设置为始终为常量值。要使其保持在触摸板的范围内,您需要检查以确保它不会移动到外面。因此,如果在布局方法中定义一些常量:

@Override
public void layout () {
    // Recalc pad and deadzone bounds
    float halfWidth = getWidth() / 2;
    float halfHeight = getHeight() / 2;
    float radius = Math.min(halfWidth, halfHeight);
    touchBounds.set(halfWidth, halfHeight, getWidth(),getHeight());
    if (style.knob != null) radius -= Math.max(style.knob.getMinWidth(), style.knob.getMinHeight()) / 2;
    knobBounds.set(halfWidth, halfHeight, getWidth(),getHeight());
    deadzoneBounds.set(halfWidth, halfHeight, deadzoneWidth, getHeight());

    yPosition = halfHeight;
    minX = style.knob.getMinWidth() / 2;
    maxX = getWidth() - style.knob.getMinWidth() / 2;

    // Recalc pad values and knob position
    knobPosition.set(halfWidth, halfHeight);
    knobPercent.set(0, 0);
}

然后当你设置位置时:

.....
if (knobBounds.contains(x, y)) {
    if (x < minX) {
       x = minX;
    }
    if (x > maxX) {
       x = maxX;
    }
    knobPosition.set(x, yPosition);
} else {
    knobPosition.set(knobPercent).nor().scl(knobBounds.getWidth()/2,0).add(knobBounds.x, knobBounds.y);
}
.....

类似的东西(可能需要tweeking)。您可能需要对knobPercent进行类似检查。

答案 1 :(得分:1)

必须调整边界以及如何根据矩形与圆形来计算位置和百分比。这是更新的布局方法和计算方法:

@Override
    public void layout () {
        // Recalc pad and deadzone bounds
        float halfWidth = getWidth() / 2;
        float halfHeight = getHeight() / 2;
        touchBounds.set(getX(), getY(), getWidth(),getHeight());

        knobBounds.set(getX(), getY(), getWidth(),getHeight());
        deadzoneBounds.set(halfWidth-deadzoneWidth/2, getY(), deadzoneWidth, getHeight());

        yPosition = halfHeight;

        // Recalc pad values and knob position
        knobPosition.set(halfWidth, halfHeight);
        knobPercent.set(0, 0);
    }

添加了一个yPosition变量,以便每次都轻松设置y位置

void calculatePositionAndValue (float x, float y, boolean isTouchUp) {
        float oldPositionX = knobPosition.x;
        float oldPositionY = knobPosition.y;
        float oldPercentX = knobPercent.x;
        float oldPercentY = knobPercent.y;
        float centerX = knobBounds.width/2;
        float centerY = knobBounds.height/2;
        knobPosition.set(centerX, centerY);
        knobPercent.set(0f, 0f);
        if (!isTouchUp) {
            if (!deadzoneBounds.contains(x, y)) {
                knobPercent.set((x - centerX) / (knobBounds.getWidth()/2), 0);
                float length = knobPercent.len();
                if (length > 1) knobPercent.scl(1 / length);
                if (knobBounds.contains(x, y)) {
                    knobPosition.set(x, yPosition);
                } else {
                    knobPosition.set(knobPercent).scl(knobBounds.getWidth()/2,0).add(knobBounds.width/2, knobBounds.height/2);
                }
            }
        }

        if (oldPercentX != knobPercent.x || oldPercentY != knobPercent.y) {
            ChangeListener.ChangeEvent changeEvent = Pools.obtain(ChangeListener.ChangeEvent.class);
            if (fire(changeEvent)) {
                knobPercent.set(oldPercentX, oldPercentY);
                knobPosition.set(oldPositionX, oldPositionY);
            }
            Pools.free(changeEvent);
        }
    }

这里的重大变化是计算百分比并在不在界限范围内时改变位置。它使用getX()作为圆心,但是对于矩形,它是左下角。所以不得不把它改成中心。