I need assistance regarding my function and game - python

def death_en():
death = pygame.Surface.blit(pygame.image.load('tombstone.png'))
if x + (WarriorSize_x * .8) == x_en:
screenDisplay.blit(death, (x_en, y_en))
I'm new to Python and over all programing. I have started learning about pygame and I'm trying to create a game. What I want this function to do is to put another image on top of the enemy that was killed, though nothing happens when I get close enough to it with the main character. I now I haven't assigned a y-axis, but want to make sure this works first. I could send the whole code if it's necessary.
Thanks in advance.

To check for collisions use the PyGame Rect Class. Keep a rectangle for your player, and a rectangle for each enemy, updating the position of the rect whenever the item it tracks changes position. Also, when an enemy or the player moves, use the function Rect.colliderect() to determine if the two items have intersected on-screen.
This might be something like:
tombstone_image = pygame.image.load('tombstone.png')
...
# Inside main loop
# Have there been any collisions?
for e_rect in all_enemy_rects:
if ( e_rect.colliderect( player_rect ) ):
screenDisplay.blit( tombstone_image, e_rect )
# TODO: remove enemy from game

Related

How to get a .Rect to follow another based on the x,y x direction and y direction on the one in front?

I've been working on a snake code for quite a while now. It is still rather primitive and very very basic. I have gotten the collisions to work, food generation and very basic movement. What I'm struggling on is figuring out the movement. Whenever you press WASD or the Arrow Keys it would move the head, and the "body" of the snake follows the part in front of it. So snakecol[1] follows snakecol[0] and so on.
Thank you in advance for any tips and pointers on how to improve my code.
#W to move up, A to move to the left, S to move down, D to move right.
#Snake by Juan Jaramillo
import pygame
import sys
import random
import math
import time
pygame.init()
screen=pygame.display.set_mode((500,500))
point=3
def collision():
global foodx
global foody
global x
global y
global xd
global yd
global point
global snakecol
if snakecol[0].colliderect(foodcol):
foodx=random.randint(0,24)*20
foody=random.randint(0,24)*20
point+=1
snakecol.append(snakecol[len(snakecol)-1])
if xd==20:
snakecol[len(snakecol)-1].x-=20
if xd==-20:
snakecol[len(snakecol)-1].x+=20
if yd==20:
snakecol[len(snakecol)-1].y-=20
if yd==-20:
snakecol[len(snakecol)-1].y==20
print "Snake is",point,"long."
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
black=(0,0,0)
block1=0
block2=1
count=0
screen.fill(black)
randFood=random.randint(0,24)
x=60
y=0
foodx=randFood*20
foody=randFood*20
snakecol=list()
snakecol.append(pygame.Rect(x,y,20,20))
snakecol.append(pygame.Rect(x-20,y,20,20))
snakecol.append(pygame.Rect(x-40,y,20,20))
foodcol=pygame.Rect(foodx,foody,20,20)
xd=[20]
yd=[0]
##snakecol=pygame.Rect(x,y,20,20)
foodcol=pygame.Rect(foodx,foody,20,20)
done=False
while not done:
screen.fill(black)
collision()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#controls
if block1==1:
if(pygame.key.get_pressed()[pygame.K_a]) or (pygame.key.get_pressed()[pygame.K_LEFT]):
yd[0]=0
xd[0]=-20
block1=0
block2=1
if block1==1:
if(pygame.key.get_pressed()[pygame.K_d]) or (pygame.key.get_pressed()[pygame.K_RIGHT]):
yd[0]=0
xd[0]=20
block1=0
block2=1
if block2==1:
if(pygame.key.get_pressed()[pygame.K_w]) or (pygame.key.get_pressed()[pygame.K_UP]):
xd[0]=0
yd[0]=-20
block1=1
block2=0
if block2==1:
if(pygame.key.get_pressed()[pygame.K_s]) or (pygame.key.get_pressed()[pygame.K_DOWN]):
xd[0]=0
yd[0]=20
block1=1
block2=0
#stop moving paddle
for m in range(0,len(snakecol)):
if snakecol[m].x<-20:
snakecol[m].x=500
if snakecol[m].x>500:
snakecol[m].x=-20
if snakecol[m].y<-20:
snakecol[m].y=500
if snakecol[m].y>500:
snakecol[m].y=-20
for m in range(0,len(snakecol)):
snakecol.pop
pygame.draw.rect(screen,(255,255,255),snakecol[m],0)
pygame.draw.rect(screen,(0,0,0),snakecol[m],1)
snakecol[m].x+=xd[0]
snakecol[m].y+=yd[0]
foodcol.x=foodx
foodcol.y=foody
pygame.draw.rect(screen,(255,255,255),(foodx,foody,20,20),0)
pygame.draw.rect(screen,(0,0,0),(foodx,foody,20,20),1)
pygame.display.flip()
time.sleep(0.4)
count+=1
pygame.quit()
The body blocks don't need to know the direction. You can just append a new head block (with the next x, y coords) to the list and remove the last block.
You could also use a collections.deque, pronounced "deck", a double ended queue which allows fast appends and pops on either end (although efficiency isn't really needed here, the code just looks a bit nicer).
A few more suggestions, you should check out how functions, classes and Pygame sprites work. There's a nice, free book about Python and Pygame called Program Arcade Games. Also, you shouldn't use global variables for everything, since they can make code really hard to understand (use classes).
Edit: To emphasize my answer above: Don't move the rects (the parts of the snake) in your list directly by changing their x and y values. Just pop or remove the last rect and append a new head rect. This will create the illusion of movement but the rects actually all stay at the same position.
I mentioned the deque, because it has efficient methods for popping and appending at the left end. For lists this is very inefficient, but I think it won't matter in your case, because the list won't grow too much and computers nowadays are very powerful.
Some code review (this should rather be in https://codereview.stackexchange.com/ though):
Line 132: You don't call pop because you forgot the parentheses. But if you actually called it, the snakecol list would shrink and the game would crash.
Handle the event loop first, then the game logic (e.g. collisions) and then the drawing. In a game class you would use different methods for these parts of the program.
You call pygame.key.get_pressed() several times. Instead assign the keys list to a variable keys = pygame.key.get_pressed() and use this variable later in the loop.
time.sleep is usually not used in Pygame (the game controls will seem to be unresponsive). There's the pygame.time.Clock class which you can use to limit the framerate and you can use a timer variable to keep track of when the snake can move. Instantiate a clock before the main loop clock = pygame.time.Clock() and in the loop you call clock.tick(enter_max_fps_here) every frame.

How do I make a rectangular sprite stop when it collides with another rectangular sprite using pygame?

I'm trying to create some obstacles for the player in my program. I can't figure out how to make the sprite stop when it comes in contact with it from all sides.
I tried to use pygame.sprite.collide_rect and pygame.sprite.spritecollide, but couldn't figure out how to do it.
If you could just try to explain the concept, I'd rather try to figure the rest out myself. Thanks in advance!
def move_rect():
new_pos = player_rect.pos
new_pos = new_pos[0]+dx,new_pos[1]+dy
new_rect = rect(new_pos,player_rect.size)
for enemy in enemy_rects:
if new_rect.colliderect(enemy):
dx,dy=dx*-1,dy*-1 #reverse direction to "bounce"
#alternatively you could just return here probably
player_rect.move(dx,dy) #do the move, no collisions
something like that at least ... (I doubt it will work, its more to give you the concept)

How to make a shot impact in a rectangle only output one event?

In pygame, I am trying to make my points increase by 1000 every time a shot impacts my zombie, who's positions are zhot[XX] and zhot[YY]. I attempted to accomplish this by creating a rectangle around my zombie, and using the collidepoint function, however as my shot passes through the rectangle, every change in it's position counts as 1000 points, so shooting one zombie will give me something like 30000 points. How can I fix this?
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]):
points+=1000
Once you've awarded points, you need to break out of the for loop.
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]):
points+=1000
break #no more points will be awarded, there's no point wasting computation checking the rest.
I guess the loop you posted runs inside your main loop and is invoked every iteration of the main loop.
You should remove the shot from the shots list once it hit your zombie, so it won't be checked again for collision in the next iteration of the main loop.
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
# make a copy of the list so we can savely remove items
# from it while iterating over the list
for shot in shots[:]:
if zomrect2.collidepoint(shot[X],shot[Y]):
points += 1000
shots.remove(shot)
# and also do whatever you have to do to
# erase the shot objects from your game
You need to track the fact that the points have been awarded already. It's not really clear how/when the method or function awarding points is being called, but something like this perhaps:
points_awarded = False
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]) and not points_awarded:
points_awarded = True
points+=1000

"for" loop in python-pygame does not break under an "if" statement

I am trying to make a "space invaders" game in pygame...I have much of the game already running, but I ran into an annoying problem I cannot solve myself (it is the first programming course I have taken). Here is the code in question:
for enemy in enemies:
if hero.sprite.rect.colliderect(enemy.sprite.rect) or enemy.posy>400:
hero.health-=1
initgame()
break
else:
enemy.moveBy(enemyPos, ENEMYVERT)
enemy.draw()
So what this should supposedly do is:
check for every item in a list named "enemies" (where I have appended all my enemy instances)
if it collides with the hero sprite or if they have reached the bottom of the screen
then remove one life from the player, initialise the game (remake the enemy list, reset positions)
and break the "for" loop.
Else, move the enemies and blit them as usual.
However, what this does is actually remove ALL lives from the player on touch. Shouldn't it stop calculating since I used break? I think it keeps calculating if any in enemies has reached 400px thus keeps removing lives from my player.
This is my initgame function
def initgame():
enemies=[]
createEnemies("1.png", 50, 250)
createEnemies("2.png", 50, 190)
createEnemies("3.png", 50, 130)
createEnemies("4.png", 50, 70)
createEnemies("5.png", 50, 10)
enemyPos=0
enemyDir=-1
hero.score=0
restartFlag=False
for enemy in enemies:
enemy.draw()
It looks like you aren't emptying enemies, so the old ones plus the new ones are there after initgame(). The problem is that the line enemies=[] is creating and setting a local variable. In order to do what you want, try:
def initgame():
global enemies
enemies=[]
Try putting
global enemies
at the row before enemies=[] in initgame()
You are not clearing your global enemies variable otherwise. In general it is better to put everything in a class and use self.enemies to share data between functions, than to rely on global variables.
You put your functions in a class, like this:
class SpaceInvaders:
def __init__(self):
self.initgame()
def initgame(self):
self.enemies = []
...#createEnemies
self.enemyPos = 0
self.enemyDir = -1
#etc
def run(self):
#your while loop here
All variables that should be shared between functions will now be referred to as self.. This distinguish them from local variables (like "enemy" in your for loop) that are only used inside the function.
You use this class by making an object an calling run.
game = SpaceInvaders()
game.run()
Your break statement should work as anticipated.
There must be another reason for health dropping all the way back (other than looping too much). Probably this reason can be found in initgame().

