python - 如何在pygame中控制单个子弹
问题描述
我正在尝试创建一个 2D 侧面射击游戏。对于子弹,我使用的是一个列表,所以每次我射击子弹都会附加到该列表中,然后我在屏幕上“绘制”列表。每当项目符号离开屏幕时,我都会从列表中删除该项目符号。
目前,我有一个功能,你不能在射击时改变子弹的方向(一个角度)(即当子弹列表大于 0 时),因为显然我不希望人们控制子弹的方向他们没有枪了。然而,这不是我的意图,因为我希望人们在射击时改变方向,而不是已经射出的子弹的方向。
如果这没有意义,为了禁止玩家神奇地改变已经射出的子弹的路径或方向(例如使用心灵感应控制子弹并使其绕圈),我禁止改变方向在拍摄的同时。但这不是我的意图,因为我仍然希望玩家能够控制子弹的方向,而不是被射出的那些。下面是我的代码:`
import pygame
import math
pygame.init()
win = pygame.display.set_mode((500,480))
pygame.display.set_caption("First Game")
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'), pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'), pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'), pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'), pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
bg = pygame.image.load('bg.jpg')
clock = pygame.time.Clock()
b_angle = 0
class player(object):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 1.5
self.isJump = False
self.left = False
self.right = False
self.walkCount = 0
self.jumpCount = 13
self.standing = True
#Boolean value which forbids players from changing the angle of bullet whilst firing
self.isFiring = False
def draw(self, win):
if self.walkCount + 1 >= 45:
self.walkCount = 0
if not(self.standing):
if self.left:
win.blit(walkLeft[self.walkCount//5], (self.x,self.y))
self.walkCount += 1
elif self.right:
win.blit(walkRight[self.walkCount//5], (self.x,self.y))
self.walkCount +=1
else:
if self.right:
win.blit(walkRight[0], (self.x, self.y))
else:
win.blit(walkLeft[0], (self.x, self.y))
#Bullet Class
class projectile(object):
def __init__(self,x,y,radius,color,facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8
def draw(self,win):
pygame.draw.circle(win, self.color, (self.x,self.y), self.radius)
#Drawing everything on screen function
def redrawGameWindow():
win.blit(bg, (0,0))
man.draw(win)
for bullet in bullets:
bullet.draw(win)
clock.tick(60)
pygame.display.update()
#mainloop
man = player(200, 410, 64,64)
#List of bullets
bullets = []
run = True
previous_time = pygame.time.get_ticks()
while run:
print(b_angle)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#Adding bullets into the list
for bullet in bullets:
if bullet.x < 500 and bullet.x > 0 and bullet.y < 480 and bullet.y > 0:
bullet.x += int((bullet.vel*math.cos(math.radians(b_angle))))
bullet.y -= int((bullet.vel*math.sin(math.radians(b_angle))))
else:
bullets.pop(bullets.index(bullet))
#Only allows changing direction when there are no bullets on screen.
if len(bullets) == 0:
man.isFiring = False
keys = pygame.key.get_pressed()
#SPACE button, which shoot out the bullets (also a time delay).
if keys[pygame.K_SPACE]:
man.isFiring = True
current_time = pygame.time.get_ticks()
if man.left:
facing = -1
else:
facing = 1
if current_time - previous_time > 200:
previous_time = current_time
if len(bullets) < 10:
#See when there are bullets and set Firing = True.
man.isFiring = True
bullets.append(projectile(round(man.x + man.width //2), round(man.y + man.height//2), 3, (0,0,0), facing))
#A and D keys control direction of bullet.
if keys[pygame.K_a]:
if not man.isFiring:
b_angle += 3
if keys[pygame.K_d]:
if not man.isFiring:
b_angle -= 3
if keys[pygame.K_LEFT] and man.x > man.vel:
man.x -= man.vel
man.left = True
man.right = False
man.standing = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.width - man.vel:
man.x += man.vel
man.right = True
man.left = False
man.standing = False
else:
man.standing = True
man.walkCount = 0
if not(man.isJump):
if keys[pygame.K_UP]:
man.isJump = True
man.standing = False
man.walkCount = 0
else:
if man.jumpCount >= -13:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) ** 0.35 * neg
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 13
redrawGameWindow()
pygame.quit()
提前致谢!
解决方案
你应该重构你的代码,以便所有与玩家相关的逻辑都在Player
类中,所有与射弹相关的逻辑都在Projectile
类中。
此外,利用 pygame 的Sprite
类,这将帮助您组织代码并保持简单。
使用一些向量数学也将简化您的代码:发射弹丸时,创建一个向量来描述弹丸应该移动的方向。然后,在移动弹丸时,只需将该向量添加到弹丸的位置即可。
这是一个正在运行的示例:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
self.org_image = self.image.copy()
self.angle = 0
self.direction = pygame.Vector2(1, 0)
self.rect = self.image.get_rect(center=(200, 200))
self.pos = pygame.Vector2(self.rect.center)
def update(self, events, dt):
for e in events:
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_SPACE:
self.groups()[0].add(Projectile(self.rect.center, self.direction.normalize()))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_a]:
self.angle += 3
if pressed[pygame.K_d]:
self.angle -= 3
self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
self.image = pygame.transform.rotate(self.org_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Projectile(pygame.sprite.Sprite):
def __init__(self, pos, direction):
super().__init__()
self.image = pygame.Surface((8, 8))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
self.rect = self.image.get_rect(center=pos)
self.direction = direction
self.pos = pygame.Vector2(self.rect.center)
def update(self, events, dt):
self.pos += self.direction * dt
self.rect.center = self.pos
if not pygame.display.get_surface().get_rect().contains(self.rect):
self.kill()
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
sprites = pygame.sprite.Group(Player())
clock = pygame.time.Clock()
dt = 0
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
sprites.update(events, dt)
screen.fill((30, 30, 30))
sprites.draw(screen)
pygame.display.update()
dt = clock.tick(60)
if __name__ == '__main__':
main()
推荐阅读
- ssms-2012 - SQL Server 版本冲突
- r - 在 ggRGB 上叠加 ggR 栅格
- java - 在 docker 上运行的 https spring 应用程序
- iis-7 - 无法启动应用程序池错误:由于权限不足无法写入配置文件
- javascript - 需要同时运行 50 个 selenium web 驱动程序
- java - 如何在函数中保留现有的换行符
- java - 在 lombok slf4j 中使用 MDC
- postgresql - Postgres 角色自动失去超级用户属性
- javascript - 如何使用javascript在矩阵中生成随机数而不是静态数
- java - Spark 地理图块加入