【问题标题】:How to control individual bullets in pygame如何在pygame中控制单个子弹
【发布时间】:2019-06-02 15:04:11
【问题描述】:

我正在尝试创建一个 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()

提前致谢!

【问题讨论】:

    标签: python pygame bullet


    【解决方案1】:

    你应该重构你的代码,使所有与玩家相关的逻辑都在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()
    

    【讨论】:

    • 谢谢,这正是我需要的。
    【解决方案2】:

    解决这个问题的一种方法是将方向存储在射弹中。

    #Bullet Class
    class projectile(object):
        def __init__(self, x, y, radius, color, facing, angle):
            self.x      = x
            self.y      = y
            self.radius = radius
            self.color  = color
            self.facing = facing
            self.vel    = 8
            self.angle  = angle   # <<== HERE
    
        def draw(self, win):
            pygame.draw.circle(win, self.color, (self.x, self.y), self.radius)
    
        # Compute the next position of the projectile, returning False
        # if it outside the screen co-oridinates
        def update(self):
            if (self.x < 500 and self.x > 0 and self.y < 480 and self.y > 0):
                self.x += int((self.vel*math.cos(math.radians(self.angle))))
                self.y -= int((self.vel*math.sin(math.radians(self.angle))))
                return True
            else:
                return False
    

    这会留下你的更新功能:

    while run:
        print(b_angle)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        # Move the bullets 
        for bullet in bullets:
            if (bullet.update() == False): 
                bullets.pop(bullets.index(bullet))  # bullet left screen
    
        #Only allows changing direction when there are no bullets on screen.
                if len(bullets) == 0:
                    man.isFiring = False
    

    当然,当你创建一个新的子弹时,它也需要被赋予b_angle

    bullets.append(projectile(round(man.x + man.width //2), round(man.y + man.height//2), 3, (0,0,0), facing, b_angle))
    

    【讨论】:

    • 你好。感谢您的快速回复,但它仍然没有解决我的问题。目前,该程序不允许在射击时改变“方向”,但我希望玩家能够在射击时改变方向,而不改变现有子弹的路径,如果这有意义的话。基本上,如果我在当前情况下允许改变方向,所有的子弹(在屏幕上)都会改变方向,这是不合逻辑的。所以我想解决这个问题,但仍然允许用户在射击时改变子弹(如果你想象枪管的话)方向。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多