My question is kinda complicated as I run it through my head but I will try to explain it as best I can. I have 2 python codes, one that I created with Python for a Mastermind game and then the other in Pygame for a Mastermind board to play it on. My question is simply this: How can I combine both of these codes into 1 to have it play from Pygame and not the command prompt window I usually get?
I'm sorry if this sounds all gibberishy, but thats my question. I merely want to take my Python code and implement it into the Pygame code and have the game run like it's supposed to.
Heres the code for the game:
import random
class InvalidMove(Exception):pass
class Game:
def __init__(self):
self.colors=('r','g','b','y')
self.to_guess=[random.choice(self.colors) for i in range(4)]
def match_guess(self,guess):
if len(guess)!=len(self.to_guess) or [g for g in guess if g not in self.colors]:
raise InvalidMove()
ret=[0,0]
usedindexes=[]
for i,g in enumerate(guess):
if g==self.to_guess[i]:
ret[0]+=1
usedindexes.append(i)
for i,g in enumerate(guess):
if i in usedindexes: continue
for j,c in enumerate(self.to_guess):
if c==g and j not in usedindexes:
ret[1]+=1
usedindexes.append(j)
return ret
class UI:
def make_move(self):
guess=raw_input("Guess: ")
return guess.split()
def main(self):
print("The game begins...")
print("Possible colors (enter first letter): [r]ed [g]reen [b]lue [y]ellow")
print("Enter your guess like: r g b y")
g=Game()
while True:
guess=self.make_move()
try:
bp,wp=g.match_guess(guess)
except InvalidMove:
print("Invalid guess, try again")
continue
print("Black pegs %s"%bp)
print("White pegs %s"%wp)
if bp==4:
print("You won!")
if __name__=="__main__":
u=UI()
u.main()
And here's the code for the board I made in Pygame:
import pygame
from pygame.locals import *
def draw_current(men, turn, spacing, corner):
current = len(men) - 1
pos = corner[0] + current * spacing[0], turn * spacing[1] + corner[1]
screen.blit(images[men[-1]], pos)
images = { K_r: pygame.image.load('red.png'), K_g: pygame.image.load('green.png'),
K_b: pygame.image.load('blue.png'), K_y: pygame.image.load('yellow.png'),
K_SPACE: pygame.image.load('empty.png') }
pygame.init()
SCREEN_SIZE = (640, 480)
background_image_filename = 'mastermind_board.jpg'
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
background = pygame.image.load(background_image_filename).convert()
screen.blit(background, (0, 0))
pygame.display.update()
men = []
margin = 5, 3
spacing = [x + m for m, x in zip(margin, images[K_r].get_size())]
corner = 74, 74
turn = 0
quit = False
while not quit:
for event in pygame.event.get():
if event.type == QUIT:
quit = True
break
if event.type == KEYUP:
if event.key in images:
#print event.key
men.append(event.key)
# update
draw_current(men,turn, spacing, corner)
if len(men) == 4:
turn += 1
men = []
pygame.display.update()
elif event.key in (K_q, K_ESCAPE):
quit = True
break
pygame.quit()
Any and all help/suggestions would be more than greatly appreciated.
As I'm sure you know, you can't just put it all in one file and have it run. You need to encapsulate the Mastermind game so you can run/update it from the pygame loop. It'd be cleaner if you keep the Mastermind game logic in a separate file and just import it, but it's not required.
Here's some semi-psuedocode:
import pygame
class Mastermind(object):
def update(self, *args):
pass #do stuff
pygame.init()
while not quit:
if event:
if event == "quit":
quit = True
else:
#update the game
Mastermind.update(args)
#update the board
pygame.display.update()
pygame.quit()
Of course, this won't work for you exactly, but I hope the idea that I'm explaining comes through.
Step 1. Fix your board so that it's a proper class definition.
Step 2. Write a third file that import the board and the game.
They're now "combined".
Now you have to do the hard work of fixing the Game to use the new, fancy Board you built.
Related
In my pygame script, I have a function to work with some images that I have to use in a while loop. The problem is that I only want to run the function once for each image. So, I want to run self.convert_img(self.img_one) once, then proceed to self.convert_img(self.img_two) and so on, untill all images are processed. Afterwards, I would like the function to stop, such that I can change the scene.
Here is a mock of my code right now:
import pygame
class Main:
def __init__(self):
pygame.init()
self.window = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
self.clock = pygame.time.Clock()
self.count = 5
# Load Images
self.img_one = pygame.image.load(os.path.join("images", "img_one.png"))
self.img_two = pygame.image.load(os.path.join("images", "img_two.png"))
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
img_one_transorm = self.convert_img(self.img_one)
img_two_transorm = self.convert_img(self.img_two)
## img three transform
self.clock.tick(30)
def convert_img(self, arg1):
self.window.blit(arg1, convert_img_rect)
pygame.display.update()
if self.count > 0:
## convert image function
create a count that increases by one then a bunch of if statements
like:
if count == 1:
img_one_transorm=self.convert_img(self.img_one)
count+=1
elif count == 2:
img_two_transorm=self.convert_img(self.img_two)
count+=1
did i understand this correctly?
I'm writing an algorithm that provides a tkinter program as output (I hope I explained myself) the program works by dragging the combobox, the text ... into a space and memorizing the coordinates.
I decided to do it with pygame, (I took the skeleton of the program from the internet and then modified it).
I have encountered several problems:
I have a problem inserting multiple images (for now I have only
inserted one),
I can't memorize the coordinates, I tried with print (event) but it doesn't work,
I can not insert the image in a specific point of the root.
here is my code:
import os,sys
import pygame as pg
pg.init()
a=0
b=0
c=200
d=200
event = pg.event.poll()
Sfondo = pg.image.load("Sfondo.jpg")
def DisegnaBackground (a,b):
Screen.blit(Sfondo,(a,b))
class Character:
def __init__(self,rect):
self.rect = pg.Rect(rect)
self.click = False
self.image = pg.image.load("ComboBox.png").convert()
Screen.blit(self.image, (c,d))
def update(self,surface):
if self.click:
self.rect.center = pg.mouse.get_pos()
surface.blit(self.image,self.rect)
def main(Surface,Player):
game_event_loop(Player)
DisegnaBackground (a,b)
Player.update(Surface)
def game_event_loop(Player):
for event in pg.event.get():
if event.type == pg.MOUSEBUTTONDOWN:
if Player.rect.collidepoint(event.pos):
Player.click = True
elif event.type == pg.MOUSEBUTTONUP:
Player.click = False
elif event.type == pg.QUIT:
pg.quit(); sys.exit()
if __name__ == "__main__":
os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
Screen = pg.display.set_mode((1500,800))
MyClock = pg.time.Clock()
MyPlayer = Character((0,0,200,24))
MyPlayer.rect.center = Screen.get_rect().center
while 1:
main(Screen,MyPlayer)
pg.display.update()
MyClock.tick(60)
print(event)
There are a number of problems. First, try to make sure not to mix global and local variables. Try re-writing the function like this:
def DisegnaBackground (surface, a, b):
surface.blit(Sfondo, (a, b))
For this to work, you have to update your main too:
def main(Surface,Player):
game_event_loop(Player)
DisegnaBackground (Surface, a, b)
Player.update(Surface)
Finally, you do not need to display your character immediately after the creation, so you can leave the init function as
def __init__(self,rect):
self.rect = pg.Rect(rect)
self.click = False
self.image = pg.image.load("ComboBox.png").convert()
I hope it helps.
I am developing a small game for learning purposes. I have created a simple animation for the title screen. Since there is also a function for full screen in the code, I wanted to create a title screen that:
Displayed the animation
Turned into full screen when the key was activated
Continued the animation at the point it was before activating full screen
In order to do this, I resorted to threading. However, this is the first time I tried to do any multi-threading, and I donĀ“t know what did I do wrong. The result is an undetermined error.
The code for the title screen is this:
try:
GameAnimation = threading.Thread(target=GameTitleAnimation, (Window, WindowDimensions, FontDictionary, CurrentVersion))
GameAnimation.start()
except:
print "There was an error while loading the screen. Press one key to exit the program."
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Quit()
if event.type == pygame.KEYDOWN:
if event.key == K_ESCAPE:
Quit()
elif event.key == K_f:
Fullscreen(Window, WindowDimensions)
else:
return
The code for the animation is:
TitleWhite = [255, 255, 255, 0]
Black = BASE_BLACK
TitleLetters = ("R", "O", "G", "U", "E", " ", "H", "U", "N", "T", "E", "R")
Title = FontDictionary["TitleFont"][1].render("ROGUE HUNTER", False, TitleWhite)
TextWidth = Title.get_width()
TextHeight = Title.get_height()
TitleXPosition = (WindowDimensions[0] - TextWidth) / 2
TitleYPosition = (WindowDimensions[1] / 2) - (TextHeight / 2)
for letter in TitleLetters:
if letter == " ":
TitleXPosition += CurrentLetterWidth
else:
while TitleWhite[3] < 100:
TitleWhite[3] += 1
CurrentLetter = FontDictionary["TitleFont"][1].render(letter, False, TitleWhite)
CurrentLetter.set_alpha(TitleWhite[3])
Window.blit(CurrentLetter, (TitleXPosition, TitleYPosition))
time.sleep(0.008)
try:
pygame.display.update()
except Exception:
traceback.print_exception
TitleWhite[3] = 0
CurrentLetterWidth = CurrentLetter.get_width()
TitleXPosition += CurrentLetterWidth
FadeInSurface = pygame.Surface((WindowDimensions[0], WindowDimensions[1]))
FadeInSurface.fill(TitleWhite)
OpacityRounds = 1
while TitleWhite[3] < 100.0:
TitleWhite[3] = 1.1 ** OpacityRounds
FadeInSurface.set_alpha(TitleWhite[3])
Window.blit(FadeInSurface, (0, 0))
OpacityRounds += 1
pygame.display.update()
time.sleep (0.015)
time.sleep(0.7)
TitleXPosition = (WindowDimensions[0] - TextWidth) / 2
Version = FontDictionary["BodyFont"][1].render(CURRENT_VERSION, False, TitleWhite)
VersionHeight = Version.get_height()
VersionWidth = Version.get_width()
VersionXPosition = (WindowDimensions[0] - VersionWidth) / 2
VersionYPosition = TitleYPosition + TextHeight
while True:
pygame.draw.rect(Window, Black, (0, 0, WindowDimensions[0], WindowDimensions[1]), 0)
Window.blit(Title, (TitleXPosition, TitleYPosition))
Window.blit(Version, (VersionXPosition, VersionYPosition))
pygame.display.update()
I'd be very grateful if anyone could help me with this. I am going crazy.
There's no reason to use threading in your code. It will only make your code harder to read, harder to debug and error prone.
Usually you want to have some kind of state in your game that you use to determinate what should happen in a frame. You can find a class based example here.
Another way to handle this, which is a bit similar to your code, is to use coroutines.
Look at your animation code and instead of calling pygame.display.update(), give the control back to the main loop. The main loop will handle events, frame limiting and drawing, then give control back to the coroutine (which keeps track of it's own state).
Here's a simple hacky example:
import pygame
import pygame.freetype
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
def game_state(surf):
rect = pygame.Rect(200, 200, 32, 32)
while True:
events = yield
pressed = pygame.key.get_pressed()
x = 1 if pressed[pygame.K_RIGHT] else -1 if pressed[pygame.K_LEFT] else 0
rect.move_ip(x*5, 0)
pygame.draw.rect(surf, pygame.Color('dodgerblue'), rect)
yield
def title_state(surf):
text = 'Awesome Game'
colors = [[255, 255, 255, 20] for letter in text]
font = pygame.freetype.SysFont(None, 22)
font.origin = True
while True:
for color in colors:
color[3] += 33
if color[3] > 255: color[3] = 0
x = 200
for (letter, c) in zip(text, colors):
bounds = font.get_rect(letter)
font.render_to(surf, (x, 100), letter, c)
x += bounds.width + 1
font.render_to(surf, (180, 150), 'press [space] to start', pygame.Color('grey'))
events = yield
yield
def main():
title = title_state(screen)
game = game_state(screen)
state = title
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_ESCAPE:
return
if e.key == pygame.K_SPACE:
state = game if state == title else title
if e.key == pygame.K_f:
if screen.get_flags() & pygame.FULLSCREEN:
pygame.display.set_mode(size)
else:
pygame.display.set_mode(size, pygame.FULLSCREEN)
screen.fill(pygame.Color('grey12'))
next(state)
state.send(events)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
See how the main loop is clean and simple, and all of the game state is handled in the coroutines. The title screen part of the code does not care about fullscreen or not or how to switch to fullscreen, and the main loop does not care of what the title screen coroutine does. And we don't need threading.
In practice it's not that different from the class based example I linked above, but using coroutines makes it easy to implement the title screen animation.
Basically you have an endless loop, you mutate some state (like the color of a letter), and then say "now draw this!" by just calling yield.
This is a large chunk of code to debug.
I'm not familiar with pygame or python threading, but it seems to me that you need to include some debug lines to determine exactly where the error occurs during your game animation thread (if it's even occuring there at all).
Something like this pattern should help determine the source of the problem:
import logging
logging.info("start animation initialization")
...
logging.info("begin animation loop")
...
logging.info("end animation loop")
https://docs.python.org/2/howto/logging.html
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.