Android openGL ES 2.0 scene scrolling

2020-05-07 18:31发布

问题:

I'm working on a simple game for android using openGL es 2.0. Game will be in 2D, something like old supermario, where player can move left-right/up-down but no depth.

Level will be larger than screen, so graphics will have to scroll. Here is where the problem comes. I don't know where/when to stop scrolling.

Example. Lets say that background is 100x100 sized square with texture. Lets say that on screen there is only 1/4 of the background visible at any time. When I then move screen to the right, I would like it to stop scrolling when right edge of background comes at the edge of the screen.

The best I can do now, is to stop scrolling when center of "view" is at the edge of background. But this isn't good, because 3/4 of the screen are than blank.

How can I calculate this "offset" from center of view to edge of screen?

Note: I don't want to use orthographic projection.

Here is code of renderer.

package com.huntedseas;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.Matrix;
import android.util.Log;


public class GameRenderer implements Renderer {
    protected LevelGenerator generator;
    protected SquareGL squareGL;

    protected static float angleX;
    protected static float angleY;
    protected static float angleZ;
    protected static float viewX = 0;
    protected static float viewY = 0;
    //private float viewZ = 0;

    private float[] mProjectionMatrix = new float[16]; //Projekcijska matrika
    private float[] mVMatrix = new float[16];
    private float[] mMVPMatrix = new float[16];

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig conunused) {
        GLES20.glClearColor(1.0f,1.0f,1.0f,1.0f);

        GLES20.glDisable(GLES20.GL_CULL_FACE); //No culling of back faces  \\ To nevem al je treba da je uklopljeno al ne
        GLES20.glDisable(GLES20.GL_DEPTH_TEST); //No depth testing          \\  --||--
        GLES20.glEnable(GLES20.GL_BLEND); //Blending
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA,GLES20.GL_ONE_MINUS_SRC_ALPHA); //Interpolated blending

        generator = new LevelGenerator();
    }

    @Override
    public void onDrawFrame(GL10 unused) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        moveView();
        Matrix.setLookAtM(mVMatrix, 0, viewY, viewX, -10, viewY, viewX, 0, 0.0f, 1.0f, 0.0f); //set view
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mVMatrix, 0); //calculate view transformation

        generator.draw(mMVPMatrix);     
    }

    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        float ratio = (float) width/height;
        float left =-ratio;
        float right = ratio;
        float bottom = -1.0f;
        float top = 1.0f;
        float near = 1.0f;
        float far = 20.0f;      
        Log.d("ratio","ratio: "+left+"  r: "+right+"  w: "+width+"  h: "+height);
        Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);

    }

    long lastTime = System.currentTimeMillis();
    public void moveView(){
        if((System.currentTimeMillis()-lastTime) >= 33){
            lastTime = System.currentTimeMillis();
            Log.d("viewX","viewX: "+viewX + "viewY:"+viewY);
            if( (viewX - angleX/10) < Level1.viewXP && (viewX - angleX/10) > Level1.viewXM) viewX -= angleX/10; 
            if( (viewY - angleY/10) < Level1.viewYP && (viewY - angleY/10) > Level1.viewYM) viewY -= angleY/10;

            //if(Math.abs(viewX - angleX/10) < 10) viewX-=angleX/10;
            //if(Math.abs(viewY - angleY/10) < 10) viewY-=angleY/10;
            //if(Math.abs(viewZ - (angleZ-5)/10) < 10) viewZ+=(angleZ-5)/10;
        }
    }


}

回答1:

I've solved this by modifying parameters for Matrix.frustumM so they represent FOV. Than when you know angle from middle to side, you can calculate offset with tangens function.

 GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width/height;
    float near = 1.0f;
    float far = 150.0f;
    float fov = 80;
    float top = (float) (Math.tan(fov * Math.PI / 360.0f) * near);
    float bottom = -top;
    float left = ratio * bottom;
    float right = ratio * top;

    offsetY = (float) (Math.tan(Math.PI/180*fov/2) * Math.abs(cameraAway));
    offsetX = offsetY * ratio; //because we know ratio between x and y

    Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);

You can also use Matrix.perspectivM(), but it is only avaliable for api 14+.