Sign in to follow this  

OpenGL Quick question about 2D scrolling

This topic is 3305 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I am creating a 2D scrolling multiplayer game using OpenGL, somewhat similar to Worms, or even Super Mario Bros. I am relatively new to OpenGL, and had very little experience with it over the years. My question is, for a game like this, do I draw the whole map/level at all times, and adjust the "viewable screen position" as it scrolls along? Could anyone please give me some pseudo-code, or a simple explanation for what the best method to use here is? Thanks,

Share this post


Link to post
Share on other sites
There are lots of approaches and the best method is boils down to the scope of what you are trying to achieve. For a small scale application - you might consider creating a really large background texture and only display a small piece of this at any one time. As the player moves the view(viewport) is moved along with the player - and thus the appearance of scrolling. Its advantages are that is is quick to implement - only requires a change of the texture coordinates. The disadvantage is the large amount of texture memory required to hold the source image.
Also, the source image *may* have to a power of two (unless you know that your target platforms can support non-power of two textures).

Another popular approach is to imagine the 2D surface area that you wish to scroll over as a grid. Each cell in the grid corresponds to a nxm pixel chunk of a texture from one or more texture maps. When ever the player moves you read the list of grid cells that the viewport currently contains and draw the corresponding set of texture cells. The advantage is scalability and re-use. A small set of textures can make a really large 2D scrollable area. The disadvantage is more complex coding required. (But its not really too hard!)

Share this post


Link to post
Share on other sites
Quote:
Original post by BionicBytes
There are lots of approaches and the best method is boils down to the scope of what you are trying to achieve. For a small scale application - you might consider creating a really large background texture and only display a small piece of this at any one time. As the player moves the view(viewport) is moved along with the player - and thus the appearance of scrolling. Its advantages are that is is quick to implement - only requires a change of the texture coordinates. The disadvantage is the large amount of texture memory required to hold the source image.
Also, the source image *may* have to a power of two (unless you know that your target platforms can support non-power of two textures).


This is what I'm looking for, but I can't seem to find much information about it.

I tried this as in example, called every frame:
float f = 0; //global

//every frame:
glViewport(f, 0.0f, 640.0f, 480.0f);
f += 0.5f;


However, it just seems to move the contents of the screen to one side, rather than scroll through my 2D world.

A psudo-code example, or a list of functions I may find helpful would be great.

Thanks,

Share this post


Link to post
Share on other sites
I dont think you want to move the viewport. That should stay constant and match the default framebuffer.

If you go for the super large texture idea, then lets say your texture is 4096x4096 (of course you must query opengl runtime to determine the max size texture and exit gracefully if the value returned does not meet your min spec).

You need to setup a 2D orthographic screen first of all - this is the viewport on which you will view the world.
Next you need to map a portion of the large texture into the visible view area. As a regular texture is always mapped between 0....1 in U and 0...1 in V, you must maintain a data structure that holds the current viewable texture coords.
You will then draw a full screen 2D quad and texture map it to the current viewable texture coordinates.

So pseudo code might be:

Setup Phase
Check for GL support for massive texture - terminate if no support found
Load massive texture - generate a GL texture object
Establish a 2D viewing camera.
Establish a data struct that holds texture coords of viewable texture

Loop:
Get Player Input()
Compute Full Screen Vertex and Texture Coords
Update data struct
bind texture
Issue GL commands for full screen quad and texture coords


// Establish a 2D view
Gl.glMatrixMode(Gl.GL_PROJECTION);
Gl.glLoadIdentity();
Gl.glOrtho(0, _iOSWindowViewport[2], 0, _iOSWindowViewport[3], -1.0f, 1.0f);
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();

// Bind Your texture here
Gl.glEnable (Gl.GL_TEXTURE_2D);
Gl.glBindTexture (Gl.GL_TEXTURE_2D, iTextureID);

// Draw a full screen quad
Gl.glBegin (Gl.GL_QUADS);
Gl.glTexCoord2f (0,0);
Gl.glVertex2f (0,0);
Gl.glTexCoord2f (0,1);
Gl.glVertex2f (0,_iOSWindowViewport[3]);
Gl.glTexCoord2f (1,1);
Gl.glVertex2f (_iOSWindowViewport[2],_iOSWindowViewport[3]);
Gl.glTexCoord2f (1,0);
Gl.glVertex2f (_iOSWindowViewport[2],0);
Gl.glEnd();



