This question already has answers here:
How to move the player across a one background image?
(1 answer)
How to scroll the background surface in PyGame?
(1 answer)
Closed 1 year ago.
What I want to do is make the background move when my player moves forward, as the background contains a story-line of sorts. Instead the background is just moving on it's own and cannot be stopped.
Here is all the relevant code:
paccpos=(0,0)
bgX=0
pX, pY = paccpos
while 1:
events = pygame.event.get()
for e in events:
if e.type == QUIT:
exit()
if e.type == KEYDOWN and e.key == K_ESCAPE:
exit()
if pX+1:
bgX -= 1.4
screen.blit(bg_img, (bgX, 0))
entities.update(dt, events)
entities.draw(screen)
pygame.display.update()
dt = timer.tick(60)
class Player(Entity):
def __init__(self, platforms, pos, *groups):
super().__init__((color),(pygame.image.load("lemon3.png")), pos)
self.vel = pygame.Vector2((0, 0))
self.onGround = False
self.platforms = platforms
self.speed = 8
self.jump_strength = 6
self.pos=pos
def globpos(self):
global paccpos
paccpos=self.pos
def update(self, dt, events):
pressed = pygame.key.get_pressed()
up = pressed[K_UP]
left = pressed[K_LEFT]
right = pressed[K_RIGHT]
running = pressed[K_SPACE]
Related
This question already has answers here:
How to do a variable jump height based on how long key is held in Pygame
(1 answer)
How to make a character jump in Pygame?
(1 answer)
Closed last year.
I'm trying to make a jumping method for my player in pygame. It goes up but I can just hold the space bar key down and it will go up for as long as I want and I don't know how to prevent it. Here's the code for my player class:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((32, 64))
self.image.fill('blue')
self.rect = self.image.get_rect(topleft = pos)
self.direction = pygame.math.Vector2(0, 0)
self.speed = 8
self.jump_speed = -16
self.gravity = 0.8
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.direction.x = 1
elif keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.direction.x = -1
else:
self.direction.x = 0
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
self.jump()
def apply_gravity(self):
self.direction.y += self.gravity
self.rect.y += self.direction.y
def jump(self):
self.direction.y = self.jump_speed
def update(self):
self.get_input()
The jump event changes the way the player is moving. When a key is released, then that speed is not reverted. Use the pygame keydown event, and then the keyup event.
import pygame
from pygame.locals import *
#Your code
while True:
#Your event loop code
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_SPACE:
player.jump()
if event.type == KEYUP:
if event.key == K_SPACE:
player.revert_jump()
if event.type == QUIT:
pygame.quit()
exit()
This question already has answers here:
How to rotate an image(player) to the mouse direction?
(2 answers)
How do I rotate a sprite towards the mouse and move it?
(2 answers)
Closed 2 years ago.
I've been trying and trying, but basically I wanna make a tank game which has a tank that can turn itself by the mouse to fire bullets; when you turn your mouse to a direction, the sprite will follow exactly. the problem is, I can't turn the tank with any code, no matter what.
import os
import pygame
import math
pygame.init()
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 30)
icon = pygame.image.load('Sprite3.png')
pygame.display.set_icon((icon))
pygame.display.set_caption('DeMass.io')
class Tank(object): # represents the bird, not the game
def __init__(self):
""" The constructor of the class """
self.image = pygame.image.load('Sprite0.png')
# the bird's position
self.x = 0
self.y = 0
def handle_keys(self):
""" Handles Keys """
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_DOWN] or key[pygame.K_s]:
self.y += dist # move down
elif key[pygame.K_UP] or key[pygame.K_w]:
self.y -= dist # move up
if key[pygame.K_RIGHT] or key[pygame.K_d]:
self.x += dist # move right
elif key[pygame.K_LEFT] or key[pygame.K_a]:
self.x -= dist # move left
def draw(self, surface):
""" Draw on surface """
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
w = 1900
h = 10000
screen = pygame.display.set_mode((w, h))
tank = Tank() # create an instance
clock = pygame.time.Clock()
connection_angle = 90
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
screen.fill((255, 255, 255))
tank.draw(screen)
pygame.display.update()
tank.handle_keys()
clock.tick(100)
You can use the atan2 function from the built-in math module to calcualte the angle between two coordinates,
and then rotate your sprite accordingly:
import pygame
from math import atan2, degrees
wn = pygame.display.set_mode((400, 400))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 40), pygame.SRCALPHA)
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect(topleft=(185, 180))
def point_at(self, x, y):
rotated_image = pygame.transform.rotate(self.image, degrees(atan2(x-self.rect.x, y-self.rect.y)))
new_rect = rotated_image.get_rect(center=self.rect.center)
wn.fill((0, 0, 0))
wn.blit(rotated_image, new_rect.topleft)
player = Player()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEMOTION:
player.point_at(*pygame.mouse.get_pos())
pygame.display.update()
Output:
This question already has answers here:
How to get keyboard input in pygame?
(11 answers)
What all things happens inside pygame when I press a key? When to use pygame.event==KEYDOWN
(1 answer)
Python PyGame press two buttons at the same time
(2 answers)
Closed 2 years ago.
In This program I want to have it register Pressed Keys But only once instead of multiple times. If you've played 2048, I am trying to make something like that.
I want to do this without slowing the Frame rate.
import pygame, sys
pygame.init()
WIDTH, HEIGHT = 450,450
win = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
class Tile:
def __init__(self, x, y):
self.x = x
self.y = y
def Move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
print("Left")
elif keys[pygame.K_RIGHT]:
print("Right")
elif keys[pygame.K_UP]:
print("Up")
elif keys[pygame.K_DOWN]:
print("Down")
keys = pygame.key.get_pressed()
running = run = True
a = Tile(200, 500)
while run:
a.Move()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sys.exit()
pygame.display.update()
You have to use the key events, rather then pygame.key.get_pressed().
pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or movement.
Get the list of events (event_list) in the main application loop and pass the list to the method Move of the class Tile. Handel the events in the method:
import pygame, sys
pygame.init()
WIDTH, HEIGHT = 450,450
win = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
class Tile:
def __init__(self, x, y):
self.x = x
self.y = y
def Move(self, event_list):
for event in event_list:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("Left")
elif event.key == pygame.K_RIGHT:
print("Right")
elif event.key == pygame.K_UP:
print("Up")
elif event.key == pygame.K_DOWN:
print("Down")
running = run = True
a = Tile(200, 500)
while run:
event_list = pygame.event.get()
a.Move(event_list)
clock.tick(60)
for event in event_list:
if event.type == pygame.QUIT:
run = False
sys.exit()
pygame.display.update()
Im wokring on my own version of Pacman and am currently trying to get the window to resize. i read an answer here :https://reformatcode.com/code/python/pygame-how-do-i-resize-a-surface-and-keep-all-objects-within-proportionate-to-the-new-window-size. but it didnt help me in my case. at the i have 2 screen, screen and fake screen. if i set everything to blit on fake screen they appear but dont update themselces (pacman wont move). if i set them to screen they appear and update but dont resize. any help or suggestions would be greatly appreciated. btw its still a work on progress
import pygame
from Variables import pelletspawns #imports pellet spwans list from different script
from pygame.locals import *
#Initialisation
pygame.init()
pygame.display.set_caption("Pacman")
myfont = pygame.font.SysFont("monospace", 15)
screen = pygame.display.set_mode((448, 576)) #Creates screen object
fake_screen = screen.copy()
pic = pygame.surface.Surface((50,50))
pic.fill((255,100,100))
clock = pygame.time.Clock() #Creates clock object
Fin = False
#Declaring Variables
FPS = 60
MoveLeft = pygame.K_LEFT
MoveRight = pygame.K_RIGHT
MoveUp = pygame.K_UP
MoveDown = pygame.K_DOWN
#Load images
PACMAN_MAP = pygame.image.load("images/pacman_map.png").convert_alpha()
PACMANSPRITE = pygame.image.load("images/pacman.png").convert_alpha()
#pacmans class
class SpriteClass(pygame.sprite.Sprite):
def __init__(self, image, x, y):
self.image = image
self.y=y
self.x=x
self.rect = self.image.get_rect()
self.rect.left = self.x
self.rect.top = self.y
self.rect.width=16
self.rect.height=16
#draws Pacman
def draw(self, surface):
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
# move pacman
def movement(self):
pressed= pygame.key.get_pressed()
if pressed[MoveUp]:
self.y -= 2
print('key pressed')
if pressed[MoveDown]:
self.y += 2
print('key pressed')
if pressed[MoveLeft]:
self.x -= 2
print('key pressed')
if pressed[MoveRight]:
self.x += 2
print('key pressed')
self.rect.left = self.x
self.rect.top = self.y
print(self.x,self.y)
#instances Pacman
Pacman = SpriteClass(PACMANSPRITE, 216 ,416)
#Function to spawn pellets
def SpawnPellets(pelletspawns):
pelletx=0 #the temp x co-ordinate for the pellet to spawn
pellety= -8 #the temp y co-ordinate for the pellet to spawn (starts at -ve 0.5(gridscpare) for allignment
for row in pelletspawns:
#adds 1 grid space to correctly align spawns
pellety += 16
for pellet in row:
pelletx= 16*pellet
pelletx -=8
pygame.draw.circle(screen,(255, 204, 153), (pelletx, pellety) , 5)
#main game loop
while not Fin:
#For event is used to close the program
for event in pygame.event.get():
if event.type == QUIT:
pygame.display.quit()
if event.type == VIDEORESIZE:
screen = pygame.display.set_mode(event.dict['size'],RESIZABLE)
screen.blit(pygame.transform.scale(fake_screen, event.dict['size']), (0, 0))
pygame.display.flip()
#calls movement function
Pacman.movement()
#blits pacman map as background
screen.blit(PACMAN_MAP, (0, 0))
#draws pacman
Pacman.draw(screen)
#Spawns pellets
SpawnPellets(pelletspawns)
#draws screen
pygame.display.flip()
clock.tick(FPS)
I figured it out, i needed to move
screen.blit(pygame.transform.scale(fake_screen, event.dict['size']), (0, 0))
into the core game loop just above clock.tick. i tried this before but ran into a key error as there was no event for event.dict['size'] to get a size from, so i made a variable in the for event in pygame.event.get(): loop, and then passed that variable where it was asking for event.dict['size']. Here is the section of code i changed:
#main game loop
while not Fin:
#For event is used to close the program
for event in pygame.event.get():
if event.type == QUIT:
pygame.display.quit()
if event.type == VIDEORESIZE:
size = event.dict['size']
screen = pygame.display.set_mode(size,RESIZABLE)
#calls movement function
Pacman.movement()
#blits pacman map as background
fake_screen.blit(PACMAN_MAP, (0, 0))
#draws pacman
Pacman.draw(fake_screen)
#Spawns pellets
SpawnPellets(pelletspawns)
#draws screen
screen.blit(pygame.transform.scale(fake_screen, size), (0, 0))
pygame.display.flip()
clock.tick(FPS)
First off, this is a school assignment so I want to be upfront about that. Second I'm just asking for advice on the approach, possible help with the code. I'm working on a MSPAINT style clone using some pre-existing code from our book. The code already has the use of the draw.line when pressing mouse button 1. Teacher wants us to add ability to make circles or rectangles. I'm working on the circle part and I have figured out (thanks to the forums on here) how to implement what I wanted to do with the MOUSEBUTTONDOWN and MOUSEBUTTONUP events.. This has brought me to a new Question.. How would I blit then erase then blit a preview of the circle until it is the size the user wants and they release the MOUSEBUTTON and view the final blit...
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.MOUSEMOTION:
lineEnd = pygame.mouse.get_pos()
if pygame.mouse.get_pressed() == (1,0,0):
pygame.draw.line(background, drawColor, lineStart, lineEnd, lineWidth)
lineStart = lineEnd
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3:
circleStart = pygame.mouse.get_pos()
elif event.type == pygame.MOUSEBUTTONUP and event.button == 3:
circleEnd = pygame.mouse.get_pos()
size = (circleEnd[0] - circleStart[0])
pygame.draw.circle(background, drawColor, circleStart, size, lineWidth)
elif event.type == pygame.KEYDOWN:
myData = (event, background, drawColor, lineWidth, keepGoing)
myData = checkKeys(myData)
event, background, drawColor, lineWidth, keepGoing) = myData
Thanks so much
-Ben
So after some thinking this is the best solution I came up with using pygame. Tell me what you think and if it has helped you.
import pygame,sys,math #---- Import modules we will need
pygame.init() #---- Initialize the module
def get_rad(origin_x,origin_y,x,y): #----- Returns the appropriate radius
return math.sqrt((origin_x - x)**2 + (origin_y - y)**2) #----- Distance between 2
#----- points
screen = pygame.display.set_mode((400,400)) #----- Sets up the screen
clock = pygame.time.Clock() #------- Sets up the clock
mouse_button = 0 #--------- This variable is used to determine whether a mouse button
#--------- has been pressed
draw_final_circle = False #---------- This variable lets us know that we should draw the
#---------- final circle
while True: #------ main loop
clock.tick(60) #------ Limit the Fps
mouse_button0 = mouse_button #-------- This variable holds the previous value of
#-------- mouse_button(it will be useful later)
mouse_x,mouse_y = pygame.mouse.get_pos() #----- Get the mosue coordinates
for e in pygame.event.get(): #---- Cycle through events
if e.type == pygame.QUIT: pygame.quit();sys.exit() #--Quit when window is closed
if e.type == pygame.MOUSEBUTTONDOWN: #---- If the mouse button is pressed
if mouse_button == 0: #---- if the mouse button is released
mouse_button = 1 #----- set it to pressed basically
originx,originy = mouse_x,mouse_y #---- keep the mouse_x,mouse_y pos
if e.type == pygame.MOUSEBUTTONUP: #---- if the mouse button is released
if mouse_button == 1: #-------- if it is pressed
mouse_button = 0 #--------- set it to released
screen.fill((255,255,255)) #---- clear the screen
#-------- If a mouse button is pressed and a circle can be drawn (rad>width) ------#
if mouse_button == 1 and get_rad(originx,originy,mouse_x,mouse_y) > 1:
rad = int(get_rad(originx,originy,mouse_x,mouse_y)) #---- get the radius(as int)
pos = mouse_x,mouse_y
pygame.draw.circle(screen,(0,0,0),pos,rad,1) #--- draw the circle
#----------------------------------------------------------------------------------#
#---------- if the button is released but in the previous loop it was pressed -----#
if mouse_button == 0 and mouse_button0 == 1:
draw_final_circle = True #----- set the final circle boolean to True
if draw_final_circle: #----- if the final circle is decided
pygame.draw.circle(screen,(0,0,0),pos,rad,1) #---- keep drawing it
pygame.display.flip() #----- flip the buffer
I suggest you implement the different modes of your drawing program into different classes that represent the current mode and its state. This way, implementing different modes become very easy.
As for a circle drawing mode, you want to take a copy the screen surface when the user presses the mouse button, and blit that copy to the screen every frame.
Then draw your circle on that copy. This way, you basically "erase" the temporary circles.
Here's a simple example. Press SPACE to cycle between the different modes (draw, circle, rect) and TAB for different colors:
import pygame
from math import hypot
from itertools import cycle
from operator import itemgetter
pygame.init()
screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
colors = cycle(sorted(pygame.color.THECOLORS.iteritems(), key=itemgetter(0)))
color = next(colors)[1]
class DrawMode(object):
def __init__(self):
self.last = None
def handle(self, e):
if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1:
self.last = pygame.mouse.get_pos()
if e.type == pygame.MOUSEBUTTONUP and e.button == 1:
self.last = None
def draw(self, screen):
pos = pygame.mouse.get_pos()
if self.last:
pygame.draw.line(screen, color, self.last, pos)
self.last = pos
class ClickReleaseMode(object):
def __init__(self):
self.tmp = None
self.start = None
def handle(self, e):
if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1:
self.start = pygame.mouse.get_pos()
if e.type == pygame.MOUSEBUTTONUP and e.button == 1:
self.start = self.tmp = None
def draw(self, screen):
if not self.tmp:
self.tmp = screen.copy()
pos = pygame.mouse.get_pos()
screen.blit(self.tmp, (0,0))
if self.start:
self.do_draw(screen, pos)
class CircleMode(ClickReleaseMode):
def __init__(self):
super(CircleMode, self).__init__()
def do_draw(self, screen, pos):
r = hypot(pos[0] - self.start[0], pos[1] - self.start[1])
if r >= 2:
pygame.draw.circle(screen, color, self.start, int(r), 2)
class RectMode(ClickReleaseMode):#
def __init__(self):
super(RectMode, self).__init__()
def do_draw(self, screen, pos):
p = pos[0] - self.start[0], pos[1] - self.start[1]
pygame.draw.rect(screen, color, pygame.Rect(self.start, p), 2)
quit = False
modes = cycle((DrawMode, CircleMode, RectMode))
mode = next(modes)()
while not quit:
quit = pygame.event.get(pygame.QUIT)
for e in pygame.event.get():
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_SPACE:
mode = next(modes)()
print 'enter', mode.__class__.__name__
if e.key == pygame.K_TAB:
name, color = next(colors)
print 'changing color to', name, color
mode.handle(e)
mode.draw(screen)
pygame.display.flip()
clock.tick(60)