My question is how can I better my shooting functionality in my game. I am trying to make it to where the player can shoot in the direction it is moving (ex.shoot up,down,left,right) as well as shoot while moving and shoot while idle.
The player and missile are both rectangular using pygame shapes to make it easier for me to understand the logic behind game development.
def player(px,py):
pygame.draw.rect(gameWindow,black,[px,py,30,30])
def missile(mx,my):
pygame.draw.rect(gameWindow,black,[mx,my,10,10])
Here is the code of the game to help better understand what I'm talking about. The small section I have commented out is what I have tried. I only have it currently set to move in the x direction going left from its initial starting point.
import pygame #####IMPORTING PYGAME MODULE###########################
pygame.init() #####INITIALIZING PYGAME##################################
gameWindow = pygame.display.set_mode((800,600)) ###Screen Width and Height###
clock = pygame.time.Clock() ## FRAMES PER SECOND ##
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
def player(px,py):
pygame.draw.rect(gameWindow,black,[px,py,30,30])
def missile(mx,my):
pygame.draw.rect(gameWindow,black,[mx,my,10,10])
def enemies():
return
def gameloop():
px = 700
py = 300
mx = 700
my = 300
px_change = 0
py_change = 0
mx_change = 0
my_change = 0
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
mx_change = -10
if event.key == pygame.K_RIGHT:
mx_change = 10
if event.key == pygame.K_UP:
my_change = -10
if event.key == pygame.K_DOWN:
my_change = 10
if event.key == pygame.K_SPACE:
mx_change = -6
#if event.key == pygame.K_SPACE and pygame.K_RIGHT:
#mx_change = 6
if event.key == pygame.K_LEFT:
px_change = -10
if event.key == pygame.K_RIGHT:
px_change = 10
if event.key == pygame.K_UP:
py_change = -10
if event.key == pygame.K_DOWN:
py_change = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
px_change = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
py_change = 0
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
mx_change = 0
mx = px
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
my_change = 0
my = py
if event.key == pygame.K_SPACE:
mx_change = 0
my_change = 0
mx = px
my = py
px += px_change
py += py_change
mx += mx_change
my += my_change
gameWindow.fill(white)
player(px,py)
missile(mx,my)
pygame.display.update()
clock.tick(100)
pygame.quit()
quit()
gameloop()
I would suggest using different objects for your player and missile. The way you have things set up right now, there can only be 1 player and 1 missile. Only having 1 player might be fine but 1 missile makes for a dull game. I suggest using a class, such as this simple example:
class Projectile():
def init(self,x,y,vx,vy):
self.x = x
self.y = y
self.vx = vx
self.vy = vy
def update(self):
self.x += self.vx
self.y += self.vy
Now that you have a class you can start doing great things! Want to have spacebar fire a new missile instead of moving the one missile on screen? ezpz! All you need is a list of your missile objects to keep track of, say my_missile_list:
if event.key == pygame.K_SPACE:
my_missile_list.append(Projectile(px,py,missile_x_velocity,missile_y_velocity))
This creates an entirely new instance of the class Projectile based on the input position and speeds.
Finally, we need to have all these missiles move! This is where the class definition makes our life easier! Once per frame we just have to update the bullets:
for b in my_missile_list:
b.update()
There are more advantages to using classes here but this is a start. If you read through this and make a few changes your game will work much more like what you are looking for.
You should set missille only when you KEYDOWN space, and not use other keys to change it. Player may have variable direction so you will know in which direction it is looking when it stay and you will know in which direction move misille.
import pygame
# --- constants --- (UPPER_CASE_NAMES)
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
# --- classes --- (CamelCaseNames)
# empty
# --- functions ---- (lower_case_names_
def player(screen, x, y):
pygame.draw.rect(screen, BLACK, (x, y, 30, 30))
def missile(screen, x, y):
pygame.draw.rect(screen, RED, (x, y, 10, 10))
def enemies():
pass
def gameloop(screen):
px = 700
py = 300
mx = 700
my = 300
px_change = 0
py_change = 0
p_direction = 'left'
mx_change = 0
my_change = 0
#m_direction = 'left'
game_exit = False
clock = pygame.time.Clock() ## FRAMES PER SECOND ##
while not game_exit:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
px_change = -10
p_direction = 'left'
if event.key == pygame.K_RIGHT:
px_change = 10
p_direction = 'right'
if event.key == pygame.K_UP:
py_change = -10
p_direction = 'top'
if event.key == pygame.K_DOWN:
py_change = 10
p_direction = 'down'
if event.key == pygame.K_SPACE:
mx = px
my = py
if p_direction == 'left':
mx_change = -16
my_change = 0
elif p_direction == 'right':
mx_change = 16
my_change = 0
elif p_direction == 'top':
mx_change = 0
my_change = -16
elif p_direction == 'down':
mx_change = 0
my_change = 16
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
px_change = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
py_change = 0
# --- changes/updates ---
px += px_change
py += py_change
mx += mx_change
my += my_change
# --- draws ----
screen.fill(WHITE)
player(screen, px, py)
missile(screen, mx, my)
pygame.display.update()
# --- FPS ---
clock.tick(30)
# --- main ---
pygame.init()
screen = pygame.display.set_mode((800,600))
gameloop(screen)
pygame.quit()
#quit()
Instead of px, py and mx,my you should use pygame.Rect() - it can be used to draw() and blit() and it has methods to check collisions.
Related
I'm just messing around with Pygame and I can't see what I'm doing incorrectly to make the red circle move with the arrow keys. I can't tell if it's in my main loop. I also haven't been able to find very many tutorials on sprite or looping animations with Pygame. If I for example wanted to make a square oscillate for example like a moving platform how would I do that?
import pygame
import time
## event handling varibles
player_x = 0
player_y = 0
x = 250
y = 250
## screen display
display_width = 500
display_height = 500
pygame.init()
game_screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("test")
# player
def player():
pygame.draw.circle(game_screen,red,(x,y),15)
# colors
white = (255,255,255)
red = (255,0,0)
black = (0,0,0)
### main loop
dead = False
while dead != True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
dead = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_x = -1
elif event.key == pygame.K_RIGHT:
player_x = +1
if event.key == pygame.K_UP:
player_y = +1
elif event.key == pygame.K_DOWN:
player_y = -1
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or pygame.K_RIGHT:
player_x = 0
if event.key == pygame.K_UP or pygame.K_DOWN:
player_y = 0
game_screen.fill(black)
player()
pygame.display.update()
x -= player_x
y -= player_y
pygame.quit()
quit()
Your indendation is all messed up.
Your code won't do anything unless the event is QUIT... which then makes it quit.
Your boolean logic is wrong.
This is not proper syntax event.key == pygame.K_UP or pygame.K_DOWN. The order of precedence here is as follows (event.key == pygame.K_UP) or (K_DOWN). Since K_DOWN is truthy, it is always true and thus this entire statement is always true.
I think you mean: event.key == pygame.K_UP or event.key == pygame.K_DOWN
Lastly, it wont' keep moving as you say you want.
It will only move when there is an event in the queue. You can make it keep moving by generating events. Perhaps with an event timer.
Here is a fixed version, hope this helps:
import pygame
import time
## event handling varibles
player_x = 0
player_y = 0
x = 250
y = 250
## screen display
display_width = 500
display_height = 500
pygame.init()
game_screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("test")
# player
def player(game_screen, red, point): # Use parameters not globals
pygame.draw.circle(game_screen, red, point, 15)
# colors
white = (255,255,255)
red = (255,0,0)
black = (0,0,0)
### main loop
pygame.time.set_timer(pygame.USEREVENT, 1) # 1 per second
dead = False
while not dead:
for event in pygame.event.get():
if event.type == pygame.QUIT:
dead = True
elif event.type == pygame.USEREVENT:
pygame.time.set_timer(pygame.USEREVENT, 1) # Set another timer for another 1 second
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_x = +10
elif event.key == pygame.K_RIGHT:
player_x = -10
elif event.key == pygame.K_UP:
player_y = +10
elif event.key == pygame.K_DOWN:
player_y = -10
elif event.type == pygame.KEYUP:
if event.key in [pygame.K_LEFT, pygame.K_RIGHT]:
player_x = 0
elif event.key in [pygame.K_UP, pygame.K_DOWN]:
player_y = 0
game_screen.fill(black)
player(game_screen,red,(x,y))
pygame.display.update()
x -= player_x
y -= player_y
pygame.quit()
I am moving a sprite on the x-axis. It is properly moving left and right. When I press both LEFT and RIGHT at the same time it stop moving properly.
I am trying to make it when a user presses both keys and then lets go of one, for it to continue moving in the direction still pressed.
Weirdly it works while I holding right and letting go of left. It continues moving right.
When I hold left and tap right it stops moving until I press right again.
I commented out some ideas I had to make this work, but they failed me.
I am sure its a simple fix or a logic failure on my part.
I have worked a couple hours on this.
Thanks for responses ahead of time.
import pygame
import time
import random
import sys
import math
pygame.init()
displayWidth = 1200
displayHeight = 800
white = (255,255,255)
black = (0,0,0)
gameDisplay = pygame.display.set_mode((displayWidth, displayHeight))
pygame.display.set_caption('Game 3')
clock = pygame.time.Clock()
class firstSquare:
def __init__(self,player_x,player_y):
self.x = player_x
self.y = player_y
self.width = 100
self.height = 100
def render(self):
pygame.draw.rect(gameDisplay, white,(self.x, self.y, self.width, self.height))
class secondSquare:
def __init__(self,cpu_x,cpu_y):
self.x = cpu_x
self.y = cpu_y
self.width = 100
self.height = 100
def render(self):
pygame.draw.rect(gameDisplay, white,(self.x, self.y, self.width, self.height))
player = firstSquare(300,300)
cpu = secondSquare(100,100)
def gameLoop():
### variables##
player_x = 100
player_y = 100
x = 100
y = 100
movement_x = 0
movement_y = 0
frame_rate = 0
frame_table = 0
inGame = True
while inGame:
for event in pygame.event.get():
if event.type == pygame.QUIT:
inGame = False
pygame.quit()
sys.exit()
keyPressed= pygame.key.get_pressed()
#### this is moving the player on x-axis##
if keyPressed[pygame.K_LEFT]:
movement_x = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
movement_x = 0
if keyPressed[pygame.K_RIGHT]:
movement_x = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
movement_x = 0
### two keys at once won't move the player###
if keyPressed[pygame.K_LEFT] and keyPressed[pygame.K_RIGHT]:
movement_x = 0
### pressing one key and letting go the other will continue movement
## if keyPressed[pygame.K_LEFT] and keyPressed[pygame.K_RIGHT]:
## if event.type == pygame.KEYUP:
## if event.key == pygame.K_LEFT:
## movement_x = 5
## print("left dropped")
## if keyPressed[pygame.K_RIGHT] and keyPressed[pygame.K_LEFT]:
## if event.type == pygame.KEYUP:
## if event.key == pygame.K_RIGHT:
## movement_x = -5
## print("Right dropped")
gameDisplay.fill(black)
player.render()
cpu.render()
player.x += movement_x
pygame.display.update()
clock.tick(60)
gameLoop()
pygame.quit()
quit()
I think what you need is this:
if keyPressed[pygame.K_LEFT]:
movement_x = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and movement_x < 0:
movement_x = 0
if keyPressed[pygame.K_RIGHT]:
movement_x = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and movement_x > 0:
movement_x = 0
And that would be it... Hope it helps.
Try to use the following code in your movement:
if keyPressed[pygame.K_LEFT]:
movement_x = -5
elif keyPressed[pygame.K_RIGHT]:
movement_x = +5
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
movement_x = 0
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
movement_x = 0
import pygame
# Some colors
GREEN = ( 0,255,0)
BLUE = ( 0, 0, 255)
WHITE = ( 255, 255, 255)
BLACK = ( 0, 0, 0)
pygame.init()
clock = pygame.time.Clock()
#Screen
SCREEN = pygame.display.set_mode([1000,700])
#Title
pygame.display.set_caption("Trying to move things")
#Variables
x_position = 100
y_position = 100
x_speed = 0
y_speed = 0
#Positions
image_image_positions = [x_position,y_position]
#Graphics
image_image = pygame.image.load("izzat.png").convert()
image_image.set_colorkey(BLACK)
#Main loop ____
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Keyboard commands.
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
y_speed = -5
elif event.key == pygame.K_DOWN:
y_speed = 5
elif event.key == pygame.K_w:
x_speed = -5
elif event.key == pygame.K_s:
x_speed = 5
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_speed = 0
elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_speed = 0
elif event.key == pygame.K_w or event.key == pygame.K_s:
x_speed += 0
if y_position + y_speed >=0 and y_position + y_speed + 60 <=500:
y_position += y_speed
x_position += x_speed
SCREEN.fill(GREEN)
SCREEN.blit(image_image, image_image_positions)
print(x_position)
print(y_position)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Hello, I have been having a problem which I'm really not happy at because I have been trying to fix it for a while now. So basically I have a image, and I wish to move the image based on the keyboard inputs, yet whatever I try nothing works. I then wondered maybe the y and x position aren't changing at all which is why the images positions are not changing, well I did print( those positions) but it the positions are definitely changing, the variables, so I do not get how the image positions do not change at all. Then I thought maybe because it's a tuple, so I changed it to parenthesis, that also did not work. I just don't get why my image position doesn't move if the variables for the position of the image do change. Thank you if you could help me in any way. I have looked this up but I couldn't find any help. Thank you for your help if you help me!
Update__________
Ok so apparently the image_image_position stays the same despite the variables changing when I printed the positions of image_image_position. Is there any way to change them and not have them stay at 100,100 all the time and change with the variables being changed?
You haven't assigned the speeds.
image_image_positions[0] = xspeed
image_image_positions[1] = yspeed
You are only changing your variables yspeed and xspeed, but you are not setting the actual positions of the image. Add the following line before the blit:
image_image_positions = [x_position,y_position]
Full code:
import pygame
# Some colors
GREEN = ( 0,255,0)
BLUE = ( 0, 0, 255)
WHITE = ( 255, 255, 255)
BLACK = ( 0, 0, 0)
pygame.init()
clock = pygame.time.Clock()
#Screen
SCREEN = pygame.display.set_mode([1000,700])
#Title
pygame.display.set_caption("Trying to move things")
#Variables
x_position = 100
y_position = 100
x_speed = 0
y_speed = 0
#Positions
image_image_positions = [x_position,y_position]
#Graphics
image_image = pygame.image.load("izzat.png").convert()
image_image.set_colorkey(BLACK)
#Main loop ____
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Keyboard commands.
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
y_speed = -5
elif event.key == pygame.K_DOWN:
y_speed = 5
elif event.key == pygame.K_w:
x_speed = -5
elif event.key == pygame.K_s:
x_speed = 5
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_speed = 0
elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_speed = 0
elif event.key == pygame.K_w or event.key == pygame.K_s:
x_speed += 0
if y_position + y_speed >=0 and y_position + y_speed + 60 <=500:
y_position += y_speed
x_position += x_speed
image_image_positions = [x_position,y_position]
SCREEN.fill(GREEN)
SCREEN.blit(image_image, image_image_positions)
print(x_position)
print(y_position)
pygame.display.flip()
clock.tick(60)
pygame.quit()
While you ARE updating the x/y positions, this isn't changing where the image is being drawn:
SCREEN.blit(image_image, image_image_positions)
image_image_positions, is never changed throughout the life-span of your application (besides startup).
To fix this simply add the update into your loop:
image_image_positions = [x_position,y_position]
I want to clamp my sprite from disappearing from screen, but I am bit confused. I think I didn't understand concept of get_rect method properly. At this stage I'm getting this error:
TypeError: Argument must be rect style object
Thats my code:
import pygame
pygame.init()
finish = False
white = ( 255, 255, 255)
black = (0, 0, 0)
grey = (211, 211, 211)
font = pygame.font.Font("C:/Windows/Fonts/BRITANIC.TTF", 20)
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Game")
line_speed = 2
line_pos_x = 100
line_pos_y = 0
end_pos = 170
player_x = 10
player_y = 10
player_move_x = 0
player_move_y = 0
dog_img = pygame.image.load("dog_brown.png")
dog_rect = dog_img.get_rect()
timer = pygame.time.Clock()
while finish == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_move_x = -5
if event.key == pygame.K_RIGHT:
player_move_x = 5
if event.key == pygame.K_UP:
player_move_y = -5
if event.key == pygame.K_DOWN:
player_move_y = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player_move_x = 0
if event.key == pygame.K_RIGHT:
player_move_x = 0
if event.key == pygame.K_UP:
player_move_y = 0
if event.key == pygame.K_DOWN:
player_move_y = 0
player_x += player_move_x
player_y += player_move_y
screen.fill(white)
screen.blit(dog_img,(player_x, player_y))
dog_rect.clamp_ip(screen)
pygame.draw.line(screen,black,[line_pos_x,line_pos_y + line_speed],[100,end_pos + line_speed],5)
line_speed = line_speed + 2
pygame.display.flip()
timer.tick(25)
pygame.quit()
clamp_ip needs another Rect as argument:
...
screen = pygame.display.set_mode((600, 400))
# create a Rect that represents the screen
screen_r = screen.get_rect()
...
while finish == False:
...
# use it instead of screen
dog_rect.clamp_ip(screen_r)
...
Also, to have it work, you should get rid of the player_x and player_y variables and use the dog_rect Rect to keep track of the position of your player.
Instead of
player_x += player_move_x
player_y += player_move_y
...
screen.blit(dog_img,(player_x, player_y))
simply do
dog_rect.move_ip(player_move_x, player_move_y)
...
screen.blit(dog_img, dog_rect)
I'm developing a very basic engine, basing myself on tutorials from Pygame, and I'm having a little problem with "smoothness". How do I make my player walk "smoother"?
My event handler is pretty basic, pretty standard, nothing new, and I even figured out how to make a "boost" (run) for test. But the thing is, at the pygame.KEYUP, those lots of zeros destroy the "smoothness" of my little player, and I don't want that, but I don't want it to walk ad infinitum.
import pygame
import gfx
# Main Class
class Setup:
background = gfx.Images.background
player = gfx.Images.player
pygame.init()
# Configuration Variables:
black = (0,0,0)
white = (255,255,255)
green = (0,255,0)
red = (255,0,0)
title = "Ericson's Game"
# Setup:
size = [700,700]
screen = pygame.display.set_mode(size)
pygame.display.set_caption(title)
done = False
clock = pygame.time.Clock()
# Logic Variables
x_speed = 0
y_speed = 0
x_speed_boost = 0
y_speed_boost = 0
x_coord = 350
y_coord = 350
screen.fill(white)
# Main Loop:
while done == False:
screen.blit(background,[0,0])
screen.blit(player,[x_coord,y_coord])
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
if event.key == pygame.K_a:
x_speed = -6
x_speed_boost = 1
if event.key == pygame.K_d:
x_speed = 6
x_speed_boost = 2
if event.key == pygame.K_w:
y_speed = -6
y_speed_boost = 1
if event.key == pygame.K_s:
y_speed = 6
y_speed_boost = 2
if event.key == pygame.K_LSHIFT:
if x_speed_boost == 1:
x_speed = -10
if x_speed_boost == 2:
x_speed = 10
if y_speed_boost == 1:
y_speed = -10
if y_speed_boost == 2:
y_speed = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
x_speed = 0
x_speed_boost = 0
if event.key == pygame.K_d:
x_speed = 0
x_speed_boost = 0
if event.key == pygame.K_w:
y_speed = 0
y_speed_boost = 0
if event.key == pygame.K_s:
y_speed = 0
y_speed_boost = 0
x_coord = x_coord + x_speed
y_coord = y_coord + y_speed
pygame.display.flip()
pygame.display.update()
clock.tick(20)
pygame.quit()
Code will be simpler/clearer using keystate polling for your use. If other parts of the game use 'on press' logic, you can use event handling. So your movement would be:
If you are calling pygame.display.flip() then you don't use pygame.display.update(). Infact it will probably slow it down to use both.
I used your x_coord variable. But it would simplify things to use a tuple or vector for player location. You can use a float, for smoother precision for movement. Then it blits as an int to screen.
while not done:
for event in pygame.event.get():
# any other key event input
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESC:
done = True
vel_x = 0
vel_y = 0
speed = 1
if pygame.key.get_mods() & KMOD_SHIFT
speed = 2
# get key current state
keys = pygame.key.get_pressed()
if keys[K_A]:
vel_x = -1
if keys[K_D]:
vel_x = 1
if keys[K_W]:
vel_y = -1
if keys[K_S]:
vel_y = 1
x_coord += vel_x * speed
y_coord += vel_y * speed
You are ticking the clock at a rate of 20 frames per second. This is probably causing the choppiness. Change it to something bigger like 70:
clock.tick(70)