© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2021
A. ElumalaiIntroduction to Python for Kids https://doi.org/10.1007/978-1-4842-6812-4_21

21. Project: Space Shooters with Pygame

Aarthi Elumalai1  
(1)
Chennai, Tamil Nadu, India
 

In the previous chapters, we learned the basics of Pygame. We learned all about creating your game screen, closing the screen, beautifying it, creating your characters, moving your characters, and more.

In this chapter, let’s apply what we’ve learned so far, and more, to create a space shooter game. You’ll also learn how to create text and scorecards for your game.

Space shooter game

../images/505805_1_En_21_Chapter/505805_1_En_21_Figa_HTML.jpg

It’s a very simple game. You have a spaceship that’s more like a gun. It can move left or right when you press on your left and right arrow keys.

Then, you have your enemies. Three rows of enemies, totaling 21, and they’ll move down towards that spaceship. If they hit the spaceship, game over!

To prevent that, the spaceship can shoot at the enemies. It has one bullet to shoot at a time. The bullet reloads after every shot (when it hits the enemy or the upper wall of the screen), so the spaceship can shoot again.

Every time the bullet hits the enemy, you gain a point and the enemy it hits disappears. If you finish killing all the 21 enemies, they’ll reload, and you’ll get a new set of 21 enemies in three rows. Start shooting again until you lose!

Look at that (Figure 21-1). The enemy is almost near, so we need to clear that row to stay alive. We’ve hit two enemies already, and our score is 2.
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig1_HTML.jpg
Figure 21-1

Final game

It’s a simple enough game with a lot of potential for improvement (more levels, increased speed, more bullets, more enemies), so let’s get started!

Import the required modules

We need the pygame module to create the game as such and the time module to slow down the characters enough that it’s visible to the human eye.
import pygame
import time

Initialize everything

Let’s initialize Pygame and its font package (to write the scoreboard).
pygame.init()
pygame.font.init() #To use text
Next, let’s create our game screen and set the caption to ‘Space Shooters’.
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption('Space Shooters')
Let’s also create a “font” variable that’ll store the font we need used, which is font type “Arial” and size 40.
font = pygame.font.SysFont('Arial',40)
We need two game conditions: an “over” that turns True when the game is over (enemy hit the spaceship) and a “game” that turns False when the user closes the window.
over = False #Game over
game = True #Closed the game window
That’s it! Let’s run the program, and we get this (Figure 21-2).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig2_HTML.jpg
Figure 21-2

Game screen

We have our screen! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figb_HTML.gif

Game loop

Next, let’s create our game loop.
while game:
Let’s create the window “close” condition first. You already know how to create that.
#Close window condition - Quit
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        game = False
Let’s also fill the screen with black while we’re at it. Of course, this wouldn’t make much of a difference because the default color of a pygame screen is black.
screen.fill((0,0,0))
After the program is out of the game loop, close the window:
pygame.quit()

Don’t worry about the code sequence. I’ll paste the entire code in the order it should be written at the end of the chapter.

Now, run the program again and try to close the window. It’ll work!

Create the spaceship

Now, let’s create our spaceship and make it appear on the screen.

Place these lines of code above the game loop.
#Create the spaceship
I’m going to load the spaceship.png image I’ve gotten for this project. It’s a nice little spaceship, pointing upward.
spaceship = pygame.image.load('spaceship.png')
Now, let’s set preliminary positions for the spaceship. Mid-way horizontally, at an x position 250 and a y position of 390 (toward the bottom of the screen). Let’s also set the direction at 0 as default. We can increase or decrease it later when we make the spaceship move.
sp_x = 250
sp_y = 390
sp_d = 0
To make the spaceship appear on the screen, in the game loop, below the for loop, include the following lines of code:
if over == False:
    screen.blit(spaceship,(sp_x,sp_y))

If the game is still true, then blit the image to the x and y coordinate positions we set.

Finally, update the display:
pygame.display.update()
Let’s run the program, and we get this (Figure 21-3).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig3_HTML.jpg
Figure 21-3

