简体   繁体   中英

OOP and inheritance advice needed

Note there's a lot of code posted below but its mostly all the same, that's what i'm looking for advice on :)

Just getting to grips with OOP and inheritance, i'm making an android pong clone, and i'm trying to separate out a bunch of duplicate code found in my "paddle" and "bomb" classes into a separate class called sprite. What i'm not sure about is handling the member variables currently in my bomb and paddle classes . I want the same variables in both classes for the same uses and reckon they should be moved to my sprite class. But then im not sure about using them in my more specialized Bomb and Paddle classes later on.. i could make them protected but this is where i get confused because that would leave me in a situation where all my more specialized classes are sharing EXACTLY the same variables surely, which i definitely dont want, i just want them to have a copy of those variables.. oh i don't know, My classes are quite simple at the moment, if you could take a look through the two of them, see whats the same (mostly getters&setters, a draw method and an update method) and suggest how i should be going about moving code to my sprite class it'd be much appreciated!

First specialised class, Bomb:

package biz.hireholly.pirateponggame;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.Log;

public class Bomb {
    private Bitmap bitmap;  //image
    private int x;  //x coordinate
    private int y;  //y coordinate

    private Speed speed; //the speed with its directions

    public Bomb(Bitmap bmp, int x, int y){
        this.bitmap = bmp;
        this.x = x;
        this.y = y;
        this.speed = new Speed();
    }

    public Bitmap getBitmap(){
        return bitmap;
    }
    public void setBitmap(Bitmap bmp){
        this.bitmap = bmp;
    }
    public int getX(){
        return x;
    }
    public int getY(){
        return y;
    }
    public void setX(int x){
        this.x = x;
    }
    public void setY(int y){
        this.y = y;
    }
    public Speed getSpeed() {
        return speed;
    }
    public void setSpeed(Speed newSpeed) {
        this.speed = newSpeed;
    }

    /**
     * X&Y += current velocity * current direction
     */
    public void update(){
        x+= (speed.getXv() * speed.getxDirection());
        y+= (speed.getYv() * speed.getyDirection());
    }

    /**
     * takes the bitmap it was instantiated with.
     * Draws it to the canvas at the coordinates the bomb is at in that moment.
     * @param canvas
     */
    public void draw(Canvas canvas){

        canvas.drawBitmap(bitmap, x-(bitmap.getWidth() /2), y-(bitmap.getHeight() /2), null );

    }

    public void handleWallCollision(int viewW, int viewH){

        //check collision with right wall if heading right
        if (speed.getxDirection() == Speed.RIGHT //if going right
                && getX() + (bitmap.getWidth() /2) >= viewW){ //and the centre of the bitmap become greater than the view width
            //reverse x direction
            speed.toggleXDirection();
        }
        //check for collision with left wall if heading left
        if (speed.getxDirection() == Speed.LEFT
                && getX() - (bitmap.getWidth() /2) <= 0){
            //reverse x direction
            speed.toggleXDirection();
        }
        //check collision with  bottom wall if heading down
        if (speed.getyDirection() == Speed.DOWN
                && getY() + (bitmap.getHeight() /2) >= viewH){
            //reverse y direction
            speed.toggleYDirection();
        }
        //check collision with top wall if heading up
        if (speed.getyDirection() == Speed.UP
                && getY() - (bitmap.getHeight() /2) <= 0){
            speed.toggleYDirection();
        }
    }
    public void handlePaddleCollision(Paddle pad){
        //THIS WILL NEED TO WORK FOR BOTH PADDLES


        int paddleHalfH = pad.getBitmap().getHeight();
        int paddleHalfW = pad.getBitmap().getWidth();
        //int bombHalfW = bitmap.getWidth();
        int bombHalfH = bitmap.getHeight();

        //first check if the bombs x is within the paddles x
        if( x >= (pad.getX() - paddleHalfW) //x > paddle leftside
            && x <= (pad.getX() + paddleHalfW)) // x < paddle rightside
        {

            if((y+bombHalfH) >= (pad.getY() + paddleHalfH)) //base of bomb is touching top of paddle
            {
                speed.toggleYDirection();
            }

        }



    }

}

Then there's my Paddle class with a lot of the same stuff in :

package biz.hireholly.pirateponggame;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.Log;
import android.view.MotionEvent;

public class Paddle {
    private static final String TAG = Paddle.class.getSimpleName();
    private Bitmap bitmap;  //image
    private Speed speed; //the speed with its directions

    private int x;  //x coordinate
    private int y;  //y coordinate
    private boolean touched; 

    public Paddle(Bitmap bmp, int x, int y){
        this.bitmap = bmp;
        this.x = x;
        this.y = y;
        this.speed = new Speed();
    }

    public void update(){
        //x+= (speed.getXv() * speed.getxDirection());
    }

