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
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:)
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.