Keyboard Controlls for video game--python - python

I'm new to python/pygame and I'm trying to make a game. Basically it is a space ship floating around in space(it will be a scrolling background) pointing towards the mouse/crosshair. on clicking it will shoot bullets. there will be flying enemies which need AI and clinging enemies which need AI. Also liquids need to "flow." Collision detection for running into walls/bullets,enemies/floor. And lastly I will need a menu GUI (if i used gui in the right context.)
But right now, i would like to move the background (or for now the sprite) with keyboard controls. also how do I do a stretched image for the background?
This is what i've got:
import pygame, random, sys, time
pygame.init()
SIZE = [1000, 1000]
screen = pygame.display.set_mode(SIZE)
crosshair = pygame.image.load('crosshair.jpg')
player = pygame.image.load('spaceship.jpg')
pygame.display.set_caption("Solar Warfare")
WHITE = [255, 255, 255]
mouse_pos = []
spaceshipX = 0
spaceshipY = 0
done = False
pygame.mouse.set_visible(False)
while not done:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
mouse_pos = pygame.mouse.get_pos([])
screen.blit(crosshair, (mouse_pos[0], mouse_pos[1]))
pygame.display.flip()#What is the other way to
#update the screen?
if event.type == pygame.QUIT:
done = True
if event.type == pygame.K_RIGHT:
spaceshipX += 1
screen.fill(WHITE)
screen.blit(player, (spaceshipX, spaceshipY))
screen.blit(crosshair, (mouse_pos))
pygame.display.flip()
pygame.quit()
I would like to add a scrolling background.
I also need AI for the enemies, but thats later. Same with the Main Menu and levels and bosses/features etc...
I talk alot XD

Related

Pygame mouse position not precise enough to rotate the 3D scene

