Using pygame.Surface.blit inside class - python

I can call my class only one time.
My code is:
class fish:
def __init__(self, x, y, image, speed):
self.x = x
self.y = y
self.image = image
self.speed = speed
def be(self):
screen.blit(self.image, (self.x, self.y))
self.x -= self.speed
if boot.x+36 > self.x and boot.x < self.x+5:
if boot.y+34 > self.y and boot.y < self.y+5:
boot.live -= 1
boot.x = 100
boot.y = 460
fishes = []
fishes.append(fish(900, 300, fish_1, 1))
And when I call 'fish' object inside or outside the game loop(fishes.append(fish(900, 300, fish_1, 1))
I got Error:
TypeError: 'fish' object is not callable

My first guess is that you have a fish variable somewhere down in your code. Rename the class to Fish as well as the constructor call to Fish(900, 300, fish_1, 1) and it should be fine.

Related

'pygame.Surface' object has no attribute 'update'

I get the message : 'pygame.Surface' object has no attribute 'update'. But as you can see, i have an update function in the code. wha did i wrong? I looked around but i didn't fina a simular question.
class Createparticle:
def __init__(self, xx, yy,img):
self.x = xx
self.y = yy
self.img = img
self.particlelist = []
self.verzoegerung = 0
self.scale_k = 0.1
self.img = scale(img, self.scale_k)
self.alpha = 255
self.alpha_rate = 3
self.alive = True
self.vx = 0
self.vy = 4 + random.randint(-10, 10) / 10
self.k = 0.01 * random.random() * random.choice([-1, 1])
def update(self):
self.x += self.vx
self.vx += self.k
self.y -= self.vy
self.vy *= 0.99
self.scale_k += 0.005
self.alpha -= self.alpha_rate
self.img = scale(self.img, self.scale_k)
self.img.set_alpha(self.alpha)
self.particlelist = [i for i in self.particlelist if i.alive]
self.verzoegerung += 1
if self.verzoegerung % 2 == 0:
self.verzoegerung = 0
self.particlelist.append(self.img)
for i in self.particlelist:
i.update()
def draw(self):
for i in self.particlelist:
screen.blit(self.img, self.img.get_rect(center=(self.x, self.y)))
createparticle = Createparticle(500,300,basisbild)
while True:
screen.fill((0, 0, 0))
createparticle.update()
createparticle.draw()
pygame.display.update()
clock.tick(FPS)
The error is caused by i.update(). i is an element from self.particlelist. In your case self.particlelist is an image (pygame.Surface). A pygame.Surface object has no update method. Probably i should not be a pygame.Surface, but you add pygame.Surface objects to the list:
self.particlelist.append(self.img)
So this line of code is obviously wrong and should be like this instead (note: Particle is a guess of mine, but I don't know how you named your classes.):
self.particlelist.append(Particle(self.img))
you have a list of surfaces called particlelist, in your update function you are calling the update function on each item in that list. Since theses are of the 'surface' type they don't have a update function. This is where the error is coming from.

Getting a type Surface error with argument 1. How would I fix it?

I'm using Python 3.7.4 and Python 1.9.6. I have a class which is the main one for the subclass's. I'm experiencing an error: the line with the error --> window.blit(self.ship_img, (self.x, self.y)) TypeError: argument 1 must be pygame.Surface, not None.
Code:
class Ship:
def __init__(self, x, y, health=100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self, window):
window.blit(self.ship_img, (self.x, self.y))
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
The reason it has to be None because it has several images of the same class(meaning using the same variables) but with different coordinates and properties. It can't be a list, because then the .get_width() and .get_height() won't work. I'm using those to create barriers for the image(s).
I'm following along with the tutorial: https://www.youtube.com/watch?v=Q-__8Xw9KTM&ab_channel=TechWithTim. I'm at around 51:41 of the video. Thank you for the advice as always.
Just test that self.ship_img is not None, before drawing the object:
class Ship:
# [...]
def draw(self, window):
if self.ship_img != None:
window.blit(self.ship_img, (self.x, self.y))

Is there a way to move an object in pygame in random directions smoothly? [duplicate]

This question already has an answer here:
Pygame game help: Easing/Acceleration
(1 answer)
Closed 2 years ago.
I'm trying to make blobs move in a random direction for several frames rather than just once so that it appears less jerky and more smooth, but have been unable to do so. Is there any way to make each object move in the same direction for several ticks before choosing another random direction and doing the same?
My code (most is irrelevant):
import pygame
import random
import numpy as np
WIDTH = 1800
HEIGHT = 1000
BLUE = (15,15,180)
RED = (150,0,0)
class Blob:
def __init__(self, colour, x_boundary, y_boundary, size):
self.colour = colour
self.size = size
self.x_boundary = x_boundary
self.y_boundary = y_boundary
self.x = random.randrange(0, self.x_boundary)
self.y = random.randrange(0, self.y_boundary)
def move(self):
self.x += random.randrange(-6,7)
self.y += random.randrange(-6,7)
def limits(self):
if self.x < 0:
self.x = 0
elif self.x > self.x_boundary:
self.x = self.x_boundary
if self.y < 0:
self.y = 0
elif self.y > self.y_boundary:
self.y = self.y_boundary
def __add__(self, other_blob):
if other_blob.size > self.size:
other_blob.size += int(self.size * 0.5)
self.size = 0
class FastBlob(Blob):
def __init__(self, colour, x_boundary, y_boundary, size):
super().__init__(colour, x_boundary, y_boundary, size)
def move(self):
self.x += random.randrange(-20,21)
self.y += random.randrange(-20,21)
pygame.init()
game_display = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Blob world')
clock = pygame.time.Clock()
def is_touching(b1,b2):
return np.linalg.norm(np.array([b1.x,b1.y])-np.array([b2.x,b2.y])) < (b1.size + b2.size)
def handle_collisions(blob_list):
blues, reds, slow_reds = blob_list
for first_blobs in blues, reds, slow_reds:
for first_blob_id, first_blob in first_blobs.copy().items():
for other_blobs in blues, reds, slow_reds:
for other_blob_id, other_blob in other_blobs.copy().items():
if first_blob == other_blob:
pass
else:
if is_touching(first_blob, other_blob):
first_blob + other_blob
return blues, reds, slow_reds
def draw_environment(blob_list):
game_display.fill((210,210,210))
handle_collisions(blob_list)
for blob_dict in blob_list:
for blob_id in blob_dict:
blob = blob_dict[blob_id]
pygame.draw.circle(game_display, blob.colour, [blob.x, blob.y], blob.size)
blob.move()
blob.limits()
pygame.display.update()
def main():
blue_blobs = dict(enumerate([FastBlob(BLUE, WIDTH, HEIGHT, random.randrange(10,15)) for i in range(20)]))
red_blobs = dict(enumerate([FastBlob(RED, WIDTH, HEIGHT, random.randrange(5,10)) for i in range(30)]))
slow_red_blobs = dict(enumerate([Blob(RED, WIDTH, HEIGHT, random.randrange(20,30)) for i in range(5)]))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
draw_environment([blue_blobs, red_blobs, slow_red_blobs])
clock.tick(7)
if __name__ == '__main__':
main()
Here, I have similar problem in my game, when enemy has to randomly change directions so it is unpredictable to the player.
def goblin_move(): #Goblin auto (random) movement
if goblin.x < 0:
goblin.go_right()
elif goblin.x > 500:
goblin.go_left()
else:
if goblin.x > (rnd_1 * win_width) and goblin.move_flag == -1:
goblin.go_left()
goblin.move_flag = -1
else:
goblin.go_right()
goblin.move_flag = 1
if goblin.x > (rnd_2 * win_width):
goblin.move_flag = -1
def set_random(rnd_1, rnd_2): #Random function generator
rnd_1 = round(random.uniform(0, 0.45), 2)
rnd_2 = round(random.uniform(0.65, 0.95), 2)
return rnd_1, rnd_2
And this is how I set it in the main loop:
if round(pg.time.get_ticks()/1000) % 3 == 0: #Calling random function
(rnd_1, rnd_2) = set_random(rnd_1, rnd_2)
Hope you will find it useful.
Use pygame.math.Vector2 to do the computations. Store the coordinates of the blob to a Vector2 and define a maximum distance (self.maxdist), a velocity (self.speed), a random distance (self.dist) a nd a random direction (self.dir). The random direction is a vector with length 1 (Unit vector) and a random angel (rotate()):
class Blob:
def __init__(self, colour, x_boundary, y_boundary, size):
self.colour = colour
self.size = size
self.x_boundary = x_boundary
self.y_boundary = y_boundary
self.x = random.randrange(0, self.x_boundary)
self.y = random.randrange(0, self.y_boundary)
self.pos = pygame.math.Vector2(self.x, self.y)
self.maxdist = 7
self.speed = 1
self.dist = random.randrange(self.maxdist)
self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))
When the blob moves, then scale the direction by the speed and add it to the position (self.pos += self.dir * self.speed). Decrement the distance (self.dist -= self.speed) and update self.x, self.y by the rounded (round) position. If self.dist falls below 0, the create a new random direction and distance:
class Blob:
# [...]
def move(self):
self.pos += self.dir * self.speed
self.dist -= self.speed
self.x, self.y = round(self.pos.x), round(self.pos.y)
if self.dist <= 0:
self.dist = random.randrange(self.maxdist)
self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))
In the method limit you have to ensure that self.pos is in bounds. Finally you have to update self.x, self.y:
class Blob:
# [...]
def limits(self):
if self.pos.x < 0:
self.pos.x = 0
elif self.pos.x > self.x_boundary:
self.pos.x = self.x_boundary
if self.pos.y < 0:
self.pos.y = 0
elif self.pos.y > self.y_boundary:
self.pos.y = self.y_boundary
self.x, self.y = round(self.pos.x), round(self.pos.y)
The class FastBlob does not need its own move method. It is sufficient do define its own self.maxdist and self.speed:
class FastBlob(Blob):
def __init__(self, colour, x_boundary, y_boundary, size):
super().__init__(colour, x_boundary, y_boundary, size)
self.maxdist = 35
self.speed = 5

