• pygame 笔记-10 摩擦力与屏幕环绕


    多年前写过一篇 Flash/Flex学习笔记(25):摩擦力与屏幕环绕,可惜的当时上传的flash,服务器后来无人维护,现在flash链接都失效了。本篇用pygame重新实现了一个:

    原理是类似,但要注意的是:pygame中旋转的角度采用逆时针系统 ,即:逆时针方向旋转,角度为正,反之为负。所以在外理角度时,y轴方向的速度要取反。

    素材图(2张):

    飞船熄火

    飞船点火

    需求:按向上键点火,飞船启动,一直加速;无按键时,飞船熄火,速度慢慢降下来(设置摩擦系数);左右键控制转向;飞出屏幕时,从另一侧切回来。

    代码:

      1 import os
      2 import pygame
      3 import sys
      4 import math
      5 
      6 pygame.init()
      7 
      8 clock = pygame.time.Clock()
      9 
     10 SIZE = WIDTH, HEIGHT = 400, 400
     11 GRAY = (200, 200, 200)
     12 RED = (255, 0, 0)
     13 screen = pygame.display.set_mode(SIZE)
     14 pygame.display.set_caption("ship")
     15 img_base_path = os.getcwd() + '/img/'
     16 
     17 
     18 class Ship(object):
     19     def __init__(self, img_base_path, screen):
     20         self.vx = 0
     21         self.vy = 0
     22         # 旋转角速度
     23         self.vr = 0
     24         # 推进力
     25         self.thrust = 0
     26         self.angle = 0
     27         self.show_flame = False
     28         self.scale = 1.0
     29         # 是否显示辅助边框
     30         self.show_rect = False
     31 
     32         self.img_src = pygame.image.load(img_base_path + 'ship.png')
     33         self.img_flame_src = pygame.image.load(img_base_path + 'ship_flame.png')
     34 
     35         self.img = self.img_src
     36         self.rect = self.img_src.get_rect()
     37 
     38         self.img_new = self.img
     39         self.rect_new = self.img_new.get_rect()
     40 
     41         self.rect = self.rect.move((WIDTH - self.rect.width) * 0.5, (HEIGHT - self.rect.height) * 0.5)
     42 
     43     def draw(self, screen):
     44         screen.blit(self.img_new, self.rect_new)
     45         if self.show_rect:
     46             pygame.draw.rect(screen, GRAY, ship.rect, 1)
     47             pygame.draw.rect(screen, RED, ship.rect_new, 1)
     48 
     49     def move(self):
     50         self.rect = self.rect.move(self.vx, self.vy)
     51         self.rect_new = self.rect_new.move(self.vx, self.vy)
     52         # 向左飞出边界
     53         if self.rect_new.right < 0 and ship.vx < 0:
     54             self.rect_new.left = WIDTH
     55             self.rect.left = WIDTH
     56         # 向右飞出边界
     57         if self.rect_new.left > WIDTH and ship.vx > 0:
     58             self.rect_new.right = 0
     59             self.rect.right = 0
     60         # 向下飞出边界
     61         if self.rect_new.top > HEIGHT and ship.vy > 0:
     62             self.rect_new.bottom = 0
     63             self.rect.bottom = 0
     64         # 向上飞出边界
     65         if self.rect_new.bottom < 0 and ship.vy < 0:
     66             self.rect_new.top = HEIGHT
     67             self.rect.top = HEIGHT
     68 
     69     def rotate_zoom(self):
     70         # rotozoom=旋转+缩放
     71         self.img_new = pygame.transform.rotozoom(self.img, self.angle, self.scale)
     72         self.rect_new = self.img_new.get_rect(center=self.rect.center)
     73         if math.fabs(self.angle) == 360:
     74             self.angle = 0
     75 
     76     def set_flame(self, show_flame=False):
     77         self.show_flame = show_flame
     78         if self.show_flame:
     79             self.img = self.img_flame_src
     80         else:
     81             self.img = self.img_src
     82 
     83 
     84 def get_speed(speed):
     85     if speed > 0:
     86         return math.ceil(speed)
     87     if speed < 0:
     88         return math.floor(speed)
     89     return speed
     90 
     91 
     92 ship = Ship(img_base_path, screen)
     93 ship.scale = 0.5
     94 ship.show_rect = True
     95 # 摩擦系数
     96 friction = 0.995
     97 while True:
     98     clock.tick(60)
     99 
    100     for event in pygame.event.get():
    101         if event.type == pygame.QUIT:
    102             sys.exit()
    103         elif event.type == pygame.KEYUP:
    104             # KEYUP时,熄火,动力归0
    105             ship.vr = 0
    106             ship.thrust = 0
    107             ship.set_flame(False)
    108         elif event.type == pygame.KEYDOWN:
    109             keys = pygame.key.get_pressed()
    110             if keys[pygame.K_LEFT]:
    111                 ship.vr = 5
    112             elif keys[pygame.K_RIGHT]:
    113                 ship.vr = -5
    114             if keys[pygame.K_UP]:
    115                 # 按向上键时,点火,动力为0.3
    116                 ship.set_flame(True)
    117                 ship.thrust = 0.3
    118             else:
    119                 ship.set_flame(False)
    120 
    121     # 将每一帧的底色先填充成白色
    122     screen.fill((255, 255, 255))
    123 
    124     pygame.draw.line(screen, GRAY, (0, HEIGHT / 2), (WIDTH, HEIGHT / 2), 1)
    125     pygame.draw.line(screen, GRAY, (WIDTH / 2, 0), (WIDTH / 2, HEIGHT), 1)
    126 
    127     ship.angle += ship.vr
    128     ax = math.cos(ship.angle * math.pi / 180) * ship.thrust
    129     # 注:pygame中,角度是逆时针转的,所以垂直加速度要取反
    130     ay = -1 * math.sin(ship.angle * math.pi / 180) * ship.thrust
    131     ship.vx += ax
    132     ship.vy += ay
    133 
    134     # 摩擦系数
    135     if math.fabs(ship.vx) > 0.001:
    136         ship.vx = ship.vx * friction
    137     if math.fabs(ship.vy) > 0.001:
    138         ship.vy = ship.vy * friction
    139 
    140     print("vx:", ship.vx)
    141 
    142     ship.rotate_zoom()
    143     ship.move()
    144     ship.draw(screen)
    145 
    146     # 更新画布
    147     pygame.display.update()
    View Code

    如果把背景变成黑色,辅助边框去掉,看上去更有漆黑宇宙的感觉:)

    源代码地址: https://github.com/yjmyzz/pygame_tutorial/blob/master/move_02.py

  • 相关阅读:
    Android MediaRecorder实现暂停断点录音功能
    Sqlite 数据库分页查询(ListView分页显示数据)
    Android 一键直接查看Sqlite数据库数据
    Android setTag()/getTag()
    sqlite3常用命令&语法
    Android 编辑框插入表情图片
    奇怪++操作
    hdu5024(dp)
    Windows Azure VM两shut down 道路
    android简单的计算器
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/pygame-tutorial-10-screen-around-and-friction.html
Copyright © 2020-2023  润新知