    /**
     * takes the bitmap it was instantiated with.
     * Draws it to the canvas at the coordinates the bomb is at in that moment.
     * @param canvas
     */
    public void draw(Canvas canvas){
        //just to make things easier to read
        int halfX = bitmap.getWidth() /2;
        int halfY = bitmap.getHeight() /2;

            canvas.drawBitmap(bitmap, x-halfX, y-halfY, null );

    }

    /**
     * checks if player is touching paddle
     * @param eventx
     * @param eventy
     */
    public void handleActionDown (int eventx, int eventy){
        int extray = 20; //extra height desired so that paddle can be easily touched

        if(eventx >= (x - bitmap.getWidth()/2) && //touch within paddles width
                eventx <= (x + bitmap.getWidth()/2)){

                if ( eventy >= (y - bitmap.getHeight() + extray ) && //within height
                        eventy <= (y + bitmap.getHeight()) + extray ) {

                        setTouched(true);
                } 
                else { setTouched(false); }
        }
        else { setTouched(false); }

    }

    public void onTouchEvents(MotionEvent e, int viewW){
        //DETECT PRESS
        if (e.getAction() == MotionEvent.ACTION_DOWN){
            // delegating event handling to the paddle
            handleActionDown((int)e.getX(), (int)e.getY());
        }
        //MOVE GESTURES
        if (e.getAction() == MotionEvent.ACTION_MOVE){
            if (isTouched()){
                //paddle is being dragged

                //SETTING NEW POSITION
                setX( (int)e.getX() );

                if (getX() - (bitmap.getWidth() /2) <= 0)
                {//Left wall collision
                    setX ( 0 + (bitmap.getWidth() /2));
                }
                if (getX() + (bitmap.getWidth()/2) >= viewW)
                {//right wall collision
                    setX( viewW - (bitmap.getWidth()/2) );                  
                }

            }
        }
        //PRESS RELEASED
        if (e.getAction() == MotionEvent.ACTION_UP){
            if (isTouched()){
                //no longer being dragged
                setTouched(false);
            }
        }
    }

    public Speed getSpeed() {
        return speed;
    }
    public void setSpeed(Speed newSpeed) {
        this.speed = newSpeed;
    }

    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    public Bitmap getBitmap(){
        return bitmap;
    }
    public void setBitmap(Bitmap bmp){
        this.bitmap = bmp;
    }
    public boolean isTouched() {
        return touched;
    }
    public void setTouched(boolean touched) {
        this.touched = touched;
    }
}

So i reckon Sprite.java should look something like this..

package biz.hireholly.pirateponggame;

import android.graphics.Bitmap;
import android.graphics.Canvas;

public class Sprite {
    private Bitmap bitmap;  //image
    private int x;  //x coordinate
    private int y;  //y coordinate

    private Speed speed; //the speed with its directions

    public Bitmap getBitmap(){
        return bitmap;
    }
    public void setBitmap(Bitmap bmp){
        this.bitmap = bmp;
    }
    public int getX(){
        return x;
    }
    public int getY(){
        return y;
    }
    public void setX(int x){
        this.x = x;
    }
    public void setY(int y){
        this.y = y;
    }
    public Speed getSpeed() {
        return speed;
    }
    public void setSpeed(Speed newSpeed) {
        this.speed = newSpeed;
    }


    public void update(){
        x+= (speed.getXv() * speed.getxDirection());
        y+= (speed.getYv() * speed.getyDirection());
    }


    public void draw(Canvas canvas){

        canvas.drawBitmap(bitmap, x-(bitmap.getWidth() /2), y-(bitmap.getHeight() /2), null );

    }

}

i'm trying to separate out a bunch of duplicate code found in my "paddle" and "bomb" classes into a separate class called sprite. What i'm not sure about is handling the member variables currently in my bomb and paddle classes. I want the same variables in both classes for the same uses and reckon they should be moved to my sprite class. But then im not sure about using them in my more specialized Bomb and Paddle classes later on.. i could make them protected but this is where i get confused because that would leave me in a situation where all my more specialized classes are sharing EXACTLY the same variables surely, which i definitely dont want, i just want them to have a copy of those variables.. oh i don't know

They are not sharing the same variables.

abstract class Sprite  { 
    protected Field a;
    protected Field b;
}

class Bomb extends Sprite { 

}

class Paddle extends Sprite { 

}

In the above example, each Bomb instance or Paddle instance you create will have its own a and b . If you did want them to share a field, it would need to be declared static .

Creating a Sprite class is a good step towards the spirit of OOP. You can even go further and have SpecialPaddleSprite and SpecialBombSprite that inherit from Sprite

Once you have that, depending on the situation, you can inherit from Sprite directly or from the special variants. This way you'd be re-using your code in OOP way.

So the class hierarchy might look like

         ------> SpecialPaddleSprite ------> SpecialPaddle
       /
Sprite --------> SpecialBombSprite ------> SpecialBomb
       \
         -------> Paddle
         \
           -------> Bomb

This way if you had more kinds of special Paddles and Bombs, their common behavior can be in SpecialPaddleSprite and SpecialBombSprite

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM