Search code examples
androidandroid-studiorectpong

Rect.offset() not working along negative x axis


I am doing a Pong clone and I've implemented the ball as a Rect() object. Now to move the ball I use the Rect.offset(dx,dy), which offsets the ball by a specefied speed. For bouncing the ball off a wall I multiply the velocity of respective axis by -1. Now for bounce along the Y-axis , it bounces perfectly, but along the X-axis it starts behavioral weirdly. Is this some glitch with the android studio or am I doing something wrong?

package com.nblsoft.pong;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;



public class PongLogic extends View {

    //set screen constrains in dip
    Configuration configuration = this.getResources().getConfiguration();
    int dpHeight = configuration.screenHeightDp; //The current height of the available screen space, in dp units, corresponding to screen height resource qualifier.
    int dpWidth = configuration.screenWidthDp; //The current width of the available screen space, in dp units, corresponding to screen width resource qualifier.

        //int smallestScreenWidthDp = configuration.smallestScreenWidthDp; //The smallest screen size an application will see in normal operation, corresponding to smallest screen width resource qualifier.

        //DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
        //float dpHeight = displayMetrics.heightPixels / displayMetrics.density;
        //float dpWidth = displayMetrics.widthPixels / displayMetrics.density;

    private int dptopixel(int DESIRED_DP_VALUE){

        final float scale = getResources().getDisplayMetrics().density;

        return (int)((DESIRED_DP_VALUE) * scale + 0.5f);
    }

    private int pixeltodp(int DESIRED_PIXEL_VALUE){

        final float scale = getResources().getDisplayMetrics().density;

        return (int) ((DESIRED_PIXEL_VALUE) - 0.5f / scale);
    }

    //set paddle size, speed, position vector

    int AI_paddle_pos_x = 4 * (dptopixel(dpWidth)/100);           //3 for 320x480, 10 for 1080x1920 etc.
    int paddle_width  =     (dptopixel(dpWidth)/10);            //
    int AI_paddle_pos_y =     (dptopixel(dpHeight)/10);           //48 for 320x480, 190 for 1080x1920 etc.
    int paddle_height =     (dptopixel(dpHeight)/100) + 3;      //the paddle is 100% of the total height of phone.

    int user_paddle_pos_x = 4 * (dptopixel(dpWidth)/100) ;
    int user_paddle_pos_y = dptopixel(dpHeight) - ((dptopixel(dpHeight)/10) + (dptopixel(dpHeight)/100) + 3)  ;




    //User Paddle
    public Rect paddle_user = new Rect(user_paddle_pos_x,
                                       user_paddle_pos_y,
                                       user_paddle_pos_x + paddle_width,
                                       user_paddle_pos_y + paddle_height);

    //AI paddle
    Rect paddle_AI = new Rect(AI_paddle_pos_x,
                              AI_paddle_pos_y,
                              AI_paddle_pos_x + paddle_width,
                              AI_paddle_pos_y + paddle_height);


    //set ball position vector, Velocity vector, acceleration

    int ball_pos_x = 0 ;
    int ball_pos_y = (dptopixel(dpHeight)/2) ;
    int ball_size = dptopixel(dpWidth)/100 ;
    int ball_velocity = 3;


    // Ball
    Rect ball = new Rect(ball_pos_x,
                         ball_pos_y,
                         ball_pos_x+ball_size,
                         ball_pos_y+ball_size);


    //Override onDraw method
    @Override
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);

        Paint mytext  = new Paint();
        mytext.setColor(Color.WHITE);
        //mytext.setStyle(Paint.Style.STROKE);
        //mytext.setStrokeWidth(2);


        // Draw Middle point
        canvas.drawRect(0, ((dptopixel(dpHeight)) / 2), (dptopixel(dpWidth)), (((dptopixel(dpHeight)) / 2) + 2), mytext);

        //draw both paddles
        canvas.drawRect(paddle_user,mytext);
        canvas.drawRect(paddle_AI, mytext);

        //draw ball
        canvas.drawRect(ball,mytext);


    //Practise Methods
        //canvas.drawText(Integer.toString(dptopixel(dpHeight)),300,300,mytext);
        //canvas.drawText(Integer.toString(dptopixel(dpWidth)), 400, 400, mytext);

        //canvas.drawText(Integer.toString(dpHeight),500,500,mytext);
        //canvas.drawText(Integer.toString(dpWidth),600,600,mytext);

        //canvas.drawText("Fuck", 700, 700, mytext);
        //canvas.drawRect(0,0,dptopixel(dpWidth),dptopixel(dpHeight),mytext);


        //Game Loop Updater
        update();
        invalidate();
    }

    private void update() {

        if (ball.centerX() > (dptopixel(dpWidth))/2){
            ball.offset(-ball_velocity,ball_velocity);
        }
        else{
        ball.offset(ball_velocity,ball_velocity);
        }
    }

    //Override Touch method

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {

            paddle_user.offset(10,0);
        }
        return true;
    }


/*    @Override
    public boolean onTouch(View v, MotionEvent event) {
        this.paddle_user.offsetTo(10,10);
        return true; //Event Handled
    }
*/


    public PongLogic(Context context) {
        super(context);
        setBackgroundColor(Color.BLACK);            //to set background
        this.setFocusableInTouchMode(true);             //to enable touch mode

    }



}

Solution

  • Ok I've Figured out why the offset method was behaving erratically. First I had the original offset position in the else part of the conditional. Second I was negating the dx component only when the if evaluated to true. Which happened for just one frame because I was evaluating Rect object's X position. Which cause it to become false as soon as the -dx was subtracted from the ball's position.

    To resolve it I had to place the offset out of the conditional and pass two separate values for the dx and dy. Then I tweaked the conditional so that it only assigned positive and negative values to the variables which were later passed into offset() function, Rather then calling the offset function itself.

    This is the new update() method

    private void update() {
    
            if (ball.centerX() > (dptopixel(dpWidth))/2){
                ball_velocity_x = -3;
            }
            else if (ball.centerY() > (dptopixel(dpHeight))) {
                ball_velocity_y = -3;
            }
    
            ball.offset(ball_velocity_x, ball_velocity_y);
        }