Bowling With Godot–Part 3 of 3

Click here for the previous section in this tutorial.

Time for the exact same process as pin and lane, except this time rename the RigidBody to BowlingBallRigidBody. The major differences are we used a SphereShape for our collision shape.

clip_image002

Plus, in physics, in addition to setting Sleep off, and Contact Listener on, we increase the Mass to 3. The value doesn’t really matter, this just means our bowling ball is 3x heavier than the pins.

clip_image004

Just for now lets get things rolling (ugh… the puns) and give our ball some initial velocity, so when we play our game, things happen. We will override this in a bit when we implement user control. Simply set the velocity to -15 or so on the Z axis:

clip_image006

Now when you play the game, if you’ve done everything correctly, the ball should roll down the lane and hit the pins.

clip_image008

Almost there! Now let’s add some audio that happens when the ball hits a pin. It’s the exact same process as back when we created our title screen, so I’m not going to go over it again. Just be sure to add the SamplePlayer to the bowling ball like so:

clip_image010

Then go in and create a sample library and add our bowling ball sound effect, in my case Hit.wav.

Now it’s time to do a bit of coding. The BowlingBall is going to be the heart of our game, so let’s add the script to it. Using the same process as back in the title screen, select the BowlingBall root node and attach a new script. Now select the child BowlingBallRigidBody node, switch to the Node tab, select body_enter and hit the Connect button at the bottom right hand corner.

clip_image012

Another window will pop up asking you which node to connect to. Select our BowlingBall node then click Connect.

clip_image014

This will open up the script editor and create a new function for us. Inside the function enter the following code:

func _on_BowlingBall_body_enter( body ):  	var name = body.get_name()  	if name == "PinBody":  		self.get_node("SamplePlayer").play("Hit")  

Now when you play the scene, when the bowling ball hits the pins, audio should play!

Handling User Input

** Before you continue… go back to the bowling ball and remove the Linear velocity we added earlier! We are going to handle that manually from this point on! **

Next we need to give the user some control over the bowling ball. First off, we need to create an Input map. We are going to use left and right arrows for moving the ball, well… left and right. Additionally, the space bar will be used to throw the ball.

Go to the Scene -> Project Settings Menu, then switch to the Input Map tab. Now we are going to add an entry. Simply enter LEFT in the text box, then click Add:

clip_image016

Click the + Icon, then select Key

clip_image018

When prompted, press the Left arrow key

clip_image020

Now repeat this process for Right and Space. You can of course map multiple keys to a single ID, so if you wanted LEFT to also trigger when the A key is pressed, or on Left mouse click, you can. Now lets wire our script up to handle input. Simply add or replace the following in your BowlingBall script:

func _ready():  	set_process_input(true)    func _input(event):  	if(event.is_action_released("LEFT")):  		self.get_node("BowlingBallRigidBody").apply_impulse(Vector3(0,0,0),Vector3(-1,0,0))    	if(event.is_action_released("RIGHT")):  		self.get_node("BowlingBallRigidBody").apply_impulse(Vector3(0,0,0),Vector3(1,0,0))  		  	if(event.is_action_released("SPACE")):  		self.get_node("BowlingBallRigidBody").apply_impulse(Vector3(0,0,0),Vector3(0,0,-35))  

Great, we can now control our ball, have collisions with pins and audio plays. We are 99% of the way toward a finished game… only one catch… you can only play once… that’s a bit of an issue no? Let’s do a quick and direct reset by reloading the scene when the user presses the R key. Add RESET to the InputMap and append the following code to your _input() function:

	if(event.is_action_released("RESET")):  		get_tree().reload_current_scene()  

And our final complete code should look like:

extends Spatial    func _ready():  	set_process_input(true)  	set_process(true)    func _input(event):  	if(event.is_action_released("LEFT")):  		self.get_node("BowlingBallRigidBody").apply_impulse(Vector3(0,0,0),Vector3(-1,0,0))    	if(event.is_action_released("RIGHT")):  		self.get_node("BowlingBallRigidBody").apply_impulse(Vector3(0,0,0),Vector3(1,0,0))  		  	if(event.is_action_released("SPACE")):  		self.get_node("BowlingBallRigidBody").apply_impulse(Vector3(0,0,0),Vector3(0,0,-35))    	if(event.is_action_released("RESET")):  		get_tree().reload_current_scene()    		  func _on_BowlingBallRigidBody_body_enter( body ):  	var name = body.get_name()  	if name == "PinRigidBody":  		self.get_node("SamplePlayer").play("Hit")  

And all done, one complete if primitive bowling game!  Once again, here is the video version.

Programming


Scroll to Top