Out of memory when using pygame.transform.rotate - python

I wrote a script that allows a user to control the sprite of an eagle to fly around to learn pygame. It seemed fine until i implemented a rotation function that makes the sprite rotate according to the direction it is flying along. The sprite becomes really fuzzy after moving a short while and an error soon pops up saying out of memory (at this line: eagle_img = pygame.transform.rotate(eagle_img,new_angle-angle))
My code:
# eagle movement script
import pygame, math, sys
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
# terminate function
def terminate():
pygame.quit()
sys.exit()
# incircle function, check if mouse click is inside controller
def incircle(coordinates,cir_center,cir_out_rad):
if math.sqrt((coordinates[0]-cir_center[0])**2+\
(coordinates[1]-cir_center[1])**2) <= cir_out_rad:
return True
return False
# speed function, translates the controller movement into eagle movement
def speed(position,cir_center,eagle_speed):
x_dist = position[0] - cir_center[0]
y_dist = position[1] - cir_center[1]
dist = math.sqrt(x_dist**2+y_dist**2) # distance from controller knob to center
if dist != 0:
return [(x_dist/dist)*eagle_speed,(y_dist/dist)*eagle_speed]
else:
return [0,0]
# rotation function, rotates the eagle image
def rotation(position,cir_center):
x_dist = position[0] - cir_center[0]
y_dist = position[1] - cir_center[1]
new_radian = math.atan2(-y_dist,x_dist)
new_radian %= 2*math.pi
new_angle = math.degrees(new_radian)
return new_angle
# screen
screenw = 1000
screenh = 700
screen = pygame.display.set_mode((screenw,screenh),0,32)
pygame.display.set_caption('eagle movement')
# variables
green = (0,200,0)
grey = (100,100,100)
red = (255,0,0)
fps = 60
# controller
cir_out_rad = 150 # circle controller outer radius
cir_in_rad = 30 # circle controller inner radius
cir_center = [screenw-cir_out_rad,int(screenh/2)]
position = cir_center # mouse position
# eagle
eaglew = 100
eagleh = 60
eagle_speed = 3
eagle_pos = [screenw/2-eaglew/2,screenh/2-eagleh/2]
eagle = pygame.Rect(eagle_pos[0],eagle_pos[1],eaglew,eagleh)
eagle_img = pygame.image.load('eagle1.png').convert()
eagle_bg_colour = eagle_img.get_at((0,0))
eagle_img.set_colorkey(eagle_bg_colour)
eagle_img = pygame.transform.scale(eagle_img,(eaglew,eagleh))
# eagle controls
stop_moving = False # becomes True when player stops clicking
rotate = False # becomes True when there is input
angle = 90 # eagle is 90 degrees in the beginning
# game loop
while True:
# controls
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == MOUSEBUTTONUP:
stop_moving = True
rotate = False
mouse_input = pygame.mouse.get_pressed()
if mouse_input[0]:
coordinates = pygame.mouse.get_pos() # check if coordinates is inside controller
if incircle(coordinates,cir_center,cir_out_rad):
position = pygame.mouse.get_pos()
stop_moving = False
rotate = True
else:
cir_center = pygame.mouse.get_pos()
stop_moving = False
rotate = True
key_input = pygame.key.get_pressed()
if key_input[K_ESCAPE] or key_input[ord('q')]:
terminate()
screen.fill(green)
[dx,dy] = speed(position,cir_center,eagle_speed)
if stop_moving:
[dx,dy] = [0,0]
if eagle.left > 0:
eagle.left += dx
if eagle.right < screenw:
eagle.right += dx
if eagle.top > 0:
eagle.top += dy
if eagle.bottom < screenh:
eagle.bottom += dy
if rotate:
new_angle = rotation(position,cir_center)
if new_angle != angle:
eagle_img = pygame.transform.rotate(eagle_img,new_angle-angle)
eagle = eagle_img.get_rect(center=eagle.center)
rotate = False
angle = new_angle
outer_circle = pygame.draw.circle(screen,grey,(cir_center[0],cir_center[1]),\
cir_out_rad,3)
inner_circle = pygame.draw.circle(screen,grey,(position[0],position[1]),\
cir_in_rad,1)
screen.blit(eagle_img,eagle)
pygame.display.update()
clock.tick(fps)
Please tell me what's wrong here and how i can improve it. Feel free to try the code out using a sprite named "eagle1.png". Thanks!

