The Python Game Book

code games. learn Python.

User Tools

Site Tools


Sidebar

Github:

en:pygame:step021

Step 021 - Rotating toward a target

video

Video link: http://www.youtube.com/watch?v=nfaOmkhK-V0 Bug: tank angle and turret angle is swapped in the video. The source code below is correct.

description

targetingdemo In the code example below, you can move both tanks (as in step020) or you can “teleport” the yellow tank toward the mouse pointer by clicking the left mouse button. The blue tank will rotate it's turrent toward the position of the yellow tank. The problem is to decide in wich direction the turret should move.

source code discussion

In the code example below this is solved by the Tank class method aim_at_player. Note that the angle diff can result in values > than 360, so the result is divided by 360 and its modulo1), is saved. You will also note that very few lines are altered since step020, mostly the tank class got a new method:

    def aim_at_player(self, targetnumber=0):
        #print "my  pos: x:%.1f y:%.1f " % ( self.pos[0], self.pos[1])
        #print "his pos: x:%.1f y:%.1f " % ( Tank.book[0].pos[0], Tank.book[0].pos[1])  
        deltax = Tank.book[targetnumber].pos[0] - self.pos[0]
        deltay = Tank.book[targetnumber].pos[1] - self.pos[1]
        angle =   math.atan2(-deltax, -deltay)/math.pi*180.0    
 
        diff = (angle - self.turretAngle - 90) %360 #reset at 360
        if diff == 0:
            self.turndirection = 0
        elif diff > 180:
            self.turndirection = 1
        else:
            self.turndirection = -1
        return diff

And also the mainloop's event handler is expanded. He now checks the MOUSEBUTTON event to teleport player1 tank around:

            # teleport player1 tank if left mousebutton is pressed
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if pygame.mouse.get_pressed()[0]:
                    #left mousebutton was pressed
                    player1.pos[0]=pygame.mouse.get_pos()[0]
                    player1.pos[1]=pygame.mouse.get_pos()[1]
<note>yipyipUser yipyip has donated a very interesting solution to this problem, using Complex numbers. See his source code here: yipyip's solution </note>

ideas

<note tip>Do you remember the keyboard-rollover problem from step020 ? Now you could use less keyboard commands by letting both players turrets automatically rotate toward each other</note> <note tip>Can you code an Artificial_intelligence for the bow machine gun ? Let it firing as soon as it's Deflection angle is low enough:

if -5 < tankDiffAngle < 5:
  Tracer(self)
</note>

additional resources

no additional resources needed

source code on github

To run this example you need:

file in folder download
021_targeting.py pygame Download the whole Archive with all files from Github:
https://github.com/horstjens/ThePythonGameBook/archives/master

View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/pygame/021_targeting.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
021_targeting.py
demo of tank game with rotating turrets
url: http://thepythongamebook.com/en:part2:pygame:step021
author: horst.jens@spielend-programmieren.at
licence: gpl, see http://www.gnu.org/licenses/gpl.html

the player2 tank rotate it's turrent always to player1 tank
you can "teleport" player1 tank by mouse click

