问题,我的游戏手柄 [英] Issue with my game Joystick

查看:211
本文介绍了问题,我的游戏手柄的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在飞船第一人称视角的游戏工作。我有一个操纵杆,而当我移动操纵杆,我可以移动屏幕的所有对象(小行星)模拟的飞船正在与移动操纵杆。

游戏工作正常,但现在我有一个问题。如果你是pressing操纵杆最大左侧位置,然后你做ACTION_UP,然后在瞬间操纵杆再次ACTION_DOWN但在最大合适的位置,飞船开始移动到最大速度的权利。 这是很难解释。例如,如果你preSS在MAX左侧位置,操纵杆的飞船每帧移动-20px到左侧,如果你preSS操纵杆最大合适的位置,飞船向右移动20像素+每框架。

所以,现在,如果我这样做留下了一个快速max和操纵杆上最大对碰,飞船做这个动作:-20 ... + 20

这不是reallistic运动。

我想获得这个运动:-20 -17 -14 -9 -5 0 +5 +9 +14 +17 +20 ....我的意思是更reallistic飞船移动。但问题是,我不是一个数学或物理等专家,我没有如何得到这样的功能在这个操纵杆任何想法...任何帮助将非常感激。

在这里您可以找到用操纵杆的演示项目: https://mega.co.nz/#!cp5FhYIT!dM88qx_xQdyhED9fX_4xeJ9ciQYJirUlNzEi-KOzU2k