Position your spaceship

We have our spaceship. Yay! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figc_HTML.gif

Move the spaceship

You already know how to make characters move, am I right? We need the following done:
  1. 1.

    Move the spaceship right or left depending on which arrow key is pressed.

     
  2. 2.

    When the user stops pressing on the arrow key, stop moving the spaceship.

     

We need to look for two events in this case: KEYUP and KEYDOWN.

Within KEYUP, we need to look for two keys: K_LEFT and K_RIGHT.

Let’s go back to our game loop and the for loop where we iterated through all the events happening on the screen and include the next two conditions.

Look for the KEYDOWN condition, and if the key pressed in the “down” event is the left key (left arrow key), then decrease the space direction by 1, which means the spaceship will move toward the left (horizontally).

If the key pressed is the right arrow key, then increase the space direction by 1, which means the spaceship will move toward the right (horizontally).
if event.type == pygame.KEYDOWN:
    #Make spaceship move
    if event.key == pygame.K_LEFT:
        sp_d = -1
    if event.key == pygame.K_RIGHT:
        sp_d = 1
Now, let’s make the spaceship stop moving if the arrow keys are let up. Let’s look for a KEYUP event and check if the keys released are the left and the right arrow keys.
#Make spaceship stop if not moving
if event.type == pygame.KEYUP:
    if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
If they are, bring the spaceship direction back to 0, so there’s no change in position, and it just stops where the user leaves it.
sp_d = 0
But we can’t stop there. We need to add the sp_d value to the sp_x value, out of the for loop, if we want it to move for every iteration of the game loop.
#Spaceship move condition
sp_x += sp_d

Place the preceding lines of code above the spaceship blit and “update” lines of code.

Now, run the code and try moving the spaceship. Whoa! That was fast. I can’t really control my spaceship. Why is that?

Well, we aren’t spacing the game loop iterations, are we? Let’s pause the program (game) 0.005 seconds after every iteration. Place this line of code above the “display” line of code.
time.sleep(0.005)
Now, run the entire program, try to move your spaceship left and right, and you’ll get this (Figure 21-4).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig4_HTML.jpg
Figure 21-4

Make spaceship move on arrow presses

It works. Yes! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figd_HTML.gif

Create and move the enemies

Now let’s move the enemies! We need three rows of seven enemies, totaling 21. They’re going to have the same properties (image), but the only difference is their positions.

Let’s create lists that hold all of our values. One that holds the images so it can be blit in the game loop, one that holds all the “x” positions, one for all the “y” positions, and, finally, one for the enemy movement (direction).
#Create enemy
enemy = []
enemy_x = []
enemy_y = []
enemy_d = []
Let’s also keep track of the number of enemies alive. The counter will start at 0 and increase by one for every enemy being shot down. When the number reaches 21, we’re going to reset everything, draw three rows of new enemies again, and make them fall down to continue the game.
enemy_count = 0

Now, let’s set the x and y positions for our enemies. We’re going to create a for loop that runs from 0 to 20 (range of 21) for this.

For the first row (from iterations 0 through 6), the x positions are going to start at 0 and increase in multiples of 70 – 0, 70, 140, 210, 280, and so on.

The y positions are going to be at –60 (away from the screen, at the top), but still near the visible portion since this is the first row.

The distance value is going to be 0.5 throughout, for every enemy, because that’s the speed at which they’re all going to fall.
for i in range(21):
#Row 1
if i <= 6:
    enemy.append(pygame.image.load('enemy.png'))
    enemy_x.append(70 * i)
    enemy_y.append(-60)
    enemy_d.append(0.5)

Look at that! To create multiples of 70, I just multiplied 70 by “i” since “i” is going to take values from 0 through 6 anyway.

Now, the second row is a little tricky. We still need multiples of 70 for the x values, but we can’t use “i” as it is again, because, for the second row, “i” is going to go from 7 through 13. So, let’s subtract “i” by 7 while multiplying it by 70.

