我想在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