我想在Python 3.2.5中使用Pygame 1.9.2a0制作一个突破克隆。 代码比真正需要的更复杂,但是这是我在python/pygame中的第一个程序,我习惯于在自己的类/对象中分解东西。在碰撞检测后Pygame 1.9.2a0列表清除错误
无论如何 - 问题的关键在于当我的球与砖块发生碰撞时,它会检测到碰撞,但它不会将它们从图纸中移除 - 如果它未从图纸中移除,从列表中删除。
for brick in bricks_.bricks:
if brick.collidepoint((ball_.pos.x+ball_.rad), (ball_.pos.y+ball_.rad)) or (brick.collidepoint((ball_.pos.x-ball_.rad),(ball_.pos.y-ball_.rad))):
ball_.speed.y = -ball_.speed.y
to_remove = [brick]
for brick in to_remove:
bricks_.bricks.remove(brick)
我试图实现一种技术,这是从早期的问题,发现在stackoverflow但它仍然无法正常工作。
当我将代码放入绘图函数中时,它在再次绘制该图块之前将其删除。问题是我只运行一次我的创建砖块功能,所以我不明白为什么它正在绘制从列表中删除的砖块。
这是创建和绘制功能:
def create(self):
y_margin = 40
self.bricks = []
for i in range(2):
""" Calculates x margin by subtracting by the number of pixels the blocks will take,
divides this on 2 so you get the "spacing" on both sides of the blocks.
Subtracts half a block width from this number and then it's aligned perfectly.
I do not know why I need to subtract half a block.
"""
x_margin = ((screen[0]-8*BRICK_W)/2)-(BRICK_W/2)
for j in range(8):
self.pos = (Vector2D((x_margin), (y_margin)))
self.bricks.append(pygame.Rect(self.pos.x, self.pos.y, BRICK_W, BRICK_H))
x_margin += BRICK_W+5
y_margin += BRICK_H+5
def draw(self):
for brick in self.bricks:
pygame.draw.rect(screen_, WHITE, brick)
自从我决定与collisiondetection我得到另一个错误,我想如果没有块会消失的简易公路。下面是游戏的图片:http://i.stack.imgur.com/0thU6.gif。
人的整个代码谁愿意来看一看: (国体不漂亮,但ATLEAST它适用于这种低级别的代码)
# Standard libraries
import sys, math, random
# Importing third party libraries
import pygame
from pygame.locals import *
# Global constants
screen = (600, 600)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
BLACK = (0, 0 ,0)
PLATFORM_W = 100
PLATFORM_H = 20
ball_dia = 20
BRICK_W = 30
BRICK_H = 15
# Set screen
screen_ = pygame.display.set_mode(screen, 0 , 32)
# Platform Y coordinate
platform_Y = screen[1] - PLATFORM_H - 10 #This can be modified to fit aesthetics
# Restrictions
platform_MAX_X = screen[0] - PLATFORM_W
BALL_MAX_X = screen[0] - ball_dia+PLATFORM_H
BALL_MAX_Y = screen[1] - ball_dia
## ======================================*Vector2D*============================================== ##
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(Self):
return 'Vector(X: {x}, Y: {y})'.format(x = self.x, y = self.y)
def __add__(self, b):
return Vector2D(self.x + b.x, self.y +b.y)
def __sub__(self, b):
return Vector2D(self.x - b.x, self.y - b.y)
def __mul__(self, b):
try:
b = float(b)
return Vector2D(self.x * b, self.y * b)
except ValueError:
print("Ooops! Right value must be a float")
raise
def magnitue(self):
try:
m = self.magnitude()
return Vector2D(self.x/m, self.y/m)
except ZeroDivisionError:
print("Ooops, cannot normalize a zero vector")
raise
def copy(self):
return Vector2D(self.x, self.y)
"""
Get distance is basically getting the distance from a to b,
in this case vector a and vector b
"""
def get_distance(a, b):
""" Using the distance formula which is derived from the Pythagorean theorem,
http://www.mathwarehouse.com/algebra/distance_formula/index.php """
a = Vector2D(a.x, a.y)
b = Vector2D(b.x, b.y)
return (((((a.x-b.x)**2)+((a.y-b.y)**2)))**.5)
## =========================================*Platform*=========================================== ##
class Platform:
""" This is the platform that the player can control in x direction with arrow keys """
def __init__(self):
self.x = screen[0]/2 - PLATFORM_W/2
self.y = platform_Y
self.width = PLATFORM_W
self.height = PLATFORM_H
self.pos = Vector2D(self.x, self.y)
self.tileRect = pygame.Rect(self.x, self.y, self.width, self.height)
def clique(self):
""" This is the one doing the magic to the Platform by getting the new x coordinates from
the input function. It then updates it's position data accordingly and draws the Platform
on the new information. """
self.x = Input().x
self.pos = Vector2D(self.x, self.y)
# Making a variable that is equal to the rectangle platform
# This will be used for collision detection.
self.tileRect = pygame.Rect(self.x, self.y, self.width, self.height)
self.draw()
def draw(self):
pygame.draw.rect(screen_, BLUE, (self.pos.x, self.pos.y, self.width, self.height))
platform_ = Platform()
## ===========================================*Bricks*========================================= ##
class Bricks:
""" Bricks that will be removed after hit by the ball.
They are created using for loops. Change the ranges on the for loops to change
amounts of bricks """
def __init__(self):
pass
def create(self):
y_margin = 40
self.bricks = []
for i in range(2):
""" Calculates x margin by subtracting by the number of pixels the blocks will take,
divides this on 2 so you get the "spacing" on both sides of the blocks.
Subtracts half a block width from this number and then it's aligned perfectly.
I do not know why I need to subtract half a block.
"""
x_margin = ((screen[0]-8*BRICK_W)/2)-(BRICK_W/2)
for j in range(8):
self.pos = (Vector2D((x_margin), (y_margin)))
self.bricks.append(pygame.Rect(self.pos.x, self.pos.y, BRICK_W, BRICK_H))
x_margin += BRICK_W+5
y_margin += BRICK_H+5
def draw(self):
for brick in self.bricks:
pygame.draw.rect(screen_, WHITE, brick)
bricks_ = Bricks()
## ========================================*Ball*============================================ ##
class Ball:
""" A ball that will move, change direction if it hits platform, walls or bricks.
"""
def __init__(self):
self.rad = ball_dia/2
self.speed = Vector2D(0, 0)
self.pos = Vector2D(platform_.x+(PLATFORM_W/2), platform_.y-self.rad)
self.status = 0
self.gameover = False
def move(self):
ball_.speed = input_.speed
ball_.pos += ball_.speed
"""
Basic wall detection. Check all walls, subtracts the radius of the ball.
"""
if self.pos.x > BALL_MAX_X - self.rad:
self.pos.x = BALL_MAX_X - self.rad
self.speed.x *= -1
if self.pos.x < 0 + self.rad:
self.pos.x = 0 + self.rad
self.speed.x *= -1
if self.pos.y > BALL_MAX_Y - self.rad:
self.gameover = True
if self.pos.y < 0 + self.rad:
self.pos.y = 0 + self.rad
self.speed.y *= -1
"""
Inter is the centre position of the rectangle platform. This can be used
for collision detection. """
inter = Vector2D(platform_.pos.x+PLATFORM_W/2, platform_.pos.y-PLATFORM_H/2)
d = get_distance(inter, self.pos)
""" Here we are checking if the rectangle platform are colliding with the point
ball's coordinates + its radius. If that is the case we are also checking which
side of the platform the ball is colliding on and having two different multipliers
giving it a feel of randomness and having a bounce to the other direction,
this we get by multiplying it by -1 (i.e)"""
if platform_.tileRect.collidepoint((self.pos.x+self.rad), (self.pos.y+self.rad)) or (platform_.tileRect.collidepoint((self.pos.x-self.rad),(self.pos.y-self.rad))):
if self.pos.x > inter.x:
self.speed.x *= -random.randrange(1,4)
self.speed.y *= -random.randrange(1,4)
if self.pos.x < inter.x:
self.speed.x *= -random.randrange(2, 4)
self.speed.y *= -random.randrange(2, 4)
for brick in bricks_.bricks:
if brick.collidepoint((ball_.pos.x+ball_.rad), (ball_.pos.y+ball_.rad)) or (brick.collidepoint((ball_.pos.x-ball_.rad),(ball_.pos.y-ball_.rad))):
ball_.speed.y = -ball_.speed.y
to_remove = [brick]
for brick in to_remove:
bricks_.bricks.remove(brick)
if self.speed.x > 10:
self.speed.x *= 0.5
if self.speed.x < -10:
self.speed.x *= 0.5
if self.speed.y > 10:
self.speed.y *= 0.5
if self.speed.y < -10:
self.speed.y *= 0.5
ball_.draw()
def collisions(self):
pass
def draw(self):
if self.gameover == False:
pygame.draw.circle(screen_, WHITE, (int(self.pos.x), int(self.pos.y)), int(self.rad))
ball_ = Ball()
## ======================================*Engine*============================================== ##
class Engine:
""" The engine initiates the game, takes care of events,
show stats and messages and basically run all the other parts
of the program """
def __init__(self):
self.alive = True
self.retarded = False
pygame.display.set_caption("Rektball by #TeamRekt")
self.clock = pygame.time.Clock()
if pygame.font:
self.font = pygame.font.Font(None, 30)
else:
self.font = None
"""
The eventhandler is a function that will check pygame.events,
for either pygame.QUIT or the ESC button. If either is executed it will set the boolean
to false and it will quit pygame using the built in pygame.quit() function.
"""
def event_handler(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.alive = False
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.alive = False
pygame.quit()
"""
Show message will basically show a message in the middle of the screen.
It will use blit to create/render/draw/show the text.
"""
def show_message(self, message):
if self.font:
size = self.font.size(message)
font_surface = self.font.render(message, False, WHITE)
x = (screen[0] - size[0])/2
y = (screen[1] - size[1]) /2
screen_.blit(font_surface, (x,y))
"""
The run-loop which runs this whole game. Everything is handled in this loop.
"""
def run(self):
while self.alive:
self.event_handler()
screen_.fill(BLACK)
self.time_passed = self.clock.tick(30)
statrun.Starts()
if statrun.start == False:
statrun.Starts()
statrun.Runs()
if ball_.gameover == True:
statrun.Gameovers()
pygame.display.update()
## =======================================*Input*============================================= ##
class Input:
""" This will take care of inputs,
i.e. keys being pressed down and use it to change
parts of the code to move the ball, the platform etc. """
def __init__(self):
self.x = platform_.pos.x
self.speed = Vector2D(0,0)
self.status = False
self.check_input()
def check_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.x -= 10
if self.x < 0:
self.x = 0
if keys[pygame.K_RIGHT]:
self.x += 10
if self.x > platform_MAX_X:
self.x = platform_MAX_X
if keys[pygame.K_SPACE] and (self.status == False):
self.status = True
self.speed = Vector2D((-random.randrange(4, 10)),(-random.randrange(4,10)))
input_ = Input()
## ==================================================================================== ##
class State_run:
"""
This was supposed to be part of a bigger state-machine code,
but after hitting the wall for too many hours I decided to abandon
the project, but keeping a little bit of the structure.
It is being called by boolean in the run function inside the engine object/class.
This is not a very good solution, but as I said, I have spent a few hours (days...),
and I just had to wrap this up.
"""
""" The init function will start the boolean circus,
although the boolean will not be used if it works as planned,
it's a fallback boolean. """
def __init__(self):
self.start = False
def Starts(self):
platform_.draw()
ball_.draw()
bricks_.create()
bricks_.draw()
self.start = True
def Runs(self):
input_.check_input()
if input_.status != True:
Engine().show_message("Press space to start game")
if input_.status == True:
ball_.move()
platform_.clique()
bricks_.draw()
def Wins(self):
Engine().show_message("You have won the game")
def Gameovers(self):
Engine().show_message("You have lost the game")
ball_.speed = Vector2D(0,0)
statrun = State_run()
## ==================================================================================== ##
""" Runs the program by first initiating pygame using the builtin function, pygame.init(),
then it runs the Engine().run() function which is doing all the work. """
if __name__ == "__main__":
pygame.init()
Engine().run()
发现我的问题。 这是在 '高清启动(个体经营): platform_.draw() ball_.draw() bricks_.create() bricks_.draw() self.start = TRUE' 其中正在运行的所有时间,当我认为它不是...... – IndentationFaulter 2015-02-11 17:02:23