zoukankan      html  css  js  c++  java
  • 【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()

     额,其实我想用一个绕着地球飞的超人小程序,来讲解一下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

    运行一下,现在超人可以非常满意的绕着地球旋转了,效果看起来还是不错的。

    下个博客我们将一起开发一个小游戏,巩固之前学到的知识。

  • 相关阅读:
    ffmpeg 简单使用总结
    使用 Solr 构建企业级搜索服务器
    Linux 常用命令整理
    基于.net standard 的动态编译实现
    基于.net core 微服务的另类实现
    Java中线程总结
    关于EF中直接执行sql语句的参数化问题
    一个关于单据审核的流程演变
    java中匿名内部类总结
    Eclipse 中打开选中文件/文件夹所在目录
  • 原文地址:https://www.cnblogs.com/msxh/p/4990435.html
Copyright © 2011-2022 走看看