天天看點

【python遊戲程式設計之旅】第四篇---pygame中加載位圖與常用的數學函數。

本系列部落格介紹以python+pygame庫進行小遊戲的開發。有寫的不對之處還望各位海涵。

在上一篇部落格中,我們學習了pygame事件與裝置輪詢。http://www.cnblogs.com/msxh/p/4979380.html

這次我們來一起了解一下如何在pygame中加載位圖,以及pygame中一些常用的數學函數。

 本篇部落格中素材連結:傳送門 (時間太久了,後補的資源,超人素材找不到了,用飛船替代了。)

一、pygame中常用的數學函數

首先介紹兩個角度和弧度轉換的函數:

math.degress()和math.radians(),用法很簡單,隻要将數值傳進去然後接收傳回值就可以了。

math.cos(angle),math.sin(angle),這裡的angle使用的是弧度表示的,是以需要先使用math.radians(),将角度轉換為弧度然後再傳參。

如果要擷取目前時間,我們需要使用datetime子產品。

首先從datetime導入date和time:

from datetime import datetime, date, time      

使用datetime.today()函數可以擷取目前的日期和事件:

today = datetime.today()      

today變量裡面包含了很多資訊,如果我們直接将其列印出來:

print today
2015-11-24 17:00:23.162000      

這樣很不友善我們使用,是以需要對其進行進一步的拆分:

today.date()
datetime.date(2015, 11, 24)

today.time()
datetime.time(17, 0, 23, 162000)      

如果隻需要目前時間而不需要目前日期的話,可以直接使用datetime.today().time()函數:

Time = datetime.today().time()      

Time有很多屬性,Time.hour Time.minute Time.second  Time.microsecond,看名字就知道是什麼了。

二、pygame中加載位圖、繪制位圖

通常,遊戲中需要加載大量的位圖,pygame中自帶了一些類和函數可以幫助我們輕松的搞定位圖加載和繪制。

screen = pygame.display.set_mode      

上面的代碼,我們在前幾期的部落格中已經使用過很多次了,實際上pygame.display.set_mode()這個函數會傳回一個Surface對象,他是位圖的一種。

執行個體中需要的一些素材可以到這裡下載下傳:http://yunpan.cn/cLI5cDKQU8sYG  通路密碼 c83a

1.加載位圖

在pygame中可以使用pygame.image.load()函數來加載位圖。(支援jpg,png,gif,bmp,pcx,tif,tga等多種圖檔格式)。

現在讓我們來加載一個位圖試試:

space = pygame.image.load("space.png").convert_alpha()      

convert_alpha()方法會使用透明的方法繪制前景對象,是以在加載一個有alpha通道的素材時(比如PNG TGA),需要使用convert_alpha()方法,當然普通的圖檔也是可以使用這個方法的,用了也不會有什麼副作用。

2.繪制位圖

Surface對象有一個名為blit()的方法,它可以繪制位圖

screen.blit(space, (0,0))      

第一個參數是加載完成的位圖,第二個參數是繪制的起始坐标。我們來看一下完整的程式和效果:

1 import sys, random, math, pygame
 2 from pygame.locals import *
 3 
 4 pygame.init()
 5 screen = pygame.display.set_mode((800,600))
 6 pygame.display.set_caption("星空")
 7 font = pygame.font.Font(None, 18)
 8 
 9 space = pygame.image.load("space.png").convert_alpha()
10 
11 while True:
12     for event in pygame.event.get():
13         if event.type == QUIT:
14             pygame.quit()
15             sys.exit()
16     keys = pygame.key.get_pressed()
17     if keys[K_ESCAPE]:
18         sys.exit()
19     screen.blit(space, (0,0))
20     
21     pygame.display.update()      
【python遊戲程式設計之旅】第四篇---pygame中加載位圖與常用的數學函數。

 額,其實我想用一個繞着地球飛的超人小程式,來講解一下pygame中的位圖。星空已經加載上了,下面加載并繪制一個地球。

為了讓地球可以在夜空的中間繪制,還得多寫幾段代碼。

planet = pygame.image.load("earth.png").convert_alpha()
#擷取位圖的寬和高
width,height = planet.get_size()
#在螢幕的中間繪制地球
screen.blit(planet, (400-width/2,300-height/2))      

get_size()可以擷取位圖的寬度和高度,然後利用他們就可以在确定在螢幕的中間繪制地球了。

最後該繪制我們的超人了。添加代碼:

superman = pygame.image.load("superman.png").convert_alpha()
screen.blit(superman,(30,30))      
【python遊戲程式設計之旅】第四篇---pygame中加載位圖與常用的數學函數。

但是超人圖像看起來好大啊,畫面比例有點不協調,還需要把超人縮小一點。

這裡使用pygame.transform 這個子產品可以滿足我們的需求,這個子產品包含了比如縮放,翻轉等一些非常有用的函數。

pygame.transform.scale()這是一個快速的縮放函數,可以快速縮放一個圖像,但是如果你試過以後就會發現他并不是那麼的理想,像素看起來會很密集,有點怪怪的。

幸好它有一個名為pygame.transform.smoothscale()的變體,這個函數通過複雜的計算産生比較平滑的圖像,當然它的運作耗時大于快速縮放函數。