The y value for this set of enemies is going to be –120, a little behind the first row.
#Row 2
elif i <= 13:
    enemy.append(pygame.image.load('enemy.png'))
    enemy_x.append(70 * (i-7))
    enemy_y.append(-120)
    enemy_d.append(0.5)
Similarly, let’s multiply 70 by i – 14 for the x value of the third, and last row, and place the y value at –180.
#Row 3
else:
    enemy.append(pygame.image.load('enemy.png'))
    enemy_x.append(70 * (i-14))
    enemy_y.append(-180)
    enemy_d.append(0.5)

That’s it! We’ve positioned our enemies now. Let’s make them appear and fall next.

Inside the game loop (while loop), and after you’ve “blit” the spaceship, let’s create yet another “for” loop that runs 21 times (0 to 20).

Just like we did with our spaceship, we’re only going to draw the enemies if the game is still not over.

We need to check for two conditions here:
  1. 1.

    If the enemy’s “y” position is more than 500 (it has reached the end of the screen), then make it go back to a “y” of –60. That’s enough. Why? Well, the first row will disappear first, then the second, and finally the third. Everything is continually moving too, so if we just move each row back to –60, the movement of the previous row will compensate for the appearance of the next row in the same point.

     
  2. 2.

    If the y position is not yet 500, then we need to move the enemy down. Add the enemy_d value to the enemy_y value and blit that particular enemy to the screen.

     
#Draw enemies and make them move
for i in range(21):
    if over == False:
        #enemy wall collision
        if enemy_y[i] >= 500:
            enemy_y[i] = -60
        else:
            #Draw enemies
            enemy_y[i] += enemy_d[i]
            screen.blit(enemy[i],(enemy_x[i],enemy_y[i]))
That’s it! Our enemy should move now. Let’s check (Figure 21-5).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig5_HTML.jpg
Figure 21-5

Create the enemies

Yes! We have three rows of moving enemies!

Fire the bullet

Next, let’s fire the bullet. We need to do three things here:
  1. 1.

    Create the bullet outside the game loop, but not blit it until the user fires (presses the spacebar).

     
  2. 2.

    Check for the “space” press event inside the game loop (in the for loop that iterates through all the events, and inside the “if” statement where we did the KEYDOWN event check), and if it happened, set the bullet’s x and y positions and change its direction.

     
  3. 3.

    Finally, outside the events “for” loop, but inside the game loop, blit the bullet to the screen (if it was fired). Let’s also check for the wall collision while we’re at it and bring the bullet back to its original position if it hits the wall.

     

Alright. Now that we know what we need to do, let’s write the code for the same.

We’re going to load the “bullet.png” image, and that’s going to be our bullet. To start with, we’re going to set the x and y position of the bullet at –100 so it’s off the screen, unseen by the gamer. Let’s also set the movement value, bullet_d, to 0 so there’s no movement.
#create the bullet
bullet = pygame.image.load('bullet.png')
#place it off the screen to start with
bullet_x = -100
bullet_y = -100
bullet_d = 0
Finally, we’re going to create a variable “fire” that’s going to hold the state of the bullet. If the user has fired the bullet, this variable’s value is going to change to True from False (its default value).
fire = False

Now, let’s register the “space” key press. Go to the game loop, and inside the for loop where we iterate through all the events, look for the “if” statement where we registered the KEYDOWN event. Inside that statement, type the following:

Register the K_SPACE press event. As long as the “fire” value is False (bullet hasn’t been fired previously), if the user clicks the space button, let’s make the bullet move.

Make “fire” True now (because the bullet has been fired). Position the x and y values of the bullet to the current x and y values of the spaceship. Finally, make the bullet_d value –2, so it moves upward.
#Make bullet fire
if event.key == pygame.K_SPACE:
    if fire == False:
        fire = True
        bullet_x = sp_x
        bullet_y = sp_y
        bullet_d = -2

Now, let’s blit the bullet.

