tryingtobeastoic
tryingtobeastoic

Reputation: 195

Understanding infinite while-loops in python

You can make an infinitely-lasting window pop-up using an infinite while loop in python:

import pygame

#Game-loop

while True:

    # Initialize the pygame
    pygame.init()

    # create the screen
    screen = pygame.display.set_mode((800, 600))

    # Title and icon
    pygame.display.set_caption("RPS Pro")
    icon = pygame.image.load('icon.png')
    pygame.display.set_icon(icon)

Now, this code does what we want it to do and it also makes sense. As we enter our code inside an infinite while-loop, it runs forever. But I tried something different:

import pygame

# Initialize the pygame
pygame.init()

#create the screen
screen = pygame.display.set_mode((800, 600))

#Title and icon
pygame.display.set_caption("RPS Pro")
icon = pygame.image.load('icon.png')
pygame.display.set_icon(icon)

#Game-loop
while True:
    pass

Surprisingly, this is able to create an infinitely lasting window as well. This is weird. The code isn't inside the while loop; why does then it do what we want it to do? It's true that the while-loop is still infinite, but our code isn't inside the while-loop. Why does it work then?

Upvotes: 0

Views: 638

Answers (2)

sloth
sloth

Reputation: 101052

I'll try to give you a rough idea:

You code isn't the only code running on your computer. There are also things called operating systems, display managers, device drivers and many more.

So when you call e.g.

pygame.display.set_mode((800, 600))

it's not your code that magically creates a window on your desktop. You code calls functions in the pygame module which in turn calls functions the SDL library which in turn calls functions of the operation system (or display manager on non-Windows systems).