Moving a sprite when mouse is pressed in Python

I'm making a Pong clone for learning purposes, and need to get the ball moving from the middle of the screen (it's sent there when it goes past a paddle) when the mouse is pressed. I've tried the following code, but it does nothing, so I probably don't understand the syntax. Try to keep it as simple as possible please, and explain it, I'd rather not have 50 lines of code for this (I want to understand everything I'm using here). I think this is all the relevant code, sorry if it isn't. Thanks.
def middle(self):
"""Restart the ball in the centre, waiting for mouse click. """
# puts ball stationary in the middle of the screen
self.x = games.screen.width/2
self.y = games.screen.height/2
self.dy = 0
self.dx = 0
# moves the ball if mouse is pressed
if games.mouse.is_pressed(1):
self.dx = -3
It's impossible to know exactly what's happening based on that code fragment, but it looks like you are using the wrong function to detect whether or not the mouse button is pressed.
Screen.is_pressed from the games module wraps pygame.key.get_pressed, which only detects the state of keyboard keys, not mouse buttons. You probably want the function Screen.mouse_buttons, which wraps pygame.mouse.get_pressed. You could use it within a loop like this (I'll pretend you have an instance of games.Screen called 'screen'):
left, middle, right = screen.mouse_buttons()
# value will be True if button is pressed
if left:
self.dx = -3
I am looking at the same issue as a beginner Python coder - Games.py (revision 1.7) includes several is_pressed methods in various classes, including both keyboard and mouse.
class Mouse(object):
#other stuff then
def is_pressed(self, button_number):
return pygame.mouse.get_pressed()[button_number] == 1
since pygame is a compiled module (I have 1.9.1) referring to the documentation rather than source code, I find here that there is a pygame.mouse.get_pressed():
the will get the state of the mouse buttons
get_pressed() -> (button1, button2, button3)
So I think the issue is the use of this in (y)our code rather than the use of the wrong function.....
OK GOT THIS TO WORK - MY FIX:
class myClass(games.Sprite):
def update(self):
if games.mouse.is_pressed(0)==1:
self.x=games.mouse.x
self.y=games.mouse.y
invoking the in Main() causes the selected sprite to move to the mouse location. HTH

Categories