the reason your eagle picture is becoming blurred is because your continually rotating the same png and not making a copy and rotating that copy while always keeping a non edited picture. here is a function i have always used when rotating square images
def rot_center(image, angle):
"""rotate an image while keeping its center and size"""
orig_rect = image.get_rect()
rot_image = pygame.transform.rotate(image, angle)
rot_rect = orig_rect.copy()
rot_rect.center = rot_image.get_rect().center
rot_image = rot_image.subsurface(rot_rect).copy()
return rot_image
here is one for any shape of picture
def rot_center(image, rect, angle):
"""rotate an image while keeping its center"""
rot_image = pygame.transform.rotate(image, angle)
rot_rect = rot_image.get_rect(center=rect.center)
return rot_image,rot_rect
source from here
as for the "out of memory" error i don't know for sure but i assume the leak is being caused by the rotation of the same png file over and over again. From some research that seems to occur often with other people.
hope this helps clear some things up:)

Related

Random Brick Color -> TypeError: 'pygame.Color' object is not callable

so this is my first time as a registered user here, so please bear with me if I was searching wrong,
but with the tags [python] or [pygame] I could not find an answer to this question of a random color.
So my problem is the following:
The Game
In this game I want the bricks to be random colors. To do so I made a function to generate a random color:
def brick_color():
color_var = random.randint(0,3)
if color_var == 0: #red
brick_color1 = pygame.Color(198,44,58)
elif color_var == 1:#blue
brick_color1 = pygame.Color(1,128,181)
elif color_var == 2:#yellow
brick_color1 = pygame.Color(255,211,92)
elif color_var == 3:#green
brick_color1 = pygame.Color(0,157,103)
return brick_color1
and implemented the function into this lines:
# brick init
brick = pygame.Surface([brick_width, brick_height]),brick_color # surface for a single brick
pygame.draw.rect(brick[0], brick[1], [0, 0, brick_width, brick_height])
bricks = [] # list of *coordinates* of the bricks
# initialize coordinates of bricks
for y in range(num_brick_rows):
brickY = (y * brick_row_height) + brick_offset_y
for x in range(num_bricks_in_row):
brickX = (x * brick_column_width) + brick_offset_x
color_of_brick = brick_color()
bricks.append((brickX, brickY),color_of_brick) # coordinates are in fact tuples (x,y)
But i keep getting this error:
File "C:\_____\unbenannt0.py", line 146, in <module>
color_of_brick = brick_color()
TypeError: 'pygame.Color' object is not callable
And this is the full code.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 2 09:33:50 2020
#author:
"""
# example from the Sloan Kelly book
# very slightly modified
# imports (or makes usable) external packages that may be 3rd party (such as pygame)
import pygame, sys, random
# enable "short-hand" notation for imported stuff
from pygame.locals import QUIT, MOUSEBUTTONUP, MOUSEMOTION, KEYDOWN, K_ESCAPE
from pygame import display
#Functions
def draw_bricks():
for b in bricks:
windowSurfaceObj.blit(brick[0], b) # makes a copy of brick image acording to coordinates, where stuff is drawn!
def draw_bat():
windowSurfaceObj.blit(bat, batRect)
def draw_ball():
windowSurfaceObj.blit(ball, ballRect)
def brick_color():
color_var = random.randint(0,3)
if color_var == 0: #red
brick_color = pygame.Color(198,44,58)
elif color_var == 1:#blue
brick_color = pygame.Color(1,128,181)
elif color_var == 2:#yellow
brick_color = pygame.Color(255,211,92)
elif color_var == 3:#green
brick_color = pygame.Color(0,157,103)
return brick_color
pygame.init()
fpsClock = pygame.time.Clock()
# new and improved:
# create surface object aka. the main window
inf = display.Info()
screen_width = inf.current_w - 200 # make window sizea little bit smaller than actual screen
screen_height = inf.current_h - 200
# windowSurfaceObj = display.set_mode(size=(screen_width, screen_height), flags=pygame.FULLSCREEN) # initialize window
windowSurfaceObj = display.set_mode(size=(screen_width, screen_height)) # initialize window
display.set_caption('New and improved Bricks'); # set window title
# brick layout
brick_width = 50
brick_height = 20
num_bricks_in_row = 7
num_brick_rows = 5
brick_row_height = 2 * brick_height
brick_offset_y = 100
brick_column_width = 2 * brick_width
brick_offset_x = int(screen_width/2 - brick_column_width*num_bricks_in_row/2) # place it in the middle of the screen
brick_color = brick_color()
# ball related stuff
ball_radius = int(screen_height/200)
# more game constants!
fps = 60 # desired frames per second
background_colour = pygame.Color(0, 0, 0) # background is black
# used variables for bat dimensions
bat_width = 100
bat_height = 10
# ball related stuff
ball_start_x = 24 # somehwere near the left of the window
ball_start_y = 200 # initial ball position when new ball is released
ball_speed = int(fps*0.15) # speed of ball in pixel per frame! use fps var. here to make real ball speed independent of frame rate
# bat init
# replace bat with crude hand drawn one
batcolor = pygame.Color(0, 0, 255) # bat color: blue!
bat = pygame.Surface([bat_width, bat_height]) # this Surface is for drawing the bat upon
pygame.draw.rect(bat, batcolor, [0, 0, bat_width, bat_height]) # draw bat. It's a simple rectangle.
bat = bat.convert_alpha() # deal with transparency
# place the bat somewhere near the bottom of the screen/window
player_start_x = 0 # initial position is on left
player_start_y = screen_height - 6 * bat_height # this is used as Y coordinate for bat, near the bottom of the screen
batRect = bat.get_rect() # rectangle around bat, used to move it around later
mousex = player_start_x
mousey = player_start_y # mousex and mousey later used for moving the bat around, not actual mouse coordinates at this point
# ball init
ball_color = pygame.Color(255, 255, 255) # white
ball = pygame.Surface([ball_radius*2, ball_radius*2]) # Surface for drawing the ball upon
pygame.draw.circle(ball, ball_color, (ball_radius, ball_radius), ball_radius) # draw circle on ball surface
ballRect = ball.get_rect() # rectangle around ball, use to move it around later
ballServed = False
bx = ball_start_x # bx is actual ball postion
by = ball_start_y # by is actual (current) ball position
sx = ball_speed # current ball speed in horizontal direction
sy = ball_speed # current ball speed vertical
ballRect.topleft = (bx, by) # move ball rectangle to initial position
# brick init
brick = pygame.Surface([brick_width, brick_height]),brick_color # surface for a single brick
pygame.draw.rect(brick[0], brick[1], [0, 0, brick_width, brick_height])
bricks = [] # list of *coordinates* of the bricks
# initialize coordinates of bricks
for y in range(num_brick_rows):
brickY = (y * brick_row_height) + brick_offset_y
for x in range(num_bricks_in_row):
brickX = (x * brick_column_width) + brick_offset_x
color_of_brick = brick_color()
bricks.append((brickX, brickY),color_of_brick) # coordinates are in fact tuples (x,y)
while True: # main loop, run once per frame (i.e. fps times per second)
windowSurfaceObj.fill(background_colour) # clear the screen
# brick draw
# for b in bricks: # remember: bricks is a list of brick coordinates, not surfaces
# windowSurfaceObj.blit(brick, b) # make copy of brick image and place it on screen, b = brick coordinates
draw_bricks()
# bat and ball draw, rectangles around bat and ball are used for positioning
# windowSurfaceObj.blit(bat, batRect) # copy surface with image of bat to screen
# windowSurfaceObj.blit(ball, ballRect) # same for ball
draw_bat()
draw_ball()
# main event loop
# process user interaction
for event in pygame.event.get():
# quit the game if window is closed or escape key is pressed
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONUP and not ballServed:
ballServed = True # start game, when mouse is clicked
elif event.type == MOUSEMOTION: # mouse has moved
mousex, mousey = event.pos # set mouse coordinate variables to actual mouse coordinates
if mousex < screen_width - bat_width:
if mousex < 0: # may occur in full screen / large window mode
batRect.topleft = (0, player_start_y)
else:
batRect.topleft = (mousex, player_start_y)
else:
batRect.topleft = (screen_width - bat_width, player_start_y)
# main game logic
if ballServed: # if game is in progress
ballRect.topleft = (bx, by) # position the ball using its rectangle
bx += sx # sx = speed of the ball in X direction
by += sy # sy = speed of the ball in Y direction
if (by >= screen_height): # ball below bottom of screen
ballServed = False # game not in progess, ball lost!
bx, by = (ball_start_x, ball_start_y) # ball is reset to start position
ballRect.topleft = (bx, by) # move the rectangle around ball to correct position
if by <= 0: # ball hits top
by = 0
sy *= -1 # reflect
if bx <= 0: # ball hits left side of window
bx = 0
sx *= -1 # reflect
if bx >= screen_width - ball_radius*2: # ball hits right side of window
bx = screen_width - ball_radius*2
sx *= -1 # reflection
# collision detection
brickForRemoval = None
for b in bricks: # remember: bricks is list of coordinates of bricks; iterating all bricks and check each one for collision
briX, briY = b # tuple unwrapping: x and y coordinates of top left of brick
if bx + ball_radius*2 >= briX and bx <= briX + brick_width: # is x coordinate of ball inside brick (or touching brick)
if (by + ball_radius*2 >= briY and by <= briY + brick_height): # same for y coordinate
brickForRemoval = b # brick was hit and is scheduled for removal
if bx <= briX + ball_radius*2: # ball hit brick from left
sx *= -1 # reflect
elif bx >= briX + brick_width - ball_radius*2: # ball hit brick from right
sx *= -1 # reflect
if by <= briY + ball_radius * 2: # ball hit brick from top
sy *= -1 # reflect
elif by >= briY + brick_height - ball_radius*2: # ball hit brick from below
sy *= -1 # reflect
break # ball hit a brick and cannot hit another one at the same time
if brickForRemoval != None: # if a brick is scheduled for removal…
bricks.remove(brickForRemoval) # … remove it!
# collision check: does bat hit ball?
if (bx >= mousex and bx <= mousex + bat_width): # using bat_width variable
if(by >= player_start_y - bat_height and by <= player_start_y):
sy *= -1 # reflect
pygame.display.update() # show updated screen
fpsClock.tick(fps) # limit fps
Any help is highly appreciated!
As per #jasonharper's comment, when you assign a value to a variable name that is the same as the function name, that name becomes "re-assigned", in this case - making the function no longer accessible.
Using any other variable name inside your function would fix it:
def brick_color():
color_var = random.randint(0,3)
if color_var == 0: #red
new_color = pygame.Color(198,44,58)
elif color_var == 1:#blue
new_color = pygame.Color(1,128,181)
elif color_var == 2:#yellow
new_color = pygame.Color(255,211,92)
elif color_var == 3:#green
new_color = pygame.Color(0,157,103)
return new_color
Your function could also use a python list to be a bit more flexible and compact:
def getRandomColor():
# red blue yellow green
color_list = [ (198,44,58), (1,128,181), (255,211,92), (0,157,103) ]
random_choice = random.randrange( len( color_list ) )
return color_list[ random_choice ]
This form is more flexible because you can easily add more colours by appending them to the list (no more to do).

Pygame. How to make a rect change direction on collision (boundary check)

Part of an assignment I'm working on is making a ball bounce around the screen, I can make it move, but my boundary test doesn't seem to be working: the ball simply moves in direction instead of changing direction. So to clarify, what I want to ball to do is change direction as it hits the screen edge.
import sys
import pygame
SCREEN_SIZE = 750, 550
BALL_DIAMETER = 16
BALL_RADIUS = BALL_DIAMETER // 2
MAX_BALL_X = SCREEN_SIZE[0] - BALL_DIAMETER
MAX_BALL_Y = SCREEN_SIZE[1] - BALL_DIAMETER
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
LEFT = 11
RIGHT = 12
pygame.init()
clock = pygame.time.Clock()
pygame.display.init()
font = pygame.font.SysFont("impact", 20)
pygame.display.set_caption("Breakout")
screen = pygame.display.set_mode(SCREEN_SIZE)
class Ball:
def __init__(self):
''' '''
self.ball = pygame.Rect(300, 730 -
BALL_DIAMETER,
BALL_DIAMETER, BALL_DIAMETER)
# Draw ball
def draw_ball(self):
pygame.draw.circle(screen,
WHITE, (self.ball.left
+ BALL_RADIUS, self.ball.top +
BALL_RADIUS), BALL_RADIUS)
# Updates the coordinates by adding the speed components
def move_ball(self, x, y):
self.xspeed = x
self.yspeed = y
self.ball = self.ball.move(self.xspeed, self.yspeed)
# bounds check
if self.ball.left <= 0:
self.ball.left = 0
self.xspeed = -self.xspeed
elif self.ball.left >= MAX_BALL_X:
self.ball.left = MAX_BALL_X
self.xspeed = -self.xspeed
if self.ball.top < 0:
self.ball.top = 0
self.yspeed = -self.yspeed
elif self.ball.top >= MAX_BALL_Y:
self.ball.top = MAX_BALL_Y
self.yspeed = -self.yspeed
# shows a message on screen, for testing purposes
class Text:
def show_message(self, message):
self.font = pygame.font.SysFont("impact", 20)
font = self.font.render(message,False, WHITE)
screen.blit(font, (200, 400))
class Game:
def __init__(self):
''' '''
def run(self):
b = Ball()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
keys = pygame.key.get_pressed()
# fps lock, screen fill and method call for input
clock.tick(60)
screen.fill(BLACK)
b.draw_ball()
b.move_ball(5, -5)
# used to keep track of various elements
# Text().show_message("P: " + str(p))
pygame.display.flip()
# Creates instance of the game class, and runs it
if __name__ == "__main__":
Game().run()
Your only call to move_ball uses a constant vector.
Since you never change the call parameters, the ball moves only that way.
b.move_ball(5, -5)
Yes, you change the vector components within move_ball when you hit a wall. However, on the next call, you change them back to the original values and move the ball in the original direction.
You have to initialize the vector outside move_ball, and then let the routine access the existing vector when it's called.

Python Pygame randomly draw non overlapping circles

Im very new to python and seem to be missing something.
I want to randomly draw circles on a pygame display but only if the circles don't overlap each other.
I believe I must find the distance between all circle centers and only draw it if the distance is bigger than circle radius * 2.
I've tried many different things but all without success, I always get the same result - circles drawn overlapping.
#!/usr/bin/env python
import pygame, random, math
red = (255, 0, 0)
width = 800
height = 600
circle_num = 10
tick = 2
speed = 5
pygame.init()
screen = pygame.display.set_mode((width, height))
class circle():
def __init__(self):
self.x = random.randint(0,width)
self.y = random.randint(0,height)
self.r = 100
def new(self):
pygame.draw.circle(screen, red, (self.x,self.y), self.r, tick)
c = []
for i in range(circle_num):
c.append('c'+str(i))
c[i] = circle()
for j in range(len(c)):
dist = int(math.hypot(c[i].x - c[j].x, c[i].y - c[j].y))
if dist > int(c[i].r*2 + c[j].r*2):
c[j].new()
pygame.display.update()
else:
continue
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
You did not check against all other circles. I added a variable shouldprint which gets set to false if any other circle is too close.
import pygame, random, math
red = (255, 0, 0)
width = 800
height = 600
circle_num = 20
tick = 2
speed = 5
pygame.init()
screen = pygame.display.set_mode((width, height))
class circle():
def __init__(self):
self.x = random.randint(0,width)
self.y = random.randint(0,height)
self.r = 100
def new(self):
pygame.draw.circle(screen, red, (self.x,self.y), self.r, tick)
c = []
for i in range(circle_num):
c.append('c'+str(i))
c[i] = circle()
shouldprint = True
for j in range(len(c)):
if i != j:
dist = int(math.hypot(c[i].x - c[j].x, c[i].y - c[j].y))
if dist < int(c[i].r*2):
shouldprint = False
if shouldprint:
c[i].new()
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
The for loop has been changed to a while loop. It will keep trying to generate circles until the target number is reached. A circle is first generated. Then, it checks if it intersects with any existing circle using the formula from this answer.
It iterates through every existing circle (store in the list circles) and performs the check using the formula. any() returns True if the formula evaluates to True for any iteration. If it's True, it means it found an intersection. Thus, it continues to the next iteration to try again with a new circle.
circles = []
while len(circles) < circle_num:
new = circle()
if any(pow(c.r - new.r, 2) <=
pow(c.x - new.x, 2) + pow(c.y - new.y, 2) <=
pow(c.r + new.r, 2)
for c in circles):
continue
circles.append(new)
new.new()
pygame.display.update()

Pygame, border of image get cut while rotating

I am rotating an image in pygame.
My image is a png and have a lot of free space around it.
However, when I rotate, I can see the invisible frame around it.
How to fix this ?
I am rotating it with this code
def rot_center(image, angle):
"""rotate an image while keeping its center and size"""
orig_rect = image.get_rect()
rot_image = pygame.transform.rotate(image, angle)
rot_rect = orig_rect.copy()
rot_rect.center = rot_image.get_rect().center
rot_image = rot_image.subsurface(rot_rect).copy()
return rot_image
perso.image = pygame.image.load("sprites/[shadow]main_char_sprite.png")#.convert_alpha()
perso.image = pygame.transform.scale(perso.image, (80,80))
perso.original=perso.image #besoin d'un originial pour faire la rotation
perso.rect = perso.image.get_rect()
perso.rect.x = 200
perso.rect.y = 200
perso.add(perso_group)
counter = 0 #counter define the angle
pygame.key.set_repeat(1,1)
while 1:
screen.fill(white)
for event in pygame.event.get(): # User did something
if event.type == KEYDOWN and event.key == K_SPACE:
counter += 2
perso.image=rot_center(perso.original, counter) #counter define the angle
print "rotating now"
all_group.add(statique_group, zombie_group, perso_group)
all_group.draw(screen)
pygame.display.flip()
any idea ?
fixed !
perso.image=pygame.transform.rotate(perso.original, angle-90)
perso.rect=perso.image.get_rect(center=perso.rect.center)

How can I mouse-scroll around a 2D tile map in pygame?

I am trying to play around with pygame and I have using some examples that I found to learn and create a simple. My next goal is to create a 2D tile map bigger than the screen size and then being able to scroll around with the mouse. I would like to make something similar as a strategic game, where if you move the mouse to the edges of the screen, the "camara" will move in that direction, showing that part of the map (I would like also to stop the camara if it reaches the end of the map). At this moment, if I hover the mouse over the edges, it will only move once.
import pygame, os
from pygame.locals import *
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
SCREEN_WIDTH = 5*40
SCREEN_HEIGHT = 7*40
#functions to create our resources
def load_image(name, colorkey=None):
try:
image = pygame.image.load(name)
except pygame.error, message:
print 'Cannot load image:', name
raise SystemExit, message
image = image.convert_alpha()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
#classes for our game objects
class Camera(object):
def __init__(self, camera_func, width, height):
self.camera_func = camera_func
self.state = pygame.Rect(100,100, width, height)
def apply(self, rect):
l, t, w, h = rect
if 0 <= self.state[0] <= (SCREEN_WIDTH/5):
l += 10
elif (SCREEN_WIDTH - (SCREEN_WIDTH/5)) < self.state[0] <= SCREEN_WIDTH:
l -=10
if 0 <= self.state[1] <= (SCREEN_HEIGHT/5):
t += 10
elif (SCREEN_HEIGHT - (SCREEN_HEIGHT/5)) < self.state[1] <= SCREEN_HEIGHT:
t -=10
return rect.move(l,t)
def update(self):
pos = pygame.mouse.get_pos()
self.state.topleft = pos
#self.state = self.camera_func(self.state)
def complex_camera(camera):
l, t, w, h = camera
l, t, _, _ = -l, -t, w, h
l = min(0, l) # stop scrolling at the left edge
l = max(-(camera.width-SCREEN_WIDTH), l) # stop scrolling at the right edge
t = max(-(camera.height-SCREEN_HEIGHT), t) # stop scrolling at the bottom
t = min(0, t) # stop scrolling at the top
return pygame.Rect(l, t, w, h)
def main ():
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
pygame.display.set_caption("W40K")
grasstile = pygame.image.load('./textures/grass.png')
watertile = pygame.image.load('./textures/water.png')
waterbeach = pygame.image.load('./textures/dirt.png')
grassrect = grasstile.get_rect()
waterrect = watertile.get_rect()
waterb = waterbeach.get_rect()
TILESIZE = 40
tilemap = [
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,waterbeach,waterbeach,waterbeach,watertile,watertile,watertile,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[waterbeach,waterbeach,waterbeach,waterbeach,watertile,watertile,watertile,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,waterbeach,waterbeach,waterbeach,waterbeach,waterbeach,grasstile,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[watertile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[watertile,watertile,waterbeach,waterbeach,waterbeach,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,waterbeach,waterbeach,waterbeach,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,grasstile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,grasstile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
[grasstile,grasstile,waterbeach,waterbeach,watertile,watertile,waterbeach,waterbeach,grasstile,grasstile,waterbeach,watertile,watertile,watertile,waterbeach,waterbeach,waterbeach,grasstile,grasstile,waterbeach],
]
#Creates surface of the background
map_surface = pygame.Surface((len(tilemap[0])*TILESIZE, len(tilemap)*TILESIZE))
#Display the surface
for y,row in enumerate(tilemap):
for x,tile_surface in enumerate(row):
map_surface.blit(tile_surface,(x*TILESIZE,y*TILESIZE))
total_level_width = len(tilemap[0]) * 40
total_level_height = len(tilemap) * 40
camera = Camera(complex_camera,total_level_width, total_level_height)
#mouse = Mouse()
#allsprites = pygame.sprite.RenderPlain((mouse))
clock = pygame.time.Clock()
while 1:
clock.tick(60)
#Handle Input Events
for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == KEYDOWN and event.key == K_ESCAPE:
return
screen.fill(BLACK)
#Camera moves.
camera.update()
#Display background.
screen.blit(map_surface, camera.apply(waterrect))
pygame.display.flip()
if __name__ == "__main__":
main()
pygame.quit()
I think that the problem is in the camara function and the apply function, but I have no clue to improve this and make the camara work properly.
Thanks!
It is hard for me to say exactly what is wrong with your sode ( i got too little experience in coding ) , but i just realised movin screen by mouse in my script and i did this :
screen=pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT),32)
Map=pygame.image.load(os.path.join('Image','MAP.png')).convert_alpha()
startX,startY=0,0 # starting coordinates for Map
while 1:
screen.fill(white)
screen.blit(Map,(startX,startY))
for event in pygame.event.get():
if event.type == MOUSEMOTION :
mousepos=pygame.mouse.get_pos()
if WINDOWHEIGHT-mousepos[1]<50: # if y-position of mouse is 50 pixel far from lower edge ..
startY -= 5 # ..move Map by 5 px
if mousepos [1]<50:
startY += 5
if mousepos [0]<50 :
startX += 5
if WINDOWWIDTH - mousepos[0]<50:
startX -= 5
pygame.display.flip()
Hope this can suggest you an idea how to improve your code

Categories