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

posted @ 2019-01-13 17:23 菩提树下的杨过 阅读(...) 评论(...) 编辑 收藏