superman = pygame.transform.smoothscale(superman,(width//2,height//2))      

好了,現在我們該考慮如何讓超人繞着地球旋轉了。

import sys, random, math, pygame
from pygame.locals import *

class Point(object):
    def __init__(self, x, y):
        self.__x = x
        self.__y = y

    #X property
    def getx(self): return self.__x
    def setx(self, x): self.__x = x
    x = property(getx, setx)

    #Y property
    def gety(self): return self.__y
    def sety(self, y): self.__y = y
    y = property(gety, sety)

def wrap_angle(angle):
    return angle % 360

radius = 250
angle = 0.0
pos = Point(0,0)
old_pos = Point(0,0)

pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("星空")
font = pygame.font.Font(None, 18)

space = pygame.image.load("space.png").convert_alpha()
planet = pygame.image.load("earth.png").convert_alpha()
superman = pygame.image.load("superman.png").convert_alpha()
width,height = superman.get_size()
superman = pygame.transform.smoothscale(superman,(width//2,height//2))


while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    keys = pygame.key.get_pressed()
    if keys[K_ESCAPE]:
        sys.exit()
        
    screen.blit(space, (0,0))

    angle = wrap_angle(angle - 0.1)
    pos.x = math.sin( math.radians(angle) ) * radius
    pos.y = math.cos( math.radians(angle) ) * radius
    
    #擷取位圖的寬和高
    width,height = planet.get_size()
    #在螢幕的中間繪制地球
    screen.blit(planet, (400-width/2,300-height/2))
    width,height = superman.get_size()
    screen.blit(superman,(400+pos.x-width//2,300+pos.y-height//2))
    pygame.display.update()      

在這裡,定義了一個point類,友善我們表示圖像的坐标,然後分别實作了set 和get方法,很簡單的,看代碼就可以了解了。

然後又定義了一個wrap_angle(angle)函數。他會傳回一個0~360之間的角度。

【python遊戲程式設計之旅】第四篇---pygame中加載位圖與常用的數學函數。

運作看一下,超人可以繞着地球旋轉了,但是看起來比較僵硬,最好讓他自己也能旋轉,指向他移動的方向,以便讓畫面柔和一些。

這裡我們需要math.atan2()這個函數,它用于計算反正切函數,需要傳遞兩個參數:delta_x,delta_y。delta_x,delta_y表示兩個坐标x,y之間的距離

工作流程是這樣的:先記錄飛船的最近位置,然後使用目前位置和最近位置調用atan2函數,然後再給atan2函數的傳回值加上180.

我們還需要一個函數是pygame.transform.rotate(),沒錯,它可以用來旋轉位圖,需要傳兩個參數:圖像,旋轉角度。

1 import sys, random, math, pygame
 2 from pygame.locals import *
 3 
 4 class Point(object):
 5     def __init__(self, x, y):
 6         self.__x = x
 7         self.__y = y
 8 
 9     def getx(self): return self.__x
10     def setx(self, x): self.__x = x
11     x = property(getx, setx)
12 
13     def gety(self): return self.__y
14     def sety(self, y): self.__y = y
15     y = property(gety, sety)
16 
17 def wrap_angle(angle):
18     return angle % 360
19 
20 radius = 250
21 angle = 0.0
22 pos = Point(0,0)
23 old_pos = Point(0,0)
24 
25 pygame.init()
26 screen = pygame.display.set_mode((800,600))
27 pygame.display.set_caption("星空")
28 font = pygame.font.Font(None, 18)
29 
30 space = pygame.image.load("space.png").convert_alpha()
31 planet = pygame.image.load("earth.png").convert_alpha()
32 superman = pygame.image.load("superman.png").convert_alpha()
33 width,height = superman.get_size()
34 superman = pygame.transform.smoothscale(superman,(width//2,height//2))
35 
36 
37 while True:
38     for event in pygame.event.get():
39         if event.type == QUIT:
40             pygame.quit()
41             sys.exit()
42     keys = pygame.key.get_pressed()
43     if keys[K_ESCAPE]:
44         sys.exit()
45         
46     screen.blit(space, (0,0))
47 
48     angle = wrap_angle(angle - 0.1)
49     pos.x = math.sin( math.radians(angle) ) * radius
50     pos.y = math.cos( math.radians(angle) ) * radius
51     
52     #擷取位圖的寬和高
53     width,height = planet.get_size()
54     #在螢幕的中間繪制地球
55     screen.blit(planet, (400-width/2,300-height/2))
56     #旋轉超人
57     delta_x = ( pos.x - old_pos.x )
58     delta_y = ( pos.y - old_pos.y )
59     rangle = math.atan2(delta_y, delta_x)
60     rangled = wrap_angle( -math.degrees(rangle) )
61     superman_rotate = pygame.transform.rotate(superman, rangled)
62     #繪制超人
63     width,height = superman_rotate.get_size()
64     screen.blit(superman_rotate,(400+pos.x-width//2,300+pos.y-height//2))
65     pygame.display.update()
66 
67     old_pos.x = pos.x
68     old_pos.y = pos.y      

運作一下,現在超人可以非常滿意的繞着地球旋轉了,效果看起來還是不錯的。

【python遊戲程式設計之旅】第四篇---pygame中加載位圖與常用的數學函數。

下個部落格我們将一起開發一個小遊戲,鞏固之前學到的知識。