special thanks to Jonathan Persson for motivation to write this
"""


import pygame
import random
import math
GRAD = math.pi / 180 # 2 * pi / 360   # math module needs Radiant instead of Grad

class Config(object):
    """ a class to hold all game constants that may be modded by the user"""
    fullscreen = False
    width = 640
    height = 480
    fps = 100
    xtiles = 30 # how many grid tiles for x axis
    ytiles = 20 # how many grid tiles for y axis
    title = "Esc: quit"

class Text(pygame.sprite.Sprite):
    """ a helper class to write text on the screen """
    number = 0 
    book = {}
    def __init__(self, pos, msg):
        self.number = Text.number # get a unique number
        Text.number += 1 # prepare number for next Textsprite
        Text.book[self.number] = self # store myself into the book
        pygame.sprite.Sprite.__init__(self, self.groups)
        self.pos = [0.0,0.0]
        self.pos[0] = pos[0]
        self.pos[1] = pos[1]
        self.msg = msg
        self.changemsg(msg)
        
    def update(self, seconds):        
        pass
        
    def changemsg(self,msg):
        self.msg = msg
        self.image = write(self.msg)
        self.rect = self.image.get_rect()
        self.rect.centerx = self.pos[0]
        self.rect.centery = self.pos[1]
        
class Bullet(pygame.sprite.Sprite):
    """ a big projectile fired by the tank's main cannon"""
    side = 7 # small side of bullet rectangle
    vel = 180 # velocity
    mass = 50
    maxlifetime = 10.0 # seconds
    def __init__(self, boss):
        pygame.sprite.Sprite.__init__(self, self.groups) # THE most important line !
        self.boss = boss
        self.dx = 0
        self.dy = 0
        self.angle = 0
        self.lifetime = 0.0
        self.color = self.boss.color
        self.calculate_heading() # !!!!!!!!!!!!!!!!!!!
        self.dx += self.boss.dx
        self.dy += self.boss.dy # add boss movement
        self.pos = self.boss.pos[:] # copy (!!!) of boss position 
        #self.pos = self.boss.pos   # uncomment this linefor fun effect
        self.calculate_origin()
        self.update() # to avoid ghost sprite in upper left corner, 
                      # force position calculation.
                      
    def calculate_heading(self):
        """ drawing the bullet and rotating it according to it's launcher"""
        self.radius = Bullet.side # for collision detection
        self.angle += self.boss.turretAngle
        self.mass = Bullet.mass
        self.vel = Bullet.vel
        image = pygame.Surface((Bullet.side * 2, Bullet.side)) # rect 2 x 1
        image.fill((128,128,128)) # fill grey
        pygame.draw.rect(image, self.color, (0,0,int(Bullet.side * 1.5), Bullet.side)) # rectangle 1.5 length
        pygame.draw.circle(image, self.color, (int(self.side *1.5) ,self.side/2), self.side/2) #  circle
        image.set_colorkey((128,128,128)) # grey transparent
        self.image0 = image.convert_alpha()
        self.image = pygame.transform.rotate(self.image0, self.angle)
        self.rect = self.image.get_rect()
        self.dx = math.cos(degrees_to_radians(self.boss.turretAngle)) * self.vel
        self.dy = math.sin(degrees_to_radians(-self.boss.turretAngle)) * self.vel
        
    def calculate_origin(self):
        # - spawn bullet at end of turret barrel instead tank center -
        # cannon is around Tank.side long, calculatet from Tank center
        # later subtracted 20 pixel from this distance
        # so that bullet spawns closer to tank muzzle
        self.pos[0] +=  math.cos(degrees_to_radians(self.boss.turretAngle)) * (Tank.side-20)
        self.pos[1] +=  math.sin(degrees_to_radians(-self.boss.turretAngle)) * (Tank.side-20)
 
    def update(self, seconds=0.0):
        # ---- kill if too old ---
        self.lifetime += seconds
        if self.lifetime > Bullet.maxlifetime:
            self.kill()
        # ------ calculate movement --------
        self.pos[0] += self.dx * seconds
        self.pos[1] += self.dy * seconds
        # ----- kill if out of screen
        if self.pos[0] < 0:
            self.kill()
        elif self.pos[0] > Config.width:
            self.kill()
        if self.pos[1] < 0:
            self.kill()
        elif self.pos[1] > Config.height:
            self.kill()
        #------- move -------
        self.rect.centerx = round(self.pos[0],0)
        self.rect.centery = round(self.pos[1],0)
        
class Tracer(Bullet):
    """Tracer is nearly the same as Bullet, but smaller
       and with another origin (bow MG rect instead cannon.
       Tracer inherits all methods of Bullet, but i overwrite
       calculate_heading and calculate_origin"""
    side = 15 # long side of bullet rectangle
    vel = 200 # velocity
    mass = 10
    color = (200,0,100)
    maxlifetime = 10.0 # seconds
    def __init__(self, boss, turret=False):
        self.turret = turret
        Bullet.__init__(self,boss ) # this line is important 
        
    def calculate_heading(self):
        """overwriting the method because there are some differences 
           between a tracer and a main gun bullet"""
        self.radius = Tracer.side # for collision detection
        self.angle = 0
        self.angle += self.boss.tankAngle
        if self.turret:
            self.angle = self.boss.turretAngle
        self.mass = Tracer.mass
        self.vel = Tracer.vel
        image = pygame.Surface((Tracer.side, Tracer.side / 4)) # a line 
        image.fill(self.boss.color) # fill yellow ? 
        pygame.draw.rect(image, (0,0,0), (Tracer.side * .75, 0, Tracer.side, Tracer.side / 4)) # red dot at front
        image.set_colorkey((128,128,128)) # grey transparent
        self.image0 = image.convert_alpha()
        self.image = pygame.transform.rotate(self.image0, self.angle)
        self.rect = self.image.get_rect()
        if self.turret:
            # turret mg
            self.dx = math.cos(degrees_to_radians(self.boss.turretAngle)) * self.vel
            self.dy = math.sin(degrees_to_radians(-self.boss.turretAngle)) * self.vel
        else:
            # bow mg
            self.dx = math.cos(degrees_to_radians(self.boss.tankAngle)) * self.vel
            self.dy = math.sin(degrees_to_radians(-self.boss.tankAngle)) * self.vel

    def calculate_origin(self):
        """overwriting because another point of origin is needed"""
        # - spawn bullet at end of machine gun muzzle (bow or turret)
        if self.turret:
            self.pos[0] +=  math.cos(degrees_to_radians(-90+self.boss.turretAngle)) * 15
            self.pos[1] +=  math.sin(degrees_to_radians(90-self.boss.turretAngle)) * 15
        else:
            self.pos[0] +=  math.cos(degrees_to_radians(30+self.boss.tankAngle)) * (Tank.side/2)
            self.pos[1] +=  math.sin(degrees_to_radians(-30-self.boss.tankAngle)) * (Tank.side/2)
        
    
