I started Python last week and I'm trying to create a game to learn. There are 4 moving circles in the screen, moving from the middle of the screen to the 4 edges. I got this part I think.
Now I'm trying to drop cubes from the 4 edges to the middle. The goal is to stop those cubes from reaching the middle of the screen, by pressing keyboard arrows. If one cube reaches the center, it's game over.
I managed to drop 4 cubes to the middle at the same time, but the idea is to drop randomly a few cubes.
Any idea how I should proceed to create this? or what should I learn to make this happen?
here's my work so far:
# ---------- Packages ----------
import pygame, random
pygame.init()
# ---------- Constants ----------
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
FPS = 60
SPEED = 1
SPEED_ENEMIES = 1
CIRCLE_RADIUS = 50
ENNEMY_SIZE = 40
red = (255,000,000)
blue = (000,000,255)
yellow = (255,255,000)
green = (000,128,000)
pink = (255,192,203)
black = (000,000,000)
transparent = (0, 0, 0, 0)
# ---------- Classes ----------
class Ennemies:
def __init__(self, x, y, size=ENNEMY_SIZE, thick=5, color=blue, speed=SPEED_ENEMIES):
self.rect = pygame.Rect(0, 0, 2*size, 2*size)
self.rect.centerx = x
self.rect.centery = y
self.size = size
self.thick = thick
self.color = color
self.speed = speed
if speed >= 0:
self.directionX = 'right'
self.direction = 'up'
else:
self.directionX = 'left'
self.direction = 'down'
def draw(self, screen):
pygame.draw.rect(screen, self.color,(self.rect.centerx,self.rect.centery,self.size,self.size))
def move_up(self):
self.rect.y -= self.speed
if self.rect.centery < int(SCREEN_HEIGHT/2) - self.size/2:
self.color = transparent
def move_down(self):
self.rect.y += self.speed
if self.rect.centery > int(SCREEN_HEIGHT/2) - self.size/2:
self.color = transparent
def move_left(self):
self.rect.x -= self.speed
if self.rect.centerx < int(SCREEN_WIDTH/2) - self.size/2:
self.color = transparent
def move_right(self):
self.rect.x += self.speed
if self.rect.centerx > int(SCREEN_WIDTH/2) - self.size/2:
self.color = transparent
class Circle:
def __init__(self, x, y, radius=CIRCLE_RADIUS, thick=5, color=blue, speed=SPEED):
self.rect = pygame.Rect(0, 0, 2*radius, 2*radius)
self.rect.centerx = x
self.rect.centery = y
self.radius = radius
self.thick = thick
self.color = color
self.speed = speed
if speed >= 0:
self.directionX = 'right'
self.direction = 'up'
else:
self.directionX = 'left'
self.direction = 'down'
def draw(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.radius, self.thick)
def swing_top(self):
self.rect.y -= self.speed
if self.rect.top <= 0 and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
if self.rect.bottom > int(SCREEN_HEIGHT/2) - self.radius and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
def swing_bot(self):
self.rect.y -= self.speed
if self.rect.top < int(SCREEN_HEIGHT/2) + self.radius and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
if self.rect.bottom >= SCREEN_HEIGHT and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
def swing_left(self):
self.rect.x -= self.speed
if self.rect.right > int(SCREEN_WIDTH/2) - self.radius and self.directionX == 'left':
self.directionX = 'right'
self.speed = -self.speed
if self.rect.left <= 0 and self.directionX == 'right':
self.directionX = 'left'
self.speed = -self.speed
def swing_right(self):
self.rect.x -= self.speed
if self.rect.left < int(SCREEN_WIDTH/2) + self.radius and self.directionX == 'right':
self.directionX = 'left'
self.speed = -self.speed
if self.rect.right >= SCREEN_WIDTH and self.directionX == 'left':
self.directionX = 'right'
self.speed = -self.speed
# ---------- Main ----------
def main():
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
enemyTop = [
Ennemies(int(SCREEN_WIDTH/2)-ENNEMY_SIZE/2, 0, color=yellow)
]
enemyBot = [
Ennemies(int(SCREEN_WIDTH/2)-ENNEMY_SIZE/2, SCREEN_HEIGHT-ENNEMY_SIZE, color=green)
]
enemyLeft = [
Ennemies(0, int(SCREEN_HEIGHT/2)-ENNEMY_SIZE/2, color=blue)
]
enemyRight = [
Ennemies(SCREEN_WIDTH-ENNEMY_SIZE, int(SCREEN_HEIGHT/2)-ENNEMY_SIZE/2, color = red)
]
circleTop = [
Circle(screen_rect.centerx, screen_rect.centery - 2*CIRCLE_RADIUS)
]
circleBot = [
Circle(screen_rect.centerx, screen_rect.centery + 2*CIRCLE_RADIUS)
]
circleRight = [
Circle(screen_rect.centerx + 2*CIRCLE_RADIUS, screen_rect.centery)
]
circleLeft = [
Circle(screen_rect.centerx - 2*CIRCLE_RADIUS, screen_rect.centery)
]
clock = pygame.time.Clock()
game_over = False
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
for item in enemyTop:
item.move_down()
for item in enemyBot:
item.move_up()
for item in enemyLeft:
item.move_right()
for item in enemyRight:
item.move_left()
for item in circleTop:
item.swing_top()
for item in circleBot:
item.swing_bot()
for item in circleLeft:
item.swing_left()
for item in circleRight:
item.swing_right()
screen.fill(black)
for item in enemyTop:
item.draw(screen)
for item in enemyBot:
item.draw(screen)
for item in enemyLeft:
item.draw(screen)
for item in enemyRight:
item.draw(screen)
for item in circleTop:
item.draw(screen)
for item in circleBot:
item.draw(screen)
for item in circleLeft:
item.draw(screen)
for item in circleRight:
item.draw(screen)
pygame.display.update()
clock.tick(FPS)
main()
pygame.quit()
Thanks
I think the answer here is to modify your Enemies
object so that it works better as a more generic object.
To this end I modified the class so that a "cube" starts at a random position at the side, and always heads into the middle (I'm, not sure if this is exactly what you planned, but it's my interpretation of your game description).
This is achieved by calculating a direction vector (since it could now be a diagonal line), and then adding this amount (times speed) to the location each "tick". One problem this creates, is that if the component of the direction is very small - say 0.1 pixels/tick, then the addition of this amount is always rounded away to nothing. So the class keeps the location as a floating point number, and only converts back to integer when the Rect is updated.
The code now keeps a list of Enemies
objects. This makes it easy to iterate through this list, updating, drawing and checking positions. To add more enemies, simply add extras to this list - perhaps as levels get harder.
The next change was for the Enemy to start in a random position if the supplied co-ordinates are (0,0). This allows the code to re-set the old enemies to a new random starting position, or add new ones.
# ---------- Packages ----------
import pygame, random
pygame.init()
# ---------- Constants ----------
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
FPS = 60
SPEED = 1
SPEED_ENEMIES = 1
CIRCLE_RADIUS = 50
ENEMY_SIZE = 40
red = (255,000,000)
blue = (000,000,255)
yellow = (255,255,000)
green = (000,128,000)
pink = (255,192,203)
black = (000,000,000)
transparent = (0, 0, 0, 0)
# ---------- Classes ----------
class Enemies:
def __init__(self, x, y, size=ENEMY_SIZE, thick=5, color=blue, speed=SPEED_ENEMIES):
self.rect = pygame.Rect(0, 0, size, size)
# if x and y are zero, choose a random starting point
if ( x == 0 and y == 0 ):
self.randomise()
self.rect.centerx = x
self.rect.centery = y
self.size = size
self.thick = thick
self.color = color
self.speed = speed
self.calcDirection()
def calcDirection( self ):
""" Work out the direction vector to (0,0) """
self.x_float = 1.0 * self.rect.centerx # keep these to stop rounding errors
self.y_float = 1.0 * self.rect.centery
# Determine direction vector from (x,y) to the centre of the screen
self.position_vector = pygame.math.Vector2( self.x_float, self.y_float )
self.velocity_vector = pygame.math.Vector2( SCREEN_WIDTH/2 - self.x_float, SCREEN_HEIGHT/2 - self.y_float )
self.velocity_vector = self.velocity_vector.normalize()
#print("Velocity Vector = "+str(self.velocity_vector) )
def update( self ):
x_delta = self.speed * self.velocity_vector[0]
y_delta = self.speed * self.velocity_vector[1]
self.x_float += x_delta
self.y_float += y_delta
self.rect.centerx = int( self.x_float )
self.rect.centery = int( self.y_float )
def draw(self, screen):
pygame.draw.rect(screen, self.color, self.rect )
def reachedPoint( self, x, y ):
return self.rect.collidepoint( x, y )
def randomise( self ):
""" Pick a random starting point """
self.rect.centerx = random.randint( 0, SCREEN_WIDTH )
self.rect.centery = random.randint( 0, SCREEN_HEIGHT )
side = random.randint( 0, 4 )
if ( side == 0 ): # top
self.rect.centery = SCREEN_HEIGHT
elif ( side == 1 ): # bottom
self.rect.centery = 0
elif ( side == 2 ): # left
self.rect.centerx = 0
else: # right
self.rect.centerx = SCREEN_WIDTH
self.calcDirection()
class Circle:
def __init__(self, x, y, radius=CIRCLE_RADIUS, thick=5, color=blue, speed=SPEED):
self.rect = pygame.Rect(0, 0, 2*radius, 2*radius)
self.rect.centerx = x
self.rect.centery = y
self.radius = radius
self.thick = thick
self.color = color
self.speed = speed
if speed >= 0:
self.directionX = 'right'
self.direction = 'up'
else:
self.directionX = 'left'
self.direction = 'down'
def draw(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.radius, self.thick)
def swing_top(self):
self.rect.y -= self.speed
if self.rect.top <= 0 and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
if self.rect.bottom > int(SCREEN_HEIGHT/2) - self.radius and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
def swing_bot(self):
self.rect.y -= self.speed
if self.rect.top < int(SCREEN_HEIGHT/2) + self.radius and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
if self.rect.bottom >= SCREEN_HEIGHT and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
def swing_left(self):
self.rect.x -= self.speed
if self.rect.right > int(SCREEN_WIDTH/2) - self.radius and self.directionX == 'left':
self.directionX = 'right'
self.speed = -self.speed
if self.rect.left <= 0 and self.directionX == 'right':
self.directionX = 'left'
self.speed = -self.speed
def swing_right(self):
self.rect.x -= self.speed
if self.rect.left < int(SCREEN_WIDTH/2) + self.radius and self.directionX == 'right':
self.directionX = 'left'
self.speed = -self.speed
if self.rect.right >= SCREEN_WIDTH and self.directionX == 'left':
self.directionX = 'right'
self.speed = -self.speed
# ---------- Main ----------
def main():
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# Start with 4 enemies
all_enemies = [
Enemies(random.randint(1,SCREEN_WIDTH), 1, color=yellow), # bottom
Enemies(random.randint(1,SCREEN_WIDTH), SCREEN_HEIGHT-ENEMY_SIZE, color=green), # top
Enemies(1, random.randint(1,SCREEN_HEIGHT), color=blue), # left
Enemies(SCREEN_WIDTH-ENEMY_SIZE, random.randint(1,SCREEN_HEIGHT), color = red) # right
]
circleTop = [
Circle(screen_rect.centerx, screen_rect.centery - 2*CIRCLE_RADIUS)
]
circleBot = [
Circle(screen_rect.centerx, screen_rect.centery + 2*CIRCLE_RADIUS)
]
circleRight = [
Circle(screen_rect.centerx + 2*CIRCLE_RADIUS, screen_rect.centery)
]
circleLeft = [
Circle(screen_rect.centerx - 2*CIRCLE_RADIUS, screen_rect.centery)
]
clock = pygame.time.Clock()
game_over = False
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
for item in circleTop:
item.swing_top()
for item in circleBot:
item.swing_bot()
for item in circleLeft:
item.swing_left()
for item in circleRight:
item.swing_right()
screen.fill(black)
for e in all_enemies:
e.update()
# Did the enemy make it to the centre?
if ( e.reachedPoint( SCREEN_WIDTH//2, SCREEN_HEIGHT//2 ) ):
# Game over?
print("Game Over?")
e.randomise()
e.draw( screen )
for item in circleTop:
item.draw(screen)
for item in circleBot:
item.draw(screen)
for item in circleLeft:
item.draw(screen)
for item in circleRight:
item.draw(screen)
pygame.display.update()
clock.tick(FPS)
main()
pygame.quit()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.