这是操纵杆code,我发现它在谷歌和工作得非常好,除了我前面描述的非真实的动作:

 公共类摇杆扩展视图{
    公共静态最终诠释INVALID_POINTER = -1;    私人JoystickMovedListener moveListener;    //报告之间需要听者像素运动#
    私人浮动moveResolution;    // Max在用户移动范围坐标系
    私人浮动movementRange;    视图坐标//最后接触点
    私人INT pointerId = INVALID_POINTER;
    私人浮动touchX;
    私人浮动敏感;
    私人浮动touchXDelayedMovement;
    私人浮动touchYDelayedMovement;    //视图坐标手柄中心
    私人浮动handleX;
    私人浮动汉德利;    视图坐标//最后报告的位置(允许不同的报告灵敏度)
    私人浮动reportX;
    私人浮动reportY;    在视图坐标中视图的//中心
    私人诠释CX;
    私人诠释CY;    //视图坐标中视图的大小
    私人诠释dimX;
    私人诠释dimY;    私人诠释innerPadding;
    私人诠释bgRadius;
    私人诠释handleRadius;
    私人诠释movementRadius;
    私人诠释handleInnerBoundaries;    最后触摸点的//直角坐标 - 操纵杆中心为(0,0)
    私人诠释cartX;
    私人诠释卡蒂;    //最后触摸点的用户坐标
    私人诠释userX;
    私人诠释userY;    //偏移坐标(使用时从父母收到的触摸事件坐标原点)
    私人诠释offsetX;
    私人诠释offsetY;    私人涂料bgPaint;
    私人涂料handlePaint;    布尔禁用;    处理程序处理程序;
    处理器handlerDelayedMovement;    公共操纵杆(上下文的背景下){
        超级(上下文);
        initJoystickView();
    }    私人无效initJoystickView(){
        setFocusable(真);        handlePaint =新的油漆(Paint.ANTI_ALIAS_FLAG);
        handlePaint.setColor(Color.RED);
        handlePaint.setStrokeWidth(1);
        handlePaint.setStyle(Paint.Style.FILL_AND_STROKE);        bgPaint =新的油漆(Paint.ANTI_ALIAS_FLAG);
        bgPaint.setColor(Color.DKGRAY);
        bgPaint.setStrokeWidth(1);
        bgPaint.setStyle(Paint.Style.FILL_AND_STROKE);        this.moveResolution = 1.0F;        处理器=新的处理程序();
        handlerDelayedMovement =新的处理程序();
    }    公共无效setMovementRange(浮动movementRange){
        this.movementRange = movementRange;
    }    公共无效setOnJostickMovedListener(JoystickMovedListener监听){
        this.moveListener =侦听器;
    }    @覆盖
    保护无效onLayout(布尔变化,诠释离开,诠释顶部,右诠释,诠释底部){
        super.onLayout(改,左,上,右,下);        INT D = Math.min(getMeasuredWidth(),getMeasuredHeight());        dimX = D;
        dimY = D;        CX = D / 2;
        CY = D / 2;        bgRadius = dimX / 2 - innerPadding;
        handleRadius =(INT)(D * 0.2);
        handleInnerBoundaries = handleRadius;
        movementRadius = Math.min(CX,CY) - handleInnerBoundaries;
    }    @覆盖
    保护无效onMeasure(INT widthMeasureSpec,诠释heightMeasureSpec){
        //这里我们要确保我们有一个完美的圆
        INT是measuredWidth =措施(widthMeasureSpec);
        INT是measuredHeight =措施(heightMeasureSpec);
        setMeasuredDimension(是measuredWidth,measuredHeight可以);
    }    私人诠释措施(INT measureSpec){
        INT结果为0;
        //德code中的测量指标。
        INT specMode = MeasureSpec.getMode(measureSpec);
        INT specSize = MeasureSpec.getSize(measureSpec);
        如果(specMode == MeasureSpec.UNSPECIFIED){
            结果= 200;如果没有指定范围//返回200默认大小。
        }其他{
            结果= specSize; //当你要填充​​的可用空间总是返回完整的可用范围。
        }
        返回结果;
    }    @覆盖
    保护无效的onDraw(帆布油画){
        canvas.save();
        //绘制背景
        canvas.drawCircle(CX,CY,bgRadius,bgPaint);        //绘制手柄
        handleX = touchX + CX;
        汉德利=敏感+ CY;
        canvas.drawCircle(handleX,汉德利,handleRadius,handlePaint);        canvas.restore();
    }    公共无效setPointerId(INT ID){
        this.pointerId = ID;
    }    公众诠释getPointerId(){
        返回pointerId;
    }    @覆盖
    公共布尔onTouchEvent(MotionEvent EV){
        最终诠释行动= ev.getAction();
        开关(动作&安培; MotionEvent.ACTION_MASK){
            案例MotionEvent.ACTION_MOVE:{
                如果(禁用==真)
                    打破;
                返回processMoveEvent(EV);
            }
            案例MotionEvent.ACTION_CANCEL:
            案例MotionEvent.ACTION_UP:{
                如果(pointerId!= INVALID_POINTER){
                    returnHandleToCenter();
                    returnHandleToCenterDelayedMovement();
                    setPointerId(INVALID_POINTER);
                }
                打破;
            }
            案例MotionEvent.ACTION_POINTER_UP:{
                如果(pointerId!= INVALID_POINTER){
                    最终诠释pointerIndex =(动作&安培; MotionEvent.ACTION_POINTER_INDEX_MASK)GT;> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                    最终诠释pointerId = ev.getPointerId(pointerIndex);
                    如果(pointerId == this.pointerId){
                        returnHandleToCenter();
                        returnHandleToCenterDelayedMovement();
                        setPointerId(INVALID_POINTER);
                        返回true;
                    }
                }
                打破;
            }
            案例MotionEvent.ACTION_DOWN:{
                handlerDelayedMovement.removeCallbacksAndMessages(NULL);
                如果(pointerId == INVALID_POINTER){
                    INT X =(int)的ev.getX();
                    如果(X GT = offsetX&放大器;&放大器; X&下; offsetX + dimX){
                        setPointerId(ev.getPointerId(0));
                        如果(禁用==真){
                            返回true;
                        }
                        返回processMoveEvent(EV);
                    }
                }
                打破;
            }
            案例MotionEvent.ACTION_POINTER_DOWN:{
                如果(pointerId == INVALID_POINTER){
                    最终诠释pointerIndex =(动作&安培; MotionEvent.ACTION_POINTER_INDEX_MASK)GT;> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                    最终诠释pointerId = ev.getPointerId(pointerIndex);
                    INT X =(INT)ev.getX(pointerId);
                    如果(X GT = offsetX&放大器;&放大器; X&下; offsetX + dimX){
                        setPointerId(pointerId);
                        返回true;
                    }
                }
                打破;
            }
        }
        返回false;
    }    私人布尔processMoveEvent(MotionEvent EV){
        如果(pointerId!= INVALID_POINTER){
            最终诠释pointerIndex = ev.findPointerIndex(pointerId);            //翻译的触摸位置的看法中心
            浮动X = ev.getX(pointerIndex);
            touchX = X - CX - offsetX;
            浮Y = ev.getY(pointerIndex);
            敏感= Y - CY - offsetY;            reportOnMoved();
            无效();            返回true;
        }
        返回false;
    }    私人无效reportOnMoved(){
        //约束圈
        浮diffX = touchX;
        浮diffY =敏感的;
        双辐射=的Math.sqrt((diffX * diffX)+(diffY * diffY));
        如果(径向> movementRadius){
            touchX =(INT)((diffX /径向)* movementRadius);
            敏感=(INT)((diffY /径向)* movementRadius);
        }        //我们calc下用户坐标
        //首先转换成直角坐标系
        cartX =(INT)(touchX / movementRadius * movementRange);
        卡蒂=(INT)(敏感/ movementRadius * movementRange);        //直角坐标
        userX = cartX;
        userY =卡蒂;        如果(moveListener!= NULL){
            布尔RX = Math.abs(touchX - reportX)> = moveResolution;
            布尔RY = Math.abs(敏感 - reportY)> = moveResolution;
            如果(RX || RY){
                this.reportX = touchX;
                this.reportY =敏感的;                moveListener.OnMoved(userX,userY);
            }
        }
    }    私人无效reportOnMovedDelayedMovement(){
        //约束圈
        浮diffX = touchXDelayedMovement;
        浮diffY = touchYDelayedMovement;
        双辐射=的Math.sqrt((diffX * diffX)+(diffY * diffY));
        如果(径向> movementRadius){
            touchXDelayedMovement =(INT)((diffX /径向)* movementRadius);
            touchYDelayedMovement =(INT)((diffY /径向)* movementRadius);
        }        //我们calc下用户坐标
        //首先转换成直角坐标系
        cartX =(INT)(touchXDelayedMovement / movementRadius * movementRange);
        卡蒂=(INT)(touchYDelayedMovement / movementRadius * movementRange);        //直角坐标
        userX = cartX;
        userY =卡蒂;        如果(moveListener!= NULL){
            布尔RX = Math.abs(touchXDelayedMovement - reportX)> = moveResolution;
            布尔RY = Math.abs(touchYDelayedMovement - reportY)> = moveResolution;
            如果(RX || RY){
                this.reportX = touchXDelayedMovement;
                this.reportY = touchYDelayedMovement;                moveListener.OnMoved(userX,userY);
            }
        }
    }    私人无效returnHandleToCenter(){
        最终诠释numberOfFrames = 5;
        最终双intervalsX =(0 - touchX)/ numberOfFrames;
        最终双intervalsY =(0 - 敏感)/ numberOfFrames;        handler.removeCallbacksAndMessages(NULL);
        的for(int i = 0; I< numberOfFrames;我++){
            最终诠释J =;
            handler.postDelayed(新的Runnable(){
                @覆盖
                公共无效的run(){
                    touchX + = intervalsX;
                    敏感+ = intervalsY;                    // reportOnMoved();
                    无效();                    如果(!moveListener =空&放大器;&放大器;Ĵ== numberOfFrames - 1){
                        moveListener.OnReturnedToCenter();
                    }
                }
            },我* 10);
        }        如果(moveListener!= NULL){
            moveListener.OnReleased();
        }
    }    私人无效returnHandleToCenterDelayedMovement(){
        最终诠释numberOfFrames = 25;
        touchXDelayedMovement = touchX;
        touchYDelayedMovement =敏感的;
        最终双intervalsX =(0 - touchXDelayedMovement)/ numberOfFrames;
        最终双intervalsY =(0 - touchYDelayedMovement)/ numberOfFrames;        handlerDelayedMovement.removeCallbacksAndMessages(NULL);
        的for(int i = 0; I< numberOfFrames;我++){
            handlerDelayedMovement.postDelayed(新的Runnable(){
                @覆盖
                公共无效的run(){
                    touchXDelayedMovement + = intervalsX;
                    touchYDelayedMovement + = intervalsY;                    reportOnMovedDelayedMovement();
                }
            },我* 50);
        }
    }    公共无效setInnerPadding(INT innerPadding){
        this.innerPadding = innerPadding;
    }    公共无效禁用(){
        禁用= TRUE;
    }    公共无效使能(){
        禁用= FALSE;
    }    公共接口JoystickMovedListener {
        公共无效OnMoved(INT平移,倾斜INT);
        公共无效OnReleased();
        公共无效OnReturnedToCenter();
    }
}

