I'm working on an RPG and after completing my first map, I had to put the possibility of passing from one to another because I don't want to use scrolling.
Actually I check if the position of my character is the same as a particular sprite (door, invisible block, etc.) and then doing the change of the font and the loading of the new *.txt file. But the problem is that the previous sprites are still there!
I checked some way to solve this problem and a lot of people said that I should use the fill() function to overlay the screen. It works but the old sprites are still there; if my character tries to go to where a wall was, he can't.
I also try emptying the list of the sprites but it crashes the game instead, as the character was in this list, even if I reload the character...
It's the only thing blocking me to achieve a test version of the universe, if anyone could help me..
Here is my game loop :
while continuer_jeu:
#Limit the speed
pygame.time.Clock().tick(30)
for event in pygame.event.get():
if event.type == QUIT:
continuer_jeu=0
continuer_accueil=0
continuer_rules=0
continuer=0
carte=0
if event.type == KEYDOWN:
#If user press escape => back to the title screen
if event.key == K_ESCAPE:
continuer_jeu = 0
#Chara's moving key
elif event.key == K_RIGHT:
Noc.deplacer('droite')
elif event.key == K_LEFT:
Noc.deplacer('gauche')
elif event.key == K_UP:
Noc.deplacer('haut')
elif event.key == K_DOWN:
Noc.deplacer('bas')
#Refresh with new positions
fenetre.blit(fond, (0,0))
niveau.afficher(fenetre)
fenetre.blit(Noc.direction, (Noc.x, Noc.y))
pygame.display.flip()
if niveau.structure[Noc.case_y][Noc.case_x] == 'ma6': #If going through a door
if carte == "n1": # if first map
fond = pygame.image.load(image_Interieur).convert()
niveau = Niveau("Maison") #Load the house sprites
niveau.generer()
niveau.afficher(fenetre)
fenetre.blit(fond,(0,0))
If you need more of the code, just ask.
I achieve to pass from a map to another by deleting the previous list, load an other one and then recreate the character :
if niveau.structure[Noc.case_y][Noc.case_x] == "up" :
if carte == "n1" :
fond = pygame.image.load(image_Map2).convert()
niveau = Niveau("n2")
niveau.reset()
niveau.generer()
niveau.afficher(fenetre)
Noc = Perso("image/Noc right.png", "image/Noc left.png","image/Noc face.png", "image/Noc back.png", niveau)
fenetre.blit(fond,(0,0))
carte = "n2"
if niveau.structure[Noc.case_y][Noc.case_x] == "down" :
if carte == "n2" :
fond = pygame.image.load(image_Map1).convert()
niveau = Niveau("n1")
niveau.reset()
niveau.generer()
niveau.afficher(fenetre)
Noc = Perso("image/Noc right.png", "image/Noc left.png","image/Noc face.png", "image/Noc back.png", niveau)
fenetre.blit(fond,(0,0))
carte = "n1"
with theses functions :
class Niveau:
def __init__(self, fichier):
self.fichier = fichier
self.structure = 0
def reset(self):
self.structure = []
def generer(self):
with open(self.fichier) as fichier:
self.structure = [ligne.split() for ligne in fichier]
But I got an other problem : I can't change the map a second time. On the 2nd map, the character reach a down case, nothing happend. I tried to put the instruction when it is "down" on a "up" + "if carte == "n2" but the character came back to his spawn position... Where could I have made mistakes ?
Related
How do I get a user keyboard input with python and print the name of that key ?
e.g:
user clicked on "SPACE" and output is "SPACE"
user clicked on "CTRL" and output is "CTRL".
for better understanding i'm using pygame libary. and i built setting controller for my game. its worked fine but i'm able to use only keys on my dict. i dont know how to add the other keyboard keys.
see example:
class KeyboardSettings():
def __init__(self,description,keyboard):
self.keyboard = keyboard
self.default = keyboard
self.description = description
self.active = False
def activate_change(self,x,y):
fixed_rect = self.rect.move(x_fix,y_fix)
pos = pygame.mouse.get_pos()
if fixed_rect.collidepoint((pos)):
if pygame.mouse.get_pressed()[0]:
self.active = True
elif pygame.mouse.get_pressed()[0]:
self.active = False
This is a part of my class. in my script i loading all related object to that class. the related object are the optional keys in the game.
e.g
SHOOT1 = KeyboardSettings("SHOOT","q")
move_right = KeyboardSettings("move_right","d")
#and more keys
key_obj_lst = [SHOOT1,move_right....]
#also i built a dict a-z, 0,9
dict_key = { 'a' : pygame.K_a,
'b' : pygame.K_b,
'c' : pygame.K_c,
...
'z' : pygame.K_z,
'0' : pygame.K_0,
...
'1' : pygame.K_1,
'9' : pygame.K_9,
then in game loop:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
for k in key_obj_lst:
#define each key by user
if k.active:
k.keyboard = event.unicode
default = False
if k.keyboard in dict_key:
if event.key == dict_key[k.keyboard]:
if k.description == 'Moving Right':
moving_right = True
if k.description == 'SHOOT':
SHOOT = True
The code worked perfectly but i trully dont know how to add keys that not letters and numbers such as "ENTER","SPACE" etc.
pygame provides a function for getting the name of the key pressed:
pygame.key.name
And so you can use it to get the name of the key, there is no need to use a dictionary for this:
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 400))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.KEYDOWN:
key_name = pygame.key.name(event.key)
print(key_name)
pip install keyboard
import keyboard #use keyboard module
while True:
if keyboard.is_pressed('SPACE'):
print('You pressed SPACE!')
break
elif keyboard.is_pressed("ENTER"):
print("You pressed ENTER.")
break
Use keyboard module
import keyboard
while True:
print(f"You pressed {keyboard.get_hotkey_name()})
as a premice i would like to say that i'm totally new to programming and i'm not a computer science student so i'm sorry if my code makes you cringe, i recently had some python classes and enjoyed them so i wanted to deepen a little so i figured that a simple chess game would be fun to do.
As you can imagine i am using pygame.
As for now i "drew" a chessboard and i blitted the pieces in place, my idea is that i would get the coordinates of every click, if the coordinates are the same (or in range) of the blitted image the variable would update with the second click, how can i make it so that the system recognizes a "first" and "second" click.
import pygame as pg
import sys
pg.init()
schermo = pg.display.set_mode((640,540))
def coordinate():
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.MOUSEBUTTONUP:
mx1, my1 = pg.mouse.get_pos()
print (mx1,my1)
return mx1,my1
pg.display.update()
this is how i get the coords
ctorrensx = (53,53)
[...omissis]
def move():
result = coordinate()
global ctorrensx
if result == ctorrensx:
ctorrensx = (200,200)
this was my first idea for the moving function, ctorrensx is an example i wanted to try on, they are the coords of the left black rook, once i would click on it i wanted it to move to the coords (200,200) but it's not happening.
this is my first time using stack overflow so i hope that i didn't create too much confusion on my question.
thank you all.
You can set a flag to determine whether the click is a first or second.
For example:
firstClick = True
while True:
for event in pg.event.get():
if event.type == pg.MOUSEBUTTONDOWN:
if(firstClick):
firstClick = False
#Code for first click
else:
#code for second click
firstClick = True #resets the flag
I currently am working on a 'Flappy Bird' remake in Pygame using Python 3.2. I thought it would be good for practice, and relativly simple. However, it is proving to be hard. Currently, I am having a problem when drawing a rectangle at different heights but keeping the rectangle at the height it is set to.
Here is my Pipe class
class Pipe:
def __init__(self,x):
self.drawn = True
self.randh = random.randint(30,350)
self.rect = Rect((x,0),(30,self.randh))
def update(self):
self.rect.move_ip(-2,0)
def draw(self,screen):
self.drawn = True
pygame.draw.rect(screen,(0,130,30),self.rect)
My while Loop is as follows:
while True:
for event in pygame.event.get():
movey = +0.8
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_SPACE:
movey = -2
x += movex
y += movey
screen.blit(background,(0,0))
screen.blit(bird,(x,y))
Pipe1 = Pipe(scrollx)
if Pipe1.drawn == True:
Pipe1.update()
else:
Pipe1 = Pipe(scrollx)
Pipe1.draw(screen)
scrollx -= 0.3
pygame.display.update()
I have being wrestling with this code for over a week, and I really appreciate any help you can give.
I'm not following the logic of this part:
Pipe1 = Pipe(scrollx)
if Pipe1.drawn == True:
Pipe1.update()
else:
Pipe1 = Pipe(scrollx)
Pipe1.draw(screen)
The drawn attribute is set to True at the constructor, so when do you expect the else condition to be triggered? Remember you are recreating this pipe every frame.
Have you tried drawing the pipe the same you way you did with the bird?
Edit: suggestion for you for loop:
PIPE_TIME_INTERVAL = 2
pipes = [] # Keep the pipes in a list.
next_pipe_time = 0
while True:
[... existing code to handle events and draw the bird ...]
for pipe in pipes:
pipe.move(10) # You'll have to write this `move` function.
if pipe.x < 0: # If the pipe has moved out of the screen...
pipes.pop(0) # Remove it from the list.
if current_time >= next_pipe_time: # Find a way to get the current time/frame.
pipes.append(Pipe()) # Create new pipe.
next_pipe_time += PIPE_TIME_INTERVAL # Schedule next pipe creation.
You are creating a new Pipe on every loop, but never hang on to the old one(s), so you get a new random height each time. Move this line:
Pipe1 = Pipe(scrollx)
outside the while loop. Better yet, have a list of pipes you can add new ones to and easily update them all. You never set self.drawn = False within Pipe either.
Also, you are resetting movey for every event, try:
movey = 0.8 # no need for plus
for event in pygame.event.get():
I need to kb input onto a pygame screen
at the moment it appears on the idle shell
any advice would be appreciated.
This code is extracted from a larger program
mostly screen based but i need to input some
data (numeric) from the kb at times
import sys
import pygame
from pygame.locals import *
pygame.init()
N= ''
screen = pygame.display.set_mode((600,600))
font= pygame.font.Font(None,40)
screen.fill((255,255,255))
pygame.display.flip
pygame.display.update()
def score(C,y):
SetWnd = font.render( C,True,(0,0,255))
screen.blit(SetWnd, (15, 100+y))
pygame.display.update()
def start():
while True:
name=''
for evt in pygame.event.get():
if evt.type == KEYDOWN:
if evt.unicode.isalnum(): # unicode
name+=evt.unicode
print name,
elif evt.key == K_BACKSPACE:
name = name[:-1]
print name,
elif evt.key == K_RETURN:
return N
elif evt.type == QUIT:
pygame.quit()
sys.exit()
def Pchange(c,y):
block = font.render(N, True, (0,0,0))
rect = block.get_rect()
rect.move_ip(75,100 + y)
screen.blit(block,rect)
pygame.display.flip()
score('wind', 0)
score('elev',20)
N = start()
Pchange(N,0)
Pchange(N,20)
Firstly you draw the score twice, which i assume works well.
The problem lies in you start function.
You are not calling any draw or update function in your while loop.
In your event foreach, you add a digit to name, and exit the while loop when enter is pressed. Then you draw twice with Pchange, but you are the function does not use the right parameters. You have:
def Pchange(c,y):
block = font.render(N, True, (0,0,0))
you are using the global N which is ''. So to fix that, you need to change N to c.
The next problem is that the game quits right after pressing enter. Since you pasted only a part of the program, this might not be the case. If it is, make another while loop, and just wait for the ESC key to call pygame.quit() and sys.exit()
Okay, so I am starting to have fun with pygame. But I've got a problem. I tried to somehow enchance my code, make it organised, so I've decided to use classes here. It looks like this:
import pygame
from pygame.locals import *
import sys
pygame.init()
class MainWindow:
def __init__(self, width, height):
self.width=width
self.height=height
self.display=pygame.display.set_mode((self.width,self.height))
pygame.display.set_caption("Caption")
def background(self)
img = pygame.image.load("image.png")
self.display.blit(img, (0,0))
mainWindow = MainWindow(800,600)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.exit()
sys.exit()
mainWindow.background()
pygame.display.update()
Okay, works. But what if I want to, for example fill the windows with white color? Then I have to define a method fill(), which will just self.display.fill(), right? Is there a way, to handle it normally, without defining hundreds of pygame-already-existing methods in my class?
And one another thing. If I do something by using my class, and I screw up, I always get this msg:
File "C:/Python35/game.py", line 23, in <module>
pygame.display.update()
pygame.error
And I actually don't know what the heck is wrong. If I do this normally, without classes, then I get erros such as, pygame object blabla has no method blablabla or something like that, I just know what's happening. Is there a way to get through this, and find what's going on?
Thanks in advance for your help!
What you are doing here is on the right track, but it is done the wrong way. Your main "game loop" should be inside the class itself as a method, rather than calling stuff from outside the class in an actual loop. Here is a basic example of what you should be doing.
# Load and initialize Modules here
import pygame
pygame.init()
# Window Information
displayw = 800
displayh = 600
window = pygame.display.set_mode((displayw,displayh))
# Clock
windowclock = pygame.time.Clock()
# Load other things such as images and sound files here
image = pygame.image.load("foo.png").convert # Use convert_alpha() for images with transparency
# Main Class
class MainRun(object):
def __init__(self,displayw,displayh):
self.dw = displayw
self.dh = displayh
self.Main()
def Main(self):
#Put all variables up here
stopped = False
while stopped == False:
window.fill((255,255,255)) #Tuple for filling display... Current is white
#Event Tasking
#Add all your event tasking things here
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN:
stopped = True
#Add things like player updates here
#Also things like score updates or drawing additional items
# Remember things on top get done first so they will update in the order yours is set at
# Remember to update your clock and display at the end
pygame.display.update()
windowclock.tick(60)
# If you need to reset variables here
# This includes things like score resets
# After your main loop throw in extra things such as a main menu or a pause menu
# Make sure you throw them in your main loop somewhere where they can be activated by the user
# All player classes and object classes should be made outside of the main class and called inside the class
#The end of your code should look something like this
if __name__ == __main__:
MainRun()
The main loop will call itself when the object MainRun() is created.
If you need more examples on specific things such as object handling let me know and I will see if I can throw some more information up for you.
I hope this helps you with your programming and the best of luck to you.
========================= EDIT ================================
In this case for these special operations make them object specific. Instead of using one generic method to blit your objects, make each object have its own function. This is done this way to allow for more options with each object you make. The general idea for the code is below... I have created a simple player object here.
#Simple player object
class Player(object):
def __init__(self,x,y,image):
self.x = x
self.y = y
self.image = image
#Method to draw object
def draw(self):
window.blit(self.image,(self.x,self.y))
#Method to move object (special input of speedx and speedy)
def move(self,speedx,speedy):
self.x += speedx
self.y += speedy
Now here is how you use the object's methods... I have included an event loop to help show how to use the move function. Just add this code to your main loop wherever it is needed and you will be all set.
#Creating a player object
player = Player(0,0,playerimage)
#When you want to draw the player object use its draw() method
player.draw()
#Same for moving the player object
#I have included an event loop to show an example
#I used the arrow keys in this case
speedx = 0
speedy = 0
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
speedy = -5
speedx = 0
elif event.key == pygame.K_DOWN:
speedy = 5
speedx = 0
elif event.key == pygame.K_RIGHT:
speedy = 0
speedx = 5
elif event.key == pygame.K_LEFT:
speedy = 0
speedx = -5
elif event.type == pygame.KEYUP:
speedx = 0
speedy = 0
#Now after you event loop in your object updates section do...
player.move(speedx,speedy)
#And be sure to redraw your player
player.draw()
#The same idea goes for other objects such as obstacles or even scrolling backgrounds
Be sure to use the same display name of the display inside your draw function.