本系列部落格介紹以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()
額,其實我想用一個繞着地球飛的超人小程式,來講解一下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))
但是超人圖像看起來好大啊,畫面比例有點不協調,還需要把超人縮小一點。
這裡使用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之間的角度。
運作看一下,超人可以繞着地球旋轉了,但是看起來比較僵硬,最好讓他自己也能旋轉,指向他移動的方向,以便讓畫面柔和一些。
這裡我們需要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
運作一下,現在超人可以非常滿意的繞着地球旋轉了,效果看起來還是不錯的。
下個部落格我們将一起開發一個小遊戲,鞏固之前學到的知識。