如何在向上移动的pygame中制作射弹?

时间:2014-09-21 00:42:15

标签: python pygame self rect

我写了一个游戏,用于在按下空格键时在屏幕上拍摄蓝色方块。但是,我得到的只是射手正上方的蓝色方块。这是我的代码:

import pygame, sys, random
from gameobjects import *


def main():

    pygame.init()

    screen = pygame.display.set_mode((800, 800))

    numberOfColumns = 5
    columnWidth = screen.get_width() / numberOfColumns

    numberOfRows = 5
    rowWidth = screen.get_width() / numberOfRows

    magazineImage = pygame.image.load("images/Magazine.bmp")
    magazineIssueOneImage = pygame.image.load("images/Magazine #1.bmp")

    monsterState1 = pygame.image.load("images/Zombie Pos 1.bmp")
    monsterState2 = pygame.image.load("images/Zombie Pos 2.bmp")
    monsterState3 = pygame.image.load("images/Zombie Pos 3.bmp")
    monsters = []

    forryState1 = pygame.image.load("images/Forry Pos 1.bmp")    
    forryState2 = pygame.image.load("images/Forry Pos 2.bmp")
    forryDelayTime = 8

    gameObjects = []
    gameObjectBlittingCounter = 0

    monsterSpawnSpotList = [(rowWidth * -5), (rowWidth * -4), (rowWidth * -3), (rowWidth * -2), (rowWidth * -1)]

    for monster in range(0, 5):
        monster = Monster(monsterState1, monsterState2, monsterState3, ((columnWidth / 2 - monsterState1.get_width() / 2) + gameObjectBlittingCounter * columnWidth), random.choice(monsterSpawnSpotList))
        monsters.append(monster)
        gameObjects.append(monster)
        gameObjectBlittingCounter += 1

    forry = Forry(forryState1, forryState2, columnWidth, rowWidth, screen, forryDelayTime, magazineImage, magazineIssueOneImage)
    gameObjects.append(forry)


    while True:


        screen.fill((0,255,0))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()

        #Update Projectiles

        if forry.projectileCall == True:
            magazine = Magazine(magazineImage, forry)
            gameObjects.append(magazine)

        #Update Game Objects

        for gameObject in gameObjects:
            gameObject.update()


        #Render
        gameObjectBlittingCounter = 0

        for gameObject in gameObjects:
            screen.blit(gameObjects[gameObjectBlittingCounter].image, ((gameObjects[gameObjectBlittingCounter].rect.x), (gameObjects[gameObjectBlittingCounter].rect.y)))
            gameObjectBlittingCounter += 1


        pygame.display.flip()




if __name__ == "__main__":
    main()

文件gameobjects.py看起来像这样:

import pygame


class Monster(pygame.sprite.Sprite):
    def __init__(self, monsterState1, monsterState2, monsterState3, xCoord, yCoord):
        self.monsterState1 = monsterState1
        self.monsterState2 = monsterState2
        self.monsterState3 = monsterState3
        self.image = self.monsterState1
        self.rect = self.image.get_rect()
        self.rect.y = yCoord
        self.rect.x = xCoord


    def update(self):
        self.moveDown()

    def moveDown(self):
        self.rect.y += 1

    def onSpawn(self):
        return

    def onDeath(self):
        return

    def reset(self):
        return



class Forry(pygame.sprite.Sprite):
    def __init__(self, forryState1, forryState2, columnWidth, rowWidth, screen, delayTime, magazineImage, magazineIssueOneImage):
        self.forryState1 = forryState1
        self.forryState2 = forryState2
        self.image = self.forryState1
        self.columnWidth = columnWidth
        self.rowWidth = rowWidth
        self.rect = self.image.get_rect()
        self.rect.y = self.columnWidth / 2 - self.image.get_width() / 2
        self.rect.y = screen.get_height() - (self.rowWidth / 2 - self.image.get_height() / 2)
        self.delayTime = delayTime
        self.delay = 0
        self.magazineImage = magazineImage
        self.magazineIssueOneImage = magazineIssueOneImage
        self.projectileCall = False
        self.rightBound = screen.get_width() - (self.columnWidth / 2 + self.image.get_width() / 2)
        self.leftBound = (self.columnWidth / 2 - self.image.get_width() / 2)


    def update(self):
        #Check Player Input
        playerInput = self.checkPlayerInput()

        #Update Position
        if self.delay > 0:
            self.delay -= 1
        elif self.delay < 0:
            self.delay = 0
        else:
            self.updatePosition(playerInput)

        #Keep on the Screen
        self.keepOnScreen()

    def checkPlayerInput(self):
        left = pygame.key.get_pressed() [pygame.K_LEFT]
        right = pygame.key.get_pressed() [pygame.K_RIGHT]
        shoot = pygame.key.get_pressed() [pygame.K_SPACE]
        return (left, right, shoot)

    def updatePosition(self, playerInput):
        left = playerInput[0]
        right = playerInput[1]
        shoot = playerInput[2]
        if self.projectileCall == True:
            self.projectileCall = False
            self.image = self.forryState1
        if shoot:
            self.image = self.forryState2
            self.projectileCall = True
            self.delay = self.delayTime
        if left:
            self.rect.x -= self.columnWidth
            self.delay = self.delayTime
        if right:
            self.rect.x += self.columnWidth
            self.delay = self.delayTime

    def keepOnScreen(self):
        if self.rect.x >= self.rightBound:
            self.rect.x = self.rightBound
        elif self.rect.x <= self.leftBound:
            self.rect.x = self.leftBound


    def onSpawn(self):
        return

    def onDeath(self):
        return

    def reset(self):
        return


