Games Old-school Parallax Scrolling

Discussion in 'Game Development' started by wonder, Aug 28, 2017.

  1. wonder

    wonder Expert Licensed User

    In the 8-bit era, most videogame consoles weren't powerful enough to support multiple background layers.
    Using a single layer, however, it would be possible to create such an illusion. :)

    Here's a small B4J implementation of the concept:
    upload_2017-8-28_6-29-15.png

    More on the subject:
    [​IMG]
    http://www.dustmop.io/blog/2015/12/18/nes-graphics-part-3/
     

    Attached Files:

    Last edited: Aug 28, 2017
    ThRuST, sorex, Ohanian and 2 others like this.
  2. sorex

    sorex Expert Licensed User

    nice example for those who would like to learn about making games.

    actually you're creating multiple (fake) layers yourself. ;)

    the nes one looks impressive altho it's just 9 splits with different scrollings speeds and map offsets.

    the more complex parallax does parallax in the same layer by shifting tileset elements.

    a really good example that comes in mind is Flimbo's Quest (c64 '90?) altho the first usage of this trick was done years before tho
    but with single char tiles or small multi char ones (Parallax (c64 '86) etc).
    The benefit here is that you don't lose sprites nor need tricky timed splits.
     
  3. wonder

    wonder Expert Licensed User

    Well, by single layer, I meant using only one bitmap. :)

    Yeah, I always thought this looks amazing on the NES! Good memories!!!
     
  4. Informatix

    Informatix Expert Licensed User

    Ah OK, because the game in the vidéo of your post #1 uses at least two layers.
    Using regions from a single bitmap is very common (sprite sheets and atlas are based on the concept).

    By the way, if you want to write much less code and get a smoother result, try SimpleGameEngine.
     
    wonder likes this.
  5. Informatix

    Informatix Expert Licensed User

    The same thing coded with SGE:
    Code:
    Sub Process_Globals
       
    Private fx As JFX
       
    Private MainForm As Form
       
       
    Dim SGE As SGE

       
    Dim Background As Image
       
    Dim Regions(3As sgeRegion
       
    Dim Actors(6As sgeActor
    End Sub

    Sub AppStart (Form1 As Form, Args() As String)
       MainForm = Form1   
       MainForm.Show

       SGE.Initialize(
    "SGE"10)
       MainForm.RootPane.AddNode(SGE, 
    00, MainForm.Width, MainForm.Height)   

       Background.Initialize(
    File.DirAssets, "test1.png")
       Regions(
    0).Initialize(Background, 00, Background.Width, 90)
       Regions(
    1).Initialize(Background, 090, Background.Width, 96)
       Regions(
    2).Initialize(Background, 090+96, Background.Width, 220)

       
    For i = 0 To 2
         Actors(i).InitializeWithRegion(Regions(i), SGE.Root, 
    "")
         Actors(i + 
    3).InitializeWithRegion(Regions(i), SGE.Root, "")
         
    If i > 0 Then
           Actors(i).Y = Regions(i - 
    1).Y + Regions(i - 1).Height
           Actors(i + 
    3).Y = Regions(i - 1).Y + Regions(i - 1).Height
         
    End If
         Actors(i + 
    3).X = Background.Width
       
    Next

       SGE.Camera.CenterOn(SGE.Width / 
    2, SGE.Height / 2)
       SGE.StartLoop
    End Sub

    Sub SGE_Update(ElapsedSinceLastFrame As Double)
       
    Dim MoveAmount(3As Double
       MoveAmount(
    0) = 0.15 * ElapsedSinceLastFrame
       MoveAmount(
    1) = 0.1 * ElapsedSinceLastFrame
       MoveAmount(
    2) = 0.6 * ElapsedSinceLastFrame
       
    For i = 0 To 2
         Actors(i).X = Actors(i).X - MoveAmount(i)
         Actors(i + 
    3).X = Actors(i + 3).X - MoveAmount(i)
         
    If Actors(i).X <= -Background.Width Then
           Actors(i).X = Actors(i + 
    3).X + Background.Width
         
    End If
         
    If Actors(i + 3).X <= -Background.Width Then
           Actors(i + 
    3).X = Actors(i).X + Background.Width
         
    End If
       
    Next
    End Sub

    Sub SGE_Render(ElapsedSinceLastFrame As Double)
       SGE.Graphics.Clear
       SGE.Root.Draw
    End Sub
     

    Attached Files:

    wonder and ilan like this.
  6. ilan

    ilan Expert Licensed User

    and now with iSpriteKit :)



    Code:

    Code:
    Sub createBackground(myScence As SKScene)
        
    'first create Sky
        Dim sky As SKSpriteNode
        sky.Initialize(
    "")
        sky.SpriteNodeWithImageNamed(
    "sky")
        sky.Size = myScence.Size
        sky.Position = Functions.CreatePoint(vpW/
    2,vpH/2)
        myScence.AddChild(sky)

        
    'create clouds
        paralexBackLayer(myScence,"clouds",0.12)

        
    'create mountains
        paralexBackLayer(myScence,"mountains",0.16)

        
    'create trees
        paralexBackLayer(myScence,"trees",0.06)
    End Sub

    Sub paralexBackLayer(myScene As SKScene, spritename As String, speed As Float)
        
    Dim MoveGroundSprite As SKAction
        MoveGroundSprite.Initialize
        MoveGroundSprite.MoveByX(-vpW,
    0,speed*vpW)

        
    Dim ResetGroundSprite As SKAction
        ResetGroundSprite.Initialize
        ResetGroundSprite.MoveByX(vpW,
    0,0)

        
    Dim GroundActions As SKAction
        GroundActions.Initialize
        GroundActions.Sequence(
    Array(MoveGroundSprite,ResetGroundSprite))

        
    Dim MoveGroundSpritesForever As SKAction
        MoveGroundSpritesForever.Initialize
        MoveGroundSpritesForever.RepeatActionForever(GroundActions)

        
    For i = 0 To 2 + GameScene.Frame.Width/vpW
            
    Dim Background As SKSpriteNode
            Background.Initialize(
    "")
            Background.SpriteNodeWithImageNamed(spritename)
            Background.Size = Functions.CreateSize(vpW,vpH)
            Background.Position = Functions.CreatePoint(i * Background.Size.Width,Background.Size.Height/
    2)
            Background.RunAction(MoveGroundSpritesForever)
            myScene.AddChild(Background)
        
    Next
    End Sub
    Create:

    Code:
    createBackground(GameScene) 'Create Parallax Scrolling
    btw. there is no Render.Call in iSpriteKit. you create all your Nodes once and add actions to them. then you just add them to your Scene and they will run until you remove them from your scene. simple :)
     
    Last edited: Aug 29, 2017
    DonManfred likes this.
  7. ilan

    ilan Expert Licensed User

    Btw i like more the effect where he picks up the power and background change to dark.

    This little things make those game special. I would never thought about such an effect (change back when pick up power).

    I like it. Can you tell me the name of the game?
     
  8. Informatix

    Informatix Expert Licensed User

    It seems that you use four different images in your code. It's not what's done in the B4J code above. Wonder wanted to demonstrate how you can use a single image to create the illusion of multiple background layers, moving independently. If you use different images, there's no trick.
     
  9. ilan

    ilan Expert Licensed User

    How is this possible ?? :confused:
     
  10. ilan

    ilan Expert Licensed User

    Do you render parts of an image with different speed like loading parts from atlas file and create textures of them and render with different speed?
     
  11. Informatix

    Informatix Expert Licensed User

    By using regions. If you use atlas with libgdx, you're already familiar with the concept. You load a single texture in memory and you draw different parts of it.
     
  12. Informatix

    Informatix Expert Licensed User

    Yes. You create regions.
     
  13. ilan

    ilan Expert Licensed User

    Ok so the only benefits would be to have a smaller app size? Because instead of having 20-30 images you have one and load regions from it to a texture correct?

    Is there any other benefit?
     
  14. Informatix

    Informatix Expert Licensed User

    It's a lot faster for your GPU because it loads only one texture and does not have to switch constantly between textures when it renders the scene.
     
    ilan likes this.
  15. ilan

    ilan Expert Licensed User

    ok thank you very much this is a very important info :)
     
  16. Informatix

    Informatix Expert Licensed User

    A GPU has a limited number of texture units. In libGDX, only two of them are used if I remember well (0 and 1).
    It's also recommended to use textures sized with a power of 2 because that helps a lot the GPU (no fraction, no rounding, no special handling).
     
    ilan likes this.
  17. ilan

    ilan Expert Licensed User

    Sorry but what does it means?

    I use a lot textures in my game (pixel knight) and i never had a problem rendering them.

    I did have problems if i used a to large spritesheet and tried to split it to regions and render it. If it was to big i get an error. (Memory related i think)

    Is there a limited number of different images i can draw in a render cycle?
     
  18. Informatix

    Informatix Expert Licensed User

    Yes, there's a limited number of meshes (which are the objects using textures that you render) in libgdx. But it's above 5000 if I remember well and you're unlikely to reach such a limit. libGDX is fast and our Android devices are optimized for OpenGL so we don't have to worry about these things except in some cases (my game Diktatour was one of these cases because of the heavy number of different sprites and animations at once on screen). When you start counting your assets by hundreds, then it's probably time to use an atlas instead of individual files. If your sprites are very big, you can also see a difference.
    For your opaque images (e.g backgrounds), you can improve dramatically the speed of your rendering in libGDX by using the KTX format instead of Jpeg. A demo proves the huge difference.

    Anyway, a texture should not be bigger than 2048x2048 to be compatible with all devices. Note that an atlas can contain more than one page.
     
    ilan likes this.
  19. wonder

    wonder Expert Licensed User

    It looks RETROASTICALLY-COOL!!!!! :D
     
    ilan and Informatix like this.
  20. sorex

    sorex Expert Licensed User

    it only works as-is because the sky is a single gradient stretched over the entire width.

    put a sun there and he is forced to seperate the clouds from the image :)
    (unless the sun is a seperate sprite and drawn before the clouds)
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice