First of all, it is assumed that everyone has a certain understanding of the Godot engine and knows the basic operations. If not, you can refer to the tutorials on the official website for a general understanding. As for flappyBird, I used cocos2DX to make a demo when I was in college. After graduation, I learned about godot engine and wanted to use this engine to make flappyBird. In 2017, I made one by referring to others’ tutorial, which was of course rather rough (it can be found below). I recently reworked the engine with a 3.0 + version to familiarize myself with the engine. For the beginning of the production of the game, we should first determine the size of the screen, which is determined according to the size of the material, such as the resolution. The game FlappyBird is a simple vertical screen display, and the size of 144×256 is determined according to the material of others. It would be nice to have a higher resolution picture. After determining the screen size, the engineering structure can be set up,

This division is based on the functionality of the engine. Godot’s development approach is based on the scene tree, where scripts can be added to each node, scenes can be spliced together, and different folders can be used to better distinguish them. Start by building a welcome interface. Some of the nodes of the start interface are spliced together from other scenes. In this interface, titles and buttons can be generated using UI nodes.

Use node2D for the root node, Sprite for the background and title, HBoxContainer for the button and TextureButton for the button, refer to the instructions in my project and website or doc for details. Button click events are bound to the signal, which can be set directly in the editor or manually linked in the script. For the ground, it can be moved. In order to look like continuous movement, just add one piece outside the screen, then move it together, and change the X coordinate to the right side of the screen. The implementation is as follows:

The ground root uses StaticBody2D mainly to increase collision feedback. It needs to add a shape, which is set to the same size as the image, adding a script to increase movement

In this script, the ground is controlled by the way of state. The state is determined according to ourselves. When the state is different, it can move or stop. There are moving water pipes in the game, which is basically the same as the production of the ground. Every time we go to the left side of the screen, we return to the right side of the screen, and then set the y coordinate randomly. The screen looks continuous, and three water pipes are sorted according to a certain distance. The production of water pipes is as follows:

Area2d add a shape, bind body_entered signal, determine whether the bird entered, if so, send a score signal. Since each scene node is made independently, it would be difficult to operate if splicing together and each node is interdependent. Therefore, GoDOT has the function of signal, and other nodes can bind signals of another node to process signals sent by other nodes, so as to realize interdependent relationship. If the nodes are related to each other then the code will be cluttered, because then the code execution will not be clear, so I don’t have nodes bound to each other, only to unify all nodes in the game scene. For the production of the bird, the physical node RigidBody2D is mainly used. It does not move forward but up and down, and its flight is to increase an upward force.

Animations use AnimatedSprite. This class is used to add a sequence of frames to an animation. Each animation can be set to FPS and whether to loop

$ani.play(“flap”,true) is required to play this animation. The main function is to change the frame index back to 0, because the flap animation only plays when pressed, not all the time. For specific animations, see my configuration or Doc to learn more about how to use them. There are four main states of birds: flying up and down in the welcome screen, dead state, game state and default state. The state of flying up and down is to move the position up and down. Since RigidBody2D cannot directly change the coordinates, the elf can directly change the coordinates to achieve this. extends RigidBody2D

varState = game.idle # Default statevar ypos=3# Distance to fly up and downvar filp=true
var flyspeed=25# The speed of flying up and downvar speed=150Func _ready():# setState(game.fly)# print($ani.position.y) #setState(game.play) add_to_group(game.group_bird) func _physics_process(delta):ifstate==game.idle: idle(delta) elif state==game.fly: fly(delta) elif state==game.play: Play (delta) elif state==game. Dead: dead(delta) # func setState(newState:int):if newState==game.idle:
		gravity_scale=0
	elif newState==game.fly:
		gravity_scale=0
		$ani.play("fly")
	elif newState==game.play:
		gravity_scale=5
		flap()
	elif newState==game.dead:
		angular_velocity=1.4
		$ani.play("idle") state=newState # flapping ():if AudioPlayer:
		AudioPlayer.playSfxWing()
	$ani.play("flap".true)
	linear_velocity.y=-speed
	angular_velocity=-3Func idle(delta): passif filp:
		if $ani.position.y>ypos:
			filp=false
		else:
			$ani.position.y+=flyspeed*delta
	else:
		if $ani.position.y<-ypos:
			filp=true
		elseY -=flyspeed*delta # Func play(delta):if Input.is_action_just_pressed("ui_accept"): Flap () # Calculate the Angle avoid rotating all the timeif rotation_degrees<-30:
		rotation_degrees=-30
		angular_velocity=0
	
	if linear_velocity.y>0:
		angular_velocity=1.5
	
func dead(delta):
	#print("dead"Func _on_bird_body_entered(body): print("_on_bird_body_entered")
	ifstate! =game. Play: # skip the state that is not startedreturn
	if body.is_in_group(game.group_ground):
		if AudioPlayer:
			AudioPlayer.playSfxHit()
		emit_signal("birdStateChange")
	elif body.is_in_group(game.group_pipe):
		if AudioPlayer:
			AudioPlayer.playSfxHit()
			AudioPlayer.playSfxDie()
		emit_signal("birdStateChange")
		var other_body = get_colliding_bodies()[0]
		add_collision_exception_with(other_body)
