美文网首页
通过游戏学Python系列之小兔要上天---手把手教你使用Pyg

通过游戏学Python系列之小兔要上天---手把手教你使用Pyg

作者: __豆约翰__ | 来源:发表于2020-12-04 15:48 被阅读0次

    配套视频教程

    配套视频教程

    本节最终效果:


    image

    一个游戏大致可以分为以下几个标准处理过程:
    init() 初始化

    new() 游戏初次进入(或主角挂了,重新开始时)

    update() 游戏逻辑更新

    events() 事件处理(响应键盘、鼠标等事件)

    draw() 屏幕渲染绘制

    show_start_screen() 游戏的启动画面

    show_go_screen() 游戏结束时的画面

    run() 游戏运行的循环入口
    我们将上节的游戏模板,实现成一个Game类:

    import pygame as pg
    import random
    from settings import *
    from sprites import *
    
    class Game:
        def __init__(self):
            # initialize game window, etc
            pg.init()
            pg.mixer.init()
            self.screen = pg.display.set_mode((WIDTH, HEIGHT))
            pg.display.set_caption(TITLE)
            self.clock = pg.time.Clock()
            self.running = True
    
        def new(self):
            # start a new game
            self.all_sprites = pg.sprite.Group()
            self.player = Player()
            self.all_sprites.add(self.player)
            self.run()
    
        def run(self):
            # Game Loop
            self.playing = True
            while self.playing:
                self.clock.tick(FPS)
                self.events()
                self.update()
                self.draw()
    
        # 为了方便观察pos,vel,acc这些变量,定义一个debug辅助函数
        def debug(self):
            font = pg.font.SysFont('Menlo', 25, True)
            pos_txt = font.render(
                'Pos:(' + str(round(self.player.pos.x, 2)) + "," + str(round(self.player.pos.y, 2)) + ")", 1, GREEN)
            vel_txt = font.render(
                'Vel:(' + str(round(self.player.vel.x, 2)) + "," + str(round(self.player.vel.y, 2)) + ")", 1, GREEN)
            acc_txt = font.render(
                'Acc:(' + str(round(self.player.acc.x, 2)) + "," + str(round(self.player.acc.y, 2)) + ")", 1, GREEN)
            self.screen.blit(pos_txt, (20, 10))
            self.screen.blit(vel_txt, (20, 40))
            self.screen.blit(acc_txt, (20, 70))
        def update(self):
            # Game Loop - Update
            self.all_sprites.update()
    
        def events(self):
            # Game Loop - events
            for event in pg.event.get():
                # check for closing window
                if event.type == pg.QUIT:
                    if self.playing:
                        self.playing = False
                    self.running = False
    
        def draw(self):
            # Game Loop - draw
            self.screen.fill(BLACK)
            self.all_sprites.draw(self.screen)
            # *after* drawing everything, flip the display
            self.debug()
            pg.display.flip()
    
        def show_start_screen(self):
            # game splash/start screen
            pass
    
        def show_go_screen(self):
            # game over/continue
            pass
    
    g = Game()
    g.show_start_screen()
    while g.running:
        g.new()
        g.show_go_screen()
    
    pg.quit()
    
    

    注:有2个控制变量,running是控制pygame是否退出,而playing是游戏情节是否继续处理
    (即:有可能游戏情况结束,比如:主角挂了,显示game over,但是pygame并不需要退出,可以选择重新开始)

    settings.py

    
    TITLE = "Rabbit jump on the sky!"
    WIDTH = 480
    HEIGHT = 600
    FPS = 60
    
    # Player properties
    PLAYER_ACC = 0.5
    PLAYER_FRICTION = -0.12
    
    # define colors
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)
    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE = (0, 0, 255)
    YELLOW = (255, 255, 0)
    
    

    定义游戏的精灵(下面代码命名为sprites.py)

    # Sprite classes for platform game
    import pygame as pg
    from settings import *
    vec = pg.math.Vector2
    
    class Player(pg.sprite.Sprite):
        def __init__(self):
            pg.sprite.Sprite.__init__(self)
            self.image = pg.Surface((30, 40))
            self.image.fill(YELLOW)
            self.rect = self.image.get_rect()
            self.rect.center = (WIDTH / 2, HEIGHT / 2)
            self.pos = vec(WIDTH / 2, HEIGHT / 2)
            self.vel = vec(0, 0)
            self.acc = vec(0, 0)
    
        def update(self):
            self.acc = vec(0, 0)
            keys = pg.key.get_pressed()
            if keys[pg.K_LEFT]:
                self.acc.x = -PLAYER_ACC
            if keys[pg.K_RIGHT]:
                self.acc.x = PLAYER_ACC
    
            # apply friction
            self.acc += self.vel * PLAYER_FRICTION
            # equations of motion
            self.vel += self.acc
            self.pos += self.vel + 0.5 * self.acc
            # wrap around the sides of the screen
            if self.pos.x > WIDTH:
                self.pos.x = 0
            if self.pos.x < 0:
                self.pos.x = WIDTH
    
            self.rect.center = self.pos
    
    
    1. 在2D游戏中,会大量用到类似(x,y)的结构,pygame中已经把这种结构封装成了Vector2.

    2. 加速度的定义:单位时间内速度的变化量。在游戏中,单位时间就是每帧,所以每一帧,我们在速度self.vel(velocity的缩写)值上的改变即为加速度self.acc( acceleration的缩写),因为

    v=a*t
    

    这里t可以理解为1.

    3.计算player新位移

    self.pos += self.vel + 0.5 * self.acc
    

    使用位移公式(t同样理解为1),1帧

    s = v*t+1/2*a*t**2
    
    1. 摩擦力的效果
    PLAYER_FRICTION = -0.12
    self.acc += self.vel * PLAYER_FRICTION
    self.vel += self.acc
    

    等价于

    self.acc = self.acc + self.vel * PLAYER_FRICTION
    self.vel = self.vel + self.acc
    

    也即:

    PLAYER_FRICTION = -0.12
    self.vel = self.vel + self.vel * PLAYER_FRICTION
    

    摩擦力的效果,表现为阻碍物体运动,具体在代码中体现,只要想办法把速度减少一点点。以上代码实现了该效果。

    image

    可以通过调试观察到,方块向右,速度由0变正,再由于摩擦力的作用变为0;反之相反。方块向右,加速度由正及负最后变为0,反之相反。速度为正,方块位置增加(表现为向右移动);速度为负,方块位置减小(表现为向左移动);方块向右,加速度为正,使得速度变大(正的大),方块向左,加速度为负,使得速度变大(负的大,实际上是变小)

    相关文章

      网友评论

          本文标题:通过游戏学Python系列之小兔要上天---手把手教你使用Pyg

          本文链接:https://www.haomeiwen.com/subject/eoxiwktx.html