So if you're on Windows, the function CreateWindow gets called that induces Windows to create a window. Windows also creates a Message queue for your applications's thread which allows Inter-process communication between your application, the window, and the operating system (or the display manager; on Windows it's dwm.exe).

This is called Event-driven programming. One part (the window created and run by the display manager) communicates with another part (your python application) via events. And that's also the reason you have to call pygame.event.get() in your application: to process the message loop. On non-Windows system it works similiar; on Linux you probaly use Xlib internally.


Think about what happens when you move your mouse: there's a device driver translating signals from your hardware to commands for your display manager. There's a driver responsible for drawing the mouse cursor on the screen. There's a display manager managing the windows.

So when you finally click cross-button, the display manager puts an event into your application's thread message queue. So far, your code is not involved in any of these things. The window is managed and run by the display manager.

As long as your application runs, the window will stay open, because it's tied to your application's thread.

Upvotes: 1

Ashim Dahal
Ashim Dahal

Reputation: 48

The window appears because you have not quit it and the while loop is infinite loop. As of that, the code runs until you are inside the while loop. also, try making a object move or some animations the you will notice that it will not get updated because the code is not inside the loop.

how the game works when we do it the correct way then? => your code is constantly getting updated inside the loop and the whole thing works. (like this is sample of a game)

import pygame
import time
import numpy as np
gravity =0
pygame.init()
gamewin = pygame.display.set_mode((650,400))
pygame.display.set_caption("flappy bird ")

bg = pygame.image.load("background-day.png")
pipes = pygame.image.load("pipe-green.png")
flipped_pipes = pygame.transform.flip(pipes,1,1)
play = [pygame.image.load("bird.png"),pygame.image.load("bird2.png"),pygame.image.load("bird3.png"),pygame.image.load("bird.png"),pygame.image.load("bird2.png"),pygame.image.load("bird3.png"),pygame.image.load("bird.png"),pygame.image.load("bird2.png"),pygame.image.load("bird3.png")]

pipe = False

def text_objects(text, font):
    textSurface = font.render(text, True,(0,0,0))
    return textSurface, textSurface.get_rect()
def message_display(text):
    largeText = pygame.font.Font('freesansbold.ttf',70)
    TextSurf, TextRect = text_objects(text, largeText)
    TextRect.center = ((700/2),(400/2))
    gamewin.blit(TextSurf, TextRect)
    pygame.display.update()
    time.sleep(2)



def seecollisions(x1,y1,w1,h1,x2,y2,w2,h2):
    if(x2+w2>=x1>=x2 and y2+h2>=y1>=y2):
        return True
    elif(x2+w2>=x1+w1>=x2 and y2+h2>=y1>=y2):
        return True
    elif(x2+w2>=x1>=x2 and y2+h2>=y1+h1>=y2):
        return True
    elif(x2+w2>=x1+w1>=x2 and y2+h2>=y1+h1>=y2):
        return True
    else:
        return False


class birdy(pygame.sprite.Sprite):
    def __init__(self,x,y,width,height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.pipe = False
        self.jumpcount= 0
        self.space = False
        self.hitbox= (self.x,self.y,self.width,self.height)
        self.rect = pygame.Rect(self.hitbox)

    def draw(self,win,obj):
        if self.jumpcount+1 > 27:
            self.jumpcount =0

        if self.space:

            win.blit(pygame.transform.rotate(obj[self.jumpcount//3],6%360),(self.x,self.y))
            #pygame.draw.rect(gamewin,(255,0,0),self.hitbox,2)



        else:

            win.blit(pygame.transform.rotate(obj[self.jumpcount//3],-6%360),(self.x,self.y))

            self.hitbox= (self.x,self.y,self.width,self.height)

            #pygame.draw.rect(gamewin,(255,0,0),self.hitbox,2)
            self.rect = pygame.Rect(self.hitbox)


        self.jumpcount +=1



class piper(pygame.sprite.Sprite):
    def __init__(self,box_x,box_y,bxuppery,width,height):
        self.width = width
        self.height = height
        self.box_x =box_x
        self.box_y = box_y
        self.bxuppery = bxuppery
        self.hitbox= (self.box_x,self.box_y,64,64)
        self.rect = pygame.Rect(self.hitbox)
        self.hitboxup= (self.box_x,self.box_y-self.bxuppery,self.width,self.height-180)



    def draw(self,win,obj,fobj):
        win.blit(obj,(self.box_x,self.box_y))
        self.hitbox= (self.box_x,self.box_y,self.width,self.height)
        self.hitboxup= (self.box_x,self.box_y-self.bxuppery,self.width,self.height-180)


        #pygame.draw.rect(gamewin,(255,0,0),self.hitbox,2)
        #pygame.draw.rect(gamewin,(255,0,0),self.hitboxup,2)

        self.rect = pygame.Rect(self.hitbox)


        win.blit(fobj,(self.box_x,self.box_y-self.bxuppery))



bird = birdy(20,200,34,26)

def redrawgame():

    gamewin.blit(bg,(0,0))
    bird.draw(gamewin,play)

    if pipe:
        pipspawn1.draw(gamewin,pipes,flipped_pipes)
        pipspawn2.draw(gamewin,pipes,flipped_pipes)
        pipspawn3.draw(gamewin,pipes,flipped_pipes)
        pipspawn4.draw(gamewin,pipes,flipped_pipes)




    pygame.display.update()


box_x = 740
box_x2 = box_x + 250
box_x3 = box_x2 + 250
box_x4 = box_x3 +250


rin = True 
upperboxy = 432

collidedpipe = False
box_y1 = np.random.randint(low=100,high=380)
box_y2 = np.random.randint(low=100,high=380)
box_y3 = np.random.randint(low=100,high=380)
box_y4 = np.random.randint(low=100,high=380)
pipspawn1=piper(box_x, box_y1,upperboxy,52,500)
pipspawn2=piper(box_x2, box_y2,upperboxy,52,500)
pipspawn3=piper(box_x3, box_y3,upperboxy,52,500)
pipspawn4=piper(box_x4, box_y4,upperboxy,52,500)
while rin:
    pygame.time.delay(30)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
    keys = pygame.key.get_pressed()
    if keys[pygame.K_UP] :

        if collidedpipe == False:
            bird.y-= 25
            bird.space = True
            gravity = 7


    if bird.x < 220:
        bird.x+=2
    if collidedpipe == False:
        bird.y+=1/2 * gravity 
        pygame.time.delay(50)
        gravity +=1.3


    if bird.y > 380:
        collidedpipe = True

    if bird.x > 120:
        pipe = True
        if collidedpipe == False:
            pipspawn1.box_x -= 10
            pipspawn2.box_x -= 10
            pipspawn3.box_x -= 10
            pipspawn4.box_x -= 10

    if pipspawn1.box_x <- 80:   
        pipspawn1.box_x= 880
        pipspawn1.box_y =  np.random.randint(low=100,high=380)


    if pipspawn2.box_x <- 80:   
        pipspawn2.box_x= 880
        pipspawn2.box_y =  np.random.randint(low=100,high=380)


    if pipspawn3.box_x <- 80:   
        pipspawn3.box_x=880
        pipspawn3.box_y =  np.random.randint(low=100,high=380)

    if pipspawn4.box_x <- 80:   
        pipspawn4.box_x= 880
        pipspawn4.box_y =  np.random.randint(low=100,high=380)


    # if score>1:
    #   print("score is",score+1)
    #print(bird.hitbox[0],bird.hitbox[1],bird.hitbox[2],bird.hitbox[3])
    #print(pipspawn1.hitboxup[0],pipspawn1.hitboxup[1],pipspawn1.hitboxup[2],pipspawn1.hitboxup[3])
    collision1 = seecollisions(bird.hitbox[0],bird.hitbox[1],bird.hitbox[2],bird.hitbox[3],pipspawn1.hitboxup[0],pipspawn1.hitboxup[1],pipspawn1.hitboxup[2],pipspawn1.hitboxup[3])
    collision2 = seecollisions(bird.hitbox[0],bird.hitbox[1],bird.hitbox[2],bird.hitbox[3],pipspawn2.hitboxup[0],pipspawn2.hitboxup[1],pipspawn2.hitboxup[2],pipspawn2.hitboxup[3])
    collision3 = seecollisions(bird.hitbox[0],bird.hitbox[1],bird.hitbox[2],bird.hitbox[3],pipspawn3.hitboxup[0],pipspawn3.hitboxup[1],pipspawn3.hitboxup[2],pipspawn3.hitboxup[3])
    collision4 = seecollisions(bird.hitbox[0],bird.hitbox[1],bird.hitbox[2],bird.hitbox[3],pipspawn4.hitboxup[0],pipspawn4.hitboxup[1],pipspawn4.hitboxup[2],pipspawn4.hitboxup[3])
    #print(collision1,collision2,collision3,collision4)
    if(collision2 or collision1 or collision3 or collision4):
        collidedpipe= True
    if(pygame.sprite.collide_rect(bird,pipspawn1)):
        collidedpipe = True
    if(pygame.sprite.collide_rect(bird,pipspawn2)):
        collidedpipe = True
    if(pygame.sprite.collide_rect(bird,pipspawn3)):
        collidedpipe = True
    if(pygame.sprite.collide_rect(bird,pipspawn4)):
        collidedpipe = True
    if collidedpipe:
        message_display("Game over")
        box_y1 = np.random.randint(low=100,high=380)
        box_y2 = np.random.randint(low=100,high=380)
        box_y3 = np.random.randint(low=100,high=380)
        box_y4 = np.random.randint(low=100,high=380)
        pipspawn1=piper(box_x, box_y1,upperboxy,52,500)
        pipspawn2=piper(box_x2, box_y2,upperboxy,52,500)
        pipspawn3=piper(box_x3, box_y3,upperboxy,52,500)
        pipspawn4=piper(box_x4, box_y4,upperboxy,52,500)

        bird = birdy(20,200,34,26)
        collidedpipe = False

    redrawgame()
    bird.space = False

pygame.quit()

In the example you can see that the loop contains only the parts where the screen needs to be updated. and that is what needs to go there you can only use it to call a function (which updates the screen) and it still will work fine

Upvotes: 0

Related Questions