I have been have a lot of trouble with my summative project where you have to make a game in python using pygame. I am currently stuck with trying to make a menu screen for my game, the problem is I can't get my buttons to show up and after that how to change to my game map once they click start. I have been getting the type error "TypeError: button() takes from 6 to 7 positional arguments but 9 were given" if any of you could help that would mean a lot. thanks.
#army man man
import pygame
from pygame import *
from tkinter import *
import time
import random
win = pygame.display.set_mode((1280,720))
pygame.display.set_caption("Armymanman")
walkright = [pygame.image.load('walk1.png'),pygame.image.load('walk2.png'),pygame.image.load('walk3.png'),pygame.image.load('walk4.png'),pygame.image.load('walk5.png'),pygame.image.load('walk6.png'),pygame.image.load('walk7.png'),pygame.image.load('walk8.png'),pygame.image.load('walk9.png')]
walkleft = [pygame.image.load('walk1L.png'),pygame.image.load('walk2L.png'),pygame.image.load('walk3L.png'),pygame.image.load('walk4L.png'),pygame.image.load('walk5L.png'),pygame.image.load('walk6L.png'),pygame.image.load('walk7L.png'),pygame.image.load('walk8L.png'),pygame.image.load('walk9L.png')]
backg = pygame.image.load('pythonbg.png')
#resize char image
char = pygame.image.load('stand.png')
char = pygame.transform.scale(char,(64,64))
x=0
y=720
w=1280
h=720
black=(0,0,0)
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
white=(255,255,255)
clock = pygame.time.Clock()
#plays music does not work?
#def playmusic():
pygame.init()
pygame.mixer.pre_init(22050, -16, 2, 2048) # setup mixer
pygame.mixer.init()
pygame.mixer.music.load('bgmusic.ogg')
pygame.mixer.music.play(-1)
#playmusic()
##song=pygame.mixer.sound('bgmusic.ogg')
##
##song.play()
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.move = 5
self.isjump = False
## self.isjump=0
self.jumpcount = 10
self.left = False
self.right = False
self.walkcount = 0
def draw(self,win):
if self.walkcount + 1 >=27:
self.walkcount = 0
if self.left:
win.blit(walkleft[self.walkcount//3], (self.x,self.y))
self.walkcount += 1
elif self.right:
win.blit(walkright[self.walkcount//3], (self.x,self.y))
self.walkcount += 1
else:
win.blit(char, (self.x,self.y))
def redrawwindow():
win.blit(backg, (0,0))
man.draw(win)
pygame.display.update()
startsc=pygame.image.load('armymanbg.jpg')
startsc=pygame.transform.scale(startsc,[1280,720])
win.blit(startsc,(0,0))
pygame.display.flip()
DIS=1
def button(x,y,w,h,ic,ac,action=None):
mouse=pygame.mouse.get_pos()
click= pygame.mouse.get_pressed()
if x+w>mouse[0] > x and y+h > mouse[1] > y:
global DIS
global intro
pygame.draw.rect(win,ac,(x,y,w,h))
if click[0] == 1 and action!= None:
if action=="START":
pygame.display.update()
time.sleep(0.5)
run= False
DIS=2
elif action=="EXIT":
pygame.quit()
quit()
elif action=="Menu":
DIS=1
else:
return True
else:
pygame.draw.rect(window, ic, (x,y,w,h))
text = pygame.font.SysFont('freesonsbold.ttf',25)
win.blit(text.render("BECOME THE ARMYMANMAN!", True,(black)), (x+(w/3.1), y+(h/2.5)))
win.blit(text.render("Start",True,(black)), (x+(w/3.1), y+(h/2.5)))
win.blit(text.render("Exit",True,(black)), (x+(w/3.1), y+(h/2.5)))
#MAIN LOOP
man = player(0, 656, 64, 64)
run = True
while run:
clock.tick(27)
if DIS==1:
for event in pygame.event.get():
if event.type==pygame.QUIT:
quit()
win.fill((0,0,0))
button("START",400, 500, 150, 75,green,blue,"START")
button("EXIT", 400,650,150,75,green,red,"EXIT" )
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
if (event.type==pygame.KEYDOWN and event.key == K_RIGHT)and man.x < 1280 - man.width - man.move:
man.x += man.move
man.right = True
man.left = False
elif (event.type==pygame.KEYDOWN and event.key == K_LEFT)and man.x > man.move:
man.x -= man.move
man.left = True
man.right = False
else:
man.right= False
man.left = False
man.walkcount = 0
if (event.type==pygame.KEYDOWN and event.key == K_SPACE):
man.isjump = True
man.right = False
man.left = False
man.walkcount = 0
else:
if(man.isjump==True):
if man.jumpcount >= -10:
neg = 1
if man.jumpcount < 0:
neg = -1
man.y -= (man.jumpcount ** 2) *0.5 * neg
man.jumpcount -= 1
else:
man.isjump = False
man.jumpcount = 10
redrawwindow()
print(man.y)
pygame.quit
For starters, you really shouldn't do from pygame import *, as it will pollute your namespace with lots of stuff you don't want, from pygame.locals import * is more normal. The TypeError you mention is due to you giving button() too many parameters. You can see that it takes six or seven parameters when you define it (def button(x,y,w,h,ic,ac,action=None):). When you call it you try to pass too many (button("START",400, 500, 150, 75,green,blue,"START")). I think the initial "START" parameter is the excess. Here are some other things I've noticed:
if(man.isjump==True): can be replaced with if man.isjump:. There seem to be lots of similar excess brackets. You do not need them around comparisons unless it's something like if x and (a or b), where it makes a difference. You also do not need them around most function parameters. This button-drawing lines with (black) are an example of this.
The final pygame.quit is unnecessary and will not work anyway (if you needed it, which you don't, it would be pygame.quit().
All of your buttons are drawn in the same place; try changing the draw coordinates to be different
Your whitespace is strange. As a general rule, do not have trailing whitespace at the end of lines or a gap of more than two blank lines.
In this line (pygame.draw.rect(window, ic, (x,y,w,h))), you draw to window instead of win, which breaks it.
The whole section of code after the huge whitespace glob (excluding pygame.quit, which should be removed) needs to be indented.
if (event.type==pygame.KEYDOWN and event.key == K_RIGHT) can be replaced with if pygame.key.get_pressed()[K_RIGHT] and similar for left. These, along with redrawwindow() should be outside of the for event in pygame.event.get(): loop.
Related
I can't figure out how to loop through the jump function without having it in the first 'while True' block. None of the proposed alternatives have worked so far. Currently the only way I get it to work is having to press spacebar for each step of the jump.
import pygame
from pygame import Color
HEIGHT = 500
WIDTH = 400
surface = pygame.display.set_mode((HEIGHT, WIDTH))
class Bird:
def __init__(self):
self.x = 10
self.y = 300
self.vy = 5
self.jumpCount = 10
self.isJump = False
def draw(self):
pygame.draw.rect(surface, Color("yellow"), (self.x, self.y, 10, 10))
pygame.display.flip()
def jump(self):
if self.isJump:
# using 'while' doesn't work either
if self.jumpCount >= -10:
# this doesn't work -> pygame.time.delay(100)
print(self.jumpCount)
self.y += (self.jumpCount * abs(self.jumpCount)) * -0.5
self.jumpCount -= 1
else:
self.jumpCount = 10
self.isJump = False
return self.isJump
def move(self):
return
def run():
bird = Bird()
while True:
pygame.time.delay(100)
# only works if I put 'bird.isJump = True, bird.jump()' here, and then it loops continuously
surface.fill(Color("blue"))
bird.draw()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == 32:
bird.isJump = True
bird.jump()
if event.type == pygame.QUIT:
pygame.quit()
pygame.display.flip()
run()
You could call the move method every time you run the game loop, along with draw, then call the jump method only once, when space is clicked.
The result will be (with a few other minor changes, such as calling pygame.init, quitting with quit instead of pygame.quit and removing redundant class members):
import pygame
from pygame import Color
class Bird:
def __init__(self):
self.x = 10
self.y = 300
self.jumpCount = 10
self.isJump = False
def draw(self):
pygame.draw.rect(surface, Color("yellow"), (self.x, self.y, 10, 10))
pygame.display.flip()
def jump(self):
self.jumpCount = 10
self.isJump = True
def move(self):
if self.isJump:
if self.jumpCount >= -10:
self.y += (self.jumpCount * abs(self.jumpCount)) * -0.5
self.jumpCount -= 1
else:
self.isJump = False
def run():
bird = Bird()
while True:
pygame.time.delay(100)
surface.fill(Color("blue"))
bird.move()
bird.draw()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == 32:
bird.jump()
if event.type == pygame.QUIT:
quit()
pygame.display.flip()
pygame.init()
HEIGHT = 500
WIDTH = 400
surface = pygame.display.set_mode((HEIGHT, WIDTH))
run()
The image I uploaded is not appearing onto the moving background. However, when the background was still it showed up normally (i was able to see the character and make it jump using the space key). Have been trying to figure out the error for days, please help - thank you!!!!
The following is the portion of code used for the character and moving background.
background = pygame.image.load('background.png')
backgroundX = 0
backgroundX2 = background.get_width()
homeScreen = pygame.image.load('home_screen.png')
def redrawGameWindow():
screen.blit(background, (0, 0))
man.draw(screen)
# background images for right to left moving screen
screen.blit(background, (backgroundX, 0))
screen.blit(background, (backgroundX2, 0))
pygame.display.update()
# create class for character (object)
class player(object):
def __init__(self, x, y, width, height): # initialize attributes
self.x = x
self.y = y
self.width = width
self.height = height
self.left = True
self.right = True
self.isJump = False
self.stepCount = 0
self.jumpCount = 10
self.standing = True
def draw(self, screen):
if self.stepCount + 1 >= 27: # 9 sprites, with 3 frames - above 27 goes out of range
self.stepCount = 0
if not self.standing:
if self.left:
screen.blit(leftDirection[self.stepCount // 5], (self.x, self.y), man.pos)
self.stepCount += 1
elif self.right:
screen.blit(rightDirection[self.stepCount // 5], (self.x, self.y), man.pos)
self.stepCount += 1
else:
if self.right:
screen.blit(rightDirection[0], (self.x, self.y)) # using index, include right faced photo
else:
screen.blit(leftDirection[0], (self.x, self.y))
class enlargement(object):
def __init__(self, x, y, radius, color, facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
def draw(self, screen):
pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius, 1)
# main loop
speed = 30 # NEW
man = player(200, 410, 64, 64) # set main character attributes
run = True
while run:
clock.tick(speed) # NEW
backgroundX -= 1.4 # Move both background images back
backgroundX2 -= 1.4
if backgroundX < background.get_width() * -1: # If our background is at the -width then reset its position
backgroundX = background.get_width()
if backgroundX2 < background.get_width() * -1:
backgroundX2 = background.get_width()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
man.left = True
man.right = False
man.standing = False # false, because man is walking
# verify that character is within window parameters
elif keys[pygame.K_RIGHT]:
man.right = True
man.left = False
man.standing = False # false, because man is walking
else:
man.standing = True
man.stepCount = 0
if not man.isJump:
if keys[pygame.K_SPACE]:
man.isJump = True # when jumping, man shouldn't move directly left or right
man.right = False
man.left = False
man.stepCount = 0
else:
if man.jumpCount >= -10:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) * 0.5 * neg # to jump use parabola
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 10
Your probably just redrawing the background last ,thus it covers your sprite every time, I've had the issue in Visual Studio's C# (the old MonoGame library). By the way that's just a guess without completely going over your code. Good luck!
I started creating a new game in pygame. first I made the game window and background. I made to backgrounds(bg and fg). I was going to leave fg as it was and make the second backgound, bg, as a scrolling background when my character sprite moves. After that, I pasted in code from a previous pygame project that was just a simple sprite character that could walk and jump in front of a background. When I pasted it in, the window came up and only displayed my backgrounds and did not show my sprite character at all. It also did not throw any errors. what's happening? Is my sprite just hidden?
import pygame
from random import randint, choice
from pygame.locals import *
pygame.init()
#(pasted code start)-----------------------------------------------------------------------------
walkRight = [pygame.image.load('/Users/luke.redwine/Documents/Python/PyGame/Examples/Ben-Game/ben characters main/R %s.png' % frame) for frame in range(1, 9)]
walkLeft = [pygame.image.load('/Users/luke.redwine/Documents/Python/PyGame/Examples/Ben-Game/ben characters main/L %s.png' % frame) for frame in range(14, 21)]
#(pasted code end)-----------------------------------------------------------------------------
bg = pygame.image.load('/Users/luke.redwine/Documents/Python/PyGame/Llama game/Llama imaging/backgrounds concepts/Mountains/PPP_BG1.png')
fg = pygame.image.load('/Users/luke.redwine/Documents/Python/PyGame/Llama game/Llama imaging/backgrounds concepts/Mountains/PPP_fg1.png')
screen = pygame.display.set_mode((276, 216), HWSURFACE|DOUBLEBUF|RESIZABLE)
#(pasted code start)---------------------------------------------------------------------------
class player(object):
def __init__(self,x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.velocity = 15
self.isJump = False
self.jumpCount = 7
self.right = False
self.left = False
self.walkCount = 0
self.screen = screen
def draw(self, screen):
if self.walkCount + 1 >= 8:
self.walkCount = 0
if self.left:
self.screen.blit(walkLeft[self.walkCount//1], (self.x, self.y))
self.walkCount += 1
elif self.right:
self.screen.blit(walkRight[self.walkCount//1], (self.x, self.y))
self.walkCount += 1
else:
self.screen.blit(char, (self.x, self.y))
#(pasted code end)-----------------------------------------------------------------------------
pygame.display.set_caption("Game")
screen.blit(pygame.transform.scale(bg,(276, 216)),(0,0))
screen.blit(pygame.transform.scale(fg,(276, 216)),(0,0))
pygame.display.flip()
#while loop for screen resize, fulscreen:
while True:
pygame.event.pump()
event=pygame.event.wait()
if event.type==QUIT:
pygame.quit()
elif event.type==VIDEORESIZE:
screen=pygame.display.set_mode(event.dict['size'],HWSURFACE|DOUBLEBUF|RESIZABLE)
screen.blit(pygame.transform.scale(bg,event.dict['size']),(0,0))
screen.blit(pygame.transform.scale(fg,event.dict['size']),(0,0))
pygame.display.flip()
#(pasted code start)---------------------------------------------------------------------------
#drawing in sprite character
def redrawGamescreen():
ben.screen.blit(bg,(0,0))
ben.screen.blit(fg,(0,0))
ben.draw(ben.screen)
pygame.display.update()
ben = player(50, 279, 64, 64)
run = True
#main loop and character control
while run:
clock.tick(8)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and ben.x > ben.velocity:
ben.x -= ben.velocity
ben.left = True
ben.right = False
elif keys[pygame.K_RIGHT] and ben.x < 735 - ben.width - ben.velocity:
ben.x += ben.velocity
ben.right = True
ben.left = False
else:
ben.right = False
ben.left = False
ben.walkCount = 0
if not(ben.isJump):
if keys[pygame.K_SPACE]:
ben.isJump = True
ben.right = False
ben.left = False
else:
if ben.jumpCount >= -7:
neg = 1
if ben.jumpCount < 0:
neg = -1
ben.y -= (ben.jumpCount ** 2) * 0.5 * neg
ben.jumpCount -= 1
else:
ben.isJump = False
ben.jumpCount = 7
ben.velocity = 15
redrawGamescreen()
#(pasted code end)-----------------------------------------------------------------------------
pygame.quit()
I can't test it but if you better organize code then you should see that you run two while loop. In first loop you display only background. And you never ends first loop so it never run second loop which draws sprite on background. You should remove first loop.
When SPACE or DOWN is held, then the sprite disappears because of the scrolling background. When the background is a still image, it works. Furthermore the animation is fast so I used a timer to make it slower, but when the DOWN button is let go of, the screen speeds up.
I have tried searching up syntax online and it works when the background image is still.
from time import sleep as s
import random
import pygame
pygame.init()
import time
window = pygame.display.set_mode((1000, 500))
pygame.display.set_caption("Practice Game")
image = pygame.image.load('pixel6.png')
image = pygame.transform.scale(image, (1000, 500))
jump1 = [pygame.image.load('adventurer-jump-00.png'),pygame.image.load('adventurer-jump-01.png'),pygame.image.load('adventurer-jump-02.png'),pygame.image.load('adventurer-jump-03.png'), pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
run2 = [pygame.image.load('adventurer-run-00.png'), pygame.image.load('adventurer-run-01.png'),pygame.image.load('adventurer-run-02.png'),pygame.image.load('adventurer-run-03.png')]
slide1 = [pygame.image.load('adventurer-slide-00.png'),pygame.image.load('adventurer-slide-01.png'),pygame.image.load('adventurer-stand-00.png'),pygame.image.load('adventurer-stand-01.png'),pygame.image.load('adventurer-stand-02.png')]
#attack = [pygame.image.load('
imagex = 0
imagex2 = image.get_width()
clock = pygame.time.Clock()
run = True
run1 = True
jump2 = True
slide2 = True
imagess = True
x = 40
y = 391
FPS = 60
speed = 0.6
jumpcount = 10
jumpcount1 = 0
runcount = 0
slide = 0
isJump = False
down = False
class obstacles(object):
img = [pygame.image.load('img.png')]
def __init__(self, x,y, width, height):
self.x = x
self.y =y
self.width = width
self.height = height
self.hitbox = (x,y,width,height)
self.count = 0
def draw(self, window):
self.hitbox = (self.x + 5, self.y + 5, self.width, self.height)
if self.count >= 8:
self.count = 0
self.count +=1
window.blit(pygame.transform.scale(self.img[self.count//1000], (150,100)), (self.x, self.y))
pygame.draw.rect(window, (255,0,0), self.hitbox, 2)
objects = []
def keepdrawing():
global runcount, slide, run1,jumpcount1
window.blit(image, (imagex,0))
window.blit(image, (imagex2,0))
for object1 in objects:
object1.draw(window)
if runcount >= 3:
runcount = 0
if run1 == True:
window.blit(run2[runcount],(int(x),int(y)))
runcount +=1
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN and y == 391:
run1 = False
if slide >= 4:
slide = 0
if slide2:
window.blit(slide1[slide],(int(x),int(y)))
slide +=1
if event.key == pygame.K_SPACE:
run1 = False
if jumpcount1 >= 7:
jumpcount1 = 0
if jump2 and y!=391:
window.blit(jump1[jumpcount1],(int(x),int(y)))
jumpcount1 +=1
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
run1 = True
if event.key == pygame.K_SPACE:
run1=True
pygame.display.update()
pygame.time.set_timer(pygame.USEREVENT+1, 500)
pygame.time.set_timer(pygame.USEREVENT+2, random.randrange(1000,2000))
obstacles = obstacles(1050,300,64,64)
while run:
clock.tick(60)
imagex -= 2
imagex2 -= 2
if imagex < image.get_width() * -1:
imagex = image.get_width()
if imagex2 < image.get_width() * -1:
imagex2 = image.get_width()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.USEREVENT+1:
speed += 1
if event.type == pygame.USEREVENT+2:
objects.append(obstacles)
for object1 in objects:
object1.x -= 1
if object1.x < -100:
objects.pop(objects.index(object1))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_SPACE]:
isJump =True
else:
if jumpcount >= -10:
neg=1
if jumpcount <0:
neg = -1
s(0.01)
y-= (jumpcount**2)*0.3*neg
s(0.01)
jumpcount -=1
else:
isJump = False
jumpcount = 10
keepdrawing()
I cannot test your game due to the lot of images I do not have, but I think you are misunderstanding how the event system works, or at least you have neglected a case.
When you press a key, the KEYDOWN is emitted, and when you lift the key, the KEYUP is emitted.
These event are instantaneous (well, not really, but they are very fast), and are catched by the event manager only when the status of the button changes (from pressed to unpressed and viceversa). You must not rely on them to check if a button is kept pressed. Have a look at this post for a better understanding.
With this in mind, let's see what happening to your keepdrawing function. Here the relevant parts:
def keepdrawing():
#...
if run1 == True:
#blitting
if event.type == pygame.KEYDOWN:
run1 = False
#stuff and blitting
if event.type == pygame.KEYUP:
run1 = True
As you can see, when you hold the button pressed (that is, between KEYDOWN and KEYUP events) the boolean run1 is False. So nothing is blit. That's why your image disappear.
You should still be able to see the beginning of the movement: the frame when you press the button the KEYDOWN event is catched and that part of the code is executed. But the frame later, nothing is blit because run1 is False and there is no event to be catched.
I do not have a working solution, as I said I cannot test the game, but I would suggest at least to be sure that keepdrawing always draw something. Try to figure what you should draw when run1 is False and add a couple of lines about it in keepdrawing.
As a more general advice, do not use the pygame event system in the keepdrawing function. Just check if a button is pressed like you do here:
keys = pygame.key.get_pressed()
I was trying to create something along the lines of mario, this is far from perfect I know. Anyways, while trying to make the "jumping" method I ran into an issue - The jumping doesn't work the way I intended it to work. Whenether I click the space bar my red square moves up and down randomly, I have to press the spacebar and hold it to complete a jump and even then its not perfect. Sometimes when I hold the space bar for too long the red square will continue to jump again. Is there any way to solve this issue? I'd be very thankful for any help, thanks.
import pygame, time, math, random, sys
from pygame.locals import *
background = pygame.image.load("assets/MarioBackground.png")
def events():
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
W, H = 640, 400
HW, HH = W / 2, H / 2
AREA = W * H
FPS = 60
bg_x = 0
isJump = False
jumpCount = 10
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((W,H))
pygame.display.set_caption("Mario")
class Mario():
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self):
pygame.draw.rect(screen, (255,0,0), (self.x, self.y, 40, 40))
def move(self):
global bg_x
if pressed_keys[K_RIGHT] and bg_x > -920:
if self.x > 490:
bg_x -= 5
else:
self.x += 5
if pressed_keys[K_LEFT] and self.x > 5:
self.x -= 5
def jump(self):
global jumpCount, isJump
if pressed_keys[K_SPACE]:
if jumpCount >= -10:
isJump = True
print(jumpCount)
neg = 1
if jumpCount < 0:
neg = -1
self.y -= (jumpCount ** 2) * 0.1 * neg
jumpCount -= 1
else:
isJump = False
jumpCount = 10
mario = Mario(50, 270)
while True:
clock.tick(FPS)
events()
pressed_keys = pygame.key.get_pressed()
screen.blit(background, (bg_x,0))
mario.move()
mario.draw()
mario.jump()
pygame.display.update()
Just check if isJump is true and then execute the jumping code in the jump method. I also recommend adding the isJump and jumpCount as attributes to Mario, so that you don't have to modify global variables.
To prevent the continuous jumping while Space is pressed, you have to handle the key press in the event queue. Then the jump action is triggered only once per key press not while the key is being held down.
import pygame, time, math, random, sys
from pygame.locals import *
background = pygame.Surface((640, 400))
background.fill((30, 90, 120))
W, H = 640, 400
HW, HH = W / 2, H / 2
AREA = W * H
FPS = 60
bg_x = 0
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((W,H))
class Mario():
def __init__(self, x, y):
self.x = x
self.y = y
# isJump and jumpCount should be attributes of Mario.
self.isJump = False
self.jumpCount = 10
def draw(self):
pygame.draw.rect(screen, (255,0,0), (self.x, self.y, 40, 40))
def move(self):
global bg_x
if pressed_keys[K_RIGHT] and bg_x > -920:
if self.x > 490:
bg_x -= 5
else:
self.x += 5
if pressed_keys[K_LEFT] and self.x > 5:
self.x -= 5
def jump(self):
# Check if mario is jumping and then execute the
# jumping code.
if self.isJump:
if self.jumpCount >= -10:
neg = 1
if self.jumpCount < 0:
neg = -1
self.y -= self.jumpCount**2 * 0.1 * neg
self.jumpCount -= 1
else:
self.isJump = False
self.jumpCount = 10
mario = Mario(50, 270)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Start to jump by setting isJump to True.
mario.isJump = True
clock.tick(FPS)
pressed_keys = pygame.key.get_pressed()
screen.blit(background, (bg_x,0))
mario.move()
mario.draw()
mario.jump()
pygame.display.update()
You can fix it by implementing the following rules:
you can only begin a jump when you touch the floor
you start a jump by pressing the space bar (set a variable) and stop it, when you touch the floor
you start a jump on keydown (pygame.KEYDOWN) not if pressed.
Some code snippets:
Begin jump
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and self.y == 0:
isJump = True
End jump
if self.y == 0:
isJump = False
With this rules you can only jump, when you're on the floor. You don't need to hold the space bar and you won't jump a second time if you hold the space bar to long