How do I solve an attribute error? - python

So like I said before my code (Or my current project that I am working on) is riddled with errors. So far I have at least solved a dozen errors or more and honestly I just give up. I mean God knows how many more there are.
The current problem that I am having is an AttributeError which is in my opinion one of the easiest errors to fix however I seem to have gone in to complete spaghetti mode and I have no clue on how to fix the problem.
{The error itself:
Traceback (most recent call last):
File "C:\Users\Burak\Desktop\boxtrial.py", line 87, in <module>
myScreen.addPane("1")
File "C:\Users\Burak\Desktop\boxtrial.py", line 67, in addPane
myPane.drawPane()
File "C:\Users\Burak\Desktop\boxtrial.py", line 19, in drawPane
self.Screen.blit(self.font.render(textToDisplay, True, (black)), (250, 115))
AttributeError: 'Pane' object has no attribute 'Screen'
}
I will list the code below but I feel as if I should explain what I am trying to do so you have some sort of understanding of the code.
Basically in the main loop I call upon the "Class Screen" which helps to create a PyGame screen that comes up once run. On that screen I am trying to get rectangles to appear on the screen in fixed positions (The coordinates are specific but the ones I use on the code are just for test purposes). I then have another class that is called "Pane" and this class is there so that I can draw many instances of the class pane within screen (If that makes sense).
If someone can help me get rid of the error that would be of grate help, but if you think that this is not a good way of solving the problem then please be my guest to come up with or teach me of a better way to do the same thing.
{The code:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
objs = []
MAIN_BUTTON = 1
class Pane():
def __init__(self, textToDisplay, coordinates, screen):
self.textToDisplay = textToDisplay
self.coordinates = coordinates
self.screen = screen
def drawPane(self):
self.Screen.blit(self.font.render(textToDisplay, True, (black)), (250, 115))
pygame.draw.rect(self.screen, (black), self.coordinates, 2)
pygame.display.update()
class Screen():
#constants/array(?) outlining the x,y boundaries of each of x10 panes
#Note to self - Remember to change co-ordinate values
NoOfPanes = 0
Panes = []
def __init__(self):
pygame.init()
pygame.display.set_caption('Box Test')
self.font = pygame.font.SysFont('Arial', 25)
Screen = pygame.display.set_mode((1000,600), 0, 32)
self.screen = Screen
self.screen.fill((white))
pygame.display.update()
def addPane(self, textToDisplay):
paneLocs = [(175, 75, 200, 100),
(0, 0, 200, 100),
(600, 400, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100)
]
if self.NoOfPanes > 10:
print("Limit Reached")
else:
myPane = Pane(textToDisplay, paneLocs[self.NoOfPanes], Screen)
myPane.drawPane()
self.NoOfPanes = self.NoOfPanes + 1
pygame.display.update()
def mousePosition(self):
global clickPos
global releasePos
for event in pygame.event.get():
if event.type == MAIN_BUTTON:
self.Pos = pygame.mouse.get_pos()
return MAIN_BUTTON
else:
return False
if __name__ == '__main__':
myScreen = Screen()
myScreen.addPane("1")
myScreen.addPane("2")
myScreen.addPane("3")
myScreen.addPane("4")
while True:
ev = pygame.event.get()
for event in ev:
if event.type == pygame.MOUSEBUTTONUP:
posx,posy = pygame.mouse.get_pos()
if (posx >= 175 and posx <= 375) and (posy >= 75 and posy <= 175):
print("BOB") #Bob was there just for test purposes
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();

Fix your case.
class Pane():
def __init__(self, textToDisplay, coordinates, screen):
...
self.screen = screen
def drawPane(self):
self.Screen.... # <<< HERE

Related

Is there a way to get the position of one object in pymunk? [duplicate]

I am trying to learn PyMunk and I used their basic example from the website:
import pymunk
space = pymunk.Space()
space.gravity = 0,-1000
body = pymunk.Body(1,1666)
body.position = 50,100
poly = pymunk.Poly.create_box(body)
space.add(body, poly)
while True:
space.step(0.02)
But it does not create a window, does not show anything. How to use PyGame to create the graphical window?
What that example does is create a simulation, add a box shaped object inside and then run the simulation infinitely. The code doesn't print or draw anything, so you will not actually see the output. To get a better understanding and something on screen I suggest you start with the tutorial: http://www.pymunk.org/en/latest/tutorials/SlideAndPinJoint.html
Pymunk is a 2d rigid body physics library, which means that what it does is simulate how objects move and interact with each other in 2 dimensions. Its not made for drawing to the screen or read input.
You can of course use it as is without anything else, and just print out the result of the simulation. But more common is that you want to draw to the screen, read input and so on. One way to do that is by using the game library Pygame that helps out with drawing to the screen, reading input, having a game loop and so on.
Pymunk itself does have some helper functions so that you can easily connect it with Pygame (and a couple of other libraries), but this is not the core part. Usually these helper functions are good for when you want something quick-n-dirty such as a prototype and you don't have need to customize the drawing.
Now, this said, if you want to see something you can add a print statement to the while loop, so it becomes like this:
while True:
space.step(0.02)
print(body.position)
Then it will print out the position of the ball each step of the simulation, and you can see that its changing all the time (because of the gravity that is set on the space).
There are more advanced examples included in Pymunk that are both interactive and show something on screen. These examples depends on mostly either Pygame or Pyglet, but the principle is the same in case you have a different library you want to use it with.
Here's an example that shows how I use Pymunk in combination with pygame. The Entity class is a pygame.sprite.Sprite subclass to which I attach a pymunk.Body and a pymunk.Shape as well as a reference to the pm.Space, so that the bodies and shapes can be added and removed from it. The position of the sprite's rect gets set to the self.body.position each frame, so that we get the correct blit position for the self.image and can simply draw all sprites by calling self.sprite_group.draw(self.screen).
import math
import pygame as pg
import pymunk as pm
from pymunk import Vec2d
def flipy(p):
"""Convert chipmunk coordinates to pygame coordinates."""
return Vec2d(p[0], -p[1]+600)
class Entity(pg.sprite.Sprite):
def __init__(self, pos, space):
super().__init__()
self.image = pg.Surface((46, 52), pg.SRCALPHA)
pg.draw.polygon(self.image, (0, 50, 200),
[(0, 0), (48, 0), (48, 54), (24, 54)])
self.orig_image = self.image
self.rect = self.image.get_rect(topleft=pos)
vs = [(-23, 26), (23, 26), (23, -26), (0, -26)]
mass = 1
moment = pm.moment_for_poly(mass, vs)
self.body = pm.Body(mass, moment)
self.shape = pm.Poly(self.body, vs)
self.shape.friction = .9
self.body.position = pos
self.space = space
self.space.add(self.body, self.shape)
def update(self, dt):
pos = flipy(self.body.position)
self.rect.center = pos
self.image = pg.transform.rotate(
self.orig_image, math.degrees(self.body.angle))
self.rect = self.image.get_rect(center=self.rect.center)
# Remove sprites that have left the screen.
if pos.x < 20 or pos.y > 560:
self.space.remove(self.body, self.shape)
self.kill()
def handle_event(self, event):
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
self.body.angular_velocity = 5.5
elif event.key == pg.K_w:
self.body.apply_impulse_at_local_point(Vec2d(0, 900))
class Game:
def __init__(self):
self.done = False
self.clock = pg.time.Clock()
self.screen = pg.display.set_mode((800, 600))
self.gray = pg.Color('gray68')
self.red = pg.Color('red')
# Pymunk stuff.
self.space = pm.Space()
self.space.gravity = Vec2d(0.0, -900.0)
self.static_lines = [
pm.Segment(self.space.static_body, (60, 100), (370, 100), 0),
pm.Segment(self.space.static_body, (370, 100), (600, 300), 0),
]
for lin in self.static_lines:
lin.friction = 0.8
self.space.add(self.static_lines)
# A sprite group which holds the pygame.sprite.Sprite objects.
self.sprite_group = pg.sprite.Group(Entity((150, 200), self.space))
def run(self):
while not self.done:
self.dt = self.clock.tick(30) / 1000
self.handle_events()
self.run_logic()
self.draw()
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
if event.type == pg.MOUSEBUTTONDOWN:
self.sprite_group.add(Entity(flipy(event.pos), self.space))
for sprite in self.sprite_group:
sprite.handle_event(event)
def run_logic(self):
self.space.step(1/60) # Update physics.
self.sprite_group.update(self.dt) # Update pygame sprites.
def draw(self):
self.screen.fill(pg.Color(140, 120, 110))
for line in self.static_lines:
body = line.body
p1 = flipy(body.position + line.a.rotated(body.angle))
p2 = flipy(body.position + line.b.rotated(body.angle))
pg.draw.line(self.screen, self.gray, p1, p2, 5)
self.sprite_group.draw(self.screen)
# Debug draw. Outlines of the Pymunk shapes.
for obj in self.sprite_group:
shape = obj.shape
ps = [pos.rotated(shape.body.angle) + shape.body.position
for pos in shape.get_vertices()]
ps = [flipy((pos)) for pos in ps]
ps += [ps[0]]
pg.draw.lines(self.screen, self.red, False, ps, 1)
pg.display.flip()
if __name__ == '__main__':
pg.init()
Game().run()
pg.quit()

why are my bullets not moving even though my tanks are

I'm making a pygame game.When I click on the tanks button and then click on the screen(play area) a tank is blitted on that coordinate. Along with the tank a bullet is also blitted. I'm able to make my tank move but the bullets are not shooting. I want the tanks to keep shooting automatically after the bullet gets reset after travelling, say 40 pixels.
This is the function that gives the tanks and the bullets the coordinates
tank_pos_list = []
bullet_list = []
def spawn_tank():
global tank_pos_list
global bullet_list
qx, qy = pygame.mouse.get_pos()
tankxy = [(qx - 35), (qy - 35)]
tank_pos_list.append(tankxy)
bullet_list.append(tankxy)
This is my movement class for tanks and bullets.
class MovementClass:
global bullet_list
global tank_pos_list
tank_surf = pygame.image.load("tank.png")
bullet = pygame.image.load("bullet.png")
def movetank(self, tankimg):
for tank_pos in tank_pos_list:
screen.blit(tankimg, (tank_pos[0], tank_pos[1]))
tank_pos[0] += 0.2
def movebullet(self, bulletimg):
for j in range(len(bullet_list)):
newx = (bullet_list[j][0] + 35)
screen.blit(bulletimg, (newx, (bullet_list[j][1] + 34)))
newx += 1
This is my main function
def main():
global new_tanks
global spawner
global tank_pos_list
global fire_bullet_tank
run = True
fps = 90
tanks = Button((59, 255, 140), 100, 610, 80, 80, text="Tanks")
tanks_over = Button((0, 255, 0), 100, 610, 80, 80, text="Tanks")
towers = Button((59, 255, 140), 510, 610, 150, 80, text="Towers")
towers_over = Button((0, 255, 0), 510, 610, 150, 80, text="Towers")
blue = pygame.image.load("blue_base.png")
red = pygame.image.load("red_base.png")
spawner = False
while run:
mx, my = pygame.mouse.get_pos()
pos = (mx, my)
x = pos[0]
y = pos[1]
mouse_pos = (mx, my)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if spawner and my < 550 and mx < 500:
spawn_tank()
spawner = False
if tanks.isOver(mouse_pos):
spawner = True
screen.fill((50, 168, 66))
if len(tank_pos_list) >= 11:
tank_pos_list.pop(-1)
pygame.draw.rect(screen, (201, 142, 47), (0, 600, 1000, 100))
pygame.draw.line(screen, (0, 0, 0), (500, 0), (500, 600))
if tanks.isOver(mouse_pos):
tanks_over.draw(screen)
else:
tanks.draw(screen)
if towers.isOver(mouse_pos):
towers_over.draw(screen)
else:
towers.draw(screen)
screen.blit(blue, (0, 100))
screen.blit(red, (800, 100))
#movement()
movingtank = MovementClass()
movingtank.movetank(pygame.image.load("tank.png"))
movingbullet = MovementClass()
movingbullet.movebullet(pygame.image.load("bullet.png"))
pygame.display.flip()
clock.tick(fps)
When you run
for tank_pos in tank_pos_list:
...
tank_pos[0] += 0.2
you're changing the first value in a list inside the tank_pos_list list. Note that you add tankxy to both lists in spawn_tank so you can see the change in tank_pos_list and bullet_list. It's the same list in both lists you're changing here.
But when you run
for j in range(len(bullet_list)):
newx = (bullet_list[j][0] + 35)
...
newx += 1
you just create a new variable newx and change its value; but you never change any values of the lists in bullet_list.
Some more notes:
The MovementClass has no internal state; it's basically useless that you create 2 new instances every frame. Use global functions instead (without a class) or just inline those functions.
You load "tank.png" and "bullet.png" every frame from disk. You should just load the images once outside your main loop. Otherwise, it becomes a major performance killer soon.
Try to create a class or multiple classes that represents the different actors of your game (pygame offers the Sprite class for this) and implement the behaviour and state in that class. While that's not the most advanced technique it is the right way to go IMHO for small games.
For an example, maybe take a look at this answer I did for another questions, which is pretty much a step-by-step guide on how I would create such a game.

Show PyMunk with PyGame - Python

I am trying to learn PyMunk and I used their basic example from the website:
import pymunk
space = pymunk.Space()
space.gravity = 0,-1000
body = pymunk.Body(1,1666)
body.position = 50,100
poly = pymunk.Poly.create_box(body)
space.add(body, poly)
while True:
space.step(0.02)
But it does not create a window, does not show anything. How to use PyGame to create the graphical window?
What that example does is create a simulation, add a box shaped object inside and then run the simulation infinitely. The code doesn't print or draw anything, so you will not actually see the output. To get a better understanding and something on screen I suggest you start with the tutorial: http://www.pymunk.org/en/latest/tutorials/SlideAndPinJoint.html
Pymunk is a 2d rigid body physics library, which means that what it does is simulate how objects move and interact with each other in 2 dimensions. Its not made for drawing to the screen or read input.
You can of course use it as is without anything else, and just print out the result of the simulation. But more common is that you want to draw to the screen, read input and so on. One way to do that is by using the game library Pygame that helps out with drawing to the screen, reading input, having a game loop and so on.
Pymunk itself does have some helper functions so that you can easily connect it with Pygame (and a couple of other libraries), but this is not the core part. Usually these helper functions are good for when you want something quick-n-dirty such as a prototype and you don't have need to customize the drawing.
Now, this said, if you want to see something you can add a print statement to the while loop, so it becomes like this:
while True:
space.step(0.02)
print(body.position)
Then it will print out the position of the ball each step of the simulation, and you can see that its changing all the time (because of the gravity that is set on the space).
There are more advanced examples included in Pymunk that are both interactive and show something on screen. These examples depends on mostly either Pygame or Pyglet, but the principle is the same in case you have a different library you want to use it with.
Here's an example that shows how I use Pymunk in combination with pygame. The Entity class is a pygame.sprite.Sprite subclass to which I attach a pymunk.Body and a pymunk.Shape as well as a reference to the pm.Space, so that the bodies and shapes can be added and removed from it. The position of the sprite's rect gets set to the self.body.position each frame, so that we get the correct blit position for the self.image and can simply draw all sprites by calling self.sprite_group.draw(self.screen).
import math
import pygame as pg
import pymunk as pm
from pymunk import Vec2d
def flipy(p):
"""Convert chipmunk coordinates to pygame coordinates."""
return Vec2d(p[0], -p[1]+600)
class Entity(pg.sprite.Sprite):
def __init__(self, pos, space):
super().__init__()
self.image = pg.Surface((46, 52), pg.SRCALPHA)
pg.draw.polygon(self.image, (0, 50, 200),
[(0, 0), (48, 0), (48, 54), (24, 54)])
self.orig_image = self.image
self.rect = self.image.get_rect(topleft=pos)
vs = [(-23, 26), (23, 26), (23, -26), (0, -26)]
mass = 1
moment = pm.moment_for_poly(mass, vs)
self.body = pm.Body(mass, moment)
self.shape = pm.Poly(self.body, vs)
self.shape.friction = .9
self.body.position = pos
self.space = space
self.space.add(self.body, self.shape)
def update(self, dt):
pos = flipy(self.body.position)
self.rect.center = pos
self.image = pg.transform.rotate(
self.orig_image, math.degrees(self.body.angle))
self.rect = self.image.get_rect(center=self.rect.center)
# Remove sprites that have left the screen.
if pos.x < 20 or pos.y > 560:
self.space.remove(self.body, self.shape)
self.kill()
def handle_event(self, event):
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
self.body.angular_velocity = 5.5
elif event.key == pg.K_w:
self.body.apply_impulse_at_local_point(Vec2d(0, 900))
class Game:
def __init__(self):
self.done = False
self.clock = pg.time.Clock()
self.screen = pg.display.set_mode((800, 600))
self.gray = pg.Color('gray68')
self.red = pg.Color('red')
# Pymunk stuff.
self.space = pm.Space()
self.space.gravity = Vec2d(0.0, -900.0)
self.static_lines = [
pm.Segment(self.space.static_body, (60, 100), (370, 100), 0),
pm.Segment(self.space.static_body, (370, 100), (600, 300), 0),
]
for lin in self.static_lines:
lin.friction = 0.8
self.space.add(self.static_lines)
# A sprite group which holds the pygame.sprite.Sprite objects.
self.sprite_group = pg.sprite.Group(Entity((150, 200), self.space))
def run(self):
while not self.done:
self.dt = self.clock.tick(30) / 1000
self.handle_events()
self.run_logic()
self.draw()
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
if event.type == pg.MOUSEBUTTONDOWN:
self.sprite_group.add(Entity(flipy(event.pos), self.space))
for sprite in self.sprite_group:
sprite.handle_event(event)
def run_logic(self):
self.space.step(1/60) # Update physics.
self.sprite_group.update(self.dt) # Update pygame sprites.
def draw(self):
self.screen.fill(pg.Color(140, 120, 110))
for line in self.static_lines:
body = line.body
p1 = flipy(body.position + line.a.rotated(body.angle))
p2 = flipy(body.position + line.b.rotated(body.angle))
pg.draw.line(self.screen, self.gray, p1, p2, 5)
self.sprite_group.draw(self.screen)
# Debug draw. Outlines of the Pymunk shapes.
for obj in self.sprite_group:
shape = obj.shape
ps = [pos.rotated(shape.body.angle) + shape.body.position
for pos in shape.get_vertices()]
ps = [flipy((pos)) for pos in ps]
ps += [ps[0]]
pg.draw.lines(self.screen, self.red, False, ps, 1)
pg.display.flip()
if __name__ == '__main__':
pg.init()
Game().run()
pg.quit()

Pygame: Rect Objects Don't Render Properly in For Loops

I'm currently using Pygame to develop a game and I've decided that I'd group all my GUI objects together in a dictionary like so:
gui_objects = {
# The GuiObject parameters define a rect (for positioning) and background colour.
"healthbar" : GuiObject((10, 10, 100, 20), Colour.BLUE),
"mini_map" : GuiObject((10, 400, 50, 50), Colour.WHITE)
}
The reason I'm grouping GUI objects like this is so I can easily modify them like:
gui_objects.get("mini_map").set_enabled(false)
Now, when I want to render my GUI objects to the screen, I simply did this:
for key, value in gui_objects.iteritems():
value.render(screen)
This works, but for some reason, the white "mini_map" GuiObject gets rendered underneath the "healthbar" GuiObject. I decided to put the "mini_map" above the "healthbar" in the dictionary, but that changed nothing. But now here's the weird part. If I render the GUI objects separately, that is, by calling their render() functions separately, like this:
gui_objects.get("healthbar").render(screen)
gui_objects.get("mini_map" ).render(screen)
Then the GuiObjects overlap properly. My question now is, why do my GuiObjects not overlap properly when I render them using the for loop? Yet they overlap just fine when rendered separately?
Unfortunately, I can't upload images because I don't have enough reputation ¬_¬ But, here's the source code:
import pygame
# Just a definition of a few colours
class Colour(object):
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
BLUE = ( 64, 128, 255)
# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
def __init__(self, rect, colour):
self.rect = rect
self.colour = colour
def render(self, screen):
pygame.draw.rect(screen, self.colour, self.rect)
def main():
############################################################################
# Initialise
pygame.init()
screen = pygame.display.set_mode((800, 600))
# if render_type = 0 then render GuiObjects using a for loop
# if render_type = 1 then render GuiObjects separately.
render_type = 1
gui_objects = {
"hpbar_bg" : GuiObject(( 0, 0, 150, 600), (Colour.BLUE)),
"enemy_hpbar" : GuiObject((10, 10, 200, 400), (Colour.WHITE)),
}
############################################################################
# Main loop
while True:
########################################################################
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
########################################################################
# Render
screen.fill((0, 0, 0))
# Here, I render the GuiObjects.
if render_type == 0:
# This for loop messes up overlapping.
for key, value in gui_objects.iteritems():
value.render(screen)
elif render_type == 1:
# This works fine.
gui_objects.get("hpbar_bg").render(screen)
gui_objects.get("enemy_hpbar").render(screen)
pygame.display.flip()
if __name__ == "__main__":
main()
Has anyone got a clue as to why overlapping GuiObjects doesn't work properly when using the for loop?
I hope I've explained myself clearly enough. If not, just ask and I'll try to clarify.
Because dictionaries aren't ordered and it is drawing the objects in a different order than your other method.
A dictionary is just not designed for holding objects that need to stay in order.
You can either:
Use a pygame render group instead.
This would be the pygame-recommended way to store groups of objects that are going to be drawn, however you would have to convert your GUI objects into sprites I believe. EDIT: Also, pygame render groups are still not ordered so this wouldn't solve your particular problem.
Use a list of tuples [(name,value),...] instead (this will be the most similar to your current method because that's actually what the iteritems() dictionary method returns).
Here is your code re-written using method 2:
import pygame
# Just a definition of a few colours
class Colour(object):
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
BLUE = ( 64, 128, 255)
# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
def __init__(self, rect, colour):
self.rect = rect
self.colour = colour
def render(self, screen):
pygame.draw.rect(screen, self.colour, self.rect)
def main():
############################################################################
# Initialise
pygame.init()
screen = pygame.display.set_mode((800, 600))
# if render_type = 0 then render GuiObjects using a for loop
# if render_type = 1 then render GuiObjects separately.
render_type = 0
gui_objects = [
("hpbar_bg", GuiObject(( 0, 0, 150, 600), (Colour.BLUE))),
("enemy_hpbar", GuiObject((10, 10, 200, 400), (Colour.WHITE))),
]
############################################################################
# Main loop
while True:
########################################################################
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
########################################################################
# Render
screen.fill((0, 0, 0))
# Here, I render the GuiObjects.
if render_type == 0:
# This for loop no longer messes up overlapping.
for key, value in gui_objects:
value.render(screen)
pygame.display.flip()
if __name__ == "__main__":
main()
Because you would like to be able to do things like gui_objects.hpbar_bg.set_enabled(False) then I would look into a third option:
Restructuring your code to contain the GUI within a class itself, and then order the drawing of its components within its draw method.
Here is an example of 3 that doesn't deviate too far from what you've got:
import pygame
# Just a definition of a few colours
class Colour(object):
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
BLUE = ( 64, 128, 255)
# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
def __init__(self, rect, colour):
self.rect = rect
self.colour = colour
self.enabled = True
def render(self, screen):
if self.enabled:
pygame.draw.rect(screen, self.colour, self.rect)
class Gui(object):
def __init__(self):
self.hpbar_bg = GuiObject(( 0, 0, 150, 600), (Colour.BLUE))
self.enemy_hpbar = GuiObject((10, 10, 200, 400), (Colour.WHITE))
self.enabled = True
def render(self, screen):
#render my gui in the order i want
if self.enabled:
self.hpbar_bg.render(screen)
self.enemy_hpbar.render(screen)
def main():
############################################################################
# Initialise
pygame.init()
screen = pygame.display.set_mode((800, 600))
gui = Gui()
#uncomment to get the enabled/disabled behavior
#gui.hpbar_bg.enabled = False
#or disable the whole gui
#gui.enabled = False
############################################################################
# Main loop
while True:
########################################################################
# Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
########################################################################
# Render
screen.fill((0, 0, 0))
# Render GUI
gui.render(screen)
pygame.display.flip()
if __name__ == "__main__":
main()

How to add text into a pygame rectangle

I have come as far as drawing a rectangle in pygame however I need to be able to get text like "Hello" into that rectangle. How can I do this? (If you can explain it as well that would be much appreciated. Thank-you)
Here is my code:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
class Pane(object):
def __init__(self):
pygame.init()
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
#This is where I want to get the text from
if __name__ == '__main__':
Pan3 = Pane()
Pan3.addRect()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
Thank you for your time.
You first have to create a Font (or SysFont) object. Calling the render method on this object will return a Surface with the given text, which you can blit on the screen or any other Surface.
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
class Pane(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Hello!', True, (255,0,0)), (200, 100))
pygame.display.update()
if __name__ == '__main__':
Pan3 = Pane()
Pan3.addRect()
Pan3.addText()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
Note that your code seems a little bit strange, since usually you do all the drawing in the main loop, not beforehand. Also, when you make heavy use of text in your program, consider caching the result of Font.render, since it is a very slow operation.
Hi!
To be honestly there is pretty good ways to write text in any place of current rect.
And now i'll show how to do it pretty easy.
First of all we need to create object of rect instance:
rect_obj = pygame.draw.rect(
screen,
color,
<your cords and margin goes here>
)
Now rect_obj is object of pygame.rect instance. So, we are free to manipulate with this methods. But, beforehand lets create our rendered text object like this:
text_surface_object = pygame.font.SysFont(<your font here>, <font size here>).render(
<text>, True, <color>
)
Afterall we are free to manipulate with all methods, as i mensioned before:
text_rect = text_surface_object.get_rect(center=rect_obj.center)
What is this code about?
We've just got center cords of out current rect, so easy!
Now, you need to blit ur screen like this:
self.game_screen.blit(text_surface_object, text_rect)
Happy coding! :)

Categories