Shooting Game using Python
This is a shooting game sample to demonstrate Python's GUI capabilities. Python is one of the most suited languages to develop simple as well as complex games.
One of the most challenging part in every game is to handle moving objects and Python just has lots of Libraries to handle this. Some of these libraries are simple and suited for beginners, while some libraries provide advanced functionalities to develop more complex games. And most of these are free to use.
Advantages of using Python
- Python is simple to understand and easy to use
- Python is open sourced
- Can develop games that works on almost all kinds of OS without much changes
- Lots of free to use libraries to suit different needs
- Even when we work on different types of applications like Web or Desktop, it feels like we are working on Core Python itself. Everything is more Pythonized.
Below sample is developed using Kivy, one of Python's most used GUI libraries. This is a simple shooting game, where we have to shoot down the objects coming from top with the gun at the base. We can use left and right arrows to move the gun. Up arrow to shoot.
Doing this sample will help you to get a better understanding of Kivy.
Particularly, on how to use canvas, create, shapes in it, move the shapes and bind event to these shapes.
Below are the step by step explanations.
-
Install Python
Download and install the latest version of python from Python Website.
Set up virtual environment also to avoid any unexpected errors.
Open command prompt and navigate to the folder where you are going to place the code and activate virtual environment.
Install Kivy using command python -m pip install kivy[base]. Kivy installations may fail some times because of incompatibility with latest version of Python. If any such error occurs, use the command py -3.9 -m pip install kivy[base] (for windows) or python3.9 -m pip install kivy[base] based on the OS.
If you wish to get a quick tutorial of Kivy before starting with the sample. Please have a look at the Kivy Quick Reference. -
Running the game
Create a file name game.py. Here we are going to place our code.
To run the game navigate to the folder in cmd and use commands python game.py or py game.py depending on the OS.
If we get any error on using above commands, it is likely because we have set up VE using older version of Python. Here we have to use commands python game.py or py game.py or python3.9 -m game or py -3.9 -m game depending on the OS and python version used.
-
Starting the code
Here we are importing kivy, required widgets and clock that helps in moving the objects.
Game is the class where our page load method build is defined. Here we create a window of size 400*400.
ShootGame is the class where we are going to define all our logic.Copiedimport kivy kivy.require('2.0.0') from kivy.app import App from kivy.core.window import Window from kivy.graphics import * from kivy.uix.widget import Widget from kivy.uix.label import Label from kivy.clock import Clock import time import random class ShootGame(Widget): pass class Game(App): def build(self): self.title = 'Arrows ← and → to move gun. ↑ to shoot.' Window.size = (400, 400) return ShootGame() if __name__ == '__main__': Game().run()
-
__init__ method
__init__ method contains code that should execute only once at the start of the game.
Here we can bind the keypress events to move the gun and shoot.
Then create a canvas and draw the gun, labels to show score and fail message.
2 clocks to move bullet and ball from top. Clocks should always be set within the init method.Copiedglobal isFailed def __init__(self, **kwargs): super(ShootGame, self).__init__(**kwargs) self._keyboard = Window.request_keyboard(self.movegun, self) self._keyboard.bind(on_key_down=self.movegun) self._keyboard.bind(on_key_up=self.shoot) global isFailed isFailed = False with self.canvas: Color(1,1,0,1, mode="rgba") self.gun = Ellipse(segments=5, pos=(185, 0), size=(30,30)) self.bullet = Rectangle(pos=(300, 400), size=(5,20)) Clock.schedule_interval(self.movebullet, .001) self.lblRes = Label(text="0") self.lblRes.pos = (310, 330) self.newball() Clock.schedule_interval(self.moveball, .2)
-
movegun function to move gun
Handles left and right movement of gun at base.
Also handles the restart after game fails. If enter key is pressed and game is in failed mode, move gun to the center and clear labels.Copieddef movegun(self, keyboard, keycode, text, modifiers): m = 0 gp = self.gun.pos[0] if(keycode[1] == 'left'): m = -3 elif(keycode[1] == 'right'): m = 3 elif(keycode[1] == 'enter'):#Restart global isFailed if(isFailed == True): isFailed = False with self.canvas: Color(1,1,0,1, mode="rgba") self.gun = Ellipse(segments=5, pos=(185, 0), size=(30,30)) self.lblFail.text = '' self.lblRes = Label(text="0") self.lblRes.pos = (310, 330) self.newball() if ((gp > 0 and m < 0) or (gp < 370 and m > 0)): self.gun.pos = (gp + m, 0)
-
movebullet function to move the bullet, check the hit and game fail
Moves bullet up. Check for the hit using x and y positions of bullet and ball. If hit, create a new ball.
Game fails when ball moves below the gun. Check if the game failed by using the y position of ball. If failed, show message.Copieddef movebullet(self, *args): x = self.gun.pos[0] + 15 y = self.bullet.pos[1] + 30 self.bullet.pos = (x, y) blx, bly = self.ball.pos #Check for hit. Ball size is 15. Bullet size is 5. if(x + 5 > blx and x < blx + 15 and y > bly and y < 400): self.canvas.remove(self.ball) self.newball() self.lblRes.text = str(int(self.lblRes.text) + 100) if(bly < 30): #Fail global isFailed isFailed = True self.canvas.clear() with self.canvas: Color(1,1,0,1, mode="rgba") self.lblFail = Label(text="Failed!!!Press Enter to restart.") self.lblFail.pos = (150, 150)
-
moveball function to continously move ball
Copieddef moveball(self, *args): rspeed = 7 y = self.ball.pos[1] - rspeed self.ball.pos = (self.ball.pos[0], y)
-
shoot function to create a bullet
shoot function to create a bullet in canvas and move it up.
Copieddef (self, keyboard, keycode): if(keycode[1] == 'up'): with self.canvas: Color(1,1,0,1, mode="rgba") self.bullet = Rectangle(pos=(300, 0), size=(5,20)) g = self.gun.pos[0] + 15 self.bullet.pos = (g, 30)
-
newball function to create a new ball
Create a new ball each time after successful hit.
Copieddef newball(self): x = random.randint(15, 385) with self.canvas: Color(1,0,0,1, mode="rgba") self.ball = Ellipse(pos=(x, 350), size=(15, 15))
Complete Code
import kivy kivy.require('2.0.0') from kivy.app import App from kivy.core.window import Window from kivy.graphics import * from kivy.uix.widget import Widget from kivy.uix.label import Label from kivy.clock import Clock import time import random class ShootGame(Widget): global isFailed def __init__(self, **kwargs): super(ShootGame, self).__init__(**kwargs) self._keyboard = Window.request_keyboard(self.movegun, self) self._keyboard.bind(on_key_down=self.movegun) self._keyboard.bind(on_key_up=self.shoot) global isFailed isFailed = False with self.canvas: Color(1,1,0,1, mode="rgba") self.gun = Ellipse(segments=5, pos=(185, 0), size=(30,30)) self.bullet = Rectangle(pos=(300, 400), size=(5,20)) Clock.schedule_interval(self.movebullet, .001) self.lblRes = Label(text="0") self.lblRes.pos = (310, 330) self.newball() Clock.schedule_interval(self.moveball, .2) def movegun(self, keyboard, keycode, text, modifiers): m = 0 gp = self.gun.pos[0] if(keycode[1] == 'left'): m = -3 elif(keycode[1] == 'right'): m = 3 elif(keycode[1] == 'enter'):#Restart global isFailed if(isFailed == True): isFailed = False with self.canvas: Color(1,1,0,1, mode="rgba") self.gun = Ellipse(segments=5, pos=(185, 0), size=(30,30)) self.lblFail.text = '' self.lblRes = Label(text="0") self.lblRes.pos = (310, 330) self.newball() if ((gp > 0 and m < 0) or (gp < 370 and m > 0)): self.gun.pos = (gp + m, 0) def movebullet(self, *args): x = self.gun.pos[0] + 15 y = self.bullet.pos[1] + 30 self.bullet.pos = (x, y) blx, bly = self.ball.pos #Check for hit. Ball size is 15. Bullet size is 5. if(x + 5 > blx and x < blx + 15 and y > bly and y < 400): self.canvas.remove(self.ball) self.newball() self.lblRes.text = str(int(self.lblRes.text) + 100) if(bly < 30): #Fail global isFailed isFailed = True self.canvas.clear() with self.canvas: Color(1,1,0,1, mode="rgba") self.lblFail = Label(text="Failed!!!Press Enter to restart.") self.lblFail.pos = (150, 150) def moveball(self, *args): rspeed = 7 y = self.ball.pos[1] - rspeed self.ball.pos = (self.ball.pos[0], y) def shoot(self, keyboard, keycode): if(keycode[1] == 'up'): with self.canvas: Color(1,1,0,1, mode="rgba") self.bullet = Rectangle(pos=(300, 0), size=(5,20)) g = self.gun.pos[0] + 15 self.bullet.pos = (g, 30) def newball(self): x = random.randint(15, 385) with self.canvas: Color(1,0,0,1, mode="rgba") self.ball = Ellipse(pos=(x, 350), size=(15, 15)) class Game(App): def build(self): self.title = 'Arrows ← and → to move gun. ↑ to shoot.' Window.size = (400, 400) return ShootGame() if __name__ == '__main__': Game().run()