Reputation: 1294
I am trying to make a simple 2d game in pygame and for some reason it only runs at 4fps.h This causes it to be very laggy and choppy. I have looked at other questions which suggest convert() but I do not have any images. Any way to make it faster?? I want it to be running at least 40 fps. I am working on MacOs currently. Here's my code so far:
import math
import sys
import pygame
from pygame.locals import *
pygame.init()
BLACK = (0,0,0)
WHITE = (255,255,255)
GREEN = (0,255,0)
RED = (255,0,0)
BLUE=(0,0,255)
PI = 3.141592653
font = pygame.font.SysFont('Times',12, True,False)
def write_text(text, pos,color):
hi = font.render(text, True,color)
screen.blit(hi, pos)
def draw_label_rect(text,color,object):
pygame.draw.rect(screen, object.color, object.Display_Rect)
hi =font.render( text, True, color)
center_x = object.pos[0]+ 1/2*object.width
center_y =object.pos[1] + 1/2 * object.length
text_width = hi.get_width()
text_height = hi.get_height()
screen.blit(hi, (math.floor(center_x-1/2*text_width),math.floor(center_y-1/2*text_height)))
def draw_image_label_rect_centered(image, color, pos,scale_factor):
pygame.draw.rect(screen, color,pos)
image = pygame.image.load(image).convert_alpha()
width = image.get_width()
height = image.get_height()
image2 = pygame.transform.smoothscale(image,(math.floor(width*scale_factor),math.floor(height*scale_factor)))
new_width = image2.get_width()
new_height = image2.get_height()
center_x = pos[0]+ 1/2*pos[2]
center_y =pos[1] + 1/2 * pos[3]
screen.blit(image2, (center_x-1/2*new_width, center_y-1/2*new_height))
def draw_image_label_rect_behind(image, color, pos,scale_factor):
pygame.draw.rect(screen, color,pos)
image = pygame.image.load(image).convert_alpha()
width = image.get_width()
height = image.get_height()
image2 = pygame.transform.smoothscale(image,(math.floor(width*scale_factor),math.floor(height*scale_factor)))
center_x = pos[0]+ 1/2*pos[2]
new_width = image2.get_width()
screen.blit(image2, (center_x-1/2*new_width, pos[3]+pos[1]+1))
size = (1500, 700)
background = pygame.display.set_mode(size)
screen = pygame.surface.Surface((10000, 10000))
pygame.display.set_caption("HI")
done = False
clock = pygame.time.Clock()
FPS = 120
scroll_y = 0
scroll_x = 0
originalmousex = None
originalmousey = None
Rects= []
Objects = []
class Camera():
def __init__(self):
self.x = 5000
self.y = 5000
self.distance_x = 750
self.distance_y = 350
def move(self,offset_x,offset_y):
self.x +=offset_x
self.y +=offset_y
for i in Objects:
i.screenpos=(i.pos[0]-self.x+750,i.pos[1]-self.y+350)
i.virtual_rect = pygame.Rect(i.screenpos[0],i.screenpos[1],i.width,i.length)
def zoom_in(self):
self.distance_x = math.floor(self.distance_x * 0.95)
self.distance_y = math.floor( self.distance_y * 0.95)
def zoom_out(self):
self.distance_x = math.floor(self.distance_x * 1.05)
self.distance_y = math.floor(self.distance_y * 1.05)
def subsurfacing(self):
self.camera_surface = screen.subsurface((self.x- self.distance_x,self.y - self.distance_y,2*self.distance_x,2*self.distance_y))
background.blit(pygame.transform.smoothscale(self.camera_surface,(1500,700)),(0,0))
main_camera = Camera()
class InfantryRect():
def __init__(self,number, color,formation,pos):
self.number = number
self.color = color
self.formation = formation
class_formation = self.formation
self.pos = pos
self.moving = False
self.movingto = None
self.startmovingframe = None
self.screenpos = (self.pos[0]-main_camera.x+750,self.pos[1]-main_camera.y+350)
if self.formation == 'line':
lengthy = 25
self.Display_Rect = pygame.Rect(self.pos[0],self.pos[1],lengthy*2,(self.number//lengthy)*2)
self.length = self.Display_Rect.height
self.width = self.Display_Rect.width
self.virtual_rect = pygame.Rect(self.screenpos[0],self.screenpos[1],self.width,self.length)
self.speed = 1
def display(self):
if self.formation== 'line':
pygame.draw.rect(screen,self.color,[self.pos[0],self.pos[1],self.width,self.length])
hi = font.render(str(self.number),True,(255,225,64))
center_x = self.pos[0]+ 1/2*self.width
center_y =self.pos[1] + 1/2 * self.length
text_width = hi.get_width()
text_height = hi.get_height()
screen.blit(hi, (math.floor(center_x-1/2*text_width),math.floor(center_y-1/2*text_height)))
def movingcreating(self,position):
self.distance = math.hypot(position[0]-self.virtual_rect.x,position[1]-self.virtual_rect.y)
if self.distance!=0:
self.dx = ((position[0]-self.virtual_rect.x)/self.distance)*self.speed
self.dy = ((position[1]-self.virtual_rect.y)/self.distance)*self.speed
def move(self,position):
if self.distance!=0:
self.pos = (self.pos[0]+self.dx,self.pos[1]+self.dy)
self.virtual_rect = pygame.Rect(int(self.pos[0]-main_camera.x+750),int(self.pos[1]-main_camera.y+350),self.width,self.length)
self.Display_Rect = pygame.Rect(int(self.pos[0]),int(self.pos[1]),self.width,self.length)
self.movingcreating(position)
TestInf = InfantryRect(100,RED,'line',[5000,5000])
Objects.append(TestInf)
count = 0
width = screen.get_width()
length = screen.get_height()
clock = pygame.time.Clock()
z_is_pressed = False
x_is_pressed = False
up_is_pressed = False
down_is_pressed = False
right_is_pressed = False
left_is_pressed = False
mouse_button_holding = False
frames = 0
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
for i in Objects:
if i.virtual_rect.collidepoint(mouse_pos):
print('Hello')
mouse_button_holding = i
break
if mouse_button_holding==False:
mouse_button_holding = 'scrolling'
originalmousex = mouse_pos[0]
originalmousey = mouse_pos[1]
elif event.type == pygame.MOUSEBUTTONUP:
if mouse_button_holding!= False and mouse_button_holding!='scrolling':
mouse_button_holding.movingto = (event.pos[0] -0.5*mouse_button_holding.width-main_camera.x+5000 , event.pos[1]-0.5*mouse_button_holding.length-main_camera.y+5000)
mouse_button_holding.movingcreating(event.pos)
mouse_button_holding.moving = True
mouse_button_holding.startmovingframe = frames
mouse_button_holding = False
originalmousex = None
originalmousey = None
mouse_button_holding = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_z:
z_is_pressed = True
elif event.key ==pygame.K_x:
x_is_pressed = True
elif event.key == pygame.K_UP:
up_is_pressed = True
elif event.key == pygame.K_DOWN:
down_is_pressed = True
elif event.key == pygame.K_RIGHT:
right_is_pressed = True
elif event.key == pygame.K_LEFT:
left_is_pressed = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_z:
z_is_pressed = False
elif event.key ==pygame.K_x:
x_is_pressed = False
if mouse_button_holding=='scrolling':
main_camera.move(-(pygame.mouse.get_pos()[0]-originalmousex),-(pygame.mouse.get_pos()[1]-originalmousey))
originalmousex = pygame.mouse.get_pos()[0]
originalmousey = pygame.mouse.get_pos()[1]
if z_is_pressed:
main_camera.zoom_in()
if x_is_pressed:
main_camera.zoom_out()
background.fill(BLACK)
screen.fill(BLACK)
# pygame.draw.line(screen, GREEN, [0, 0], [100, 100], 5)
#for y_offset in range(0, 100, 10):
#pygame.draw.line(screen,RED,[0,10+y_offset],[100,110+y_offset],5)
#draw_label_rect('Hello',RED,[250,250,50,50],WHITE)
TestInf.display()
for i in Objects:
if i.moving:
i.move(i.movingto)
main_camera.subsurfacing()
print(clock.get_fps())
clock.tick(60)
pygame.display.update()
frames+=1
pygame.quit()
Upvotes: 1
Views: 88
Reputation: 210909
The major issue is that, screen
is a pygame.Surface
object with a size of 10000x10000. This surface is cleared in every frame and that's what causes the performance impact:
screen = pygame.surface.Surface((10000, 10000))
screen.fill(BLACK)
Since just a small area (subsurface) of the surface is blit
to the screen,
def subsurfacing(self): self.camera_surface = screen.subsurface((self.x- self.distance_x,self.y - self.distance_y,2*self.distance_x,2*self.distance_y)) background.blit(pygame.transform.smoothscale(self.camera_surface,(1500,700)),(0,0))
It is not necessary to clear the complete screen
Surface in every frame. Just clear that area which is drawn into the window later, by pygame.draw.rect
:
class Camera():
# [...]
def clearsubsurface(self, color):
px = self.x- self.distance_x,self.y - self.distance_y
py = 2*self.distance_x,2*self.distance_y
pygame.draw.rect(screen, color, (px, py))
while not done:
# [...]
#screen.fill(BLACK) <--- DELETE
main_camera.clearsubsurface(BLACK)
# [...]
Upvotes: 1