I need to rotate a 3D scene or a character using the mouse position: for example, if I move the mouse to the right, I want to turn to the right / the character should turn right.
I've seen lots of games place the mouse in the center of the screen, then get its position relatively to the previous frame, update the game accordingly and move the mouse back in the center.
I tried to replicate this but I ran into the issue that pygame does not rotate reliably: with higher framerates, I tend to get a slower rotation. This is not a problem when rotating a character in a 2D game, but this is concerning when a 3D scene rotates differently if there are more objects to draw.
I used this simple code to make sure the problem actually came from this:
import pygame
from pygame.locals import *
pygame.init()
WIDTH, HEIGHT = (640, 480)
screen = pygame.display.set_mode((WIDTH, HEIGHT))
font = pygame.font.SysFont('consolas', 20)
clock = pygame.time.Clock()
angle = 0
time_passed = 0
pygame.mouse.set_pos((WIDTH//2, HEIGHT//2))
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
# I did not use the MOUSEMOTION event because it used to glitch a bit
x, y = pygame.mouse.get_pos()
angle += (WIDTH//2 - x) * 360 / WIDTH # 360° every WIDTH pixels
pygame.mouse.set_pos((WIDTH//2, HEIGHT//2))
screen.fill(0)
text = font.render('Angle: %d°' %angle, True, (255, 255, 255))
w, h = text.get_size()
screen.blit(text, (WIDTH//2 - w//2, HEIGHT//2 - h//2))
pygame.display.flip()
time_passed = clock.tick(60)/1000
I think either the mouse or the OS tweak the travelled distance according to the mouse speed, so I did the following tests at similar and relatively constant speed:
Going say 5 centimeters with the framerate limited to 60 FPS did not result in the same final angle as with 120 FPS for example, even when moving the mouse at the same speed, with the same mouse with high DPI.
Do I need to implement a tick system for example, where I only update the position every few frames? I think the problem wouldn't be solved with slower framerates then, and maybe the movement would not be as responsive as I want.
Or perhaps there is an alternative to pygame.mouse.get_pos() / event.pos, getting the raw, more precise position from the mouse?
I would appreciate any help.
You get the position of the mouse with pygame.mouse.get_pos() and you reset the position with pygame.mouse.set_pos(). What if there was an event between pygame.mouse.get_pos() and pygame.mouse.set_pos()? Also pygame.mouse.get_pos() only tells you the current position of the mouse curosr, but it does not tell you how the mouse got there.
I suggest to use the MOUSEMOTION event. The event queue gives you all movements of the mouse. The relative movement of the mouse pointer since the last movement can be queried with the rel attribute:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
angle += event.rel[0] * 360 / screen.get_width()
Minimal example
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
font = pygame.font.SysFont('consolas', 20)
clock = pygame.time.Clock()
angle = 0
text = font.render(f'Angle: {angle}°', True, (255, 255, 255))
pygame.mouse.set_pos(screen.get_rect().center)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
run = False
if event.type == pygame.MOUSEMOTION:
angle += event.rel[0] * 360 / screen.get_width()
text = font.render(f'Angle: {angle}°', True, (255, 255, 255))
pygame.mouse.set_pos(screen.get_rect().center)
screen.fill(0)
screen.blit(text, text.get_rect(center = screen.get_rect().center))
pygame.display.flip()
pygame.quit()
exit()

Doing something after a period of time: Pygame

I wanted to do something after a period of time. On stack overflow I found a question that helps solve that, (Link) but when I run the program the code works, however it goes away after a millisecond. Whereas I want it to stay there after the amount of time I want it to wait. In this case for a test run I am blitting some text onto the screen. Here is the code:
import pygame
# Importing the modules module.
pygame.init()
# Initializes Pygame
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((800, 600))
# Sets the screen to pygame looks and not normal python looks.
pygame.display.set_caption("Test Run")
# Changes the title
# Heading
headingfont = pygame.font.Font('Bouncy-PERSONAL_USE_ONLY.otf', 45)
headingX = 230
headingY = 10
class Other():
def show_heading():
Heading = headingfont.render("Health Run!", True, (255, 255, 255))
screen.blit(Heading, (headingX, headingY))
pygame.time.set_timer(pygame.USEREVENT, 100)
running = True
while running:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.USEREVENT:
Other.show_heading()
#Update Display
pygame.display.update()
If you want to draw the text permanently, you need to draw it in the application loop. Set a Boolean variable "draw_text" when the timer event occurs. Draw the text depending on draw_text in the application loop:
draw_text = False
running = True
while running:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.USEREVENT:
draw_text = True
if draw_text:
Other.show_heading()
#Update Display
pygame.display.update()
For more information about timers and timer events, see Spawning multiple instances of the same object concurrently in python, How can I show explosion image when collision happens? or Adding a particle effect to my clicker game and many more.

Python PyGame Moving Rectangle

I am struggling with moving a drawn rectangle on the screen in pygame, I am trying to create a Snake game. I am very new to Python and object oriented programming in general so it is probably a stupid mistake. Code below.
#X coordinate of snake
lead_x = 300
#sets window position on screen
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (320,240)
#imports pygame module
import sys, pygame
#initialises pygame module
pygame.init()
#changes background colour to green
background_colour = 155, 188, 15
blue =(0,0,255)
red = (100,40,20)
#sets screen size
screen = pygame.display.set_mode((640, 480))
#changes the background colour
screen.fill(background_colour)
#creates rectangle on the screen
pygame.draw.rect(screen, blue, [lead_x,lead_x,10,10])
#updates display to show new background colour
pygame.display.update()
#Sets the window title to 'Python'
pygame.display.set_caption('Python')
#closes the window when user presses X
running = True
#if cross is clicked set running = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#Controls
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x -= 10
if event.key == pygame.K_RIGHT:
lead_x += 10
#if running = False close pygame window
if running == False:
pygame.quit()
You need to put pygame.draw.rect(screen, blue, [lead_x, lead_y, 10, 10]) in your game loop. As of right now you're drawing the rect on the screen only once, and that's in the beginning of the program. You want to continuously draw the rect at different lead_x and lead_y positions in order for a rect to move on the screen.
You should also put a screen.fill(background_colour) (to clear the previous drawing) and pygame.display.update() (to update the changes) in your loop as well.
EDIT: I noticed something: you probably want to create a variable lead_y and use pygame.draw.rect(screen, blue, [lead_x, lead_y, 10, 10]) so you don't move diagonally every time.

Pygame, move a square on the screen, but can not erase the previous movements

This is my first post in StackOverflow, hope you guys can help a newbie programmer. It's Pygame Python simple ask.
I am trying to move a square on the screen, but can not erase the previous movements.
import pygame
pygame.init()
screen = pygame.display.set_mode((400,300))
pygame.display.set_caption("shield hacking")
JogoAtivo = True
GAME_BEGIN = False
# Speed in pixels per frame
x_speed = 0
y_speed = 0
cordX = 10
cordY = 100
def desenha():
quadrado = pygame.Rect(cordX, cordY ,50, 52)
pygame.draw.rect(screen, (255, 0, 0), quadrado)
pygame.display.flip()
while JogoAtivo:
for evento in pygame.event.get():
print(evento);
#verifica se o evento que veio eh para fechar a janela
if evento.type == pygame.QUIT:
JogoAtivo = False
pygame.quit();
if evento.type == pygame.KEYDOWN:
if evento.key == pygame.K_SPACE:
print('GAME BEGIN')
desenha()
GAME_BEGIN = True;
if evento.key == pygame.K_LEFT and GAME_BEGIN:
speedX=-3
cordX+=speedX
desenha()
if evento.key == pygame.K_RIGHT and GAME_BEGIN:
speedX=3
cordX+=speedX
desenha()
You have to draw over the previous image. Easiest is to fill the screen with a background color in the beginning of the game loop, like so:
screen.fill((0, 0, 0))
I am doing something similar and I hope this helps
import pygame
clock=pygame.time.Clock() #the frames per second BIF in pygame
pygame.init()
FPS=30
display_width=800
display_height=600
white=(255,255,255)
black=(0,0,0)
block_size=10
gameExit=False
lead_x = display_width / 2
lead_y = display_height / 2
lead_x_change = 0 # 0 beacuse we will not be changing the position in the beginning
lead_y_change = 0
gameDisplay=pygame.display.set_mode((display_width,display_height))
while not gameExit: #game loop
for event in pygame.event.get(): #event handling BIF in pygame EVENT LOOP
#print(event) # prints out the position of the mouse and the buttons pressed when in game window
if event.type== pygame.QUIT: #if the user presses the [x] in game window, it quits the window
gameExit=True
if event.key == pygame.K_LEFT:
lead_x_change = -block_size #block size is number of pixels moved in one loop
lead_y_change=0
elif event.key==pygame.K_RIGHT:
lead_x_change= block_size
lead_y_change=0
elif event.key==pygame.K_UP:
lead_y_change= -block_size
lead_x_change=0
elif event.key==pygame.K_DOWN:
lead_y_change= block_size
lead_x_change=0
lead_y+=lead_y_change
lead_x+=lead_x_change
gameDisplay.fill(white) #fills the display surface object, backgroud color is the parameter filled in
pygame.draw.rect(gameDisplay,black,[lead_x,lead_y,block_size,block_size])
pygame.display.update() #after done with all the action,update the surface
clock.tick(FPS) #runs the game at 30FPS
pygame.quit()
quit()
You also can draw everything from a previous surface, before the square was in place, then draw the square on it always in a different place.
Then draw the new surface to screen each time.
But not really good strategy, it can be slow and/or induce flickering.
For instance:
# Draw anything to the display surface named screen, then do:
# By display surface I mean the surface returned by pygame.display.set_mode()
orig = screen.copy()
# Sometimes it will not be filled with a image from screen that you have drawn before, so you draw
# all to orig surface
# Then you make a surface that will be shown on the screen and do:
s = pygame.surface.Surface()
s.blit(orig, 0, 0)
# Then you draw the rectangle or whatever on s, and then:
screen.blit(s, 0, 0)
pygame.display.flip()
# and you keep orig as a starting point for every move
If you have many movable objects on the screen simultaneously this is good, or if you are refreshing restricted areas only, else redraw over the last image as suggested in other answer.
If you go about drawing directly to the display surface flicker will be bigger and sometimes, especially when display is hardware accelerated you will have problems. On non desktop devices like mobile phones especially. Drawing over and adding new usually works fine directly on display surface and would be the correct approach to your problem.
I know I sound contradictive, but some stuff you simply must see for yourself. Get experience by experimenting.

Pygame draw interactively

Hi I'm having some trouble realizing my ideas. I first wanted to draw rectangles with two mouse clicks, but it didn't work properly so i reduced it to this: to draw fixed-size rectangles with one mouse click.
However it still doesn't work/...
import pygame
windowSize = (500,500)
white = (255,255,255)
black = (0,0,0)
pygame.init()
screen = pygame.display.set_mode(windowSize)
running = 1
while running:
screen.fill(white)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = 0
THE PROBLEM IS HERE SOMEWHERRE
elif event.type == pygame.MOUSEBUTTONDOWN:
rect = pygame.Rect(event.dict["pos"],(30,50))
pygame.draw.rect(screen,black,rect,1)
pygame.display.flip()
I know there might be a lot of conceptual errors with my code... please help!
You are filling white the entire screen every tick. So after you actually draw the screen become blank again on the next tick. Just move screen.fill(white) out of main cycle:
import pygame
windowSize = (500,500)
white = (255,255,255)
black = (0,0,0)
pygame.init()
screen = pygame.display.set_mode(windowSize)
running = 1
screen.fill(white)
while running:
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEBUTTONDOWN:
rect = pygame.Rect(event.dict["pos"],(30,50))
pygame.draw.rect(screen,black,rect,1)
pygame.display.flip()

Categories

Resources