You could have a background sprite of the vertical ladder in two halves as you mentioned and just offset them accordingly and move them as needed to show the player moving.
Figure out the max # of collectibles you will ever need onscreen at one time and then maybe double that amount to allow for them to still be available one screen of "scrolling" away. Create an array to track these.
A common structure might be something like...
#constant COLLECTIBLES_MAX = 127 // 0-indexed so 127= 128items
#constant CKIND_UNDEFINED = -1
#constant CKIND_COIN = 0
#constant CKIND_SOMETHINGELSE = 1
#constant CSTATE_INACTIVE = -1
#constant CSTATE_NORMAL = 0
#constant CSTATE_COLLECT = 1
type TCollectible
kind as integer
state as integer
points as integer
sprite as integer
state as integer
xp as float
yp as float
image as integer
frame as float
stateTimer as float
endtype
global collectibles as TCollectible[COLLECTIBLES_MAX]
// this would be called by your collision checking routine when it loops through the collectible items and checks to see if the player has collected them
// if a collision happens just pass the index value of your loop in so that collectible can be processed as having been collected
function CollectiblesPlayerCollected(index)
// this would call a method you need to write and have available someplace that increments the current score by the value passed in and would update the score value that is displayed onscreen accordingly.
AddToScore(collectibles[index].points)
// any special processing based on the collectible type
select collectibles[index].kind
// anything special you want to do for the coin being collected
case CKIND_COIN
endcase
// anything special you want to do for this other item being collected
case CKIND_SOMETHINGELSE
endcase
endselect
CollectiblesDeactivate(index)
// maybe here you play a sound
// and maybe here you spawn an animation object, points fading out, particles, whatever
endfunction
// called one time only to initialize the array of collectibles
function CollectiblesInit()
i as integer
// just initialize these properties as you want them to be
for i = 0 to COLLECTIBLES_MAX
collectibles[i].sprite = CreateSprite(0)
SetSpriteDepth(collectibles[i].sprite, 3)
SetSpriteTransparency(collectibles[i].sprite, 1)
SetSpriteScale(collectibles[i].sprite, 1, 1)
SetSpriteSize(collectibles[i].sprite, 16, 16)
SetSpriteOffset(collectibles[i].sprite, 8, 15)
CollectiblesDeactivate(i)
next i
endfunction
// called when you need to deactivate all of these such as displaying the title screen, etc.
function CollectiblesDeactivateAll()
i as integer
for i = 0 to COLLECTIBLES_MAX
CollectiblesDeactivate(i)
next i
endfunction
// called each frame passing in the yvel for the collectibles to move (based on the player having moved up or down this frame so you'd handle player movement first before calling this from your main loop)
function CollectiblesUpdate(yvel as float, miny as float, maxy as float)
i as integer
for i = 0 to COLLECTIBLES_MAX
// move the collectible based on its own velocity plus the velocity passed in representing the player moving up or down
Add collectibles[i].yp, collectibles[i].yv + yvel
// check for the collectible moving far enough off screen to be deactivated... upper and lower limits are passed in and probably based on playerYpos - and + a fairly large number
if collectibles[i].yp > maxy
CollectiblesDeactivate(i)
elseif collectibles[i].yp < miny
CollectiblesDeactivate(i)
// update the collectible's sprite position
SetSpritePositionByOffset(collectibles[i].sprite, collectibles[i].xp, collectibles[i].yp)
// collectible is still active so animate it
else
Add collectibles[i].frame, 0.1
if collectibles[i].frame >= NUMBER OF FRAMES OF ANIMATION Then collectibles[i].frame = 0
SetSpriteImage(collectibles[i].sprite, collectibles[i].image + floor(collectibles[i].frame)
endif
next i
endfunction
// called whenever a collectible appears
// example call would be CollectiblesActivate(CKIND_COIN, 100, -20, IMG_COIN)
function CollectiblesActivate(kind as integer, xp as integer, yp as integer, image as integer)
i as integer
// find a free collectible object to use
i = CollectiblesGetIndexOfInactive()
collectibles[i].state = CSTATE_NORMAL
collectibles[i].xp = xp
collectibles[i].yp = yp
collectibles[i].image = image // first image of this collectible item's sequence of images for animation
// if you want the collectibles to fall set initial velocity otherwise set to 0
collectibles[i].yv = 1
// finally set the actual sprite image to display this collectible and then set the sprite visible so it actually appears
SetSpriteImage(collectibles[i].sprite, collectibles[i].image)
SetSpriteVisible(collectibles[i].sprite, 1)
endfunction
// called when you need to get the index of a currently inactive collectible object to reuse to spawn a new collectible
function CollectiblesGetIndexOfInactive()
i as integer
result as integer
result = -1
for i = 0 to COLLECTIBLES_MAX
if collectibles[i].state = CSTATE_INACTIVE
result = i
exit
endif
next i
endfunction result
// this is called anytime a specific collectible item (by index) needs to be deactivated
function CollectiblesDeactivate(i as integer)
collectibles[i].points = 0
collectibles[i].frame = 0
collectibles[i].kind = CKIND_UNDEFINED
collectibles[i].state = CSTATE_INACTIVE
SetSpriteVisible(collectibles[i].sprite, FALSE)
endfunction
Note that code may well have errors in it but that is the gist of how I do things and represents one way you could do this as far as the collectibles management is concerned.
Obviously, you don't need to follow this structure. I just like to modularize things. And this would be in its own code file most likely named CollectibleManager which I basically see as a Collectibles class.
Nothing outside would directly update a collectible and instead would call a method inside this file. Basically encapsulating and isolating everything to do with collectibles to this code.
Hope it helps. If not hey I gave it go. lol
TI/994a (BASIC) -> C64 (BASIC/PASCAL/ASM/Others) -> Amiga (AMOS/BLITZ/ASM/C/Gamesmith) -> DOS (C/C++/Allegro) -> Windows (C++/C#/Monkey X/GL Basic/Unity/Others)