You should replace the texture coordinates with the fractional values in your data struct.


Share this post


Link to post
Share on other sites
Look at my game engine. There's the engine itself, an editor and some examples. You can look at the source code to understand the main idea.

Share this post


Link to post
Share on other sites
okay - I've had a look at this editor. All very good stuff.
When you are designing the level using the editor - when the current brush paints a cell on the level - what's happening here. Where is this 'bit' of information stored. Essentially, i'm trying to figure out how you have stored the visual representation the data for the level. I guess this would determine the best strategy for the scrolling aspect.

Share this post


Link to post
Share on other sites
Each level contains several layers (tile layer, collision layer...)

Look at *.bnk files, it's actually xml and binary files in zip files (use WinZip or 7zip). In Levels/Level5.xml (it's a small level) look at the xml tag <tiles> in <layer>. It contains several <row> tags. Each one represents a row in the layer. Each number represent the tile ID.

Share this post


Link to post
Share on other sites
Okay - then this is all you need to do the scrolling.

This type of tile based arrangement is similar to a retro vertical scrolling game i did several years ago. In that game i kept a fixed viewport and 2D ortho-screen and simply draw each tile on the screen.
You need a way to track where in the tile array your current scrolling offset should start from and a way to track your partial scrolled tile offset.
So, for example _fTileFractionOffset might range from 0....31 to represent a fraction of a tile, whilst _iTileOffsetX,_iTileOffsetY might represent the upper left tile of scrolling region.

Each frame:
_fTileFractionOffset ++;
if (_fTileFractionOffset > 31)
{
_fTileFractionOffset = 0 ;
_iTileOffsetX ++;
}

DrawTiles (_iTileOffsetX, _iTileOffsetY)
}

The key thing to remember is that OpenGL will automatically CULL pixels that go outside of the viewport region. That means that the fractional tile will always display correctly - even though the draw code draws a full Quad for the tile.

So, if your upper left corner of the viewport is say (0,0), then you must offset the drawing code by upto -31,-31 (for a 32x32 tile size). That is the x,y coordinates do not necessarily start at 0,0. They will start at - (_fTileFractionOffset) in X or in Y (depending if you want horizontal or vertical scrolling).



Share this post


Link to post
Share on other sites

This topic is 3305 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By xhcao
      Does sync be needed to read texture content after access texture image in compute shader?
      My simple code is as below,
      glUseProgram(program.get());
      glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
      glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
      glDispatchCompute(1, 1, 1);
      // Does sync be needed here?
      glUseProgram(0);
      glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
      glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                     GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
      glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
       
      Compute shader is very simple, imageLoad content from texture[0], and imageStore content to texture[1]. Does need to sync after dispatchCompute?
    • By Jonathan2006
      My question: is it possible to transform multiple angular velocities so that they can be reinserted as one? My research is below:
      // This works quat quaternion1 = GEQuaternionFromAngleRadians(angleRadiansVector1); quat quaternion2 = GEMultiplyQuaternions(quaternion1, GEQuaternionFromAngleRadians(angleRadiansVector2)); quat quaternion3 = GEMultiplyQuaternions(quaternion2, GEQuaternionFromAngleRadians(angleRadiansVector3)); glMultMatrixf(GEMat4FromQuaternion(quaternion3).array); // The first two work fine but not the third. Why? quat quaternion1 = GEQuaternionFromAngleRadians(angleRadiansVector1); vec3 vector1 = GETransformQuaternionAndVector(quaternion1, angularVelocity1); quat quaternion2 = GEQuaternionFromAngleRadians(angleRadiansVector2); vec3 vector2 = GETransformQuaternionAndVector(quaternion2, angularVelocity2); // This doesn't work //quat quaternion3 = GEQuaternionFromAngleRadians(angleRadiansVector3); //vec3 vector3 = GETransformQuaternionAndVector(quaternion3, angularVelocity3); vec3 angleVelocity = GEAddVectors(vector1, vector2); // Does not work: vec3 angleVelocity = GEAddVectors(vector1, GEAddVectors(vector2, vector3)); static vec3 angleRadiansVector; vec3 angularAcceleration = GESetVector(0.0, 0.0, 0.0); // Sending it through one angular velocity later in my motion engine angleVelocity = GEAddVectors(angleVelocity, GEMultiplyVectorAndScalar(angularAcceleration, timeStep)); angleRadiansVector = GEAddVectors(angleRadiansVector, GEMultiplyVectorAndScalar(angleVelocity, timeStep)); glMultMatrixf(GEMat4FromEulerAngle(angleRadiansVector).array); Also how do I combine multiple angularAcceleration variables? Is there an easier way to transform the angular values?
    • By dpadam450
      I have this code below in both my vertex and fragment shader, however when I request glGetUniformLocation("Lights[0].diffuse") or "Lights[0].attenuation", it returns -1. It will only give me a valid uniform location if I actually use the diffuse/attenuation variables in the VERTEX shader. Because I use position in the vertex shader, it always returns a valid uniform location. I've read that I can share uniforms across both vertex and fragment, but I'm confused what this is even compiling to if this is the case.
       
      #define NUM_LIGHTS 2
      struct Light
      {
          vec3 position;
          vec3 diffuse;
          float attenuation;
      };
      uniform Light Lights[NUM_LIGHTS];
       
       
    • By pr033r
      Hello,
      I have a Bachelor project on topic "Implenet 3D Boid's algorithm in OpenGL". All OpenGL issues works fine for me, all rendering etc. But when I started implement the boid's algorithm it was getting worse and worse. I read article (http://natureofcode.com/book/chapter-6-autonomous-agents/) inspirate from another code (here: https://github.com/jyanar/Boids/tree/master/src) but it still doesn't work like in tutorials and videos. For example the main problem: when I apply Cohesion (one of three main laws of boids) it makes some "cycling knot". Second, when some flock touch to another it scary change the coordination or respawn in origin (x: 0, y:0. z:0). Just some streng things. 
      I followed many tutorials, change a try everything but it isn't so smooth, without lags like in another videos. I really need your help. 
      My code (optimalizing branch): https://github.com/pr033r/BachelorProject/tree/Optimalizing
      Exe file (if you want to look) and models folder (for those who will download the sources):
      http://leteckaposta.cz/367190436
      Thanks for any help...

    • By Andrija
      I am currently trying to implement shadow mapping into my project , but although i can render my depth map to the screen and it looks okay , when i sample it with shadowCoords there is no shadow.
      Here is my light space matrix calculation
      mat4x4 lightViewMatrix; vec3 sun_pos = {SUN_OFFSET * the_sun->direction[0], SUN_OFFSET * the_sun->direction[1], SUN_OFFSET * the_sun->direction[2]}; mat4x4_look_at(lightViewMatrix,sun_pos,player->pos,up); mat4x4_mul(lightSpaceMatrix,lightProjMatrix,lightViewMatrix); I will tweak the values for the size and frustum of the shadow map, but for now i just want to draw shadows around the player position
      the_sun->direction is a normalized vector so i multiply it by a constant to get the position.
      player->pos is the camera position in world space
      the light projection matrix is calculated like this:
      mat4x4_ortho(lightProjMatrix,-SHADOW_FAR,SHADOW_FAR,-SHADOW_FAR,SHADOW_FAR,NEAR,SHADOW_FAR); Shadow vertex shader:
      uniform mat4 light_space_matrix; void main() { gl_Position = light_space_matrix * transfMatrix * vec4(position, 1.0f); } Shadow fragment shader:
      out float fragDepth; void main() { fragDepth = gl_FragCoord.z; } I am using deferred rendering so i have all my world positions in the g_positions buffer
      My shadow calculation in the deferred fragment shader:
      float get_shadow_fac(vec4 light_space_pos) { vec3 shadow_coords = light_space_pos.xyz / light_space_pos.w; shadow_coords = shadow_coords * 0.5 + 0.5; float closest_depth = texture(shadow_map, shadow_coords.xy).r; float current_depth = shadow_coords.z; float shadow_fac = 1.0; if(closest_depth < current_depth) shadow_fac = 0.5; return shadow_fac; } I call the function like this:
      get_shadow_fac(light_space_matrix * vec4(position,1.0)); Where position is the value i got from sampling the g_position buffer
      Here is my depth texture (i know it will produce low quality shadows but i just want to get it working for now):
      sorry because of the compression , the black smudges are trees ... https://i.stack.imgur.com/T43aK.jpg
      EDIT: Depth texture attachment:
      glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24,fbo->width,fbo->height,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo->depthTexture, 0);
  • Popular Now