Outside the for loop and above the code where we blit the spaceship, but after we’ve changed the spaceship’s x value (so the new x value is assigned to the bullet), blit the bullet if “fire” is True and “over” is False (game is still live).
#Fire bullet
if fire == True and over == False:
We’ve set the x value to bullet_x+12 so it disappears behind the spaceship to start with.
screen.blit(bullet,(bullet_x+12, bullet_y))
Next, let’s increase y value of the bullet by the bullet_d’s value (decrease, in this case, since the bullet_d value would be –2).
bullet_y += bullet_d
Finally, let’s check for wall collision. Once the bullet reaches the top of the screen (y is 0 or less), if the “fire” value is still True (still fired), let’s change the x and y values of the bullet back to the x and y values of the spaceship and make the bullet_d value 0, so it starts moving. Let’s also make the value of “fire” False so the bullet is no longer “blit” into the screen until it is fired again.
#bullet wall collision
if bullet_y <= 0 and fire == True:
    bullet_x = sp_x
    bullet_y = sp_y
    bullet_d = 0
    fire = False
Run the code, and you’ll get this (Figure 21-6).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig6_HTML.jpg
Figure 21-6

Shoot the arrow

Our bullet works now! ../images/505805_1_En_21_Chapter/505805_1_En_21_Fige_HTML.gif

Create and display the scoreboard

Now that we have all our characters, and they’re moving as we want them to, let’s create our scoreboard so we can display scores as we shoot at our enemies.

Let’s create our scoreboard first.
#Create scoreboard
The value of “score” is going to be 0 to start with.
score = 0
Next, let’s create another variable score_text that stores the string we want displayed when the game starts, which is Score: 0.
score_text = 'Score: {}'.format(score)
Finally, let’s render this score_text using the “font” option in Pygame. The text color is going to be (255,255,255), which is white. This is RGB. We’ve already talked about that.
score_board = font.render(score_text,False,(255,255,255))
If we run the program now, we can’t see anything because we haven’t rendered the scoreboard inside the game loop yet. Let’s do that now.
screen.blit(score_board,(350,0))

Place the preceding code above the time.sleep line of code.

Let’s run our code, and we’ll get this (Figure 21-7).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig7_HTML.jpg
Figure 21-7

Scoreboard

We have our scoreboard, yay! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figf_HTML.gif

Kill the enemies

Now, let’s create the lines of code that kill the enemies when the bullet hits it. For every iteration of the loop, we’re going to continuously look for collision between our bullet and all 21 of our enemies.

So, let’s open a “for” loop to do that. Place this in the game loop, below where you “blit” all the enemies.
for i in range(21):

Now, we need the collision condition. It’s going to be pretty simple. If the distance between the bullet and the enemy (the top-left-most corner position) is less than or equal to 55, we have a collision. This’ll cover the bullet hitting any point from the top-left-most corner to the rest of the parts of the enemy.

To do this, let’s subtract the coordinates of the bullet (which are higher since they are at the bottom of the screen) from the coordinates of the enemy. Let’s get the absolute value of this subtraction so that no matter where the two characters are, we just get the “difference” value we need, without the sign.
if abs(bullet_x+12 - enemy_x[i]) <= 55 and abs(bullet_y - enemy_y[i])

Why bullet_x+12? That’s because we “blit” the bullet at that “x” point.

If there’s a collision, we need to bring the bullet back to position and make the bullet movement value, bullet_d, 0.
#bring bullet back to position
bullet_x = sp_x
bullet_y = sp_y
bullet_d = 0
Let’s also make “fire” False because we’re done firing the bullet. It did what we sent it to do.
fire = False

Now, within the same “if” statement, let’s open more if and else statements to bring that enemy back to position (and not move). It’ll just wait in that position until all the enemies in the current set are killed so the three rows of enemies are formed again.

Remember the conditions we used while positioning the enemies? Let’s use the same to position them now so they’ll be ready to go once all 21 enemies have been killed.
#bring enemy back to position
if i < 7:
    enemy_x[i] = 70 * i
    enemy_y[i] = -60
elif i < 14:
    enemy_x[i] = 70 * (i-7)
    enemy_y[i] = -120
else:
    enemy_x[i] = 70 * (i-14)
    enemy_y[i] = -180
