Search code examples
androidsurfaceview

Surface view shows black screen


I was trying to learn surface view and i did read about it.

So , i tried making a game, i thought it would help learn me a bit better.

I created a surface view class which looks like this :

class SnakeEngine extends SurfaceView implements Runnable,View.OnTouchListener {
    private Thread thread = null;
    private Context context;
    private SoundPool soundPool;
    private int eat_bob = -1;
    private int snake_crash = -1;
    private Rect rect2;
    private Rect rect1;
    private boolean snakeHungry=true;
    private boolean runThread=true;

    public enum Heading {UP, RIGHT, DOWN, LEFT}
    private Heading heading = Heading.RIGHT;
    private int screenX;
    private int screenY;
    private int snakeLength=1;

    private float x;
    private float y;
    private float bobX=0;
    private float bobY=0;
    private final int blockSize=40;
    private final int FPS = 10;
    private int score=0;
    private int[] snakeXs;
    private int[] snakeYs;
    private int xSpeed=FPS;
    private int yspeed=FPS;
    private boolean foodOnTable=false;
    private volatile boolean isPlaying=true;
    private SurfaceHolder surfaceHolder;
    private Paint paint;

    public SnakeEngine(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public SnakeEngine(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }

    public SnakeEngine(Context context) {
        super(context);
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = null;
        if (wm != null) {
            display = wm.getDefaultDisplay();
        }
        Point size = new Point();
        if (display != null) {
            display.getSize(size);
        }
        screenX = size.x;
        screenY = size.y;

        surfaceHolder=getHolder();
        setOnTouchListener(this);
        paint=new Paint();
        paint.setColor(Color.GREEN);
        snakeXs=new int[200];
        snakeYs=new int[200];
    }

    @Override
    public void run() {
        while (runThread) {

            try {
                long MILLIS_PER_SECOND = 20;
                Thread.sleep(MILLIS_PER_SECOND);
            } catch (InterruptedException e) {
                e.printStackTrace();
                thread.interrupt();
            }
            if(!surfaceHolder.getSurface().isValid())
                continue;
            Canvas canvas = surfaceHolder.lockCanvas();
            update();
            draw(canvas);
            surfaceHolder.unlockCanvasAndPost(canvas);
        }
    }

    public void resume() {
        thread=new Thread(this);
        thread.start();

    }


    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        canvas.drawColor(Color.argb(255, 26, 128, 182));
        int foodSize = 20;
        canvas.drawRect(x, y, (int) (x + foodSize), y + foodSize, paint);
        for (int i = 0; i < snakeLength; i++) {
            canvas.drawRect(snakeXs[i], snakeYs[i], snakeXs[i] + blockSize, snakeYs[i] + blockSize, paint);
        }
    }


    public void getLocation() {
        Random random = new Random();
        x= random.nextInt(screenX-blockSize);
        y= random.nextInt(screenY-blockSize);
    }

    private void update() {
        Log.e("here","here");
        if(!foodOnTable){
            getLocation();
            foodOnTable=true;
        }

        if(bobX<x && bobY<y && (bobX+blockSize)>x && (bobY+blockSize)>y){
            eatFood();
            getLocation();
            foodOnTable=true;
        }

        bobX+=xSpeed;
        bobY+=yspeed;


        moveSnake((int)bobX,(int)bobY);



        if(bobX+blockSize>=screenX || bobY+blockSize>=screenY ||
                (bobY+FPS<=0 && bobX!=0) || (bobX!=0 && bobY>=screenY) || (bobX==0 && bobY+FPS==0)
                ||(bobX+FPS==0 && bobY==0)|| (bobY!=0 && bobX+FPS<=0)){
            bobX-=xSpeed;
            bobY-=yspeed;
        }

    }

    private void moveSnake(int bobX,int bobY) {
        if (snakeHungry) {
            for (int i = 0; i < snakeLength - 1; i++) {
                snakeXs[i] = snakeXs[i + 1];
                snakeYs[i] = snakeYs[i + 1];
            }
        }else snakeHungry=!snakeHungry;
        snakeXs[snakeLength - 1] = bobX;
        snakeYs[snakeLength - 1] = bobY;
    }