您必须将使用操纵杆类做到这一点:

 私人JoystickMovedListener joystickListener =新JoystickMovedListener(){
    @覆盖
    公共无效OnMoved(INT平移,倾斜INT){
        //这里我移动的物体在游戏中
        }
    }    @覆盖
    公共无效OnReleased(){}    公共无效OnReturnedToCenter(){};
};joystickOnScreen =新操纵杆(本);
        joystickOnScreen.setMovementRange(screenHeight / 50);
        joystickOnScreen.setInnerPadding(screenHeight / 30);
        joystickOnScreen.setOnJostickMovedListener(joystickListener);
        RelativeLayout.LayoutParams joystickParams =新RelativeLayout.LayoutParams(SH / 3,SH / 3);
        joystickParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        joystickParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        joystickParams.setMargins(SH / 100,0,0,SH / 100);
        joystickOnScreen.setLayoutParams(joystickParams);
        joystickOnScreen.setAlpha(0.3f);


解决方案

我将不执行你的变化,但希望这回答可以帮助你对你自己的这个实施

根据您目前的实现要更新的目标位置(X,Y),每帧。为了得到你想要的更逼真的物理,你需要存储和更新速度,以及(VX,VY)。

添加两个新的变量, VX VY (为零初始值)在你的对象目前正在更新的职位。操纵杆应控制速度,而不是位置的变化。改变code,更新的位置x和y,以更新速度Vx和Vy代替。当操纵杆向左最大,例如,您可以设置 VX = VX - 3

