I've got a really long code for my game, but I'll paste in the part that counts which is the bullet shooting part. The game is essentially a Mortal Kombat-esque game but with flying robots and bullets.
Before the game loop, I first predefined functions for the bullets and robots:
def robotr(xr,yr):
gameDisplay.blit(robrimg, (xr,yr))
def robotl(xl,yl):
gameDisplay.blit(roblimg, (xl,yl))
def bulletsr(xbr,ybr):
pygame.draw.circle(gameDisplay, THECOLORS['orange'],(xbr,ybr), 10)
def bulletsl(xbl,ybl):
pygame.draw.circle(gameDisplay, THECOLORS['orange'],(xbl,ybl), 10)
Then the numerous variables for the moving objects:
xr = 929
yr = 250
xl = 250
yl = 250
####
xbr=950
ybr=300
xbl=380
ybl=300
#####
xbr_change = 0
ybr_change = 0
ybl_change = 0
xbl_change = 0
####
xr_change = 0
yr_change = 0
xl_change = 0
yl_change = 0
robotr_speed = 3000
robotl_speed = 3000
After that, the code went for a really long run (about 300-400 lines more), but to the point where I shot the bullets I had an event like this to represent the bullets "moving" with the robot as it moved with the arrow keys.:
if event.type == pygame.KEYDOWN:
#-------PLAYER 1 MOVEMENT-------
#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
if event.key == pygame.K_a:
xr_change = -5
xbr_change = -5 #I have to change the position of the bullet as well so that it doesn't stay in one place and rather shoots from the robot (duh.)
And then a similar code to SHOOT the bullets:
#-------FIRE CANNON MK1-------
#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
if event.key == pygame.K_LSHIFT:
bulletsfx=pygame.mixer.Sound ('boomchickchickmp3.ogg')
bulletsfx.play()
bulletsfx.set_volume(0.2)
xbl_change = 5
if xbl_change == 5:
bulletsl(xbl,ybl)
xbl=xl
Of course, I defined such codes multiple times for the robot on the right as well.
Near the end of my program (this is as a short form of my end as I had extra variables so things wouldn't fall off the screen, but disregard that for now) I had a code like this so I could redefine the changes back to "0" so that the movements could be reused and so forth:
if event.type == pygame.KEYUP:
#Player 1 events
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN or event.key == pygame.K_RCTRL or event.key == pygame.K_DELETE: #or event.key == pygame.K_RSHIFT:
xr_change = 0
yr_change = 0
xbr_change= 0
ybr_change= 0
#Player 2 events
if event.key == pygame.K_a or event.key == pygame.K_d or event.key == pygame.K_w or event.key == pygame.K_s or event.key == pygame.K_LCTRL or event.key == pygame.K_f: #or event.key == pygame.K_LSHIFT:
xl_change = 0
yl_change = 0
xbl_change= 0
ybl_change= 0
##
xr += xr_change
yr += yr_change
xl += xl_change
yl += yl_change
##
xbr += xbr_change
ybr += ybr_change
xbl += xbl_change
ybl += ybl_change
##
bulletsr(xbr,ybr)
bulletsl(xbl,ybl)
robotr(xr,yr)
robotl(xl,yl)
pygame.display.update()
clock.tick(320)
Now my problem is that when I shoot the bullets, it shoots, but I can only shoot it once until it goes off the screen of my program (It's okay, I made it so it returns to the robots once it goes off the screen as well). Otherwise, if I keep hitting the key to shoot, it just returns the bullet coordinates back to where it originally should be (as in I shoot, and if I shoot again, I can see the bullet disappearing to return to its original location).
There is not an infinite number of bullets and I want to know how I can modify the function and some of the variables (probably) to make it so that happens.
You need to use sprites in your code which is missing. It can be done without sprites also but it will be difficult task.
Make a class of bullets so you can make different objects of this.
After you just make a instance to the bullet object every time shoot button is pressed and keep updating it.
In update method you will make bullet move.
Last step is to destroy the bullet object once its out of your screen. One easy way is to put an if statement to check if certain x or y length is achieved and if so delete that sprite or object (bullet in this case).
Here is an example of bullet class I used. In this the char is assumed to be on bottom of screen and shoot bullets upwards as y += -10
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super(Bullet, self).__init__()
self.image = pygame.Surface([10,40])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 10
if you still need to see the full picture you can check out my code here : https://github.com/deepaksandhu/SpaceTurds/blob/master/game.py
also here is an excellent tutorial of making bullets:
http://programarcadegames.com/python_examples/show_file.php?file=bullets.py
Related
I am trying to recreate a game commonly known as Tron. The goal of the game is for the player to stay alive as long as possible. The player is constantly moving and can change direction only in 90-degree turns, if the player steps on a place which they have already stood on before, they die and the game resets.
I have an issue with the lists that store the coordinates of the places the player has already stood on. When the player moves for the first time it instantly registers a loss and resets the game.
Please take a look at my code below, and tell me the issue, especially with the final 'if block' at the end of the game loop.
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((600, 600))
clock = pygame.time.Clock()
player_y = 300
player_x = 300
player_x_list = [300]
player_y_list = [300]
player_rect = pygame.Rect(0, 0, 25, 25)
player_direction_y = 0
player_direction_x = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s and player_direction_y == 0:
player_direction_y = 25
player_direction_x = 0
if event.key == pygame.K_w and player_direction_y == 0:
player_direction_y = -25
player_direction_x = 0
if event.key == pygame.K_d and player_direction_x == 0:
player_direction_x = 25
player_direction_y = 0
if event.key == pygame.K_a and player_direction_x == 0:
player_direction_x = -25
player_direction_y = 0
player_y += player_direction_y
player_x += player_direction_x
# This is supposed to record every x coord the player was located in on a list,
# and every y coord a player was located in on a list
# I only record the coord once as seen below
if player_x_list.count(player_x) == 0:
player_x_list.append(player_x)
if player_y_list.count(player_y) == 0:
player_y_list.append(player_y)
player_rect.center = player_x, player_y
# This right here is supposed to reset the game when the player steps on
# coords that were already stepped on previosly.
# If you remove this, the player is able to move freely, so the issue is here
if player_x_list.count(player_x) > 0 and player_y_list.count(player_y) > 0:
player_x = 300
player_y = 300
player_direction_x = 0
player_direction_y = 0
player_x_list.clear()
player_y_list.clear()
screen.fill((pygame.Color('black')))
pygame.draw.rect(screen, (pygame.Color('white')), player_rect)
pygame.display.update()
clock.tick(10)
I appreciate your time sincerely.
I believe the problem is that you're checking the coordinates after you've already updated and appended them to the coordinate list. So try moving your if statement to the top of the loop, before any changes to the coordinate lists are made.
Also, on an unrelated note, you could use a single list of tuples for coordinates, instead of two lists of integers.
I am having a problem with pyGame (complete newbie here). I practice with event.key and would like to unpress / cut off key that is pressed continuously. I have tried to google it and checked this site, but that led to no promising results. Whole thing takes place in
if event.key == pygame.K_UP and isJumping == False:
(full lines 49 - 55)
## HOW TO UNPRESS K_UP IN CASE IT WAS PRESSED AND NOT RELEASED?
if event.key == pygame.K_UP and isJumping == False:
yChange -= 10
isJumping = True
elif event.key == pygame.K_UP and isJumping == True:
print("X")
This works just fine if up arrow is pressed once, but keeps on executing yChange in a loop in case it was not released - that of course is not desired at all. Could you help me with this please?
import pygame
pygame.init() # Initialize pyGame module
# Set screen dimensions
screenW = 800
screenH = 600
# Set color
AQUA = (155, 255, 255)
# Set FPS
FPS = 60
fpsClock = pygame.time.Clock()
# Set character
mainChar = pygame.image.load('p1_front.png')
mainCharX = screenH / 2 # char X position
mainCharY = screenW / 2 # char Y position
isJumping = False
xChange = 0
yChange = 0
MOVSPEED = 1
# Set backgrounds
mainBg = pygame.image.load('bg_castle.png')
mainBg = pygame.transform.scale(mainBg, (screenW, screenH))
# Set the window, param in a tuple is width / height
DISPLAYSURF = pygame.display.set_mode((screenW, screenH))
# Set window name (game title)
pygame.display.set_caption("Newbie training")
while True: # Main loop of the game
#set BG
DISPLAYSURF.blit(mainBg, (0,0))
# Events loop below
for event in pygame.event.get():
if event.type == pygame.QUIT: # Quit window when [x] is pressed
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
xChange += MOVSPEED
elif event.key == pygame.K_LEFT:
xChange -= MOVSPEED
## HOW TO UNPRESS K_UP IN CASE IT WAS PRESSED AND NOT RELEASED?
if event.key == pygame.K_UP and isJumping == False:
yChange -= 10
isJumping = True
elif event.key == pygame.K_UP and isJumping == True:
print("X")
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
xChange = 0
if event.key == pygame.K_UP:
yChange = 0
#print(event)
mainCharX += xChange
mainCharY += yChange
DISPLAYSURF.blit(mainChar, (mainCharX, mainCharY)) # Load character
pygame.display.update() #update window
fpsClock.tick(FPS) # FPS goes always after update
If you only want the player to be able to jump 10 'units' per up press then stop in place, you could simply set yChange to 0 each frame after you add it to mainCharY.
However, if you're looking for a more robust jumping system (button is pressed, player moves up for a few frames, then stops and falls back down) more is required.
To give you an idea: what if you had some logic at the end of each frame that checks if mainCharY > 0 (player is not on ground) and, if so, subtracts some number from yChange (as if gravity were pulling them down)?
In the above case, your code should avoid the repeating up press problem. It might be easier to just test (mainCharY > 0) instead of using an isJumping variable.
It seems you're misunderstanding how the event queue and event loop work. When you press a key, a single pygame.KEYDOWN event gets added to the event queue. Calling pygame.event.get empties the event queue and puts all events into a list over which you iterate with the for loop: for event in pygame.event.get():. That means pygame doesn't know that you're still holding the key, it will only see that you've pressed UP once. It will also notice that you release the key and add a pygame.KEYUP event to the queue.
In your case you're decreasing the yChange variable to -10 when you press the UP key. In the while loop mainCharY will then be decremented by -10 each frame and the character will move upwards. As soon as you release the key, the yChange is reset to 0 and the player character stops.
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
yChange = 0
To implement jumping in your game, you should add a GRAVITY constant which you add to your y-velocity each frame to accelerate downwards. When the character touches the ground, set the y-velocity to 0 and a variable (on_ground or something similar) to True, so that you know that the player can jump. When the player presses the jump key, you can set the y-velocity to a negative value and the sprite will start to move upwards until the GRAVITY pulls him down again. Here's a complete example.
I don't think it's likely at all that pygame could miss a key event.
I think the problem is that you're not setting isJumping to false anywhere, which stops the changing of yChange forever after the first press. If I'm interpreting this correctly, the following code should work:
if event.type == pygame.KEYDOWN:
... # Your other code
if event.key == pygame.K_UP and not isJumping: # "== False" is not necessary
yChange -= 10
isJumping = True
if event.type == pygame.KEYUP:
... # Your other code
if event.key == pygame.K_UP and isJumping:
yChange = 0
isJumping = False # <-- This is the addition to the code
One thing to keep in mind is that this jumping system won't look very natural. Look to #SamHolloway's answer for more clarification on this.
I am trying to make a shooter in pygame. I am able to have the player move around, and when space is pressed, the bullet will go to its position. I am wondering how i can get it to move away from the player, until it hits the edge of the screen. Here is what i have so far:
if AMMO > 0:
if event.type == pygame.KEYDOWN and Gun.image == NOGUN:
if event.key == pygame.K_SPACE and Gun.image == NOGUN:
Bullet.rect.center = Player.rect.center
if Player.direction == 0:
Bullet.direction = 0 #WHERE THE BULLET WILL MOVE
shot.play()
print "BANG"
AMMO = AMMO - 1
time.sleep(0.09)
We'd need more code here.
In pseudocode:
def frameUpdate( timeBetweenFrame, bulletSpeed, playerDirectionVector ):
bullet.position = bullet.position + playerDirectionVector.MultiplyByScalar(bulletSpeed * timeBetweenFrame);
Where playerDirectionVector is a normalized vector in the direction the player is facing.
Try this
if AMMO > 0:
if event.type == pygame.KEYDOWN and Gun.image == NOGUN:
if event.key == pygame.K_SPACE and Gun.image == NOGUN:
#Initialize Bullet so it's not null and do the rest
Bullet.rect.center = Player.rect.center
if Player.direction == 0:
Bullet.direction = 0
if Bullet != null
Bullet.X += 10
if Bullet.X > ScreenWidth()
Bullet = null
#These are all examples so you can understand the logic, I don't remember exactly how pygame works, but since you can move a character around you can find this :P
Keep in mind that this code allows only one bullet!
What I use when I make bullet instances in psudocode
#making your starting bullet cords
Bulletx = playerx
Bullety = playery
#this stores the angle the bullet was shot from
Bulletangle = degreesplayerisrotated
This converts the angle to a radian
Bulletangle = Bulletangle×pi/180
#this line updates the cords speed is a set value of how fast you want the bullet to move
Bulletx = bulletx-cos(bulletangle)×speed
Bullety = bullety-sin (bulletangle)×speed
Screen.blit (bullet, (bulletx, bullety))
Or draw a circle with the cords
If you have a question be sure to ask hope this cleared things up
I'm a beginner programmer and my first language is Python 2.7, I'm trying to make a space invader type game but i want to have multiple bullets at once and cant find a way to do that. so i made my own way here is my code ill explain more after you see it
if event.type ==pygame.KEYDOWN and event.key==K_SPACE:
if m < 5:
m+=1
if m==1:
m1a=1
m1x=ls
if m==2:
m2a=1
m2x=ls
if m==3:
m3a=1
m3x=ls
if m==4:
m4a=1
m4x=ls
if m==5:
m5a=1
m5x=ls
print m
#missle 1
if m1a==1:
screen.blit(rship,(m1x,m1))
if m1>=0:
m1-=1
else:
m-=1
m1a=0
m1=460
#missle 2
if m2a==1:
screen.blit(rship,(m2x,m2))
if m2>=0:
m2-=1
else:
m-=1
m2a=0
m2=460
#missle 3
if m3a==1:
screen.blit(rship,(m3x,m3))
if m3>=0:
m3-=1
else:
m-=1
m3a=0
m3=460
#missle 4
if m4a==1:
screen.blit(rship,(m4x,m4))
if m4>=0:
m4-=1
else:
m-=1
m4a=0
m4=460
#missle 5
if m5a==1:
screen.blit(rship,(m5x,m5))
if m5>=0:
m5-=1
else:
m-=1
m5a=0
m5=460
I'm sure its laughably noobish but I'm just learning but the problem is the first and second missile are fine its the third and beyond that get messed up. when you fire the third it moves the second over the where your shooting from and then if you fir again the code wont go back down to 1 it stays at 2 and gets even more glitches. If you need me to try and explain it better I gladly will. Just trying to Learn.
Full code here: pastebin.com/FnPaME6N
You should make your "bullets" sprites and then add them to a group called bullets or something. Calling the update method on the group will update all your bullets in a single go.
Here is some working code, but I wouldn't call it great.
import pygame
import math
from pygame.locals import *
background_colour = (122, 100, 155)
(width, height) = (500, 500)
pygame.init()
#ship = pygame.image.load('lolol.jpeg')\
rship = pygame.image.load('js.jpg')
mis = pygame.image.load('lot.jpg')
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('A.N.T.O.N.I.A.')
screen.fill(background_colour)
pygame.display.flip()
running = True
MAX_MISSILES = 5
ls = 250 # Horizontal ship location
LEFT = False
RIGHT = False
def move(ls, RIGHT, LEFT):
'''Moves the ship 3 pixels to the left or right.
Only moves if just one direction key is down, and not both.
Also, will not move if the ship is at either horizontal screen edge.
ls is the ship location.
'''
if LEFT and not RIGHT:
if ls >= 10:
ls -= 3
elif RIGHT and not LEFT:
if ls <= 440:
ls += 3
return ls
def fire_missile(ls, missiles):
'''Fire a missile, as long as we are not at the maximum number.
We use a list to hold our missile locations.
'''
if len(missiles) >= MAX_MISSILES:
return
else:
missiles.append((ls, 460))
def draw_missiles(missiles):
'''Draw all the missiles.'''
if missiles:
for missile in missiles:
screen.blit(mis, (missile))
def move_missiles(missiles):
'''If there are any missiles, move them up 1 pixel, and append
them to the newlist. The new list will replace the old list.
'''
if missiles:
newmissiles = []
for missile in missiles:
# Do not append the missile to the new list if it is going
# off the screen
if missile[1] > 0:
newmissiles.append((missile[0], missile[1] - 1))
return newmissiles
else:
return missiles
missiles = []
while running:
screen.blit(rship, (ls, 450))
pygame.display.flip()
screen.fill(background_colour)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
if event.type == pygame.KEYDOWN and event.key == K_ESCAPE:
# You can now quit with the escape key.
pygame.quit()
running = False
if event.type == pygame.KEYDOWN and event.key == K_LEFT:
LEFT = True
# LEFT is True untli you let up in the LEFT key
if event.type == pygame.KEYUP and event.key == K_LEFT:
LEFT = False
if event.type == pygame.KEYDOWN and event.key == K_RIGHT:
RIGHT = True
if event.type == pygame.KEYUP and event.key == K_RIGHT:
RIGHT = False
if event.type == pygame.KEYDOWN and event.key == K_SPACE:
fire_missile(ls, missiles)
ls = move(ls, RIGHT, LEFT)
draw_missiles(missiles)
missiles = move_missiles(missiles)
Any time you find yourself making variables with numbers in them, it's a code smell, and means you probably should use a different data type.
As has been suggested, you'll probably want to look into the sprite and group modules, but this will at least do what you were trying to do so far.
I have the following class:
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.init()
pygame.sprite.Sprite.__init__(self)
# Basic variables
self.speed = [2,2]
# Sets up the image and Rect
self.bitmap = pygame.image.load("badguy.png")
self.bitmap.set_colorkey((0,0,0))
self.shipRect = self.bitmap.get_rect()
self.shipRect.topleft = [100,200]
def move(self, x, y):
self.shipRect.center = (x,y)
def render(self):
screen.blit(self.bitmap, (self.shipRect))
Now, I want to have it move whenever I hit an arrow key. However, there's a big problem with my move function. It simply moves the center of the ship to the coordinates fed into the function. In case you aren't seeing the problem, it's that I'm trying to call it like this:
if event.key == K_RIGHT:
enemy.x += 5
if event.key == K_LEFT:
enemy.move(-5,0)
if event.key == K_UP:
enemy.move(0,5)
if event.key == K_DOWN:
enemy.move(0,-5)
I was expecting it to move my five in the direction of the key that I hit. However, it shoots to the top left of the screen because I'm making the center set at zero on one axis and +- 5 on the other axis.
What method can be used to make it move in the correct direction and still give me the ability to put the sprites at a starting position on the screen that I choose.
Any help is much appreciated.
change move to:
def move(self, x, y):
self.shipRect.center[0] += x
self.shipRect.center[1] += y
This way it just increments the position by the move amount you specify.
move_ip and centerx/yis what you want:
if event.key == K_RIGHT:
enemy.centerx.move_ip(5,0)
if event.key == K_LEFT:
enemy.centerx.move_ip(-5,0)
if event.key == K_UP:
enemy.centerx.move_ip(0,5)
if event.key == K_DOWN:
enemy.centerx.move_ip(0,-5)