Newbie Side Scrolling Question

As was mentioned in one of my earlier threads, I am developing a typical side scroller game in the theme of Fly With Me to keep a glider aloft with a tap on the screen. I am using juaxix’s Sprint Animal example code as a starting point, editing as I go along to get the results that I need. Again, thank you very much juaxix for providing this most helpful code and to West for the character animation example code.

My question is instead of random backgrounds and collectible objects, how would one go about incorporating pre-drawn elements? I’m not looking for code per se but a nod in the right direction would be much appreciated. Is this a good time to use tables and if so, what would be the best way to use them?

How big should the background images be in order to preserve frame rate? Is a complete screen size graphic too large or should it be broken up into several image files per screen and deleted as they roll off screen? I want to use parallax scrolling for extra eye candy (I looked at an example using parallax scrolling that I have found here but a forum search did not turn up the code or the author, sorry) and wondered how the extra graphics will come in to play.

Searching the forum, I have read conflicting reports whether off screen graphics are culled or maybe not. Perhaps I missed the decision but could someone provide a definitive answer? Two of my three splash screens are full screen and I would like to know if they should somehow be removed from memory and if so how?

Again, this project will probably never get to the app store as this is only a very fulfilling hobby to help keep my old mind ticking and to see the immediate benefits on the iPad via Codea.

If my posts are too drawn out please let me know and I will certainly contract my questions. I do not want to be a burden to this great forum by no means.

Any help would be much appreciated.

Thanks in advance for those who may reply.

I don’t think there is necessarily a right or wrong answer, it just depends what you are trying to do.

In terms of your splash screens, provided you are only calling one of them at a time from your main draw function it shouldn’t matter.

I’m guessing the size of your sprites shouldn’t matter either too much as long as you don’t have too much overlap.

The other consideration is how much storage space is used. Back in the olden days this was at a premium so smaller reusable blocks were used to make big maps. This is also an advantage that your playing area can be customised from the program rather than being hard wired into a big static image

Here is the simple demo of parallax scrolling I suggested in an earlier thread (http://twolivesleft.com/Codea/Talk/discussion/comment/9020#Comment_9020) but I’ve stretched a sprite as the background. I’ve also added a simple array/table to control the sprite used in the ground. This could be expanded to a longer array and you could track the location within the array so you only generate the sprites that appear in the visible area.

-- Use this function to perform your initial setup
function setup()
    xpos=0
    grass={1,1,0,0,0,1,1,0,0,0}
end

-- This function gets called once every frame
function draw()

sprite("SpaceCute:Background",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)

    for i = 1,40 do
       sprite("Small World:Tree Round Dark", xpos/4+ 25*i-100, 90,40,50) 
    end  
        
    for i = 1,20 do
       sprite("Small World:Tree Round", xpos/2+ 50*i-100, 60,60,70) 
    end
        
    for i = 1,10 do
        if grass[i]==1 then
            sprite("Planet Cute:Grass Block", xpos+101*i-100, 0)
        else
            sprite("Planet Cute:Brown Block", xpos+101*i-100, 0)
        end
    end
    xpos=xpos-1
    --need to reset xpos at an appropriate point to get wraparound
end

Finally, meshes rather than sprites might be the way to go as I think they’ll give you better performance but I’ve not looked into them in much detail.

Thanks for your thoughts, West. I thought about meshes as well but like you, haven’t spent much time with them yet. I’ll try a few things and see how they work out.

Yes, this is the parallax example I was referring to that did not turn up in my forum search. Perhaps I misspelled it. Anyway, I liked it then and also how you added the new wraparound functionality. Thanks.

Uhm, i think it would be nice to create some kind of running time ground generation algorithm , such like we are talking in this post:

I’m coding the processing game in which Tiny Wings is based (Wave Spark : http://nmccoy.net/games/game04_wavespark/applet/index.html ) , I’m submiting the code here:
https://gist.github.com/3123491
and i need help to make it real :slight_smile:
Can you help me @Keebo?
Stoling your post like a boss XD

@juaxix, I would be glad to help in any way that I can if you are serious. Being a newb with Codea/Lua, I don’t how much help I can provide but it will be a great learning experience. Plus I think a successful ground generator would be quite useful for everyone interested in this type of function.

Cutting and pasting to follow.

Thanks for all of your contributions.

@Keebo
Your post got me thinking so I put together a simple side scroller along the lines of the “helicopter game”. It’s super basic and not as smooth as I’d like so the next stage is to try out some meshes but meanwhile here is the code.

-- Use this function to perform your initial setup
function setup()
   displayMode(FULLSCREEN)
    --gameState is the current state of play
    -- 0 is the splash screen
    -- 1 is normal gameplay
    -- 2 is gameover
    gameState=0
end

-- This function gets called once every frame
function draw()
--One if statement checks what game state we are currently in and executes the relevant code
if gameState==0 then
    --Draw the splash screen
    background(0,0,0,255)
    font("AmericanTypewriter-Bold")
    fontSize(40)
    --Set up a title
    text("Sideways Scroller Demo",WIDTH/2,HEIGHT/2)
    fontSize(25)
    --add your name
    text("by West",WIDTH/2,HEIGHT/2-50)
    --Draw a start button
    fill(127, 220, 23, 255)
    ellipse(WIDTH/2,HEIGHT/2-200,100)
    stroke(220, 217, 172, 255)
    fill(223, 230, 222, 255)
    fontSize(50)
    text("Go",WIDTH/2,HEIGHT/2-200)
    --Calculate the distance of the edge away from the centre of the button
    dist=math.sqrt(((CurrentTouch.x-WIDTH/2)^2)+((CurrentTouch.y-(HEIGHT/2)+200))^2)
    --check to see if the user has touched the button
    if CurrentTouch.state==ENDED and dist<50 then
        --put into the play game state
        gameState=1
        --Initialise some variables
        xpos=0 --used for the movement of the background
        speed=5 --initial speed
        speedCounter=0 --a counter to increment the speed
        speedMax=200 --the value at which the speed will increment
        topSpeed=50 --the top speed
        upthrust=0 --the upward force applied to the hero character
        herovel=0 --the vertical velocity of the hero character
        herox=100 --the horizontal position of the hero
        heroy=HEIGHT/2  -- the vertical position of the hero
        --an array of height values for the ground
        --add more values into the array to create a longer level
        ground={3,3,3,3,3,4,3,2,1,1,1,1,2,2,3,4,4,3,3,4,4,4,4,5,4,3}
        --an array of height values for the ceiling
        --make sure that the two arrays are the same length
          roof={3,3,2,3,4,4,5,6,7,6,6,5,4,4,4,3,2,3,4,5,6,5,5,4,3,2}   
        t=0.1 -- a time variable used to calculate the position and velocity between frames
        acc=0  --an acceleration variable calculated each frame
        grav=-10 --a constant gravitational force
        score=0  --the current score
        restartwait=0 --a timer for restarting the game at the end
    end           

elseif gameState==1 then
--Stretch an sprite to fill the background
--As this is the furthest away thing draw first and everything else will be drawn on top
    sprite("SpaceCute:Background",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)

--the screen in landscape will allow 12 sprites with a width of 100 to be drawn
--try reducing the second number to 10 to see the effect (make sure you hold in landcsape)    
    for i = 1,12 do
--the value in the current position (i) of the ground array is the number of blocks high to 
--draw at the current position
        for h=1,ground[i] do
            --draw the sprite at the current x position i * width of one sprite with the xpos
            --offset which creates the movement
            --the y position is calculated as a multiplier of the the height
            sprite("Planet Cute:Ramp South",xpos+100*i-100,-40+70*h,100,100)
        end       
        --repeat the process for the ceiling
        for h=1,roof[i] do
            sprite("Planet Cute:Ramp South",xpos+100*i-100,HEIGHT+50-70*h,100,100)
        end           
    end

--Display the hero sprite
    sprite("Planet Cute:Enemy Bug",herox,heroy,110,160)

--Simple version with no gravity, touch above the hero sprite to move up and below to move down
--handle a touch input from the user     
    if CurrentTouch.state == MOVING or CurrentTouch.state== BEGAN then
    if CurrentTouch.y > heroy then
          heroy = heroy + 3
        elseif CurrentTouch.y<heroy then
            heroy = heroy - 3
      end      
    end
--Gravity based version, touch anywhere to provide upthrust to counter gravity
   -- if CurrentTouch.state == MOVING or CurrentTouch.state== BEGAN then    
   --     upthrust = upthrust + speed/2
   --     if upthrust>20 then
   --         upthrust=20
   --     end
   -- end
   -- if CurrentTouch.state==ENDED then
   --     upthrust=0
   -- end
   -- acc=upthrust+grav
--equation of motion to calculate the displacement in the y direction s=ut+0.5at*t
   -- heroy=heroy+herovel*t+0.5*acc*t*t
--equation of motion for the new velocity v=u+at
   -- herovel=herovel+acc*t
    
--stop the sprite going off the top of the screen
--redundant here, but if you wanted to have a narrower field of play then this what you would use
--try replacing both HEIGHT with HEIGHT/1.5 to try it out
    if heroy>HEIGHT then
        heroy=HEIGHT
    end
    if heroy<0 then
        heroy=0
    end
--dealing with collisions
--normally we would have to check to see if the hero has hit anything on the screen
--however as we are restricting the movement to up and down only then we only 
--need to check the sprites in the same vertical location
    if heroy<(-40+70*(ground[2]+1)) then
        gameState=2
    end
    if heroy>(HEIGHT+70-70*(roof[2]+1)) then
        gameState=2
    end
    
--xpos is a variable used to control the position of the sprites on the screen
--the variable speed determines how much each sprite is moved each time the screen is redrawn
    xpos=xpos-speed
--score is based on distance travelled
    score = score + speed
    fill(255, 255, 255, 255)
    text("Score: "..score,WIDTH/2,HEIGHT-30)
--need to reset xpos at an appropriate point to get wraparound
    if xpos<-100 then
        xpos=0
--store the value of the current first element of the array   
--for example, for the array {a,b,c,d} store the first element a in the variable temp
        temp=ground[1]
        tempr=roof[1]
--shift the ground array along by one, overwriting the first element by the second element,
--the second element by the third element, etc, etc
--Note the last element is not overwritten yet
-- {a,b,c,d} becomes {b,c,d,d}
        for c=1,#ground-1 do
            ground[c]=ground[c+1]
            roof[c]=roof[c+1]
        end
--Move the previously saved first element (saved in the temp variable)to the last position
--{b,c,d,d} becomes {b,c,d,a}
        ground[#ground]=temp
        roof[#roof]=tempr
    end
--get faster over time
    speedCounter = speedCounter + 1
    if speedCounter>speedMax then
        speed=speed+1
        speedCounter=0
--set an upper limit on the speed
        if speed>topSpeed then
            speed=topSpeed
        end
    end 
--game over state       
elseif gameState==2 then   
    background(96, 77, 77, 255)   
    text("Game over",WIDTH/2,HEIGHT/2)
    text("Score:  "..score,WIDTH/2,HEIGHT/2-50)
--add a delay to stop overspill from the gameplay restarting the game instantly
    if restartwait>100 then
          text("Tap screen to restart",WIDTH/2,HEIGHT/2-100)
    end    
    if CurrentTouch.state==BEGAN and restartwait>100 then
        gameState=0
    end
    restartwait = restartwait + 1
end    
        
end

Was messing about with it further. Using meshes does make it significantly smoother and faster

@West, this is very cool. I really like how you are not shy with commented lines. That really helps to understand what is going on in the code.

I was amazed at the speed increase with meshes in your example in the other thread as well. Keep up the great work.

Thanks again for sharing your knowledge.

No worries. Glad it was of help :slight_smile: