• Godot Help2D
  • Arcade style scrolling background for "shoot em up"

Hey, i got stuck at trying to find solution how to make stage for my project the thing i am aiming is to have nice vertically scrolling backgrounds, all tutorials i find just shows very basic thing for infinity scrolling. So i cant figure way out how to make more advanced things like for example, after you are halfway stage background changes from just clouds but now you are over the ocean, you encounter "mid boss" and background dynamically changes to "infinite" scrolling until you defeat him. I have few ideas how to do it (instancing scenes with extra layers to hide transition) but all of my "ideas" feel like workarounds and not scalable. If somebody encounter similar "problems" maybe you could give an advice.

I hope i was able to convey my question

As for result i am aiming is something like DoDonPachi and similar arcade "shmups"

  • I have been working on a vertically scrolling shooting game in Godot for a few months and learned a few things that may help you:

    The way my scrolling works is that the background along with ground enemies are (sub)children to a node that moves down the screen. This allows for things such as player movement and enemy behavior to use their global_position with screen coordinates; e.g:

    extends Pseudocode2D #not checked for errors
    
    Player_Character = $Player_Node2D
    _Scroll_Node = $Scroll_Node2D
    _Enemy_NPC = _Scroll_Node.get_child("Enemy_Node2D")
    _Background_Node = _Scroll_Node.get_child("Background_Tilemap")
    
    const SCREEN_SIZE : Vector2 = Vector2(240,320) #vertical aspect ratio
    var _Stop_Scroll_for_Boss : bool = false
    
    func _process(delta):
    	if _Stop_Scroll_for_Boss == false:	
    		_Scroll_Node.position.y += delta #scrolls screen down 
    	#^ remember: larger y values are further down the screen in godot
    
    		#Move character inside the screen using global coords:
    	var _Player_Translation = Input.get_vector("left","right","up","down") * Vector2(delta,delta) #idk off the top of my head if get_vector is normalized or not. if it isn't; add .normalized() to Input,get_vector()
    	Player_Character.global_position = clamp(Player_Character.global_position + Input.Controller_Vector, Vector2.ZERO, SCREEN_SIZE) 
    		# ^ in practice, you'll probably want to add some 'cushion pixels' to the clamp for game feel		
    
    		#Make an enemy change state right before it scrolls onto the screen:
    	if _Enemy_NPC.global_position.y > -10:
    		_Enemy_NPC._do_enemy_activate_function()
    		
    	if _Enemy_NPC.is_a_boss == true and _Enemy_NPC.global_position > 40: #stop the scroll when the boss is 40px from the top of the screen
    		_Enemy_NPC.emit_signal("Scroll_Stop_Signal") #imply signal is connected to this script
    
    		#Seal enemies from shooting when offscreen:	
    	if _Enemy_NPC.global_position != clamp(_Enemy_NPC.global_position, Vector2.ZERO, SCREEN_SIZE):
    		_Enemy_NPC.can_shoot = false
    		# ^ again, for game feel, you'll probably want to add some cushion pixels to this clamp
    
    func Scroll_Stop_Signal():
    	_Stop_Scroll_for_Boss = true

    In a way this is 'backwards': the whole world moves down instead of the player and camera moving up, but it really should be considered for an arcade autoscroller. I'm certainly open to any better ideas if anyone has any.

    Also, in my game I also have some side to side horizontal scrolling. This X position is determined by the player's global_position divided by some_number. All bullets should move independently of the vertical scrolling, but SHOULD move with horizontal scrolling, if you choose to have it (not a necessary mechanic)

    Hope this helps

a month later

I have been working on a vertically scrolling shooting game in Godot for a few months and learned a few things that may help you:

The way my scrolling works is that the background along with ground enemies are (sub)children to a node that moves down the screen. This allows for things such as player movement and enemy behavior to use their global_position with screen coordinates; e.g:

extends Pseudocode2D #not checked for errors

Player_Character = $Player_Node2D
_Scroll_Node = $Scroll_Node2D
_Enemy_NPC = _Scroll_Node.get_child("Enemy_Node2D")
_Background_Node = _Scroll_Node.get_child("Background_Tilemap")

const SCREEN_SIZE : Vector2 = Vector2(240,320) #vertical aspect ratio
var _Stop_Scroll_for_Boss : bool = false

func _process(delta):
	if _Stop_Scroll_for_Boss == false:	
		_Scroll_Node.position.y += delta #scrolls screen down 
	#^ remember: larger y values are further down the screen in godot

		#Move character inside the screen using global coords:
	var _Player_Translation = Input.get_vector("left","right","up","down") * Vector2(delta,delta) #idk off the top of my head if get_vector is normalized or not. if it isn't; add .normalized() to Input,get_vector()
	Player_Character.global_position = clamp(Player_Character.global_position + Input.Controller_Vector, Vector2.ZERO, SCREEN_SIZE) 
		# ^ in practice, you'll probably want to add some 'cushion pixels' to the clamp for game feel		

		#Make an enemy change state right before it scrolls onto the screen:
	if _Enemy_NPC.global_position.y > -10:
		_Enemy_NPC._do_enemy_activate_function()
		
	if _Enemy_NPC.is_a_boss == true and _Enemy_NPC.global_position > 40: #stop the scroll when the boss is 40px from the top of the screen
		_Enemy_NPC.emit_signal("Scroll_Stop_Signal") #imply signal is connected to this script

		#Seal enemies from shooting when offscreen:	
	if _Enemy_NPC.global_position != clamp(_Enemy_NPC.global_position, Vector2.ZERO, SCREEN_SIZE):
		_Enemy_NPC.can_shoot = false
		# ^ again, for game feel, you'll probably want to add some cushion pixels to this clamp

func Scroll_Stop_Signal():
	_Stop_Scroll_for_Boss = true

In a way this is 'backwards': the whole world moves down instead of the player and camera moving up, but it really should be considered for an arcade autoscroller. I'm certainly open to any better ideas if anyone has any.

Also, in my game I also have some side to side horizontal scrolling. This X position is determined by the player's global_position divided by some_number. All bullets should move independently of the vertical scrolling, but SHOULD move with horizontal scrolling, if you choose to have it (not a necessary mechanic)

Hope this helps

    5 days later

    Verticen your game has great "Strikers 1945" vibe looks really cool and in few months wow
    As of designing game. Yes i also trying to move "all world" down on y axis idk if its the right way but as you mentioned seems logical for arcade style shmup. I will definitely try to implement some ideas from your example. As of scrolling horizontal i kinda had it working very early on but i had problem with clamping camera and player so at this stage i abandon the idea. Cause "struggling" with coding my progress is very slow 😃

    this is video from some older "build"