class Tank(pygame.sprite.Sprite):
    """ A Tank, controlled by the Player with Keyboard commands.
    This Tank draw it's own Turret (including the main gun) 
    and it's bow rectangle (slit for Tracer Machine Gun"""
    side = 100 # side of the quadratic tank sprite
    recoiltime = 0.75 # how many seconds  the cannon is busy after firing one time
    mgrecoiltime = 0.2 # how many seconds the bow mg (machine gun) is idle
    turretTurnSpeed = 50 # turret
    tankTurnSpeed = 80 # tank
    movespeed = 80
    #maxrotate = 360 # maximum amount of degree the turret is allowed to rotate
    book = {} # a book of tanks to store all tanks
    number = 0 # each tank gets his own number
    # keys for tank control, expand if you need more tanks
    #          player1,        player2    etc
    firekey = (pygame.K_k, pygame.K_DOWN)
    mgfirekey = (pygame.K_LCTRL, pygame.K_KP_ENTER)
    mg2firekey = (pygame.K_i, pygame.K_UP)
    turretLeftkey = (pygame.K_j, pygame.K_LEFT)
    turretRightkey = (pygame.K_l, pygame.K_RIGHT)
    forwardkey = (pygame.K_w, pygame.K_KP8)
    backwardkey = (pygame.K_s, pygame.K_KP5)
    tankLeftkey = (pygame.K_a, pygame.K_KP4)
    tankRightkey = (pygame.K_d, pygame.K_KP6)
    color = ((200,200,0), (0,0,200))
    #msg = ["wasd LCTRL, ijkl", "Keypad: 4852, ENTER, cursor"]
          
    def __init__(self, startpos = (150,150), angle=0):
        self.number = Tank.number # now i have a unique tank number
        Tank.number += 1 # prepare number for next tank
        Tank.book[self.number] = self # store myself into the tank book
        pygame.sprite.Sprite.__init__(self, self.groups) # THE most important line !
        self.pos = [startpos[0], startpos[1]] # x,y
        self.dx = 0
        self.dy = 0
        self.ammo = 30 # main gun
        self.mgammo = 500 # machinge gun
        self.color = Tank.color[self.number]
        self.turretAngle = angle #turret facing
        self.tankAngle = angle # tank facing
        self.msg =  "tank%i: x:%i y:%i facing: turret:%i tank:%i"  % (self.number, self.pos[0], self.pos[1], self.turretAngle, self.tankAngle )
        Text((Config.width/2, 30+20*self.number), self.msg) # create status line text sprite
        self.firekey = Tank.firekey[self.number] # main gun
        self.mgfirekey = Tank.mgfirekey[self.number] # bow mg
        self.mg2firekey = Tank.mg2firekey[self.number] # turret mg
        self.turretLeftkey = Tank.turretLeftkey[self.number] # turret
        self.turretRightkey = Tank.turretRightkey[self.number] # turret
        self.forwardkey = Tank.forwardkey[self.number] # move tank
        self.backwardkey = Tank.backwardkey[self.number] # reverse tank
        self.tankLeftkey = Tank.tankLeftkey[self.number] # rotate tank
        self.tankRightkey = Tank.tankRightkey[self.number] # rotat tank
        # painting facing north, have to rotate 90° later
        image = pygame.Surface((Tank.side,Tank.side)) # created on the fly
        image.fill((128,128,128)) # fill grey
        if self.side > 10:
             pygame.draw.rect(image, self.color, (5,5,self.side-10, self.side-10)) #tank body, margin 5
             pygame.draw.rect(image, (90,90,90), (0,0,self.side/6, self.side)) # track left
             pygame.draw.rect(image, (90,90,90), (self.side-self.side/6, 0, self.side,self.side)) # right track
             pygame.draw.rect(image, (255,0,0), (self.side/6+5 , 10, 10, 5)) # red bow rect left
             #pygame.draw.rect(image, (255,0,0), (self.side/2 - 5, 10, 10, 5)) # red bow rect middle
        pygame.draw.circle(image, (255,0,0), (self.side/2,self.side/2), self.side/3 , 2) # red circle for turret
        image = pygame.transform.rotate(image,-90) # rotate so to look east
        self.image0 = image.convert_alpha()
        self.image = image.convert_alpha()
        self.rect = self.image0.get_rect()
        #---------- turret ------------------
        self.firestatus = 0.0 # time left until cannon can fire again
        self.mgfirestatus = 0.0 # time until mg can fire again
        self.mg2firestatus = 0.0 # time until turret mg can fire again
        self.turndirection = 0    # for turret
        self.tankturndirection = 0
        self.movespeed = Tank.movespeed
        self.turretTurnSpeed = Tank.turretTurnSpeed
        self.tankTurnSpeed = Tank.tankTurnSpeed
        Turret(self) # create a Turret for this tank
        
    def update(self, seconds):
        # no need for seconds but the other sprites need it
        #-------- reloading, firestatus----------
        if self.firestatus > 0:
            self.firestatus -= seconds # cannon will soon be ready again
            if self.firestatus <0:
                self.firestatus = 0 #avoid negative numbers
        if self.mgfirestatus > 0:
            self.mgfirestatus -= seconds # bow mg will soon be ready again
            if self.mgfirestatus <0:
                self.mgfirestatus = 0 #avoid negative numbers
        if self.mg2firestatus > 0:
            self.mg2firestatus -= seconds # turret mg will soon be ready again
            if self.mg2firestatus <0:
                self.mg2firestatus = 0 #avoid negative numbers
        
        # ------------ keyboard --------------
        pressedkeys = pygame.key.get_pressed()
        # -------- turret manual rotate ----------
        self.turndirection = 0    #  left / right turret rotation
        if self.number == 1:   # only for tank2
            self.aim_at_player()       # default aim at player0
        else:
            if pressedkeys[self.turretLeftkey]:
                self.turndirection += 1
            if pressedkeys[self.turretRightkey]:
                self.turndirection -= 1
           
        #---------- tank rotation ---------
        self.tankturndirection = 0 # reset left/right rotation
        if pressedkeys[self.tankLeftkey]:
            self.tankturndirection += 1
        if pressedkeys[self.tankRightkey]:
            self.tankturndirection -= 1
        
        # ---------------- rotate tank ---------------
        self.tankAngle += self.tankturndirection * self.tankTurnSpeed * seconds # time-based turning of tank
        # angle etc from Tank (boss)
        oldcenter = self.rect.center
        oldrect = self.image.get_rect() # store current surface rect
        self.image  = pygame.transform.rotate(self.image0, self.tankAngle) 
        self.rect = self.image.get_rect()
        self.rect.center = oldcenter 
        # if tank is rotating, turret is also rotating with tank !
        # -------- turret autorotate ----------
        self.turretAngle += self.tankturndirection * self.tankTurnSpeed * seconds  + self.turndirection * self.turretTurnSpeed * seconds # time-based turning
        # ---------- fire cannon -----------
        if (self.firestatus ==0) and (self.ammo > 0):
            if pressedkeys[self.firekey]:
                self.firestatus = Tank.recoiltime # seconds until tank can fire again
                Bullet(self)    
                self.ammo -= 1
                #self.msg =  "player%i: ammo: %i/%i keys: %s" % (self.number+1, self.ammo, self.mgammo, Tank.msg[self.number])
                #Text.book[self.number].changemsg(self.msg)
        # -------- fire bow mg ---------------
        if (self.mgfirestatus ==0) and (self.mgammo >0):
            if pressedkeys[self.mgfirekey]:
                self.mgfirestatus = Tank.mgrecoiltime
                Tracer(self, False) # turret mg = False
                self.mgammo -= 1
                #self.msg = "player%i: ammo: %i/%i keys: %s" % (self.number+1, self.ammo, self.mgammo, Tank.msg[self.number])
                #Text.book[self.number].changemsg(self.msg)
        # -------- fire turret mg ---------------
        if (self.mg2firestatus ==0) and (self.mgammo >0):
            if pressedkeys[self.mg2firekey]:
                self.mg2firestatus = Tank.mgrecoiltime # same recoiltime for both mg's
                Tracer(self, True) # turret mg = True
                self.mgammo -= 1
                #self.msg =  "player%i: ammo: %i/%i keys: %s" % (self.number+1, self.ammo, self.mgammo, Tank.msg[self.number])
                #Text.book[self.number].changemsg(self.msg)
        # ---------- movement ------------
        self.dx = 0
        self.dy = 0
        self.forward = 0 # movement calculator
        if pressedkeys[self.forwardkey]:
            self.forward += 1
        if pressedkeys[self.backwardkey]:
            self.forward -= 1
        # if both are pressed togehter, self.forward becomes 0
        if self.forward == 1:
            self.dx =  math.cos(degrees_to_radians(self.tankAngle)) * self.movespeed
            self.dy =  -math.sin(degrees_to_radians(self.tankAngle)) * self.movespeed
        if self.forward == -1:
            self.dx =  -math.cos(degrees_to_radians(self.tankAngle)) * self.movespeed
            self.dy =  math.sin(degrees_to_radians(self.tankAngle)) * self.movespeed
        # ------------- check border collision ---------------------
        self.pos[0] += self.dx * seconds
        self.pos[1] += self.dy * seconds
        if self.pos[1] + self.side/2 >= Config.height:
            self.pos[1] = Config.height - self.side/2
            self.dy = 0 # crash into border
        elif self.pos[1] -self.side/2 <= 0:
            self.pos[1] = 0 + self.side/2
            self.dy = 0
        
        self.rect.centerx = round(self.pos[0], 0) #x
        self.rect.centery = round(self.pos[1], 0) #y    
        self.msg =  "tank%i: x:%i y:%i facing: turret:%i tank:%i"  % (self.number, self.pos[0], self.pos[1], self.turretAngle, self.tankAngle )
        Text.book[self.number].changemsg(self.msg)
                    
    def aim_at_player(self, targetnumber=0):
        #print "my  pos: x:%.1f y:%.1f " % ( self.pos[0], self.pos[1])
        #print "his pos: x:%.1f y:%.1f " % ( Tank.book[0].pos[0], Tank.book[0].pos[1])  
        deltax = Tank.book[targetnumber].pos[0] - self.pos[0]
        deltay = Tank.book[targetnumber].pos[1] - self.pos[1]
        angle =   math.atan2(-deltax, -deltay)/math.pi*180.0    
        
        diff = (angle - self.turretAngle - 90) %360 #reset at 360
        if diff == 0:
            self.turndirection = 0
        elif diff > 180:
            self.turndirection = 1
        else:
            self.turndirection = -1
        return diff

