import pygame
import random
import os
import time
pygame.init()
#window and background
win = pygame.display.set_mode((1000,750))
pygame.display.set_caption("TD GaME")
background_img = pygame.image.load('best_backgroundv2.png')
background = pygame.transform.scale(background_img,(1000,750))
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y, scale):
pygame.sprite.Sprite.__init__(self)
img = pygame.image.load('Run/HeavyBandit_Run_0.png')
self.image = pygame.transform.scale(img, (int(img.get_width() * scale), int(img.get_height() * scale)))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def draw(self):
win.blit(self.image, self.rect)
e_1 = Enemy(400, 500, 3)
So I am relatively new and trying to make a enemy(image) appear but is seems it has been overlapped by my background. I think it is due to how poor my code is in reference to setting the "background"
Your issue is missing the bit of code you have in your program that explains the order you are adding background and images to the window. Lacking that, I came up with the additional code snippet that I added to the end of the code you included above.
while True:
win.blit(background,(0, 0)) # Place the background into the window first
e_1.draw() # Draw the bandit or other image(s) next
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
pygame.display.update()
pygame.quit()
The takeaway here is the order in which the background and image are placed into the window. In this sequence, I got the following screen.
I didn't have your actual image files so I substituted some image files. See if you can work with that.
Related
I am working with Pygame currently, and I made a simple function to create window instances much like Windows 10 UI. the code I made doesn't give any errors or any unwanted outputs. It just seems not to be working properly, what I mean by "not working properly"; it just doesn't seem to be moving the frames that are meant to be dragged around by a master frame...
This is my code:
import pygame
from pyautogui import size
import datetime
pygame.init()
infoObject = pygame.display.Info()
surface = pygame.display.set_mode((900, 700))
run = True
clock = pygame.time.Clock()
def draw_text(text, font, text_col, x,y):
img = font.render(text, True, text_col)
rect = img.get_rect()
rect.center = (x,y)
surface.blit(img, rect)
return rect
class make_a_window():
def __init__(self,app,width=750,height=500):
self.app_name = str(app)
self.width = width
self.height = height
def run(self):
self.top_frame = pygame.draw.rect(surface, "#C0C0C0", pygame.Rect(0,0,int(self.width),40))#master frame
self.main_frame = pygame.draw.rect(surface, (255,255,255), pygame.Rect(0,40,int(self.width),int(self.height)))
self.red_frame_for_exit_btn_X = pygame.draw.rect(surface, (255,0,0), pygame.Rect(self.width-42,0,42,40))
self.exit_btn_X = draw_text("x", pygame.font.SysFont("calibri",25), "black", self.width-20, 15)
self.mouse_position = pygame.mouse.get_pos()
if pygame.mouse.get_pressed()[0] == 1:
if self.top_frame.collidepoint(self.mouse_position):
#moving the frames
self.top_frame.move(self.mouse_position[0],self.mouse_position[1])
self.main_frame.move(self.mouse_position[0]-40,self.mouse_position[1])
self.red_frame_for_exit_btn_X.move(self.mouse_position[0]-42,self.mouse_position[1])
self.exit_btn_X.move(self.mouse_position[0]-20,self.mouse_position[1])
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
run = False
app = make_a_window("hello")
app.run()
pygame.display.update()
clock.tick(60)
Sorry for my bad English. and thanks for the help, I really appreciate it 😃!
There is some logic error from line 32 to 41.
Firstly you should use the event queue by pygame.event.get() to track mouse activities(this is really important) and secondly why are you recording the mouse position before hand you are checking for its collision. Instead you should insert your
{self.mouse_position = pygame.mouse.get_pos()}
inside the collision checking if statement (rather that would not work smoothly until you use pygame.event.get())
One more thing that the function
pygame.Rect().move()
takes x and y offesets as its arguments not x and y coordinates.
So, mainly give focus on your event loop and the destination positions of your manual window. Maybe I would share the correct code later (don't wait for it.)
The method pygame.Rect.move doesn't move the rectangle itself, but it returns new rectangle that is moved. In compare, the method pygame.Rect.move_ip move the object in place.
However, these methods do not move anything that has been drawn on the screen. These methods simply move a rectangle representing an area of the screen. This rectangle can later be used to draw something on the screen at a new location.
Create the pygame.Rect objects in the class's constructor and use them to draw the objects. Use move_ip to move the rectangles:
class make_a_window():
def __init__(self,app,width=750,height=500):
self.app_name = str(app)
self.width = width
self.height = height
self.top_frame = pygame.Rect(0,0,int(self.width),40)
self.main_frame = pygame.Rect(0,40,int(self.width),int(self.height))
self.red_frame_for_exit_btn_X = pygame.Rect(self.width-42,0,42,40)
self.exit_btn_X = pygame.Rect(self.width-20, 15, 0, 0)
def run(self):
pygame.draw.rect(surface, "#C0C0C0", self.top_frame)
pygame.draw.rect(surface, (255,255,255), self.main_frame)
pygame.draw.rect(surface, (255,0,0), self.red_frame_for_exit_btn_X)
draw_text("x", pygame.font.SysFont("calibri",25), "black", self.exit_btn_X.topleft)
self.mouse_position = pygame.mouse.get_rel()
if pygame.mouse.get_pressed()[0] == 1:
if self.top_frame.collidepoint(self.mouse_position):
#moving the frames
move_rel = pygame.mouse.get_rel()
self.top_frame.move_ip(*move_rel)
self.main_frame.move_ip(*move_rel)
self.red_frame_for_exit_btn_X.move_ip(*move_rel)
self.exit_btn_X.move_ip(*move_rel)
I am reading data from a file. Basically, those are coordinates where I want my ball to appear after every iteration. The code is working fine except for the fact that the output window 'Trial 1' crashes as soon as I press the exit button. This problem wasn't there before I added for t in range (np.size(T)):; however I require that. Please suggest some possible changes in the code to get rid of the problem.
import numpy as np
import pygame
pygame.init()
T = np.loadtxt('xy_shm1.txt', usecols=range(0,1))
Xcor = np.loadtxt('xy_shm1.txt', usecols=range(1,2))
Ycor = np.loadtxt('xy_shm1.txt', usecols=range(2,3))
clock = pygame.time.Clock()
background_colour = (255,255,255)
(width, height) = (800, 800)
class Particle():
def __init__(self, xy, size):
self.x, self.y = xy
self.size = size
self.colour = (0, 0, 255)
self.thickness = 1
def display(self):
pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)
def move(self):
self.x = Xcor[t] + 400
self.y = Ycor[t] + 400
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Trial 1')
number_of_particles = 1
my_particles = []
for n in range(number_of_particles):
size = 5
x = Xcor[0] + 400
y = Ycor[0] + 400
particle = Particle((x, y), size)
my_particles.append(particle)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for t in range(np.size(T)):
screen.fill(background_colour)
for particle in my_particles:
particle.move()
particle.display()
pygame.display.flip()
clock.tick(60)
pygame.quit()
The main problem is that you are trying to draw multiple frames within a frame. The frame loop should look like this:
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Draw one frame here
clock.tick(60) # If the game runs faster than 60fps, wait here
Note that in each iteration of the while loop, only one frame is drawn.
In your current code however, you start the loop, check the events once,
and then you draw a frame for each item in your list, without checking the events again.
This most likely causes the QUIT event to be missed, and the operating system intervening because the game seemingly is not responding.
In general, your code is quite messy. I suggest that you read some tutorials on pygame, or you will run into all sorts of similar problems. See for example: http://programarcadegames.com/python_examples/f.php?file=bouncing_rectangle.py
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! :)
I am currently making a game in python where a ball hits a group of boxes. I have loaded an image of a grass that I wanted the boxes to stand on, the grass image is 600 by 151 pixels. So far I have all the boxes and the ball appearing perfectly however, What is not working currently is when I try to load the image and display it so that the boxes can stand on the grass image instead of falling off.
import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import sys
from random import randint
def to_pygame(p):
"""Small hack to convert pymunk to pygame coordinates"""
return int(p[0]), int(-p[1]+600)
def add_box(space, size, pos, mass=1.0):
# pos is a Vec2d object
points = [(-size, -size), (-size, size), (size,size), (size, -size)]
moment = pm.moment_for_poly(int(mass), points, (0,0))
body = pm.Body(mass, moment)
body.position = pos
shape = pm.Poly(body, points, (0,0))
shape.friction = 1
space.add(body,shape)
return shape
def draw_box(screen, box):
ps = box.get_points()
ps.append(ps[0])
ps = map(to_pygame, ps)
pygame.draw.polygon(screen, THECOLORS["blue"], ps, 3)
def main():
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Piling boxes")
clock = pygame.time.Clock()
boxes = []
x = 170
y = 120
space = pm.Space()
space.gravity = (0.0, -100.0)
### ground
body = pm.Body()
shape = pm.Segment(body, (150,100), (450,100), .0)
shape.friction = 4.4
space.add(shape)
for i in range(5):
# what is the mass of the box?
mass = randint(1,3)
# what size is the box?
size = randint(10, 35)
# calculate its position & hold it in a Vec2d
#x = x + size + 10
y = y + size
pos = Vec2d(x,y)
box = add_box(space, size, pos, mass)
boxes.append(box)
while 1:
clock.tick(15)
space.step(1/30.0)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
screen.fill(THECOLORS["white"])
test_image = pygame.image.load("grass.png")
screen.blit(test_image, to_pygame((450,100)), to_pygame((150,100)),3)
for i in range(len(boxes)):
draw_box(screen, boxes[i])
pygame.display.flip()
if __name__ == '__main__':
main()
No traceback or error log so it is a bit hard to identify the point of the error, an educated guess would be that you are passing Rectstyle arguments incorrectly somewhere. Please see the documentation for pygame.Rect on how to pass Rectstyle args correctly.
pygame.Rect(left, top, width, height): return Rect
pygame.Rect((left, top), (width, height)): return Rect
pygame.Rect(object): return Rect
The problem is
screen.blit(test_image, to_pygame((450,100)), to_pygame((150,100)),3)
To blit a surface to to screen, a valid blit is:
screen.blit(test_image, (450,100))
So you want:
screen.blit(test_image, to_pygame((450,100)))
Note: The extra args make me think maybe you're trying to use a source rect argument, to use a tileset. But in that case you wouldn't convert world to screen coords twice. Just on destination, not source.
If you do want the spritesheet/tileset, then out How do you select a sprite image from a sprite sheet in python? and Pygame.org/cookbook/SpriteSheet
The third argument in blit is the source area argument, should be a rectangle, not coordinates:
screen.blit(test_image, to_pygame((450,100)), to_pygame((150,100)),3)
Perhaps you want this:
screen.blit(test_image, to_pygame((450,100)), pygame.Rect((0,0), (150,100)), 3)
The problem is because your call to screen.blit is incorrect. See here.
The call could be
screen.blit(test_image, to_pygame((450,100)))
or perhaps if you wanted to use the area argument,
screen.blit(test_image, to_pygame((450,100)), pygame.Rect((0,0), (150,100)), 3)
Also, you are loading guess.png in every loop, instead move it out of the while loop, your code will perform better.
How can i prevent the sprite image from flickering uncontrollably? (image name is plumbers). when you run the program the only image flickering is the sprite.
import pygame
import os, sys
import itertools
import pygame
from pygame.sprite import Sprite
cloud_background = pygame.image.load('clouds.bmp')
brick_tile = pygame.image.load('brick_tile.png')
plumbers = pygame.image.load('Mario_sideways_sprite_2xL.png')
pink = (255, 64, 64)
w = 640
h = 480
screen = pygame.display.set_mode((w, h))
running = 1
def setup_background():
screen.fill((pink))
screen.blit(cloud_background,(0,0))
brick_width, brick_height = brick_tile.get_width(), brick_tile.get_height()
for x,y in itertools.product(range(0,640,brick_width),
range(390,480,brick_height)):
# print(x,y)
screen.blit(brick_tile, (x,y))
def show_sprites():
screen.blit(plumbers,(50,337))
pygame.display.flip()
while running:
show_sprites()
setup_background()
pygame.display.flip()
event = pygame.event.poll()
if event.type == pygame.QUIT: sys.exit()
I don't really know pygame, but whilst you wait for answer from someone with more experience in this area. I can offer this advice which might help.
Your setting up the background from scratch each time which is a processor intensive process. The best approach is to instead actually only re-render the part of the background required. I.e the parts where your plumber sprite occupied before.
Normally you do this by creating two variables called old X, old Y. This the rendering process is spend up.
Currently your render the entire screen every loop cycle.