This question already has an answer here:
Nested arguments not compiling
(1 answer)
Closed 8 years ago.
I'm just learning python/pygame and I'm doing a physics tutorial. Unfortunately, I think it was made in an older version of python. I copied the code in the video exactly, but when I run it it returns "Failed to run script - syntax error - invalid syntax(physics.py, line 7)". I'm sure it's just something stupid and obvious that I'm missing, but any answer would go a long way for me!
import os, sys, math, pygame, pygame.mixer
from pygame.locals import *
screen_size = screen_width, screen_height = 600, 400
class MyCircle:
def __init__(self, (x, y), size, color = (255,255,255), width = 1):
self.x = x
self.y = y
self.size = size
self.color = color
self.width = width
def display(self):
pygame.draw.circle(screen, self.color, (self.x, self.y), self.size, self.width)
screen = pygame.display.set_mode(screen_size)
my_circle = MyCircle((100,100), 10, red)
my_circle_2 = MyCircle((200,200), 30, blue)
my_circle_3 = MyCircle((300,150), 40, green, 4)
my_circle_4 = MyCircle((450,250), 120, black, 0)
fps_limit = 60
run_me = True
while run_me:
clock.tick(fps_limit)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run_me = False
my_circle.display()
my_circle_2.display()
my_circle_3.display()
my_circle_4.display()
pygame.display.flip()
pygame.quit()
sys.exit()
You're probably using Python 3. Tuple parameter unpacking was removed in 3.X, so you have to change this:
def __init__(self, (x, y), size, color = (255,255,255), width = 1):
self.x = x
self.y = y
self.size = size
self.color = color
self.width = width
To:
def __init__(self, position, size, color = (255,255,255), width = 1):
self.x, self.y = position
self.size = size
self.color = color
self.width = width
Well, line 7 is this line:
def __init__(self, (x, y), size, color = (255,255,255), width = 1):
See that (x, y) in the middle of the parameter list? This is a feature called "tuple parameter unpacking", and it was removed in Python 3.0. (It's also discouraged in Python 2.6-2.7, but it works, so some people still use it.)
PEP 3113 has the full details.
If you run the 2to3 tool on your script, it'll tell you how to fix it.
But the simple fix is to replace that tuple (x, y) with a single parameter xy, and split it inside the function:
def __init__(self, xy, size, color = (255,255,255), width = 1):
self.x, self.y = xy
self.size = size
self.color = color
self.width = width
Related
I follow a youtube video 'https://www.youtube.com/watch?v=cCiXqK9c18g' and in the video he make a class that represent a ball and he used pymunk to make a body and added it to the space and after that he created a method inside the ball class that will use pygame to draw the ball and I did almost like him
import pygame
import pymunk
pygame.init()
fps = 60
dt = 1/fps
dsX = 800 # screen width
dsY = 500 # screen height
display = pygame.display.set_mode((dsX, dsY))
space = pymunk.Space()
clock = pygame.time.Clock()
def convert_cor(point): # convet the coordinates from pymunk to pygame coordinates
return point[0], dsY - point[1]
class Particle: # v: velocity, pos: position[x, y], r: radius of particle(Circle)
def __init__(self, pos = [0, 0], v = [0, 0], r = 10, color = (255, 0, 0)):
self.pos = pos
self.v = v
self.r = r
self.color = color
self.body = pymunk.Body()
self.body.position = self.pos
self.body.velocity = self.v # this is the veclocity
self.shape = pymunk.Circle(self.body, self.r)
self.shape.dencity = 1
self.shape.elasticity = 1
space.add(self.body, self.shape)
def draw(self):
pygame.draw.circle(display, self.color, convert_cor(self.pos), self.r)
class Box: # thickness of the sides of the box and L1, L2, L3, L4 are the sides of the box
def __init__(self, thickness, color):
self.thickness = thickness
self.color = color
L1 = pymunk.Body(body_type = pymunk.Body.STATIC)
L2 = pymunk.Body(body_type = pymunk.Body.STATIC)
L3 = pymunk.Body(body_type = pymunk.Body.STATIC)
L4 = pymunk.Body(body_type = pymunk.Body.STATIC)
L1_shape = pymunk.Segment(L1, (0, 0), (dsX, 0), self.thickness)
L2_shape = pymunk.Segment(L2, (dsX, 0), (dsX, dsY), self.thickness)
L3_shape = pymunk.Segment(L3, (dsX, dsY), (0, dsY), self.thickness)
L4_shape = pymunk.Segment(L4, (0, dsY), (0, 0), self.thickness)
space.add(L1, L1_shape)
space.add(L2, L2_shape)
space.add(L3, L3_shape)
space.add(L4, L4_shape)
def draw(self):
pygame.draw.line(display, self.color, convert_cor((0, 0)), convert_cor((dsX, 0)), self.thickness * 2)
pygame.draw.line(display, self.color, convert_cor((dsX, 0)), convert_cor((dsX, dsY)), self.thickness * 2)
pygame.draw.line(display, self.color, convert_cor((dsX, dsY)), convert_cor((0, dsY)), self.thickness * 2)
pygame.draw.line(display, self.color, convert_cor((0, dsY)), convert_cor((0, 0)), self.thickness * 2)
def Sim(): # the infinite while loop as a function
box = Box(2, (0, 255, 255))
particle = Particle(pos =[dsX/2, dsY/2], v = [-200, 500]) # here i gave the position and the velocity
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
display.fill((255, 255, 255))
box.draw()
particle.draw()
clock.tick(fps)
space.step(dt)
pygame.display.update()
Sim()
pygame.quit()
The thing is, I did also a class that will add a rigid sides for the display and i drew the sides from the Box class using the method 'draw' The problem is in the time 5:58 in the video he gave the ball velocity and it start moving and in my code it does not move. any idea why it doen't move?
note: I called the ball particle in my code
You error is both a typo and using the wrong variable.
Inside your particles draw function...
# OLD
def draw(self):
pygame.draw.circle(display, self.color, convert_cor(self.pos), self.r)
# New
def draw(self):
pygame.draw.circle(display, self.color, convert_cor(self.body.position), self.r)
You have to use the body's position cause that is the position of the physics body in pymunk's space.
Secondly...
class Particle: # v: velocity, pos: position[x, y], r: radius of particle(Circle)
def __init__(self, pos, v, r=10, color=(255, 0, 0)):
...
# Old
self.shape.dencity = 1
# New
self.shape.density = 1
Since density was not set to anything Pymunk was having a divide by zero error so it wouldn't update the body's position.
self.body.position = self.pos
To be clear about the problem:
From what I could find in the documentation, pymunk.Body.position is a property; it expects you to pass either an ordinary Python tuple or a Vec2d (not a list, although anything it's relying on internally to handle a tuple probably handles a list just fine), and calls some internal code written in another programming language. The effect is that, instead of storing your list object and then making changes to the list (which would be visible in your class, since it would be the same object), it just gets the initial values out of your list, and then doesn't use the list object.
This means that when Pymunk applies physics calculations, self.body.position changes, but self.pos does not. So the current self.pos is useless; we can't use it to check the object position.
If you don't need to do that, then there is no need to create a self.pos at all - just feed self.body.position = pos directly, and make sure to use self.body.position when drawing.
If you do, I recommend using your own property instead of trying to set self.pos. Do the above, and then add to the class:
#property
def pos(self):
return self.body.position
And if you want to change the position from your code (but you probably shouldn't! Why else are you using the physics engine in the first place?), also add:
#pos.setter
def pos(self, value):
self.body.position = value
This question already has answers here:
How to change an image size in Pygame?
(4 answers)
Closed 1 year ago.
I'm curious to know how and why when I hover over the potato that it slightly becomes ever so more pixelated until it reaches a 16x16 pixel potato image? I don't really know where to begin with an explanation myself.
main.py
import pygame
import math
import random
from potato import Potato
knife = pygame.image.load("knife.png")
knife = pygame.transform.rotate(knife, 270)
knife = pygame.transform.scale(knife, (200, 200))
potato = pygame.image.load("potato.png")
potato = pygame.transform.scale(potato, (200, 160))
WIDTH, HEIGHT = 800, 500
window = pygame.display.set_mode((WIDTH, HEIGHT))
def main():
done = False
potatoThing = Potato(knife, potato, WIDTH/2-100, HEIGHT/2 - 80)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
mousex, mousey = pygame.mouse.get_pos()
window.fill((195, 245, 98))
potatoThing.draw(window)
potatoThing.update(mousex, mousey)
pygame.display.update()
pygame.quit()
main()
potato.py
import pygame
import math
import random
from pygame.math import Vector2 as vect
def distanceBecauseMeep(min, max, value):
if value < min:
return min
elif value > max:
return max
else:
return value
class Potato:
def __init__(self, sprite1, sprite2, x, y):
self.knifeSprite = sprite1
self.potatoSprite = sprite2
self.pos = vect(x, y)
self.isHoveringOver = False
self.sizeOfPotato = (200, 160)
self.sizeOfKnife = (200, 200)
def draw(self, win):
if self.isHoveringOver:
self.sizeOfPotato = (220, 180)
self.sizeOfKnife = (220, 220)
else:
self.sizeOfPotato = (200, 160)
self.sizeOfKnife = (200, 200)
self.potatoSprite = pygame.transform.scale(self.potatoSprite, self.sizeOfPotato)
self.knifeSprite = pygame.transform.scale(self.knifeSprite, self.sizeOfKnife)
win.blit(self.potatoSprite, (self.pos))
win.blit(self.knifeSprite, (self.pos))
def update(self, xPos, yPos):
self.x = xPos
self.y = yPos
self.CosX = distanceBecauseMeep(self.pos.x, self.pos.x + self.sizeOfPotato[0], self.x)
self.CosY = distanceBecauseMeep(self.pos.y, self.pos.y + self.sizeOfPotato[1], self.y)
self.distance = math.sqrt((self.CosX - self.x)**2 + (self.CosY - self.y)**2)
if self.distance <= 0.0:
self.isHoveringOver = True
else:
self.isHoveringOver = False
here are some pictures to help show my point and confusion
when you first start the program:
when you hover over it a couple times
it could have something to do with the Tuples in potato.py but I'm not quite sure. I am really confused and didn't even know this was a possibility for images to become pixelated.
ive tried
pygame.transform.smoothscale
but all that does is blur the image instead of pixelate the image
You're repeatedly scaling the same image to different sizes and replacing the original with it. Each time that's a lossy operation; instead, keep the pristine version and scale it to each desired size. (With just two sizes, you might do this for each size ahead of time rather than doing it once every frame.)
I just added a function to my code which should display an image from a directory. It requires an argument which specifies which window it displays it in. When I try to pass it in I receive the following error:
Traceback (most recent call last):
File "Pygame.py", line 122, in <module>
Player.load()
File "Pygame.py", line 74, in load
screen.blit(self.path, (self.x, self.y))
TypeError: argument 1 must be pygame.Surface, not str
My code:
import pygame
#init the pygame and create a screen
pygame.init()
screen = pygame.display.set_mode((1080,720))
done = False
#colours
blue = (0,0,255)
red = (255,0,0)
green = (0,255,0)
black = (0,0,0)
white = (255,255,255)
yellow = (255,255,0)
#path to the background
bg_path = "Racing.png"
#path to the car image
car_path = "car.png"
#starts the game clock
clock = pygame.time.Clock()
#opening bg image
background_image = pygame.image.load(bg_path).convert()
#class for all of the objects on the screen
class shape():
def __init__(self, place, x, y):
self.place = place
self.x = x
self.y = y
class rectangle(shape):
def __init__(self, place, colour, x, y, length, width):
super().__init__(place,x, y)
self.colour = colour
self.length = length
self.width = width
def draw(self):
pygame.draw.rect(screen, self.colour, pygame.Rect(self.x, self.y,
self.length, self.width))
def move_up(self):
self.y = self.y - 10
def move_down(self):
self.y = self.y + 10
def move_right(self):
self.x = self.x + 10
def move_left(self):
self.x = self.x - 10
class player(shape):
def __init__(self, place, x, y, length, width, path):
super().__init__(place,x, y)
self.length = length
self.width = width
self.path = path
def load(self):
screen.blit(self.path, (self.x, self.y))
Rectangle = rectangle(screen, yellow, 540, 660, 60, 60)
Player = player(screen, 540, 600, 60, 60, car_path)
Player.load()
This isn't all of the code but the rest isn't related to the problem (I think). Please tell me if more code is needed.
car_path is set as a string here
car_path = "car.png"
But blit() requires a pygame.Surface object for the first argument which pygame.image.load would give you, i.e.
car_path = pygame.image.load("car.png")
instead.
In the game I'm trying to create, I want to spawn mummies outside of the screen and have them run towards the player. The problem I'm getting is that it won't take one variable for both the x and y coordinates. How can I make it so I can use just one variable for both the x and y coordinates?
screenx = 800
screeny = 600
class enemy():
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.alive = False
self.vel = 2
randomspawnabove = (random.randint(0, screenx), -100)
randomspawnbelow = (random.randint(0, screenx), (screeny + 100))
randomspawnleft = (-100, random.randint(0, screeny))
randomspawnright = ((screenx + 100), random.randint(0, screeny))
mummy_Spawn = [randomspawnleft, randomspawnright, randomspawnabove, randomspawnbelow]
mummy = enemy(random.choice(mummy_Spawn), 134, 134)
You can use the * operator to unpack the coordinates tuple:
mummy = enemy(*random.choice(mummy_Spawn), 134, 134)
I am trying to make a script in python for pygame to draw a button with text centered, but when I blit onto the screen, it blits to the x and y I give it, not a proportionally centered location. I want to be able to center it to a set of (x,y,w,h). How would I do this? Here's my code:
# Imports
import pygame
class Text:
'Centered Text Class'
# Constructror
def __init__(self, text, (x,y,w,h), color = (0,0,0)):
self.x = x
self.y = y
self.w = w
self.h = h
# Start PyGame Font
pygame.font.init()
font = pygame.font.SysFont("sans", 20)
self.txt = font.render(text, True, color)
# Draw Method
def Draw(self, screen):
coords = (self.x, self.y)
screen.blit(self.txt, coords)
Edit: Comments, yes I know but I only used x and y as temporary variables because I have no idea what the centered x and y would be to center the text. (I want to know how to center its CENTER to a rect, not its top left corner)
You'll want to use the font.size() method to determine how large the rendered text will be.
Something like:
class Text:
"""Centered Text Class"""
# Constructror
def __init__(self, text, (x,y), color = (0,0,0)):
self.x = x #Horizontal center of box
self.y = y #Vertical center of box
# Start PyGame Font
pygame.font.init()
font = pygame.font.SysFont("sans", 20)
self.txt = font.render(text, True, color)
self.size = font.size(text) #(width, height)
# Draw Method
def Draw(self, screen):
drawX = self.x - (self.size[0] / 2.)
drawY = self.y - (self.size[1] / 2.)
coords = (drawX, drawY)
screen.blit(self.txt, coords)
I think something like the following does what you want. It uses pygame.font.Font.size() to determine the amount of space needed to render the text, and then centers that within rectangular region defined by CenteredText instance.
class CenteredText(object):
""" Centered Text Class
"""
def __init__(self, text, (x,y,w,h), color=(0,0,0)):
self.x, self.y, self.w, self.h = x,y,w,h
pygame.font.init()
font = pygame.font.SysFont("sans", 20)
width, height = font.size(text)
xoffset = (self.w-width) // 2
yoffset = (self.h-height) // 2
self.coords = self.x+xoffset, self.y+yoffset
self.txt = font.render(text, True, color)
def draw(self, screen):
screen.blit(self.txt, self.coords)
# for testing purposes, draw the rectangle too
rect = Rect(self.x, self.y, self.w, self.h)
pygame.draw.rect(screen, (0,0,0), rect, 1)
Given:
text = CenteredText('Hello world', (200,150,100,100))
Here's the results from calling text.draw(screen) in a 500x400 pixel window.
If you want to perfectly centre an object:
When you give Pygame coordinates for an object it takes them to be the coordinates for the upper left corner. Thus we have to halve the x and y coordinates.
coords = (self.x/2, self.y/2)
screen.blit(self.txt, coords)
Other than that your question is unclear.
Let pygame do the maths for you by using Rects and assigning the text's center to the destination center:
# Start PyGame Font
pygame.font.init()
font = pygame.font.SysFont("sans", 20)
class Text:
'Centered Text Class'
# Constructror
def __init__(self, text, (x,y,w,h), color = (0,0,0)):
self.rect = pygame.Rect(x, y, w, h)
self.txt = font.render(text, True, color)
# Draw Method
def Draw(self, screen):
coords = self.txt.get_rect()
coords.center = self.rect.center
screen.blit(self.txt, coords)