import pygame
import sys
from pygame.sprite import Sprite
class Settings:
def __init__(self):
self.raindrop_speed = 3
self.raindrop_direction = -1
self.raindrop_dropseed = 3
self.backgroundcolor = (30,30,30)
class Drop(Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("raindrop.png")
self.rect = self.image.get_rect()
self.rect.y = self.rect.height
self.rect.x = self.rect.width
self.x_cord = self.rect.x
self.y_cord = self.rect.y
class RainDrop:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((1200,800))
self.settings = Settings()
self.backgroundcolor = self.settings.backgroundcolor
self.raindrops = pygame.sprite.Group()
self.screen_rect = self.screen.get_rect()
self._add_raindrops()
def _add_raindrops(self):
new_raindrop = Drop()
drop_height = new_raindrop.rect.height
drop_width = new_raindrop.rect.width
print(drop_width)
screen_space = self.screen_rect.width
screen_height_space = self.screen_rect.height
aviable_row_space = screen_height_space//(drop_height*2)
avivable_screen_space = screen_space - (drop_width*2)
amount_of_columns = avivable_screen_space//(drop_width*2)
self._add_columns(amount_of_columns,aviable_row_space)
def _add_columns(self,amount_of_columns,aviable_row_space):
for height_of_drops in range(aviable_row_space):
for number_of_drops in range(amount_of_columns):
drop = Drop()
drop.x_cord = (drop.rect.width *2)* number_of_drops
drop.y_cord =(drop.rect.height *2)* height_of_drops
drop.rect.x = drop.x_cord
drop.rect.y = drop.y_cord
self.raindrops.add(drop)
def _bring_down_raindrops(self):
for drop in self.raindrops:
drop.y_cord += self.settings.raindrop_dropseed
drop.rect.y = drop.y_cord
def _update_drops(self):
height_counter = 1
self.raindrops.update()
for drop in self.raindrops.copy():
drop.x_cord += self.settings.raindrop_direction * self.settings.raindrop_speed
drop.rect.x = drop.x_cord
if drop.rect.right >= self.screen_rect.right:
self.settings.raindrop_direction = -1
self._bring_down_raindrops()
elif drop.rect.left <= 0:
self.settings.raindrop_direction = 1
self._bring_down_raindrops()
#if drop.rect.y >= self.screen_rect.height or drop.rect.y <= 0:
# drop.rect.x = drop.rect.width
# drop.y_cord = drop.rect.height
# drop.rect.y = drop.y_cord
print(height_counter)
print(self.raindrops)
def _update_game(self):
self.screen.fill(self.backgroundcolor)
self.raindrops.draw(self.screen)
pygame.display.flip()
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
def run_game(self):
while True:
self._check_events()
self._update_drops()
self._update_game()
if __name__ == "__main__":
rd = RainDrop()
rd.run_game()
Everytime I run this program the rectangle(waterdrops) when they reach the end of the screen a bigger gap appears I have looked at the code for several hours and I can not see what the problem is, I think it has to do with the condition in bottom but I am not sure I have messed with it and changed some values but it still does the same thing.
Your problem is in what you do when you recognize that you've hit the edge of the screen. You do this when you find any drop that has gone off of the screen, and at that point, you reverse direction. The problem is, you've already moved some of the drops on the top row in one direction, but after you recognize the edge of the screen, you then go on to move the rest of the drops in the opposite direction in that same pass. This is how things get out of wack.
What you want to do is note that you've hit the edge of the screen, but not do anything differently right away, so that you still deal with all of the drops on the screen the same way in that pass. After you've drawn all of the drops, you then change direction.
Here's a version of _update_drops that will do this:
def _update_drops(self):
height_counter = 1
self.raindrops.update()
# assume we haven't hit either edge of the screen
reverse = 0
for drop in self.raindrops.copy():
drop.x_cord += self.settings.raindrop_direction * self.settings.raindrop_speed
drop.rect.x = drop.x_cord
if drop.rect.right >= self.screen_rect.right:
# remember that we hit the right edge of the screen
reverse = -1
elif drop.rect.left <= 0:
# remember that we hit the left edge of the screen
reverse = 1
# if we hit one of the edges, change directions and drop down
if reverse != 0:
self.settings.raindrop_direction = reverse
self._bring_down_raindrops()
What I want is two things:
count the number of enemies on the screen. And remove all enemies from the screen with a contion.
The second chose is to allow enemies to shoot randomly
class Enemy(Particle):
active = False
tex_name = 'ufo'
v = 0
def reset(self, created=False):
self.active = False
self.x = -100
self.y = -100
self.v = 0
def advance(self, nap):
if self.active:
if self.check_hit():
self.reset()
return
self.x -= 200 * nap
if self.x < -50:
self.reset()
return
self.y += self.v * nap
if self.y <= 0:
self.v = abs(self.v)
elif self.y >= self.parent.height:
self.v = -abs(self.v)
elif self.parent.spawn_delay <= 0:
self.active = True
self.x = self.parent.width + 50
self.y = self.parent.height * random()
self.v = randint(-100, 100)
self.parent.spawn_delay += 1
def check_hit(self):
if math.hypot(self.parent.player_x - self.x,
self.parent.player_y - self.y) < 60:
return True
for b in self.parent.bullets:
if not b.active:
continue
if math.hypot(b.x - self.x, b.y - self.y) < 30:
b.reset()
return True
What I want is two things:
count the number of enemies on the screen. And remove all enemies from the screen with a contion.
The second chose is to allow enemies to shoot randomly
You can accomplish the first two of your questions by modifying the PSWidget class. By adding two attributes enemy_count and killall to the class:
class PSWidget(Widget):
indices = []
vertices = []
particles = []
enemy_count = 0
killall = False
And using those attributes in the update_glsl() method:
def update_glsl(self, nap):
self.enemy_count = 0 # initialize enemy count
for p in self.particles:
if isinstance(p, Enemy) and p.active:
if self.killall:
p.reset() # kill this enemy
else:
self.enemy_count += 1 # increment enemy count
p.advance(nap)
p.update()
self.canvas.clear()
with self.canvas:
Mesh(fmt=self.vfmt, mode='triangles',
indices=self.indices, vertices=self.vertices,
texture=self.texture)
# reset killall
self.killall = False
So, anytime you want the count of active enemies, just use the enemy_count attribute of the PSWidget instance. And whenever you want to kill all the active enemies, just set the killall attribute of the PSWidget instance.
As far as your third question, show us your attempt at coding that.
If you are using an answer that I gave in another question, where I suggested using the on_enter() method to start the game updates, then you can use on_leave() to stop the updates. The game movements are faster every time you enter MainScreen because more updates are scheduled on each entry. Here is a modified MainScreen that handles that handles that issue:
class MainScreen(Screen):
started = BooleanProperty(False)
def on_enter(self, *args):
if not self.started:
self.ids.game.initialize()
self.started = True
self.update_event = Clock.schedule_interval(self.ids.game.update_glsl, 1.0/60.0)
def on_leave(self, *args):
if self.update_event is not None:
self.update_event.cancel()
I'm working on a 2D python game project for my CS class, and I've hit a bump, I don't know what the problem is:
The project is a large part of my grade, and up until now I've had an A+
This project is incredibly frustrating
NEW
ok so i've got everything working so far, except for some reason My protaganist() is stuck at the top left corner of the game screen !
Also, i need ideas on how to create a jump action
If anyone could help I would be incredibly grateful!
I am importing a game engine my teacher made available from his book website, but i it is too long for me to add but i will try to add some of it at the bottom
Here is all my code:
import gameEngine
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.mixer.init()
sndAtk = pygame.mixer.Sound("OOT_AdultLink_Attack1.wav")
#goal is to create a game
#must have menu to start game
#menu should have a start and quit button.. start runs gaming operations and quit exits program
#sprites for character and enemies and bullets maybe, use one large image and simply move visibiliy
#this saves memory as 1 image is loaded instead of many
"""
class game(gameEngine.scene):
def __init__(self, scene):
self.background()
self.sprites["spawn.gif", "badguys.gif"]
"""
"""
protaganist is our hero sprite
should run left and right, jump left and right
and attack left and right...
I might add in the bow and jump attack
"""
class scrollinggrass(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("gamebackground.jpg")
self.rect.centerx = 20
self.rect.centery = 500
self.rect = self.image.get_rect()
self.dx = 10
self.dy = 0
self.checkKeys()
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
print("working")
self.forward(3)
run.play()
if keys[pygame.K_LEFT]:
self.forward(-3)
class hearts(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("heart.png")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.setPosition((550 , 30))
class badguy(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("badguy1.png")
self.rect = self.imageMaster.get_rect()
self.health = 2
self.DEAD = 1
self.state = 0
class protaganist(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.imageList = []
self.rect = self.imageMaster.get_rect()
self.STANDING = 0
self.RUNNING = 1
self.ATTACKING = 2
self.JUMPING = 3
self.DEAD = 10
self.imageFrame = 0
self.state = self.STANDING
self.hearts = 1
self.heartPts = self.hearts * 3
self.stats()
self.loadImages()
# self.image = self.imageList[0]
self.checkKeys()
def stats(self):
#sets it up so each heart is essentially 3 hit points
if self.heartPts >= 3:
self.hearts = 1
elif self.heartPts >= 6:
self.hearts = 2
elif self.heartPts == 9:
self.hearts = 3
elif self.heartPts > 9:
self.heartPts = 9
# changes state to dead if hp == 0
if self.heartPts == 0:
self.state = DEAD
def loadImages(self):
self.setPosition((320 , 380))
self.setImage("heroSTANDING.gif")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.state = runRight
self.frame += 1
if self.frame >= len(self.imageList):
self.frame = 1
self.image = self.imageList[self.frame]
# self.image = self.image.get_rect()
# self.rect.center = (320, 240)
if keys[pygame.K_LEFT]:
self.state = 1
while keys[pygame.K_g]:
self.state = Attacking
sndAtk.play()
if self.state == self.DEAD:
self.image = self.deadImgList[0]
self.frame += 1
self.image = self.deadImgList[self.frame]
#self.image = self.image.get_rect()
#self.rect.center = (320, 240)
class game(gameEngine.Scene):
def __init__ (self):
gameEngine.Scene.__init__(self)
pygame.display.set_caption("Link's Mediocre Adventure")
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
pro = protaganist(self)
baddy = badguy(self)
baddy1 = badguy(self)
heart = hearts(self)
grass = scrollinggrass(self)
goodlySprites = self.makeSpriteGroup((grass, pro, heart))
baddySprites = self.makeSpriteGroup((baddy, baddy1))
# self.addSpriteGroup(goodlySprites)
self.addGroup((baddySprites))
clock = pygame.time.Clock()
keepGoing = True
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
if pro.state == pro.ATTACKING:
if pro.collidesGroup(baddySprites):
baddy.health -= 1
baddy1.health -= 1
if baddy.health == 0:
baddy.reset()
elif baddy1.health == 0:
baddy.reset()
elif pro.state != pro.ATTACKING:
if pro.collideGroup(baddySprites):
pro.heartPts -= 1
goodlySprites.update()
baddySprites.update()
goodlySprites.draw(screen)
baddySprites.draw(screen)
pygame.display.flip()
def main():
game.start()
if __name__ == "__main__":
game()
game engine
class SuperSprite(pygame.sprite.Sprite):
""" An enhanced Sprite class
expects a gameEngine.Scene class as its one parameter
Use methods to change image, direction, speed
Will automatically travel in direction and speed indicated
Automatically rotates to point in indicated direction
Five kinds of boundary collision
"""
def __init__(self, scene):
pygame.sprite.Sprite.__init__(self)
self.scene = scene
self.screen = scene.screen
#create constants
self.WRAP = 0
self.BOUNCE = 1
self.STOP = 2
self.HIDE = 3
self.CONTINUE = 4
#create a default text image as a placeholder
#This will usually be changed by a setImage call
self.font = pygame.font.Font("freesansbold.ttf", 30)
self.imageMaster = self.font.render(">sprite>", True, (0, 0,0), (0xFF, 0xFF, 0xFF))
self.image = self.imageMaster
self.rect = self.image.get_rect()
#create properties
#most will be changed through method calls
self.x = 200
self.y = 200
self.dx = 0
self.dy = 0
self.dir = 0
self.rotation = 0
self.speed = 0
self.maxSpeed = 10
self.minSpeed = -3
self.boundAction = self.WRAP
self.pressed = False
self.oldCenter = (100, 100)
self.states = {}
self.currentState = "default"
def update(self):
self.oldCenter = self.rect.center
self.checkEvents()
self.__rotate()
self.__calcVector()
self.__calcPosition()
self.checkBounds()
self.rect.center = (self.x, self.y)
def checkEvents(self):
""" overwrite this method to add your own event code """
pass
def __rotate(self):
""" PRIVATE METHOD
change visual orientation based on
rotation property.
automatically called in update.
change rotation property directly or with
rotateBy(), setAngle() methods
"""
oldCenter = self.rect.center
self.oldCenter = oldCenter
self.image = pygame.transform.rotate(self.imageMaster, self.rotation)
self.rect = self.image.get_rect()
self.rect.center = oldCenter
def __calcVector(self):
""" calculates dx and dy based on speed, dir
automatically called in update
"""
theta = self.dir / 180.0 * math.pi
self.dx = math.cos(theta) * self.speed
self.dy = math.sin(theta) * self.speed
self.dy *= -1
def __calcPosition(self):
""" calculates the sprites position adding
dx and dy to x and y.
automatically called in update
"""
self.x += self.dx
self.y += self.dy
def checkBounds(self):
""" checks boundary and acts based on
self.BoundAction.
WRAP: wrap around screen (default)
BOUNCE: bounce off screen
STOP: stop at edge of screen
HIDE: move off stage and wait
CONTINUE: keep going at present course and speed
automatically called by update
"""
scrWidth = self.screen.get_width()
scrHeight = self.screen.get_height()
#create variables to simplify checking
offRight = offLeft = offTop = offBottom = offScreen = False
if self.x > scrWidth:
offRight = True
if self.x < 0:
offLeft = True
if self.y > scrHeight:
offBottom = True
if self.y < 0:
offTop = True
if offRight or offLeft or offTop or offBottom:
offScreen = True
if self.boundAction == self.WRAP:
if offRight:
self.x = 0
if offLeft:
self.x = scrWidth
if offBottom:
self.y = 0
if offTop:
self.y = scrHeight
elif self.boundAction == self.BOUNCE:
if offLeft or offRight:
self.dx *= -1
if offTop or offBottom:
self.dy *= -1
self.updateVector()
self.rotation = self.dir
elif self.boundAction == self.STOP:
if offScreen:
self.speed = 0
elif self.boundAction == self.HIDE:
if offScreen:
self.speed = 0
self.setPosition((-1000, -1000))
elif self.boundAction == self.CONTINUE:
pass
else:
# assume it's continue - keep going forever
pass
def setSpeed(self, speed):
""" immediately sets the objects speed to the
given value.
"""
self.speed = speed
def speedUp(self, amount):
""" changes speed by the given amount
Use a negative value to slow down
"""
self.speed += amount
if self.speed < self.minSpeed:
self.speed = self.minSpeed
if self.speed > self.maxSpeed:
self.speed = self.maxSpeed
def setAngle(self, dir):
""" sets both the direction of motion
and visual rotation to the given angle
If you want to set one or the other,
set them directly. Angle measured in degrees
"""
self.dir = dir
self.rotation = dir
def turnBy (self, amt):
""" turn by given number of degrees. Changes
both motion and visual rotation. Positive is
counter-clockwise, negative is clockwise
"""
self.dir += amt
if self.dir > 360:
self.dir = amt
if self.dir < 0:
self.dir = 360 - amt
self.rotation = self.dir
def rotateBy(self, amt):
""" change visual orientation by given
number of degrees. Does not change direction
of travel.
"""
self.rotation += amt
if self.rotation > 360:
self.rotation = amt
if self.rotation < 0:
self.rotation = 360 - amt
def setImage (self, image):
""" loads the given file name as the master image
default setting should be facing east. Image
will be rotated automatically """
self.imageMaster = pygame.image.load(image)
self.imageMaster = self.imageMaster.convert()
def setDX(self, dx):
""" changes dx value and updates vector """
self.dx = dx
self.updateVector()
def addDX(self, amt):
""" adds amt to dx, updates vector """
self.dx += amt
self.updateVector()
def setDY(self, dy):
""" changes dy value and updates vector """
self.dy = dy
self.updateVector()
def addDY(self, amt):
""" adds amt to dy and updates vector """
self.dy += amt
self.updateVector()
def setComponents(self, components):
""" expects (dx, dy) for components
change speed and angle according to dx, dy values """
(self.dx, self.dy) = components
self.updateVector()
def setBoundAction (self, action):
""" sets action for boundary. Values are
self.WRAP (wrap around edge - default)
self.BOUNCE (bounce off screen changing direction)
self.STOP (stop at edge of screen)
self.HIDE (move off-stage and stop)
self.CONTINUE (move on forever)
Any other value allows the sprite to move on forever
"""
self.boundAction = action
def setPosition (self, position):
""" place the sprite directly at the given position
expects an (x, y) tuple
"""
(self.x, self.y) = position
def moveBy (self, vector):
""" move the sprite by the (dx, dy) values in vector
automatically calls checkBounds. Doesn't change
speed or angle settings.
"""
(dx, dy) = vector
self.x += dx
self.y += dy
self.checkBounds()
def forward(self, amt):
""" move amt pixels in the current direction
of travel
"""
#calculate dx dy based on current direction
radians = self.dir * math.pi / 180
dx = amt * math.cos(radians)
dy = amt * math.sin(radians) * -1
self.x += dx
self.y += dy
def addForce(self, amt, angle):
""" apply amt of thrust in angle.
change speed and dir accordingly
add a force straight down to simulate gravity
in rotation direction to simulate spacecraft thrust
in dir direction to accelerate forward
at an angle for retro-rockets, etc.
"""
#calculate dx dy based on angle
radians = angle * math.pi / 180
dx = amt * math.cos(radians)
dy = amt * math.sin(radians) * -1
self.dx += dx
self.dy += dy
self.updateVector()
def updateVector(self):
#calculate new speed and angle based on dx, dy
#call this any time you change dx or dy
self.speed = math.sqrt((self.dx * self.dx) + (self.dy * self.dy))
dy = self.dy * -1
dx = self.dx
radians = math.atan2(dy, dx)
self.dir = radians / math.pi * 180
def setSpeedLimits(self, max, min):
""" determines maximum and minimum
speeds you will allow through
speedUp() method. You can still
directly set any speed you want
with setSpeed() Default values:
max: 10
min: -3
"""
self.maxSpeed = max
self.minSpeed = min
def dataTrace(self):
""" utility method for debugging
print major properties
extend to add your own properties
"""
print "x: %d, y: %d, speed: %.2f, dir: %.f, dx: %.2f, dy: %.2f" % \
(self.x, self.y, self.speed, self.dir, self.dx, self.dy)
def mouseDown(self):
""" boolean function. Returns True if the mouse is
clicked over the sprite, False otherwise
"""
self.pressed = False
if pygame.mouse.get_pressed() == (1, 0, 0):
if self.rect.collidepoint(pygame.mouse.get_pos()):
self.pressed = True
return self.pressed
def clicked(self):
""" Boolean function. Returns True only if mouse
is pressed and released over sprite
"""
released = False
if self.pressed:
if pygame.mouse.get_pressed() == (0, 0, 0):
if self.rect.collidepoint(pygame.mouse.get_pos()):
released = True
return released
def collidesWith(self, target):
""" boolean function. Returns True if the sprite
is currently colliding with the target sprite,
False otherwise
"""
collision = False
if self.rect.colliderect(target.rect):
collision = True
return collision
def collidesGroup(self, target):
""" wrapper for pygame.sprite.collideany
simplifies checking sprite - group collisions
returns result of collision check (sprite from group
that was hit or None)
"""
collision = pygame.sprite.spritecollideany(self, target)
return collision
def distanceTo(self, point):
""" returns distance to any point in pixels
can be used in circular collision detection
"""
(pointx, pointy) = point
dx = self.x - pointx
dy = self.y - pointy
dist = math.sqrt((dx * dx) + (dy * dy))
return dist
def dirTo(self, point):
""" returns direction (in degrees) to
a point """
(pointx, pointy) = point
dx = self.x - pointx
dy = self.y - pointy
dy *= -1
radians = math.atan2(dy, dx)
dir = radians * 180 / math.pi
dir += 180
return dir
def drawTrace(self, color=(0x00, 0x00, 0x00)):
""" traces a line between previous position
and current position of object
"""
pygame.draw.line(self.scene.background, color, self.oldCenter,
self.rect.center, 3)
self.screen.blit(self.scene.background, (0, 0))
def addState(self, stateName, stateImageFile):
""" Creates a new sprite state with the associated name
and image. Useful to build multi-state sprites.
"""
#load the image
tempImage = pygame.image.load(stateImageFile)
tempImage.convert()
self.states[stateName] = tempImage
def setState(self, stateName):
""" attempts to set the sprite to the indicated state
(image)
"""
self.imageMaster = self.states[stateName]
self.rect = self.imageMaster.get_rect()
self.currentState = stateName
def getState(self):
""" returns the current state name
(default if no states have been explicitly set)
"""
return self.currentState
if pro.state == pro.ATTACKING:
if pro.collidesWith(baddySprites):
baddy.health -= 1
if baddy.health == 0:
baddy.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesWith(baddySprites):
pro.heartPts -= 1
baddySprites is a sprite group, so I bet you have to use collidesGroup instead of collidesWith.
if pro.state == pro.ATTACKING:
if pro.collidesGroup(baddySprites):
baddy.health -= 1
if baddy.health == 0:
baddy.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesGroup(baddySprites):
pro.heartPts -= 1
But even if you do this, it seems like you'll still have problems. Namely, this code only ever deducts health from baddy and not baddy1. I'm assuming sprite groups support iteration. If so, you should perform collision detection independently on each enemy.
for enemy in baddySprites:
if pro.state == pro.ATTACKING:
if pro.collidesWith(enemy):
enemy.health -= 1
if enemy.health == 0:
enemy.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesWith(enemy):
pro.heartPts -= 1
Working on a pong game while I am reading the Python Programming for the beginner book and I am lost as to what I am missing in this game's code. Everything in the game works except for whenever the ball overlaps the board sprite it doesn't detect it and it goes right to the edge of the window, ending the game.
# single player pong
# the player must rebound the ball to avoid it going off screen.
from livewires import games, color
games.init(screen_width = 1152, screen_height = 768, fps = 60)
class board(games.Sprite):
"""The object used to bounce the ball."""
image = games.load_image("paddle.png")
def __init__(self):
"""initialize the board"""
super(board, self).__init__(image = board.image,
y = games.mouse.y,
right = games.screen.width)
def update(self):
"""
:return:move mouse to y position
"""
self.y = games.mouse.y
if self.top < 0:
self.top = 0
if self.bottom > games.screen.height:
self.bottom = games.screen.height
self.check_rebound()
def check_rebound(self):
"""Check for ball rebound"""
for ball in self.overlapping_sprites:
ball.rebound()
class ball(games.Sprite):
""" A bouncing pizza."""
image = games.load_image("ball.png")
def __init__(self):
"""initialize the ball"""
super(ball, self).__init__(image = ball.image,
x = games.screen.width/2,
y = games.screen.height/2,
dx = 1,
dy = 1)
def end_game(self):
""" End the game. """
end_message = games.Message(value = "Game Over",
size = 90,
color = color.red,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 5 * games.screen.fps,
after_death = games.screen.quit)
games.screen.add(end_message)
def update(self):
""" Reverse a velocity component if edge of screen is reached and end game if the right wall is reached."""
if self.left < 0:
self.dx = -self.dx
if self.bottom > games.screen.height or self.top < 0:
self.dy = -self.dy
if self.right > games.screen.width:
self.end_game()
self.destroy()
def rebound(self):
"Ball rebounds from board."
self.dx = -self.dx
self.dy = -self.dy
def main():
""" Play the game. """
the_board = board()
games.screen.add(the_board)
the_ball = ball()
games.screen.add(the_ball)
games.screen.add(the_ball)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
# start it up!
main()
Apologies if the code is sorted a bit wonky, I had to quadruple space it to work on the site.
Remove dy = -dy in the rebound method.
Just what the title says...the ball sprite will often collide and ghost through the paddle and alien sprite causing it to stall or get stuck. Trying to figure out a way to fix this so the game operates better. This is my only attempt at making a game so far just trying to polish it more.
class Alien(games.Sprite):
"""
An alien which moves.
"""
image = games.load_image("crab.jpg")
def __init__(self, y, speed = 2, odds_change = 250):
""" Initialize alien. """
super(Alien, self).__init__(image = Alien.image,
x = games.screen.width/2,
y = y,
dx = speed)
self.odds_change = odds_change
self.timer = 0
def update(self):
""" Determine if direction needs to be reversed. """
if self.left < 0 or self.right > games.screen.width:
self.dx = -self.dx
elif random.randrange(self.odds_change) == 0:
self.dx = -self.dx
self.check_collide()
if self.timer > 0:
self.timer -= 1
##if ball hits alien add points
def check_collide(self):
for ball in self.overlapping_sprites:
if self.timer == 0:
self.timer = 100
Paddle.score.value+=10
ball.handle_collide()
else:
ball.handle_collide2()
class Paddle(games.Sprite):
##load up paddle sprite
image=games.load_image("platform.jpg")
score=games.Text(value=0, size=75, color = color.white, top=5,
right=games.screen.width - 20, is_collideable = False)
def __init__(self, theY=games.screen.height - 25):
super(Paddle, self).__init__(image=Paddle.image, angle = 0,
y = theY,
x=games.mouse.x,
left=20)
games.screen.add(Paddle.score)
def update(self):
self.x=games.mouse.x
if self.left<0:
self.x=0
if self.right>games.screen.width:
self.x=games.screen.width
self.check_collide()
def check_collide(self):
for ball in self.overlapping_sprites:
ball.handle_collide2()
class Ball(games.Sprite):
image=games.load_image("ball.jpg")
speed=2
def __init__(self, x=100, y=70):
super(Ball, self).__init__(image=Ball.image,
x=x, y=y,
dx=Ball.speed, dy=Ball.speed)
##make the ball bounce off walls
def update(self):
if self.right>games.screen.width:
self.dx=-self.dx
if self.left<0:
self.dx=-self.dx
if self.top<0:
self.dy=-self.dy
if self.bottom>games.screen.height:
self.end_game()
self.destroy()
##ball gets faster as score rises
def handle_collide(self):
if Paddle.score.value == 30:
self.dx *= 2
self.dy *= 2
if Paddle.score.value == 60:
self.dx *= 2
self.dy *= 2
self.dy=-self.dy
def handle_collide2(self):
self.dy=-self.dy
I have asked multiple people I know who create games with python but none of them could come up with a better solution.