Finally, let’s make the enemy movement value 0, to stop its movement (waiting for the rest to join it), and increase the enemy_count by 1.
enemy_d[i] = 0
enemy_count += 1

What happens when the bullet hits an enemy? The enemy dies and goes back to its original position. The bullet also goes back to its original position, but the score increases as well!

Let’s do that next. Let’s increase the score and render it again.
#increase score
score += 1
score_text = 'Score: {}'.format(score)
score_board = font.render(score_text,False,(255,255,255))
That’s it! We can kill enemies now. Let’s see if it works, shall we? (Figure 21-8)
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig8_HTML.jpg
Figure 21-8

Kill the enemies

Whohoo! We can kill our enemies now, and our score increases accordingly! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figg_HTML.gif

Kill the spaceship!

Finally, let’s create a collision condition for the spaceship and the enemies, so we can end the game. Place these lines of code below the code where you wrote the enemy-bullet collision lines of code.

The process is the same. For every iteration of our game loop, we’re going to loop through all the enemies and check if one of them hit our spaceship.
#Enemy-spaceship collision
for i in range(21):
The collision condition is going to be a difference between the x and y values of the spaceship and the enemies, and if they are less than or equal to 50, game over.
if abs(sp_x - enemy_x[i]) <= 50  and abs(sp_y - enemy_y[i]) <= 50:
    #game over
Make “over” True. If over is True, then we won’t blit the spaceship and the enemies (not to mention the bullet) to the screen, remember? That means they’ll disappear from the screen and we’ll be left with just the scoreboard.
#make everything disappear
over = True
Let’s try that now (Figure 21-9).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig9_HTML.jpg
Figure 21-9

Kill the spaceship

Yup, it works! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figh_HTML.gif

Re-draw the enemies

After the collision checks, we need to check if the user is done killing all the enemies. If all 21 are gone from the screen, we need to reset the enemy_count value back to 0 and make them fall from the top of the screen again.
#Set enemy move condition
if enemy_count == 21:
    for i in range(21):
        enemy_d[i] = 0.5
    enemy_count = 0
Let’s run the program, and check if this works (Figure 21-10).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig10_HTML.jpg
Figure 21-10

Re-draw the enemies

Look at that! We got our second row of enemies, and our score is 23 now! :O

Game over!

Finally, let’s write “GAME OVER” when the enemy hits the spaceship. Write “GAME OVER” when “over” is True, which means there’s been a collision.
#Game over
if over == True:
    #Draw game over text
Let’s create a new game_over_font and make it font type Arial and font size 80. Let’s render that font over our desired text. Make the color white. Finally, “blit” it into the screen in the position 50,200 (around the center of the screen).
game_over_font = pygame.font.SysFont('Arial',80)
game_over = game_over_font.render('GAME OVER',False,(255,255,255))
screen.blit(game_over,(50,200))
Let’s run our code, and we get this (Figure 21-11).
../images/505805_1_En_21_Chapter/505805_1_En_21_Fig11_HTML.jpg
Figure 21-11

Game over screen

Whohoo! Our game’s over! ../images/505805_1_En_21_Chapter/505805_1_En_21_Figi_HTML.gif

It was quite simple, wasn’t it? Try it out, and maybe try improving it (more levels, more difficulty, etc.).

Entire code

Now, here’s the entire code, as promised:
import pygame
import time
pygame.init()
pygame.font.init() #To use text
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption('Space Invaders')
font = pygame.font.SysFont('Arial',40)
over = False #Game over
game = True #Closed the game window
#Create the spaceship
spaceship = pygame.image.load('spaceship.png')
sp_x = 250
sp_y = 390
sp_d = 0
#Create enemy
enemy = []
enemy_x = []
enemy_y = []
enemy_d = []
enemy_count = 0
#Position enemies - 3 rows of enemies
for i in range(21):
    #Row 1
    if i <= 6:
        enemy.append(pygame.image.load('enemy.png'))
        enemy_x.append(70 * i)
        enemy_y.append(-60)
        enemy_d.append(0.5)
    #Row 2
    elif i <= 13:
        enemy.append(pygame.image.load('enemy.png'))
        enemy_x.append(70 * (i-7))
        enemy_y.append(-120)
        enemy_d.append(0.5)
    #Row 3
    else:
        enemy.append(pygame.image.load('enemy.png'))
        enemy_x.append(70 * (i-14))
        enemy_y.append(-180)
        enemy_d.append(0.5)
