Just learning to use pyglet for some graphics, i have a grid in the image below. The "player" is a circle. When i change the x positon of the circle:
circle.x = new x
cirle.draw()
This works to render the second circle as you can see, but how do i now remove the original circle? It doesn't update the actual initial object it seems.
You have to redraw the entire scene in every frame. Clear the window with clear. e.g.:
window.event
def on_draw():
window.clear()
# draw board
# [...]
cirle.draw()
Related
I have a project where i have to create a 4 way split screen using pygame. On this screen i have to draw the same image on each of the screen just have different view of the image. I just can not figure out how to create this 4 way split screen using pygame.
I need my screen to be divided like above so i can draw my points onto each section.
I have been looking around and I can not find anything like this so any help would be great
thanks
In addition to the surface you have that gets rendered to the display, likely called something like screen, you should create another surface which all of the "action" gets drawn to. You can then use a Rect object for each quadrant of the screen which will represent the "camera" (assuming each quadrant doesn't necessarily need to show exactly the same image). When you draw back to screen, you use each camera Rect object to select a portion of the game space to draw to a specific quadrant.
# canvas will be a surface that captures the entirety of the "action"
canvas = pygame.Surface((800, 600))
# the following are your "camera" objects
# right now they are taking up discrete and even portions of the canvas,
# but the idea is that they can move and possibly cover overlapping sections
# of the canvas
p1_camera = pygame.Rect(0,0,400,300)
p2_camera = pygame.Rect(400,0,400,300)
p3_camera = pygame.Rect(0,300,400,300)
p4_camera = pygame.Rect(400,300,400,300)
On each update, you would then use these "camera" objects to blit various portions of the canvas back to the screen surface.
# draw player 1's view to the top left corner
screen.blit(canvas, (0,0), p1_camera)
# player 2's view is in the top right corner
screen.blit(canvas, (400, 0), p2_camera)
# player 3's view is in the bottom left corner
screen.blit(canvas, (0, 300), p3_camera)
# player 4's view is in the bottom right corner
screen.blit(canvas, (400, 300), p4_camera)
# then you update the display
# this can be done with either display.flip() or display.update(), the
# uses of each are beyond this question
display.flip()
There is no functions to split screen. But you can draw 4 views directly on screen or you can draw on 4 surfaces (pygame.Surface) and than blit surfaces on screen.
Since you were looking for a way to split the screen in to 4 sections and draw some points on to them I'd suggest creating 4 subsurface surfaces of the original "canvas" image for convenience.
These surfaces would act as your player(split screen) canvasses which can easily be modified.
This will enable the usage of normalized coordinates for player specific drawing purposes.
Assuming you have a screen surface set up
# Image(Surface) which will be refrenced
canvas = pygame.Surface((800, 600))
# Camera rectangles for sections of the canvas
p1_camera = pygame.Rect(0,0,400,300)
p2_camera = pygame.Rect(400,0,400,300)
p3_camera = pygame.Rect(0,300,400,300)
p4_camera = pygame.Rect(400,300,400,300)
# subsurfaces of canvas
# Note that subx needs refreshing when px_camera changes.
sub1 = canvas.subsurface(p1_camera)
sub2 = canvas.subsurface(p2_camera)
sub3 = canvas.subsurface(p3_camera)
sub4 = canvas.subsurface(p4_camera)
Now drawing on any of of the subsurfaces with these normalized coordinates
# Drawing a line on each split "screen"
pygame.draw.line(sub2, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (0,300), 10)
pygame.draw.line(sub3, (255,255,255), (0,0), (400,0), 10)
pygame.draw.line(sub4, (255,255,255), (0,0), (400,0), 10)
# draw player 1's view to the top left corner
screen.blit(sub1, (0,0))
# player 2's view is in the top right corner
screen.blit(sub2, (400, 0))
# player 3's view is in the bottom left corner
screen.blit(sub3, (0, 300))
# player 4's view is in the bottom right corner
screen.blit(sub4, (400, 300))
# Update the screen
pygame.display.update()
Note that modifications to the subsurface pixels will affect the canvas as well. I'd recommend reading the full documentation on subsurfaces.
I want to add a grid to my level that stays with the terrain and not the screen. The way I thought of doing it is to add all the lines that form the grid as sprites and move them with the terrain, but I can't figure out how to represent the line as an image.
I tried to do this myself, but had no success.
EDIT: Here's what I've tried
class Grid():
def __init__(self):
self.grid = pygame.Surface(size)
self.grid.set_colorkey((0,0,0))
def draw(self):
# DRAW TILE LINES ----------------------------------------------------------
grid_x = 0
grid_y = 0
for i in range(total_level_width // TILE_SIZE):
pygame.draw.aaline(self.grid,BLACK,[grid_x,0],[grid_x,total_level_height])
pygame.draw.aaline(self.grid,BLACK,[0,grid_x],[total_level_width,grid_y])
grid_x += TILE_SIZE
grid_y += TILE_SIZE
# tile test
pygame.draw.rect(screen,BLACK,(49*TILE_SIZE,34*TILE_SIZE,TILE_SIZE,TILE_SIZE))
screen.blit(self.grid,(0,0))
Creating the object:
grid = Grid()
Calling class: (in main program loop)
grid.draw()
I had a similar problem while i was trying to do a project. I used the following code to get a line onto a surface and then bliting it onto my screen. I hope this entire function might help you.
def blitBoundary(self):
""" helper function to blit boundary on screen """
# create a surface
self.boundSurf=pygame.Surface((1024,768))
self.boundSurf.set_colorkey((0,0,0))
"""
if not self.boundary.closePoly:
(x,y)=pygame.mouse.get_pos()
pointList=self.boundary.pointList +[[x,y]]
else:
pointList=self.boundary.pointList"""
if len(pointList)>1:
pygame.draw.aalines(self.boundSurf, (255,255,255),
self.boundary.closePoly , pointList, 1)
self.screen.blit(self.boundSurf,(0,0))
I was trying to draw a polygon. The commented out the if statement that would be most probably not useful for you.
All my lines were in a polygon class object.
You might want to look into pygame.draw.aalines function.
How do I bind a pyglet sprite to a pymunk body so that if the body is rotating the sprite also rotates?
There is no built in syncing so you have to do it on your own each frame. But dont worry, its very easy.
If you have your body positioned in the middle of the shape/shapes, and the image is the same size there's two things you need. First, set the image anchor to half its size. Then in your update method you loop the bodies you want to sync and set the sprite position to the body position and sprite rotation to body rotation converted into degrees. You might also need to rotate it 180 degrees (in case your model is flipped) and/or invert the rotation.
In code
img = pyglet.image.load('img.png')
img.anchor_x = img.width/2
img.anchor_y = img.height/2
sprite = pyglet.sprite.Sprite(img)
sprite.body = body
def update(dt):
sprite.rotation = math.degrees(-sprite.body.angle)
sprite.set_position(sprite.body.position.x, sprite.body.position.y)
For a full example take a look at this example I created: https://github.com/viblo/pymunk/blob/master/examples/using_sprites_pyglet.py
(Im the author of pymunk)
def rotate(self):
#Save the original rect center
self.saved_center=self.rect.center
#Rotates a saved image every time to maintain quality
self.image=pygame.transform.rotate(self.saved_image, self.angle)
#Make new rect center the old one
self.rect.center=self.saved_center
self.angle+=10
When I rotate the image, there is a weird shifting of it despite the fact that I'm saving the old rect center and making the rotated rect center the old one. I want it to rotate right at the center of the square.
Here's what it looks like:
http://i.imgur.com/g6Os9.gif
You are just calculating the new rect wrong. Try this:
def rotate(self):
self.image=pygame.transform.rotate(self.saved_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
self.angle+=10
It tells the new rect to center itself around the original center (the center never changes here. Just keeps getting passed along).
The issue was that the self.rect was never being properly updated. You were only changing the center value. The entire rect changes as the image rotates because it grows and shrinks in size. So what you needed to do was completely set the new rect each time.
self.image.get_rect(center=self.rect.center)
This calculates a brand new rect, while basing it around the given center. The center is set on the rect before it calculate the positions. Thus, you get a rect that is properly centered around your point.
I had this issue. My method has a bit of a different purpose, but I solved it quite nicely.
import pygame, math
def draw_sprite(self, sprite, x, y, rot):
#'sprite' is the loaded image file.
#'x' and 'y' are coordinates.
#'rot' is rotation in radians.
#Creates a new 'rotated_sprite' that is a rotated variant of 'sprite'
#Also performs a radian-to-degrees conversion on 'rot'.
rotated_sprite = pygame.transform.rotate(sprite, math.degrees(rot))
#Creates a new 'rect' based on 'rotated_sprite'
rect = rotated_sprite.get_rect()
#Blits the rotated_sprite onto the screen with an offset from 'rect'
self.screen.blit(rotated_sprite, (x-(rect.width/2), y-(rect.height/2)))
I am learning pygame and want a graphic for a button with the three states: normal, hover, and pressed. I have an image like this one ...
... and I want to get a new Surface using a portion of it.
I'm loading the image with this code:
buttonStates = pygame.image.load(os.path.join('image','button.png'))
How can I make a new surface using just a portion of that graphic?
cropped = pygame.Surface((80, 80))
cropped.blit(buttonStates, (0, 0), (30, 30, 80, 80))
The blit method on a surface 'pastes' another surface on to it. The first argument to blit is the source surface. The second is the location to paste to (in this case, the top left corner). The third (optional) argument is the area of the source image to paste from -- in this case an 80x80 square 30px from the top and 30px from the left.
You can also use the pygame.Surface.subsurface method to create subsurfaces that share their pixels with their parent surface. However, you have to make sure that the rect is inside of the image area or a ValueError: subsurface rectangle outside surface area will be raised.
subsurface = a_surface.subsurface((x, y, width, height))
There are 2 possibilities.
The blit method allows to specify a rectangular sub-area of the source _Surface:
[...] An optional area rectangle can be passed as well. This represents a smaller portion of the source Surface to draw. [...]
In this way you can blit an area of the source surface directly onto a target:
cropped_region = (x, y, width, height)
target.blit(source_surf, (posx, posy), cropped_region)
Alternatively, you can define a subsurface that is directly linked to the source surface with the subsurface method:
Returns a new Surface that shares its pixels with its new parent. The new Surface is considered a child of the original. Modifications to either Surface pixels will effect each other.
As soon as a subsurface has been created, it can be used as a normal surface at any time:
cropped_region = (x, y, width, height)
cropped_subsurf = source_surf.subsurface(cropped_region)
target.blit(cropped_subsurf, (posx, posy))
I think the best way to do it is crop the image of these 3 kind of buttons in a external program and load in different surface instead use pygame to crop it