class Turret(pygame.sprite.Sprite):
    """turret on top of tank"""
    def __init__(self, boss):
        pygame.sprite.Sprite.__init__(self, self.groups) # THE most important line !
        self.boss = boss
        self.side = self.boss.side
        
        self.images = {} # how much recoil after shooting, reverse order of apperance
        self.images[0] = self.draw_cannon(0)  # idle position
        self.images[1] = self.draw_cannon(1)
        self.images[2] = self.draw_cannon(2)
        self.images[3] = self.draw_cannon(3)
        self.images[4] = self.draw_cannon(4)
        self.images[5] = self.draw_cannon(5)
        self.images[6] = self.draw_cannon(6)
        self.images[7] = self.draw_cannon(7)
        self.images[8] = self.draw_cannon(8)  # position of max recoil
        self.images[9] = self.draw_cannon(4)
        self.images[10] = self.draw_cannon(0) # idle position
         
    def update(self, seconds):        
        # painting the correct image of cannon
        if self.boss.firestatus > 0:
            self.image = self.images[int(self.boss.firestatus / (Tank.recoiltime / 10.0))]
        else:
            self.image = self.images[0]
        # --------- rotating -------------
        # angle etc from Tank (boss)
        oldrect = self.image.get_rect() # store current surface rect
        self.image  = pygame.transform.rotate(self.image, self.boss.turretAngle) 
        self.rect = self.image.get_rect()
        # ---------- move with boss ---------
        self.rect = self.image.get_rect()
        self.rect.center = self.boss.rect.center

    
    def draw_cannon(self, offset):
         # painting facing right, offset is the recoil
         image = pygame.Surface((self.boss.side * 2,self.boss.side * 2)) # created on the fly
         image.fill((128,128,128)) # fill grey
         pygame.draw.circle(image, (255,0,0), (self.side,self.side), 22, 0) # red circle
         pygame.draw.circle(image, (0,255,0), (self.side,self.side), 18, 0) # green circle
         pygame.draw.rect(image, (255,0,0), (self.side-10, self.side + 10, 15,2)) # turret mg rectangle
         pygame.draw.rect(image, (0,255,0), (self.side-20 - offset,self.side - 5, self.side - offset,10)) # green cannon
         pygame.draw.rect(image, (255,0,0), (self.side-20 - offset,self.side - 5, self.side - offset,10),1) # red rect 
         image.set_colorkey((128,128,128))
         return image

