Introduction to Python Game Programming 4

Math and Graphics: Analog Clock Example Program
This chapter introduces Python's math module, which can perform calculations such as common trigonometric sine, cosine, and tangent functions.

Use the sine and cosine functions to draw a circle
to create an example program for Anlog Clock

About the math module
https://docs.python.org/3/library/math.html
https://docs.python.org/2.7/library/math.html


math .cos(x)
    Return the cosine of x radians.

math.sin(x)
    Return the sine of x radians.

math.tan(x)
    Return the tangent of x radians.

math.degrees(x)
    Convert angle x from radians to

degrees.math.radians(x)
    Convert angle x from degrees to radians.math.pi

The
    mathematical constant π = 3.141592..., to available precision.

math.e
    The mathematical constant e = 2.718281..., to available precision.

Note:
    For negative numbers, the modulo
    remainder should be the number greater than or equal to 0 and less than the absolute value of the number, for example (-5)%3=1, consider -5 =3*(-2)+1

The example given in the book can be optimized.


Draw circle in hard way

import sys,pygame,math,random
from pygame.locals import *
pygame.init()

screen=pygame.display.set_mode((600,500))
pygame.display.set_caption("Circle Demo")
angle=0
color=random.randint(0,255),random.randint(0,255),random.randint(0,255)
while True:
    for event in pygame.event.get():
        if event.type==QUIT:
            sys.exit()
    keys =pygame.key.get_pressed()
    if keys[K_ESCAPE]:
        sys.exit()
    
    screen.fill((255,255,255))    

    
    x=300
    y=250
    radius=200
    
    
    circle_x=x+radius*math.cos(math.radians(angle))
    circle_y=y+radius*math.sin(math.radians(angle))

    pygame.draw.circle(screen,color,(int(circle_x),int(circle_y)),10,0)
    angle+=1
    if angle>359:
        color=random.randint(0,255),random.randint(0,255),random.randint(0,255)
        angle=0    
    
    pygame.display.update()    


Anlog Clock示例程序

import sys,datetime,pygame,math
from pygame.locals import *
from datetime import datetime,date,time
pygame.init()
def print_text(font,x,y,text,color=(255,255,255)):
    imgtext=font.render(text,True,color)
    screen.blit(imgtext,(x,y))

def wrap_angle(angle):
    return angle%360

#main program begins
screen=pygame.display.set_mode((600,500))
pygame.display.set_caption("Anlog Clock Demo")
font=pygame.font.Font(None,36)
orange=220,180,0
white=255,255,255
yellow=255,255,0
pink=255,100,100

pos_x=300
pos_y=250
radius=250
angle=360

#repeating loop
while True:
    for event in pygame.event.get():
        if event.type==QUIT:
            sys.exit()
    keys=pygame.key.get_pressed()
    if keys[K_ESCAPE]:
        sys.exit()
    
    screen.fill((0,0,100))
    #draw one step around the circle
    pygame.draw.circle(screen,white,(pos_x,pos_y),radius,6)
    
    #draw the clock numbers1-12
    for n in range(1,13):
        angle=math.radians(n*30-90)
        x=(radius-20)*math.cos(angle)+pos_x-10
        y=(radius-20)*math.sin(angle)+pos_y-10
        print_text(font,int(x),int(y),str(n))
    
    #get the time of day
    today=datetime.today()
    hours=today.hour%12
    minutes=today.minute
    seconds=today.second
    
    #draw the hours hand
    hour_angle=wrap_angle(hours*30-90)
    hour_angle=math.radians(hour_angle)
    hour_x=pos_x+math.cos(hour_angle)*(radius-80)
    hour_y=pos_y+math.sin(hour_angle)*(radius-80)
    target_h=(int(hour_x),int(hour_y))
    pygame.draw.line(screen,pink,(pos_x,pos_y),target_h,25)
    
    #draw the minutes hand
    minute_angle=wrap_angle(minutes*6-90)
    minute_angle=math.radians(minute_angle)
    minute_x=pos_x+math.cos(minute_angle)*(radius-60)
    minute_y=pos_y+math.sin(minute_angle)*(radius-60)
    target_m=(int(minute_x),int(minute_y))
    pygame.draw.line(screen,orange,(pos_x,pos_y),target_m,12)
    
    #draw the seconds hand
    second_angle=wrap_angle(seconds*6-90)
    second_angle=math.radians(second_angle)
    second_x=pos_x+math.cos(second_angle)*(radius-40)
    second_y=pos_y+math.sin(second_angle)*(radius-40)
    target_s=(int(second_x),int(second_y))
    pygame.draw.line(screen,yellow,(pos_x,pos_y),target_s,6)
    
    # cover the center
    pygame.draw.circle(screen,white,(pos_x,pos_y),20)

    print_text(font,0,0,str(hours)+":"+str(minutes)+":"+str(seconds ))

    pygame.display.update()