    private void eatFood() {
        snakeLength++;
        snakeHungry=false;
    }

    public void pause() {
        if(thread!=null){
            runThread=false;
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void directSnake(Heading heading){
        switch (heading){
            case UP:
                xSpeed=0;
                yspeed=-FPS;
                break;
            case DOWN:
                xSpeed=0;
                yspeed=FPS;
                break;
            case LEFT:
                xSpeed=-FPS;
                yspeed=0;
                break;
            case RIGHT:
                xSpeed=FPS;
                yspeed=0;
                break;
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int x=(int)event.getX();
        int y=(int)event.getY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:{
                if(heading==Heading.LEFT || heading ==Heading.RIGHT){
                    if(y>(bobY+blockSize)){
                        directSnake(Heading.DOWN);
                        heading=Heading.DOWN;
                    }else {
                        directSnake(Heading.UP);
                        heading=Heading.UP;
                    }
                    break;

                }else if(heading==Heading.DOWN || heading==Heading.UP) {
                    if(x<(bobX+blockSize)){
                        directSnake(Heading.LEFT);
                        heading=Heading.LEFT;

                    }else {
                        directSnake(Heading.RIGHT);
                        heading=Heading.RIGHT;
                    }
                    break;
                }
                break;
            }
        }
        return true;
    }



}

My mainactivity file looks like this:

public class MainActivity extends AppCompatActivity {

    SnakeEngine snakeEngine;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        snakeEngine=new SnakeEngine(this);
        setContentView(R.layout.activity_main);
    }


    @Override
    protected void onResume() {
        super.onResume();
        snakeEngine.resume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        snakeEngine.pause();
    }
}

Layout file:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.snake.tilak.myapplication.MainActivity">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.snake.tilak.myapplication.SnakeEngine
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/surfaceView">
            </com.snake.tilak.myapplication.SnakeEngine>
        <LinearLayout android:id="@+id/linearLayout1" android:layout_width="wrap_content" android:layout_height="wrap_content">
            <ImageButton android:contentDescription="@string/down_button" android:id="@+id/buttonDown" android:background="@mipmap/ic_keyboard_arrow_down_black_24dp" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
            <ImageButton android:contentDescription="@string/up_button"  android:id="@+id/buttonUp" android:background="@mipmap/ic_keyboard_arrow_up_black_24dp" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
            <ImageButton android:contentDescription="@string/left_button" android:id="@+id/buttonLeft" android:background="@mipmap/ic_keyboard_arrow_left_black_24dp" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
            <ImageButton android:contentDescription="@string/right_button"  android:id="@+id/buttonRight" android:background="@mipmap/ic_keyboard_arrow_right_black_24dp" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
        </LinearLayout>
    </FrameLayout>
</android.support.constraint.ConstraintLayout>

Now when i run it, all i see is a black screen?

Where did i go wrong ? what should i change in it?

I read various questions here on this topic and can't seem to make anything working.


Solution

  • That's because you trying to instantiate new SnakeEngine, but you should find an instance of it by id because you already add it to XML file:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // snakeEngine = new SnakeEngine(this);
        setContentView(R.layout.activity_main);
        snakeEngine = findViewById(R.id.surfaceView);
    }
    

    Then, when you will fix it, you should move all your initiating logic from public SnakeEngine(Context context) constructor to separate method and call it from each constructor of SnakeEngine:

    public SnakeEngine(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
    public SnakeEngine(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }
    
    public SnakeEngine(Context context) {
        super(context);
        init(context);
    }
    
    private void init(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = null;
        if (wm != null) {
            display = wm.getDefaultDisplay();
        }
        Point size = new Point();
        if (display != null) {
            display.getSize(size);
        }
        screenX = size.x;
        screenY = size.y;
    
        surfaceHolder = getHolder();
        setOnTouchListener(this);
        paint = new Paint();
        paint.setColor(Color.GREEN);
        snakeXs = new int[200];
        snakeYs = new int[200];
    }