class Magazine(pygame.sprite.Sprite):
    def __init__(self, image, shooter):
        self.image = image
        self.rect = image.get_rect()
        self.rect.x = shooter.rect.x
        self.rect.y = shooter.rect.y - shooter.image.get_height()

        def update(self):
            self.rect.y -= 5
            if self.rect.y <= 0 - self.image.get_height():
                self.kill()

我的杂志是一个蓝色方块

那么为什么我的射弹不会出现在屏幕上?

++++++++

在下面的答案中有所有修复,现在我有另一个错误:

当蓝色框离开屏幕时,由于杂志类的更新功能中的self.kill(),它应该被杀死。

然而,它们不是被杀,而是其中一个人离开了屏幕,它给了我这些错误:

Traceback (most recent call last):
  File "main.py", line 106, in <module>
    main()
  File "main.py", line 78, in main
    projectileObject.update()
  File "/Users/number1son100/Desktop/Famous Monsters Game/gameobjects.py", line 117, in update
    self.kill()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pygame/sprite.py", line 174, in kill
    for c in self.__g.keys():
AttributeError: 'Magazine' object has no attribute '_Sprite__g'

1 个答案:

答案 0 :(得分:0)

答案

困扰我一段时间,这是一个经典案例“在我们的鼻子下”:

查看“杂志”下“更新”功能的缩进,它向右缩进了一个,这意味着它是一个函数定义-inside- __init __()而不是你想要的杂志方法。如果这对你来说没有多大意义,那就是“dedent”阻止它看起来像这样

class Magazine(pygame.sprite.Sprite):
    def __init__(self, image, shooter):
        self.image = image
        self.rect = image.get_rect()
        self.rect.x = shooter.rect.x
        self.rect.y = shooter.rect.y - shooter.image.get_height()

    def update(self):
        self.rect.y -= 5
        if self.rect.y <= 0 - self.image.get_height():
            self.kill()

一些解释为什么没有发生但没有错误:由于你的更新功能不是杂志的方法,它没有覆盖从pygame.sprite.Sprite继承的那个。因此,当从主循环调用它时,调用了placehold / basic方法,而不是自定义方法。这意味着你没有得到错误/异常,但它没有用!

接下来,这里也存在一些与纠正有关的重大问题:

附录

1)

不是一个问题,但你可以像在这里一样使用python“for x in y”语法:

    for gameObject in gameObjects:
        gameObject.update()

稍后在渲染部分,即:

    #Render
    gameObjectBlittingCounter = 0

    for gameObject in gameObjects:
        screen.blit(gameObjects[gameObjectBlittingCounter].image, ((gameObjects[gameObjectBlittingCounter].rect.x), (gameObjects[gameObjectBlittingCounter].rect.y)))
        gameObjectBlittingCounter += 1

变为:

    for gameObject in gameObjects:
        screen.blit(gameObject.image, gameObject.rect)

另请注意,您只需传递整个rect而不是拆分为rect.x和rect.y

2)

一旦你修复了更新功能,你会注意到这一点,当你按下空格键时,你的当前代码会产生多个镜头,这是因为你的生成机制看起来是否持有空格键并在每个循环中产生一个射弹,尝试从中删除此产卵循环,只需在按下或释放空间时执行一次

3)

限制帧速率

在我的测试中,帧率可能会非常高,并使游戏运行奇怪。使用pygame.Clock对象限制帧速率并在循环中调用clock.tick(framerate)

4)

为了准备进一步的复杂性,请考虑将“gameObjects”列表分成几种不同的类型(enemyObjects,projectileObjects等),因为这些可能需要在某些时候进行不同的处理,或者保存您循环整个列表以仅如果发生这种情况会影响敌人。


最后是我的网站的一个小插件,我有一些你可以使用的pygame库的源代码和文档,可能会对你有所帮助。