有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

我的游戏操纵杆的java问题

我在太空船第一人称观看游戏中工作。我有一个操纵杆,当我移动操纵杆时,我可以移动屏幕上的所有物体(小行星),模拟宇宙飞船正在用操纵杆移动

游戏很好,但现在我有个问题。如果在最左侧位置按下操纵杆,然后在操纵杆上执行向上操作,然后立即执行向下操作,但在最右侧位置,宇宙飞船开始以最大速度向右移动<很难解释。例如,如果在最大左侧位置按下操纵杆,宇宙飞船将向左移动每帧-20px,如果在最大右侧位置按下操纵杆,宇宙飞船将向右移动每帧+20px

那么,现在,如果我在操纵杆上快速进行“最大向左”和“最大向右”触摸,宇宙飞船会做这个动作:-20+20

这不是现实主义运动

我想做这个动作:-20-17-14-9-50+5+9+14+17+20。。。。我指的是更现实的宇宙飞船运动但问题是我不是数学或物理专家,我不知道如何在这个操纵杆中获得这种功能。。。任何帮助都将不胜感激

在这里,你可以找到一个带有操纵杆的演示项目:https://mega.co.nz/#!cp5FhYIT!dM88qx_xQdyhED9fX_4xeJ9ciQYJirUlNzEi-KOzU2k

这是操纵杆代码,我在谷歌找到了它,除了我之前描述的非现实运动外,它工作得非常好:

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();
    }
}

你必须在使用操纵杆的课堂上这样做:

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);

共 (1) 个答案

  1. # 1 楼答案

    我不会为你实施这些改变,但希望这个答案能帮助你自己实施

    在当前的实现中,每个帧都会更新对象位置(x,y)。为了得到你想要的更真实的物理,你还需要存储和更新速度(vx,vy)

    在当前更新位置的对象中添加两个新变量vxvy(初始值为零)。操纵杆应该控制速度的变化,而不是位置的变化。更改更新位置x和y的代码,改为更新速度vx和vy。当操纵杆处于最大左侧时,您可以设置vx = vx - 3

    更新速度后,需要使用速度变量更新位置。例如,设置位置x = x + vx。理想情况下,即使不移动操纵杆,您也希望以另一种方法运行,但为了保持简单,您可以在更新速度变量后立即执行此更新

    通过这个实现,你将得到一个更真实的游戏物理。作为下一步,你可能想要增加速度限制,以避免移动太快。这可以通过if语句来实现,在添加更多值之前检查值是否太大,或者在从中减去值之前检查值是否太小。祝你好运