速度更新

后,您需要更新利用速度变量的位置。例如,设置位置 X = X + VX 。理想情况下,你想这在运行,即使你不动操纵杆,但要保持它的简单,你可以速度变量更新之后做此更新不同的方法发生了。

通过这个实现,你会得到更逼真的游戏物理。作为下一步可能要对速度增加限制不动太快。这可以用一个if语句,你检查的值不给它增加更多的前太大,或从中减去之前太SMaL公司来完成。祝你好运!

I'm working in a spaceship first person view game. I have a joystick, and when i move the joystick i can move all the objects (asteroids) of the screen simulating that the spaceship is being moved with the joystick.

The game works fine, but now i have a problem. If you are pressing the joystick in the max left position and then you do ACTION_UP and then instantly ACTION_DOWN in the joystick again but in the max right position, the spaceship starts moving to the right at max speed. It is hard to explain it. For example, If you press the joystick in max left position the spaceship is moving -20px per frame to the left and if you press the joystick in the max right position, the spaceship moves to the right +20px per frame.

So, now, if i do a fast max left and max right touch on the joystick, the spaceship does this movement: -20....+20

It is not reallistic movement.

I want to get this movement: -20 -17 -14 -9 -5 0 +5 +9 +14 +17 +20.... I mean a more reallistic spaceship movement. But the problem is that i am not a math or physics expert, and i dont have any idea of how to get that kind of functionality in this joystick... any help will be very grateful.