How to inherit specific variables from one class to another class?

I'm making a game in python using the pygame module and I wish to inherit one specific variable from one class to another class, but have no clue how. I have tried super() but it has not worked, however, me being a novice may just mean I did it wrong so please do not discount that as a possibility if it works.
I have listed which variable I wish inherited in the code below as well.
Here's my relevant code below:
Class I want to inherit FROM:
class player():
def __init__(self, x, y, width, height, walkCount):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 15
self.lastDirection = "right" or "left" or "up" or "down" #<--- variable I want to inherit
self.walkCount = walkCount
def drawCharacter(self, window):
dest = (self.x, self.y)
if self.walkCount + 1 >= 30:
self.walkCount = 0
if self.lastDirection == "left":
window.blit(protagL[0], dest)
elif self.lastDirection == "right":
window.blit(protagR[0], dest)
elif self.lastDirection == "up":
window.blit(protagU[0], dest)
elif self.lastDirection == "down":
window.blit(protagD[0], dest)
Class that I want to receive the inheritance:
class projectile(player):
def __init__(self, x, y, direction, travelCount):
self.x = x
self.y = y
self.direction = direction
self.vel = 20 * direction
self.travelCount = travelCount
def drawBullet(self, window):
dest = (self.x, self.y)
if self.travelCount + 1 >= 15:
self.walkCount = 0
if lastDirection == "right" or "left": # <--- I Want to call lastDirection variable here
if self.travelCount < 15:
window.blit(bulletsP[self.travelCount//3], dest) #dest)
self.travelCount += 1
self.x += self.vel
Any help would be greatly appreciated, thank you.
You have to invoke the constructor of the base class. See super():
class projectile(player):
def __init__(self, x, y, direction, travelCount):
super().__init__(x, y, 10, 10, travelCount)
# [...]
Note the arguments for width and height are unclear in you example, so I've exemplarily used (10, 10).

How can i keep updating variables to class from outside of it?

I'm New to python/pygame classes and I'm making a game.
So my problem is that i have a class that draws spaceships to screen but i would need somehow add spacemove_x,spacemove_y to their x and y.
These spacemove_x,spacemove_y are defined when user moves he's own spaceship
(I use spacemove_x,spacemove_y for updating places for other stuff too like stars because this game is from top down view so when i move my spacecraft other things should get closer/farther away depending what direction my character is going)
So spacemove_x,spacemove_y is always updating it self but how can I give this info to class?
CODE:
import pygame
import random
class BaseClass(pygame.sprite.Sprite):
allsprites = pygame.sprite.Group()
def __init__(self, x, y, width, height,spacemove_x,spacemove_y):
pygame.sprite.Sprite.__init__(self)
BaseClass.allsprites.add(self)
self.shipDefaultUp = pygame.image.load("textures/ships/shipDefault/shipUP.png")
self.shipDefaultRight = pygame.image.load("textures/ships/shipDefault/shipRIGHT.png")
self.shipDefaultDown = pygame.image.load("textures/ships/shipDefault/shipDOWN.png")
self.shipDefaultLeft = pygame.image.load("textures/ships/shipDefault/shipLEFT.png")
self.shipCargo1Up = pygame.image.load("textures/ships/shipCargo1/shipCargo1UP.png")
self.shipCargo1Right = pygame.image.load("textures/ships/shipCargo1/shipCargo1RIGHT.png")
self.shipCargo1Down = pygame.image.load("textures/ships/shipCargo1/shipCargo1DOWN.png")
self.shipCargo1Left = pygame.image.load("textures/ships/shipCargo1/shipCargo1LEFT.png")
self.shipCargo2Up = pygame.image.load("textures/ships/shipCargo2/shipCargo2UP.png")
self.shipCargo2Right = pygame.image.load("textures/ships/shipCargo2/shipCargo2RIGHT.png")
self.shipCargo2Down = pygame.image.load("textures/ships/shipCargo2/shipCargo2DOWN.png")
self.shipCargo2Left = pygame.image.load("textures/ships/shipCargo2/shipCargo2LEFT.png")
self.image = pygame.image.load("textures/ships/shipDefault/shipUP.png")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.width = width
self.height = height
self.spacemove_x = spacemove_x
self.spacemove_y = spacemove_y
#self.dirrection = random.randrange(1,5)
self.dirrection = 1
self.timer = random.randrange(10,50)
self.speed = random.randrange(2,10)
self.shiptype = 3#random.randrange(1,3)
#shiptypes#
#1 = shipDefault
#2 = shipCargo1
#3 = shipCargo2
self.move1 = ((1),(2),(4))
self.move2 = ((1),(2),(3))
self.move3 = ((2),(3),(4))
self.move4 = ((1),(3),(4))
class spacecraftBOT(BaseClass):
ships = pygame.sprite.Group()
def __init__(self, x, y, width, height,spacemove_x,spacemove_y):
BaseClass.__init__(self, x, y, width, height,spacemove_x,spacemove_y)
spacecraftBOT.ships.add(self)
def motion(self):
#1 = UP
#2 = RIGHT
#3 = DOWN
#4 = LEFT
self.timer -=1
if self.dirrection == 1: ##############SHIP UP
self.rect.y -=self.speed
self.rect.y -=self.spacemove_x
if self.shiptype == 1:
self.image = self.shipDefaultUp
if self.shiptype == 2:
self.image = self.shipCargo1Up
if self.dirrection == 2:################SHIP RIGHT
self.rect.x +=self.speed
self.rect.x +=self.spacemove_x
if self.shiptype == 1:
self.image = self.shipDefaultRight
if self.shiptype == 2:
self.image = self.shipCargo1Right
if self.shiptype == 3:
self.image = self.shipCargo2Right
if self.dirrection == 3: ##############SHIP DOWN
self.rect.y +=self.speed
self.rect.y +=self.spacemove_y
if self.shiptype == 1:
self.image = self.shipDefaultDown
if self.shiptype == 2:
self.image = self.shipCargo1Down
if self.shiptype == 3:
self.image = self.shipCargo2Down
if self.dirrection == 4: ################SHIP LEFT
self.rect.x -=self.speed
self.rect.x -=self.spacemove_x
if self.shiptype == 1:
self.image = self.shipDefaultLeft
if self.shiptype == 2:
self.image = self.shipCargo1Left
if self.shiptype == 3:
self.image = self.shipCargo2Left
if self.dirrection == 5:
print("loitter")
if self.timer < 0:
self.dirrection = random.randrange(1,6)
self.timer = random.randrange(10,50)
This is how I create spacecraft to my game:
spacecraft1 = spacecraftBOT(500,500,100,34,spacemove_x,spacemove_y)
So how can I give this class updated spacemove_x,spacemove_y?
So how can i give this class updated spacemove_x,spacemove_y?
Just assigning them should work:
spacecraft1.spacemove_x = 100
spacecraft1.spacemove_y = 200
BTW, spacecraft1 is an instance of class spacecraftBOT, not a class.
You access instance members with the dot operator. In fact, you already do this with self many times. The name self is not special; it is just a variable which refers to a class instance. Similarly, spacecraft1 is a variable which refers to a class instance. This means you can use the exact same notation:
spacecraft1.spacemove_x = 100
or
spacecraft1.spacemove_x += 50
Or basically anything you want.
Alternatively, you can define a move() method:
class spacecraftBOT(BaseClass):
# ... all of the code you already have ...
def move(self, x, y):
self.spacemove_x = x
self.spacemove_y = y
Now you can call the method with something like
spaceship1.move(100, 50)
Notice that this jumps directly to the given location. If you want to increment the x and y coordinates instead, you just need to implement the correct logic. (Hint: Use += instead of =.)

Categories