#create the bullet
bullet = pygame.image.load('bullet.png')
#place it off the screen to start with
bullet_x = -100
bullet_y = -100
bullet_d = 0
fire = False
#Create scoreboard
score = 0
score_text = 'Score: {}'.format(score)
score_board = font.render(score_text,False,(255,255,255))
while game:
    #Close window condition - Quit
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game = False
        if event.type == pygame.KEYDOWN:
            #Make spaceship move
            if event.key == pygame.K_LEFT:
                sp_d = -1
            if event.key == pygame.K_RIGHT:
                sp_d = 1
            #Make bullet fire
            if event.key == pygame.K_SPACE:
                if fire == False:
                    fire = True
                    bullet_x = sp_x
                    bullet_y = sp_y
                    bullet_d = -2
        #Make spaceship stop if not moving
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                sp_d = 0
    screen.fill((0,0,0))
    #Spaceship move condition
    sp_x += sp_d
    #Fire bullet
    if fire == True and over == False:
        screen.blit(bullet,(bullet_x+12, bullet_y))
        bullet_y += bullet_d
    #bullet wall collision
    if bullet_y <= 0 and fire == True:
        bullet_x = sp_x
        bullet_y = sp_y
        bullet_d = 0
        fire = False
    if over == False:
        screen.blit(spaceship,(sp_x,sp_y))
    #Draw enemies and make them move
    for i in range(21):
        if over == False:
            #enemy wall collision
            if enemy_y[i] >= 500:
                enemy_y[i] = -60
            else:
                #Draw enemies
                enemy_y[i] += enemy_d[i]
                screen.blit(enemy[i],(enemy_x[i],enemy_y[i]))
        #Bullet-enemy collision
    for i in range(21):
        if abs(bullet_x+12 - enemy_x[i]) <= 55 and abs(bullet_y - enemy_y[i]) <= 55:
            #bring bullet back to position
            bullet_x = sp_x
            bullet_y = sp_y
            bullet_d = 0
            fire = False
            #bring enemy back to position
            if i < 7:
                enemy_x[i] = 70 * i
                enemy_y[i] = -60
            elif i < 14:
                enemy_x[i] = 70 * (i-7)
                enemy_y[i] = -120
            else:
                enemy_x[i] = 70 * (i-14)
                enemy_y[i] = -180
            enemy_d[i] = 0
            enemy_count += 1
            #increase score
            score += 1
            score_text = 'Score: {}'.format(score)
            score_board = font.render(score_text,False,(255,255,255))
    #Enemy-spaceship collision
    for i in range(21):
        if abs(sp_x - enemy_x[i]) <= 50  and abs(sp_y - enemy_y[i]) <= 50:
            #game over
            #make everything disappear
            over = True
    #Set enemy move condition
    if enemy_count == 21:
        for i in range(21):
            enemy_d[i] = 0.5
        enemy_count = 0
    screen.blit(score_board,(350,0))
    #Game over
    if over == True:
        #Draw game over text
        game_over_font = pygame.font.SysFont('Arial',80)
        game_over = game_over_font.render('GAME OVER',False,(255,255,255))
        screen.blit(game_over,(50,200))
    time.sleep(0.005)
    pygame.display.update()
pygame.quit()

Summary

In this chapter, we created a space shooter game with Pygame. We applied what we learned in the previous chapter in our game, and we also learned all about collision detection and rendering text on our game screen.

In the next chapter, let’s look at an overview of web development with Python. We’ll get a brief look at creating web pages with HTML, designing them with CSS, making them dynamic with JavaScript, and creating your very first program in Python’s very own Flask.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
54.166.170.195