Random direction bullets? - python

I've been working on a bullet-hell game, but when I try to make the bullets spawn in random directions and travel in a straight line, I can't seem to be able to do it. I can see that making the bullet travel +/- certain pixels in x and y axis only causes them to travel in a random pattern that seems unnatural.
My code:
class Bullet(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Bullet.png")
self.rect = self.image.get_rect()
def update(self) :
self.rect.x += random.randrange(-10,10)
self.rect.y += random.randrange(-10,10)

In the __init__ method, you can create self.dx and self.dy variables that will be randomly chosen once upon instantiation and then stay constant every update:
class Bullet(pygame.sprite.Sprite):
def init(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Bullet.png")
self.rect = self.image.get_rect()
self.dx = random.randrange(-10,10)
self.dy = random.randrange(-10,10)
def update(self):
self.rect.x += self.dx
self.rect.y += self.dy

Related

Pygame: How to call defined variable that is inside a class in my main game loop?

So, i'm making some stupid platform game, and i'm currently working with a projectile. Right now everything works fine, but I don't know how to make the projectile move left, I can only move it right. I have a variable called 'Bullet' that is inside a class, but I don't know how to call it in the main loop. When ever I try to call it, its not defined. Heres my code for the bullet:
def shoot(self):
if self.ammo > 0:
Bullet = bullet(self.Game,self.rect.x,self.rect.top)
self.Game.all_sprites.add(Bullet)
self.Game.bullets.add(Bullet)
self.ammo -= 1
Heres the bullet class
class bullet(pg.sprite.Sprite):
def __init__(self, Game,x,y):
pg.sprite.Sprite.__init__(self)
self.image = pg.image.load('magicBullet.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.Game = Game
self.Player = Player
self.speed = 10
def update(self):
self.rect.x += self.speed
Can anyone help?
Why start the variable name with a capital letter and the class name is lowercase? It should be the other way around. See Style Guide for Python Code - Class Names
Anyway, you have to define the direction of movement when the bullet spawns.
Add an additional argument for the speed to the constructor of the class bullet:
class bullet(pg.sprite.Sprite):
def __init__(self, Game, x, y, speed):
pg.sprite.Sprite.__init__(self)
self.image = pg.image.load('magicBullet.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.Game = Game
self.Player = Player
self.speed = speed
def update(self):
self.rect.x += self.speed
Add an argument which defines the direction to the method shoot. The accepted values for the argument direction are either -1 for the movement to the left or 1 for the movement to the right:
def shoot(self, direction):
if self.ammo > 0:
speed = 10 * direction
Bullet = bullet(self.Game, self.rect.x, self.rect.top, speed)
self.Game.all_sprites.add(Bullet)
self.Game.bullets.add(Bullet)
self.ammo -= 1

Shooting multiple bullets and changing their position with the press of a key

I'm creating a SHMUP type of game for my own amusement and I was having trouble on how I could change the "bullet spawner" position to another fixed position whenever I pressed a key, let's say I want an offensive playstyle and a defensive one, I wanted a visual difference and decided to close the bullets distance from the player, yet I do not know how, care to aid me?
Current situation:
class MainFire(pygame.sprite.Sprite):
def __init__(self, x, y, filename, posx, posy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join(img_folder, filename)).convert()
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
self.speedy = - 20
posx += self.rect.centerx
posy += self.rect.bottom
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class SubFire(pygame.sprite.Sprite):
def __init__(self, x, y, filename, posx, posy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join(img_folder, filename)).convert()
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
self.speedy = - 20
posx += self.rect.centerx
posy += self.rect.bottom
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
elif self.rect.left < -10:
self.kill()
elif self.rect.right > GAMEWIDTH:
self.kill()
I reckon that if I fix posx and posy it would finally work, posx should add x and integer as posy with y (giving a new position to the bullet, the velocity is already established, the problem is "from where does the gun appear and not the bullet itself")
Ok, first thing is get rid of these separate classes for different firing angles. Once we know everything that can be different for different shots (start position, speed, image) we can make 1 class for all of them, passing these parameters into the init() function. I have called it Bullet() with all your Main_fire and sub_fire classes gone this should be easier to work with.
def fire(self):
#this is lv2 and the base needs to be changed, it gains the subfire then another subfire set
mfl = Bullet(self.rect.centerx, self.rect.top, "Alessa_MF.png",-20,0)
all_sprites.add(mfl)
bullets.add(mfl)
sfl = Bullet(self.rect.centerx, self.rect.top, "Alessa_SF.png",-15,2)
all_sprites.add(sfl)
bullets.add(sfl)
mfr = Bullet(self.rect.centerx, self.rect.top,"Alessa_SF.png",-15,-2)
all_sprites.add(mfr)
bullets.add(mfr)
sfr = Bullet(self.rect.centerx, self.rect.top,"Alessa_SF.png",-10,-2)
all_sprites.add(sfr)
bullets.add(sfr)
#fire_sound.play()
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y,filename,vx,vy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join(img_folder, filename)).convert()
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x-25
self.speedy = vy
self.speedx = vx
def update(self):
self.rect.y += self.vy
self.rect.x += self.vx
if self.rect.bottom < 0:
self.kill()

Pygame: Making things move slower than 1 [duplicate]

This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Closed 1 year ago.
I made a little Space Invaders like game, everything is good except that I feel like my enemies I programmed move too fast. If I make their movement speed under 1 such as 0.5, they won't even move. Is there a way I can make the movement even slower?
Here is the code for my enemy unit:
import math
WINDOW = pygame.display.set_mode((800, 900))
class Enemy (pygame.sprite.Sprite):
def __init__(self):
super(). __init__ ()
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((20,20))
self.image.fill((255,0,0))
pygame.draw.circle(self.image,(COLOUR4), (10,10),10)
self.rect=self.image.get_rect()
self.rect.center=(0,0)
self.dx=2
self.dy=1
def update(self):
self.rect.centery += self.dy
for i in range (100):
enemy = Enemy()
enemy.rect.x=random.randrange(750)
enemy.rect.y=random.randrange(100)
enemy_list.add(enemy)
all_sprites_list.add(enemy)
The problem is that pygame.Rects can only have ints as their coordinates and floats get truncated. If you want floating point values as the velocities, you have to store the actual position as a separate attribute (or two as in the first example below), add the velocity to it every frame and then assign the new position to the rect.
class Enemy(pygame.sprite.Sprite):
def __init__(self, pos): # You can pass the position as a tuple, list or vector.
super().__init__()
self.image = pygame.Surface((20, 20))
self.image.fill((255, 0, 0))
pygame.draw.circle(self.image, (COLOUR4), (10, 10), 10)
# The actual position of the sprite.
self.pos_x = pos[0]
self.pos_y = pos[1]
# The rect serves as the blit position and for collision detection.
# You can pass the center position as an argument.
self.rect = self.image.get_rect(center=(self.pos_x, self.pos_y))
self.dx = 2
self.dy = 1
def update(self):
self.pos_x += self.dx
self.pos_y += self.dy
self.rect.center = (self.pos_x, self.pos_y)
I recommend using vectors, since they are more versatile and concise.
from pygame.math import Vector2
class Enemy(pygame.sprite.Sprite):
def __init__(self, pos):
# ...
self.pos = Vector2(pos)
self.velocity = Vector2(2, 1)
def update(self):
self.pos += self.velocity
self.rect.center = self.pos

how to create an instance of class with two different variable parameters in python?

This code has two classes, it looks like the class Player() have the same code as Block(), I want to minimalize the code, so I don't repeat the spell-like that, and the way to do that is the instances the class, the Player() is an instance of the Block(), how?
class Block(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([20, 15])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
After looking for an answer from you guys, the code just like this:
class Block(pygame.sprite.Sprite):
def __init__(self, color, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
class Player(Block):
def __init__(self, color, width, height, x, y):
Block.__init__(self, color, width, height)
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
Is that code true? When I'm running the program, it works.
Just like Player and Block inherit from pygame.sprite.Sprite, you can have Player instead inherit from Block:
class Player(Block):
Then, call super().__init__() to use Block's constructor (which in turn will also call pygame.sprite.Sprite's constructor):
class Player(Block):
def __init__(self, x, y):
super().__init__()
Then under that, add all the code specific to Player.
add a middle Class:
class Middle(pygame.sprite.Sprite):
super().__init__()
self.image = pygame.Surface([20, 15])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
then class Block and class Player inherit from the Middle class

how does collide.rect work in pygame

I'm having some trouble understanding how colliderect works with sprites. I have a good idea about it, but whenever I try to implement it into my game, I just get the error message "attributeError:'pygame.surface' object has no attribute 'rect'"
ufo_lvl_1 = pygame.image.load("ufo1.png")
bullet = pygame.image.load("bullet.png")
class Bullet(pygame.sprite.Sprite):
def __init__(self):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
self.image = bullet
self.damage = 5
self.rect = self.image.get_rect()
def update(self):
if 1 == 1:
self.rect.x += 15
if self.rect.x >1360:
self.kill()
class ufo1(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = ufo_lvl_1
self.health = 10
self.rect = self.image.get_rect()
def update(self):
if 1==1:
self.rect.x -= 10
if self.rect.colliderect(bullet.rect):
self.health -= bullet.damage
if self.health >= 0:
self.kill()
bullet.kill()
Basically all my sprites work (excluding ufo1), but the moment I create a ufo1 sprite it crashes and I don't know how to fix it.
Thanks in advance.
you called your class Bullet and your surface for that class bullet. When you are calling colliderect you are having it check bullet instead of Bullet or whatever you named the object of class Bullet

Categories

Resources