# ---------------- End of classes --------------------

#------------ defs ------------------
def radians_to_degrees(radians):
    return (radians / math.pi) * 180.0

def degrees_to_radians(degrees):
    return degrees * (math.pi / 180.0)

def write(msg="pygame is cool"):
    """helper function for the Text sprite"""
    myfont = pygame.font.SysFont("None", 28)
    mytext = myfont.render(msg, True, (0,0,0))
    mytext = mytext.convert_alpha()
    return mytext        

def main():
    """the game itself"""
    pygame.init()
    screen=pygame.display.set_mode((Config.width,Config.height)) 
    #screenrect = screen.get_rect()
    background = pygame.Surface((screen.get_size()))
    #backgroundrect = background.get_rect()

    background.fill((128,128,255)) # fill grey light blue:(128,128,255) 
    # paint a grid of white lines
    for x in range(0,Config.width,Config.width/Config.xtiles): #start, stop, step
        pygame.draw.line(background, (255,255,255), (x,0), (x,Config.height))
    for y in range(0,Config.height,Config.height/Config.ytiles): #start, stop, step
        pygame.draw.line(background, (255,255,255), (0,y), (Config.width,y))
    # paint upper rectangle to have background for text
    pygame.draw.rect(background, (128,128,255), (0,0,Config.width, 70))
    
    background = background.convert()
    screen.blit(background, (0,0)) # delete all
    clock = pygame.time.Clock()    # create pygame clock object
    FPS = Config.fps               # desired max. framerate 
    playtime = 0
    
    tankgroup = pygame.sprite.Group()
    bulletgroup = pygame.sprite.Group()
    allgroup = pygame.sprite.LayeredUpdates()
    
    Tank._layer = 4   # base layer
    Bullet._layer = 7 # to prove that Bullet is in top-layer
    Tracer._layer = 5 # above Tank, but below Turret
    Turret._layer = 6 # above Tank & Tracer
    Text._layer = 3   # below Tank
 
    #assign default groups to each sprite class
    Tank.groups = tankgroup, allgroup
    Turret.groups = allgroup
    Bullet.groups = bulletgroup, allgroup
    Text.groups = allgroup
    player1 = Tank((150,250), 90) # create  first tank, looking north
    player2 = Tank((450,250), 90) # create second tank, looking south
     
    status3 = Text((Config.width/2, 10), "difference angle (from blue to yellow): %i" % Tank.book[1].aim_at_player())
    mainloop = True           
    while mainloop:
        status3.changemsg( "difference angle (from blue to yellow): %i" % Tank.book[1].aim_at_player() )
        milliseconds = clock.tick(Config.fps)  # milliseconds passed since last frame
        seconds = milliseconds / 1000.0 # seconds passed since last frame (float)
        playtime += seconds
            
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # pygame window closed by user
                mainloop = False 
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    mainloop = False # exit game
            # teleport player1 tank if left mousebutton is pressed
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if pygame.mouse.get_pressed()[0]:
                    #left mousebutton was pressed
                    player1.pos[0]=pygame.mouse.get_pos()[0]
                    player1.pos[1]=pygame.mouse.get_pos()[1]
        
        pygame.display.set_caption("%s FPS: %.2f playtime: %.1f " % ( Config.title,clock.get_fps(), playtime))
        #screen.blit(background, (0,0)) # delete all
        allgroup.clear(screen, background) # funny effect if you outcomment this line
        allgroup.update(seconds)
        allgroup.draw(screen)
        pygame.display.flip() # flip the screen 30 times a second
    return 0

if __name__ == '__main__':
    main()


1)
the part remaining after a division by 360. See the modulo operator %
en/pygame/step021.txt · Last modified: 2020/05/15 22:55 by horst