Here you can find a demo project with the joystick: https://mega.co.nz/#!cp5FhYIT!dM88qx_xQdyhED9fX_4xeJ9ciQYJirUlNzEi-KOzU2k

This is the joystick code, i found it in google and works very well except for the non realistic movement that i described before:

public class Joystick extends View {
    public static final int INVALID_POINTER = -1;   

    private JoystickMovedListener moveListener;

    //# of pixels movement required between reporting to the listener
    private float moveResolution;

    //Max range of movement in user coordinate system
    private float movementRange;

    //Last touch point in view coordinates
    private int pointerId = INVALID_POINTER;
    private float touchX;
    private float touchY;
    private float touchXDelayedMovement;
    private float touchYDelayedMovement;

    //Handle center in view coordinates
    private float handleX; 
    private float handleY;

    //Last reported position in view coordinates (allows different reporting sensitivities)
    private float reportX; 
    private float reportY;

    //Center of the view in view coordinates
    private int cX;
    private int cY;

    //Size of the view in view coordinates
    private int dimX;
    private int dimY;

    private int innerPadding;
    private int bgRadius;
    private int handleRadius;
    private int movementRadius;
    private int handleInnerBoundaries;

    //Cartesian coordinates of last touch point - joystick center is (0,0)
    private int cartX;
    private int cartY;

    //User coordinates of last touch point
    private int userX;
    private int userY;

    //Offset co-ordinates (used when touch events are received from parent's coordinate origin)
    private int offsetX;
    private int offsetY;

    private Paint bgPaint;
    private Paint handlePaint;

    boolean disabled;

    Handler handler;
    Handler handlerDelayedMovement;

    public Joystick(Context context) {
        super(context);
        initJoystickView();
    }

    private void initJoystickView() {
        setFocusable(true);

        handlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        handlePaint.setColor(Color.RED);
        handlePaint.setStrokeWidth(1);
        handlePaint.setStyle(Paint.Style.FILL_AND_STROKE);

        bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bgPaint.setColor(Color.DKGRAY);
        bgPaint.setStrokeWidth(1);
        bgPaint.setStyle(Paint.Style.FILL_AND_STROKE);      

        this.moveResolution = 1.0f;

        handler = new Handler();
        handlerDelayedMovement = new Handler();
    }   

    public void setMovementRange(float movementRange) {
        this.movementRange = movementRange;
    }   

    public void setOnJostickMovedListener(JoystickMovedListener listener) {
        this.moveListener = listener;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        int d = Math.min(getMeasuredWidth(), getMeasuredHeight());

        dimX = d;
        dimY = d;

        cX = d / 2;
        cY = d / 2;

        bgRadius = dimX/2 - innerPadding;
        handleRadius = (int)(d * 0.2);
        handleInnerBoundaries = handleRadius;
        movementRadius = Math.min(cX, cY) - handleInnerBoundaries;
    }   

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Here we make sure that we have a perfect circle
        int measuredWidth = measure(widthMeasureSpec);
        int measuredHeight = measure(heightMeasureSpec);
        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    private int measure(int measureSpec) {
        int result = 0;
        // Decode the measurement specifications.
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.UNSPECIFIED) {          
            result = 200; // Return a default size of 200 if no bounds are specified.
        } else {            
            result = specSize; // As you want to fill the available space always return the full available bounds.
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        // Draw the background
        canvas.drawCircle(cX, cY, bgRadius, bgPaint);

        // Draw the handle
        handleX = touchX + cX;
        handleY = touchY + cY;
        canvas.drawCircle(handleX, handleY, handleRadius, handlePaint);

        canvas.restore();
    }

    public void setPointerId(int id) {
        this.pointerId = id;
    }