wrap_angle function is redundant, because +-360° has no effect on the result in the operation of trigonometric functions.
After removing all the parts with wrap_angle(), the program works fine.

1. Modify the circle program so that a different shape is drawn at each angle instead of a small filled circle.
import sys,pygame,math,random
from pygame.locals import *
pygame.init()

screen=pygame.display.set_mode((600,500))
pygame.display.set_caption("Circle Demo")
angle=0
color=random.randint(0,255),random.randint(0,255),random.randint(0,255)
while True:
    for event in pygame.event.get():
        if event.type==QUIT:
            sys.exit()
    keys=pygame.key.get_pressed()
    if keys[K_ESCAPE]:
        sys.exit()
    
    screen.fill((0,0,0))    

    
    x=300
    y=250
    radius=200
    
    
    circle_x=int(x+radius*math.cos(math.radians(angle)))
    circle_y=int(y+radius*math.sin(math.radians(angle)))
    
    if angle%3==0:
        pygame.draw.circle(screen,color,(circle_x,circle_y),12)
    elif angle%3==1:
        pygame.draw.rect(screen,color,(circle_x-10,circle_y-10,20,20))
    elif angle%3==2:
        pygame.draw.ellipse(screen,color,(circle_x-15,circle_y-10,30,20))

    angle+=1
    if angle>359:
        color=random.randint(0,255),random.randint(0,255),random. randint(0,255)
        angle=0    
    
    pygame.display.update()    

feels like drawing a little thing that will wriggle, which is a little interesting.

2. The Analog Circle looks better. I didn't implement this. I fine-tuned the angle of the hour hand, and it felt more customary. Now
the hour hand does not always point to the position of the hour, but instead points between two hours according to the minute.
import sys,datetime,pygame,math
from pygame.locals import *
from datetime import datetime,date,time
pygame.init()
def print_text(font,x,y,text,color=(255,255,255)):
    imgtext=font.render (text,True,color)
    screen.blit(imgtext,(x,y))

def wrap_angle(angle):
    return angle%360

#main program begins
screen=pygame.display.set_mode((600,500))
pygame.display.set_caption("Anlog Clock Demo")
font=pygame.font.Font(None,36)
orange=220,180,0
white=255,255,255
yellow=255,255,0
pink=255,100,100

pos_x=300
pos_y=250
radius=250
angle=360

#repeating loop
while True:
    for event in pygame.event.get():
        if event.type==QUIT:
            sys.exit()
    keys=pygame.key.get_pressed()
    if keys[K_ESCAPE]:
        sys.exit()
    
    screen.fill((0,0,100))
    #draw one step around the circle
    pygame.draw.circle(screen,white,(pos_x,pos_y),radius,6)
    
    #draw the clock numbers1-12
    for n in range(1,13):
        angle=math.radians(n*30-90)
        x=(radius-20)*math.cos(angle)+pos_x-10
        y=(radius-20)*math.sin(angle)+pos_y-10
        print_text(font,int(x),int(y),str(n))
    
    #get the time of day
    today=datetime.today()
    hours=today.hour%12
    minutes=today.minute
    seconds=today.second
    
    #draw the hours hand
    hour_angle=wrap_angle(hours*30-90+minutes*0.5)  #对比原来的程序修改了这一行。
    hour_angle=math.radians(hour_angle)
    hour_x=pos_x+math.cos(hour_angle)*(radius-80)
    hour_y=pos_y+math.sin(hour_angle)*(radius-80)
    target_h=(int(hour_x),int(hour_y))
    pygame.draw.line(screen,pink,(pos_x,pos_y),target_h,25)
    
    #draw the minutes hand
    minute_angle=wrap_angle(minutes*6-90)
    minute_angle=math.radians(minute_angle)
    minute_x=pos_x+math.cos(minute_angle)*(radius-60)
    minute_y=pos_y+math.sin(minute_angle)*(radius-60)
    target_m=(int(minute_x),int(minute_y))
    pygame.draw.line(screen,orange,(pos_x,pos_y),target_m,12)
    
    #draw the seconds hand
    second_angle=wrap_angle(seconds*6-90)
    second_angle=math.radians(second_angle)
    second_x=pos_x+math.cos(second_angle)*(radius-40)
    second_y=pos_y+math.sin(second_angle)*(radius-40)
    target_s=(int(second_x),int(second_y))
    pygame.draw.line(screen,yellow,(pos_x,pos_y),target_s,6)
    
    #cover the center
    pygame.draw.circle(screen,white,(pos_x,pos_y),20)

    print_text(font,0,0, str(hours)+":"+str(minutes)+":"+str(seconds))

    pygame.display.update()

seems more idiomatic. As far as aesthetic requirements are concerned.






Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324466487&siteId=291194637