So I'm making an rpg project in Pygame and I need a button class that has text. This is my Code so far. I tried to use some code examples online and on this site but I couldn't make them work in the way I wanted. ;-;
What I want is a button that can drawn to my GameWindow that includes text. I'll figure out the event handling later on.
It would be greatly appreciated if someone could give me an explanation of how a button class that utilises text would work in pygame and explain it in a way I could implement in my Button Class. Previously I have tried simply placing text in the centre of the screen by dividing the width and height by two and placing coloured rects adjacent to the text to try and label the rects so I could use them as buttons. However I realised this wasn't a practical solution, as I would be needing many buttons throughout my game and this method took up large portions of my screen.
I do not understand how to blit a message onto a rect using a class. The Button class below is where I attempted to place text onto top of a rect but I found this very hard.
Ideally my goal here is to be able to call an instance of my button class which I can use as a button.
BTW asking here was a last resort. I spent almost three hours trying to figure this out and its bad for me to stare at a screen for that long.
import pygame, random, sys, math, time
from pygame.locals import *
pygame.init()
FPS = 30
fpsClock = pygame.time.Clock()
GameWindow = pygame.display.set_mode((650,520))
#Variables
Blue = (0,0,255)
Green = (0,255,0)
Red = (255,0,0)
White = (255,255,255)
Black = (0,0,0)
def Button():
def__init__(self, surface, x, y, width, height, colour, message, action=None)
self.x = x
self.y = y
self.width = width
self.height = height
self.font = pygame.font.Font(None, 20)
self.message = message
background_image = pygame.image.load('map.JPG')
title_image = pygame.image.load('title.PNG')
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
GameWindow.blit(background_image, [0,0])
GameWindow.blit(title_image, [100,0])
pygame.display.flip()
fpsClock.tick(FPS)
Here is a button class:
class Button(object):
global screen_width,screen_height,screen
def __init__(self,x,y,width,height,text_color,background_color,text):
self.rect=pygame.Rect(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.text=text
self.text_color=text_color
self.background_color=background_color
self.angle=0
def check(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def draw(self):
pygame.draw.rect(screen, self.background_color,(self.rect),0)
drawTextcenter(self.text,font,screen,self.x+self.width/2,self.y+self.height/2,self.text_color)
pygame.draw.rect(screen,self.text_color,self.rect,3)
Use the check function to see if your button is clicked on, and the draw function to draw your button.
Implemented into your main loop:
button=Button(x,y,width,height,text_color,background_color,text)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type==pygame.MOUSEBUTTONDOWN:
if button.check()==True:
#do what you want to do when button is pressed
GameWindow.blit(background_image, [0,0])
GameWindow.blit(title_image, [100,0])
pygame.display.flip()
fpsClock.tick(FPS)
I also recommend using these functions to draw text:
def drawTextcenter(text,font,screen,x,y,color):
textobj=font.render(text,True,color)
textrect=textobj.get_rect(center=(x,y))
screen.blit(textobj,textrect)
def drawText(text, font, surface, x, y,color):
textobj=font.render(text, 1, color)
textrect=textobj.get_rect()
textrect.topleft=(x, y)
surface.blit(textobj, textrect)
While you're question is still a bit confusing, I can tell you how you blit your text near or in your button. So what you just do is just place the location of the text near the button, basing the texts x and y variables on the buttons x and y variable.
Copied from your code:
def Button():
def__init__(self, surface, x, y, width, height, colour, message, action=None)
self.x = x
self.y = y
self.width = width
self.height = height
self.font = pygame.font.Font(None, 20)
self.message = message
self.font = pygame.font.SysFont('Comic Sans MS', 30) #Example Font
def draw_button(self):
pygame.draw.rect(GameWindow, Red, (self.x, self.y, self.width, self.height))
self.text = myfont.render(message, False, (0, 0, 0))
GameWindow.blit(self.text, (self.x + self.width/2, self.y + self.height/2)) #Displays text at coordinates at middle of the button.
This draws the button (it still doesn't do anything), but also displays the text in the button. HOWEVER, since the text is displayed at the top-left corner of the surface it is on, it will not be exactly in the middle, and will look odd. You can modify the exact location if you want.
I hope this answers your question.
I am working on this project to move a sprite, but I can't seem to figure out how to move a sprite to the right as well as move it downwards. Any thoughts?
Here is my program:
import pygame
import time
import sys
pygame.init()
# Set up window
screen = pygame.display.set_mode((320, 240))
# Load an image
rocket = pygame.image.load("rocket.png")
rocketrect = rocket.get_rect()
x_coord = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
screen.fill((0,0,0))
screen.blit(rocket, rocketrect)
pygame.display.flip()
x_coord += 1
rocketrect.centerx = x_coord
In your method of mving the sprite, you change the coordinatses (x) and then assign it to the centerx of the images rectangle. If you want to keep this kind of method (changing and assigning), and also move the image down, you will need to give a y value. For example
# Define y variable
y_coord = 0
# Your code
…
y_coords += 1
rocketrect.centery = y_coord
This works similarly to how you moved your x_coords, but in total, the program is a bit basic and is not how programmers (or at least me) usually code. Another person might used a tuple for the location, along with making a rocket class. There are also some other ways to move the sprite, such as the .move() or .move_ip() that I would suggest. But it's up to you.
I am struggling to move the sprite correctly. Instead of smooth move I can see blur move and I do not know how to solve it.
Is there any chance you can point what I do incorrectly ?
My target with it to drop the pizza so it hits the bottom and bounce back and bounc back if it hits the top and again the bottom -> bounce -> top -> bounce etc. etc.
import pygame
gravity = 0.5
class PizzaSprite:
def __init__(self, image, spritepos):
self.image = image
self.spos = spritepos
(x, y) = spritepos
self.posx = x
self.posy = y
self.xvel = 1
self.yvel = 1
print "x ", x
print "y ", y
def draw(self, target_surface):
target_surface.blit(self.image, self.spos)
def update(self):
self.posy -= self.yvel
self.spos = (self.posx, self.posy)
return
def main():
pygame.init()
screen_width = 800
screen_height = 600
x = screen_width
y = screen_height
screen = pygame.display.set_mode((screen_width, screen_height))
wall_image = pygame.image.load("wall.png")
sky_image = pygame.image.load("sky.png")
pizza_image = pygame.image.load("pizza.png")
screen.blit(wall_image,(0,200))
screen.blit(sky_image,(0,0))
all_sprites = []
pizza1 = PizzaSprite(pizza_image, (x/2, y/2))
all_sprites.append(pizza1)
while True:
ev = pygame.event.poll()
if ev.type == pygame.QUIT:
break
for sprite in all_sprites:
sprite.update()
for sprite in all_sprites:
sprite.draw(screen)
pygame.display.flip()
pygame.quit()
main()
in the beginning of your main game while loop add
white = (255,255,255)
screen.fill(white)
let me give you a small analogy of what is happening now,
you have paper and a lot of pizza stickers with the intent to make a flip book. To make the illusion of movement on each piece of paper you place a sticker a little bit lower. The screen.fill command essentially clears the screen with the rgb color value you give it. When you dont fill the screen essentially what you are doing is trying to make that flipbook on one piece of paper. You just keep placing more and more stickers a little bit lower making a blur when what you want is one on each page.
and place
pygame.init()
screen_width = 800
screen_height = 600
x = screen_width
y = screen_height
screen = pygame.display.set_mode((screen_width, screen_height))
wall_image = pygame.image.load("wall.png")
sky_image = pygame.image.load("sky.png")
all outside of your main game loop assuming you wont be making changes to these variables ever in your program it is tedious and inefficient to redefine screen,,x,y,and your two images over and over again if they dont change.
so to sum it all up:
use the screen.fill(white) command to reset the color of your screen
You only need to import pngs and define variables once if they are never going to change and don't need them in your main loop
hope this helps clear things up.
I'm using an example regarding sprite generation for a space scroller shootup that I'm developing. By slowly trying to understand how it works, I've managed to get multiple sprites to transverse across the screen. However, there are many sprites that are generated.
So what I'm having trouble with is limiting the initial number of sprites instead of the multitude that the code produces. I thought of using if sprites.__len__ < 10: sprites.add(drone) but when I tried that, it didn't work.
My thinking was that each time it looped, it would check the number of sprites in the group and if it was less then 10, add a sprite to the group until it hit 10. That way if it went off screen or is destroyed, then it would keep doing the check and keeping it constant.
This is the player class:
class Player(pygame.sprite.Sprite):
def __init__(self, *groups):
super(Player, self).__init__(*groups)
self.image = pygame.image.load('player.png')
self.rect = pygame.rect.Rect((screen_width, (random.randrange(0,screen_height))), self.image.get_size())
self.dx = -10
self.pos = random.randrange(0,screen_height)
def update(self):
self.rect.centerx += self.dx
if self.rect.right < 0:
self.kill()
and this is the section regarding the adding of the sprite.
sprites.update()
screen.fill((200, 200, 200))
sprites.draw(screen)
drone = Player()
self.y = random.randrange(0,screen_height)
sprites.add(drone)
pygame.display.flip()
It's probably obvious, but I'm still learning so guidance would be great.
Second question - More of a confirmation of thought. If I don't want the sprite to be half drawn on the bottom of the screen. Do I basically say that if self.rect.bottom > screen_height, then position the sprite # screen_height
Full source: http://pastebin.com/PLRVHtxz
EDIT - I think I've solved it, just need to make the sprites run smoother.
while 1:
clock.tick(40)
numberAlien = 5
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
sprites.update()
screen.fill((200, 200, 200))
sprites.draw(screen)
drone = Player()
if sprites.__len__() < numberAlien:
self.y = random.randrange(0,screen_height)
sprites.add(drone)
pygame.display.flip()
You could subclass SpriteGroup, add a new field of the total number of sprites, and check in the add method to see if it can be added.
You shouldn't test check any variables with __.
As for the movement, i believe, you do not see a smooth movement because of clock.tick(40).
It waits for 40ms until it resumes running. You could reduce tick to 10, and tune the dx you change for the sprites, or try a more universal approach.
A call to clock.tick() returns amount of ms since the last call. This will be your time delta. You can then have a global SPEED. The amount of pixels to be moved would be calculated from SPEED * delta.
I'm having difficulty making my sprite skate.
The thing is my sprite should be sliding until it hits something like the border of the screen or a block. Also, this should be done when the sprite is on ice and if the sprite isn't on ice then the sprite should walk. So if the person presses up once, then the sprite will skate until it hits something that will stop its movement.
Thanks!
I don't know how you currently have your code, but a general template would be:
# main loop
while True:
for each object:
update(framerate)
render()
# skater code
class skater:
moving = True
speed = [0,0]
x = 0
y = 0
def update(framerate):
# check for collisions
if collision:
self.moving = False
# move the skater
if self.moving:
self.x += self.speed[0]*framerate
self.y += self.speed[1]*framerate
moving will be set to true then an arrow key is pressed.
where speed is decided by what arrow keys have been pressed (- for left and up, + for right and down)
From looking at your code at http://pastebin.com/cEpp44NS you're doing things like:
self.speedX1 *= (self.ice * self.normal_friction)
Which is going to very rapidly reduce self.speedX1 (especially since self.ice is set to 0.01)
From what you've said, it sounds like you don't want the speed to be decreasing at all whilst sliding, so try just removing this code.