Copy the code

The main script code is above, the main attention in the game state, is to control the Angle, the Angle can not be too large, keep within a range, otherwise it will always rotate

# Calculate the Angle to avoid rotating all the timeif rotation_degrees<-30:
    rotation_degrees=-30
    angular_velocity=0
Copy the code

RigidBody2D needs to set the collision report point, otherwise there is no collision result notification, set it to a point, no collision information.

After these major nodes are completed, it is basically the main scene production. The function of the main scene is to include all the nodes and functions, and then control the beginning and end of the game

The main scene consists of these nodes, the information displayed at the end of the game and the information displayed when the game is paused. Here, each node can set whether the index position is displayed in the front or not, and the display position can be determined according to the tree from top to bottom. For details, please refer to the script of the main scene. The first is the score, which needs to be constantly changed, so the main thing is to calculate the score, and then generate the corresponding picture according to the digit and add it to the node.

Func get_digits(number): var str_number = STR (number) var digits = [] for I in range(str_number.length): digits.append(str_number[i].to_int()) return digitsCopy the code

The scoring board is displayed at the end of the game. The process is mainly made using texturerect, TextureButton and container. Adding an animation node is mainly to change the way the board is displayed

The effect. Then there is also a pause interface, so the pause interface is to display a dark background, the solid background is to use colorrect, so here if the display level of the two buttons is

Same thing, then you can’t click, so why should these pause screens be placed at the bottom of the tree, otherwise they will be overwritten by other nodes? The beginning of the game is to set the bird’s state into the state of the game, the ground began to move, the water pipe began to move at different heights, as long as the bird touched the ground or water pipe game end popup end screen, the player can only control the bird’s flight. The bird collision signals need to be connected to determine the results.

$bird.connect(“birdStateChange”,self,”_on_bird_state_change”)

# gameOver()->void: # gameOver if $ready.visible: $ready.hide() state=game.endGame $pipe.setState(game.stop) $pipe2.setState(game.stop) $pipe3.setState(game.stop) $ground.setState(game.stop) $ground1.setState(game.stop) $bird.setState(game.dead) showGameOverPanel() setFinalSorce() Func ->void: print('_on_bird_state_change') gameOver()Copy the code

If the bird status changes, the game ends. All water pipes and ground stops moving. Paused the game by calling get_tree().paused=true. Paused state can be set at each node, which can be set to inherit the parent node and continue running, so that some nodes are not affected by the paused interface.

Where singletons are needed in the game, such as sound or global configuration, Godot provides singletons that automatically load scripts and nodes from the start.

Here are a few scripts and nodes that will be used in each scene. For sound, AudioStreamPlayer is used to play, but each AudioStreamPlayer can only play one sound. Godot itself provides sound playback functions, such as some special effects. All use AudioStreamPlayer to play the sound.

extendsNode2D # play sound func _ready(): pass func playSfxDie()->void:
	$sfxDie.play()

func playSfxHit()->void:
	$sfxHit.play()
		
func playSfxPoint()->void:
	$sfxPoint.play()

func playSfxSwooshing()->void:
	$sfxSwooshing.play()

func playSfxWing()->void:
	$sfxWing.play()
Copy the code

Provides methods for playing sound. For jitter, set the offset of Camera2D. If the offset changes over a period of time, the screen will jitter, but if the background needs to be fixed, you need to use CanvasLayer. CanvasLayer can be set not to follow camera changes,

# gameOver func gameOver()->void: # Game overif $game/ready.visible:
		$game/ready.hide()
	$game/score.visible=false
	$game/btnPause.visible=false
	state=game.endGame
	$game/pipe.setState(game.stop)
	$game/pipe2.setState(game.stop)
	$game/pipe3.setState(game.stop)
	$game/ground.setState(game.stop)
	$game/ground1.setState(game.stop)
	$game/bird.setState(game.dead)
	
	while num<offsetNum:		
		$game/camera.offset.x += rand_range(-magnitude,magnitude)
		$game/camera.offset.y+=rand_range(-magnitude,magnitude)
		num+=1
		yield(get_tree(), "idle_frame")
	num=0
	$game/camera.offset.x=72
	$game/camera.offset.y=128
Copy the code

In the function yield(get_tree(), “IDle_frame “). The main function is to pause for 1 frame.

Specific content can be reference godotengine.org/qa/19422/wh…

Other content is added.

Godot engine: godotengine.org/

Address: github.com/absolve/god…

Inside the flappyBird1 file is the project, and Godot uses version 3.0 or higher

Bitbucket.org/EdwardAngel…

This is the flappybird tutorial for godot2.0 for reference. I have referenced some of it