    public int getPointerId() {
        return pointerId;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_MOVE: {
                if (disabled==true)
                    break;
                return processMoveEvent(ev);
            }       
            case MotionEvent.ACTION_CANCEL: 
            case MotionEvent.ACTION_UP: {
                if ( pointerId != INVALID_POINTER ) {
                    returnHandleToCenter();
                    returnHandleToCenterDelayedMovement();
                    setPointerId(INVALID_POINTER);
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_UP: {
                if ( pointerId != INVALID_POINTER ) {
                    final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                    final int pointerId = ev.getPointerId(pointerIndex);
                    if ( pointerId == this.pointerId ) {
                        returnHandleToCenter();
                        returnHandleToCenterDelayedMovement();
                        setPointerId(INVALID_POINTER);
                        return true;
                    }
                }
                break;
            }
            case MotionEvent.ACTION_DOWN: {
                handlerDelayedMovement.removeCallbacksAndMessages(null);
                if ( pointerId == INVALID_POINTER ) {
                    int x = (int) ev.getX();
                    if ( x >= offsetX && x < offsetX + dimX ) {
                        setPointerId(ev.getPointerId(0));
                        if (disabled==true){
                            return true;
                        }                       
                        return processMoveEvent(ev);
                    }
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_DOWN: {
                if ( pointerId == INVALID_POINTER ) {
                    final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                    final int pointerId = ev.getPointerId(pointerIndex);
                    int x = (int) ev.getX(pointerId);
                    if ( x >= offsetX && x < offsetX + dimX ) {
                        setPointerId(pointerId);
                        return true;
                    }
                }
                break;
            }
        }
        return false;
    }

    private boolean processMoveEvent(MotionEvent ev) {
        if ( pointerId != INVALID_POINTER ) {
            final int pointerIndex = ev.findPointerIndex(pointerId);

            // Translate touch position to center of view
            float x = ev.getX(pointerIndex);
            touchX = x - cX - offsetX;
            float y = ev.getY(pointerIndex);
            touchY = y - cY - offsetY;

            reportOnMoved();
            invalidate();

            return true;
        }
        return false;
    }

    private void reportOnMoved() {
        //constraint circle
        float diffX = touchX;
        float diffY = touchY;
        double radial = Math.sqrt((diffX*diffX) + (diffY*diffY));
        if ( radial > movementRadius ) {
            touchX = (int)((diffX / radial) * movementRadius);
            touchY = (int)((diffY / radial) * movementRadius);
        }

        //We calc user coordinates      
        //First convert to cartesian coordinates
        cartX = (int)(touchX / movementRadius * movementRange);
        cartY = (int)(touchY / movementRadius * movementRange);

        //Cartesian Coordinates
        userX = cartX;
        userY = cartY;      

        if (moveListener != null) {
            boolean rx = Math.abs(touchX - reportX) >= moveResolution;
            boolean ry = Math.abs(touchY - reportY) >= moveResolution;
            if (rx || ry) {
                this.reportX = touchX;
                this.reportY = touchY;

                moveListener.OnMoved(userX, userY);
            }
        }
    }

    private void reportOnMovedDelayedMovement() {
        //constraint circle
        float diffX = touchXDelayedMovement;
        float diffY = touchYDelayedMovement;
        double radial = Math.sqrt((diffX*diffX) + (diffY*diffY));
        if ( radial > movementRadius ) {
            touchXDelayedMovement = (int)((diffX / radial) * movementRadius);
            touchYDelayedMovement = (int)((diffY / radial) * movementRadius);
        }

        //We calc user coordinates      
        //First convert to cartesian coordinates
        cartX = (int)(touchXDelayedMovement / movementRadius * movementRange);
        cartY = (int)(touchYDelayedMovement / movementRadius * movementRange);

        //Cartesian Coordinates
        userX = cartX;
        userY = cartY;      

        if (moveListener != null) {
            boolean rx = Math.abs(touchXDelayedMovement - reportX) >= moveResolution;
            boolean ry = Math.abs(touchYDelayedMovement - reportY) >= moveResolution;
            if (rx || ry) {
                this.reportX = touchXDelayedMovement;
                this.reportY = touchYDelayedMovement;

                moveListener.OnMoved(userX, userY);
            }
        }
    }

    private void returnHandleToCenter() {
        final int numberOfFrames = 5;
        final double intervalsX = (0 - touchX) / numberOfFrames;
        final double intervalsY = (0 - touchY) / numberOfFrames;

        handler.removeCallbacksAndMessages(null);
        for (int i = 0; i < numberOfFrames; i++) {
            final int j = i;
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    touchX += intervalsX;
                    touchY += intervalsY;

                    //reportOnMoved();
                    invalidate();

                    if (moveListener != null && j == numberOfFrames - 1) {
                        moveListener.OnReturnedToCenter();
                    }
                }
            }, i * 10);
        }

        if (moveListener != null) {
            moveListener.OnReleased();
        }
    }

    private void returnHandleToCenterDelayedMovement() {
        final int numberOfFrames = 25;
        touchXDelayedMovement=touchX;
        touchYDelayedMovement=touchY;
        final double intervalsX = (0 - touchXDelayedMovement) / numberOfFrames;
        final double intervalsY = (0 - touchYDelayedMovement) / numberOfFrames;

        handlerDelayedMovement.removeCallbacksAndMessages(null);
        for (int i = 0; i < numberOfFrames; i++) {
            handlerDelayedMovement.postDelayed(new Runnable() {
                @Override
                public void run() {
                    touchXDelayedMovement += intervalsX;
                    touchYDelayedMovement += intervalsY;

                    reportOnMovedDelayedMovement();
                }
            }, i * 50);
        }
    }

    public void setInnerPadding(int innerPadding){
        this.innerPadding=innerPadding;
    }

    public void disable(){
        disabled=true;
    }   

    public void enable(){
        disabled=false;
    }

    public interface JoystickMovedListener {
        public void OnMoved(int pan, int tilt);
        public void OnReleased();
        public void OnReturnedToCenter();
    }
}

You must do this in the class that will use the joystick:

private JoystickMovedListener joystickListener = new JoystickMovedListener() {
    @Override
    public void OnMoved(int pan, int tilt) {    
        //here i move the objects in the game
        }
    }

    @Override
    public void OnReleased() {}

    public void OnReturnedToCenter() {};
}; 

joystickOnScreen = new Joystick(this);
        joystickOnScreen.setMovementRange(screenHeight/50);
        joystickOnScreen.setInnerPadding(screenHeight/30);
        joystickOnScreen.setOnJostickMovedListener(joystickListener);
        RelativeLayout.LayoutParams joystickParams = new RelativeLayout.LayoutParams(sh/3, sh/3);
        joystickParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        joystickParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        joystickParams.setMargins(sh/100, 0, 0, sh/100);
        joystickOnScreen.setLayoutParams(joystickParams);
        joystickOnScreen.setAlpha(0.3f);

解决方案

I will not implement the changes for you but hopefully this answer can help you towards implementing this on your own.

With your current implementation you are updating the object position (x, y) each frame. To get the more realistic physics that you want, you need to store and update velocity as well (vx, vy).

Add two new variables, vx and vy (with initial values of zero) in the objects that you are currently updating the position for. The joystick should control the change of the velocity instead of the position. Change the code that updates the positions x and y, to update the velocities vx and vy instead. When the joystick is max left, you can for example set vx = vx - 3.

After the velocity is updated, you need to update the position using the velocity variables. For example, set the position x = x + vx. Ideally you want this to happen in a different method that runs even if you don't move the joystick, but to keep it simple you can do this update right after the update of the velocity variables.

With this implementation you will get a more realistic game physics. As a next step you might want to add limits on the velocity to not move too fast. This can be done with an if-statement where you check that the value is not too big before adding more to it, or too smal before subtracting from it. Good luck!

这篇关于问题,我的游戏手柄的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