Python/pygame flocking boids can't create borders [duplicate] - python

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Not letting the character move out of the window
(2 answers)
How to make ball bounce off wall with PyGame?
(1 answer)
Closed 1 year ago.
I'm new to python/pygame and I'm trying to make a boids simulation but can't seem to get to create the borders so that the boids don't go outside of the window. Here's what I've done so far.
#importing the needed modules and libraries
import pygame, sys, random, pygame.math
#Initialize pygame and pygame time
pygame.init()
clock = pygame.time.Clock()
#This is some screen settings, giving the screen size.
screen_width = 1000
screen_height = 750
screen = pygame.display.set_mode((screen_width, screen_height))
#Making the background, loading it and scaling the background to fit the screen.
background = pygame.image.load("Background.jpg")
background = pygame.transform.scale(background, (screen_width, screen_height))
#Make parent-class for boids and hoiks
class Moving_Object(pygame.sprite.Sprite):
def __init__(self, picture_load, X_pos, Y_pos): #speed_x, speed_y
super().__init__()
#Creating picture_load to make it easier to load image. Creating a rectangle around image
self.image = pygame.image.load(picture_load)
self.image = pygame.transform.scale(self.image, (40, 40))
#Make rectangle around image
self.rect = self.image.get_rect()
self.rect.center = [X_pos, Y_pos]
self.speed_x = random.randint(-3,3)
self.speed_y = random.randint(-3,3)
def border(self):
if self.rect.right >= screen_width or self.rect.left <= 0:
self.speed_x *= -1
if self.rect.bottom >= screen_height or self.rect.top <= 0:
self.speed_y *= -1
if self.rect.collidrect(boid):
print("yesir")
def update(self):
self.rect.x += self.speed_x
self.rect.y += self.speed_y
#making moving_object group and adding boids & hoiks
moving_object_group = pygame.sprite.Group()
for boid in range(50):
new_boid = Moving_Object("Logo.png", random.randrange(0, screen_width), random.randrange(0, screen_height))
moving_object_group.add(new_boid)
for hoiks in range(10):
new_hoik = Moving_Object('skullObstacle.png',random.randrange(0, screen_width), random.randrange(0, screen_height))
moving_object_group.add(new_hoik)
"""Game loo, it keeps the window open and checks
for events and calls differnt classes and methods"""
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.flip()
screen.blit(background, (0,0))
moving_object_group.draw(screen)
moving_object_group.update()
clock.tick(60)

Related

How do I make a sprite expand from its center using pygame.transform.scale? [duplicate]

This question already has answers here:
How do I scale a PyGame image (Surface) with respect to its center?
(1 answer)
How to change an image size in Pygame?
(4 answers)
Closed 12 hours ago.
I am making a game where I am trying to have an enemy grow in the air then drop like a bomb. For the most part, everything works well. The only problem I have is that it is while it is growing, it is moving down and right.
Here is the code I am using
import pygame
class BloodyTear(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.sprite=pygame.image.load('image')
self.image = self.sprite
self.rect = self.image.get_rect()
self.rect.x =500
self.rect.y = 50
self.size1 = 10
self.size2 = 10
self.mask = pygame.mask.from_surface(self.image)
self.size = self.size1, self.size2
def update(self):
if self.size1 < 135:
self.size1 += 1
self.size2 += 1
self.size = self.size1, self.size2
self.image = pygame.transform.scale(self.sprite, self.size)
if self.size1 == 135:
self.rect.y += 3
self.mask = pygame.mask.from_surface(self.image)
if self.rect.y >= 500:
self.kill()
def collide(self, spriteGroup):
if pygame.sprite.spritecollide(self, spriteGroup, True, pygame.sprite.collide_mask):
pass
pygame.init()
blood = BloodyTear()
window = pygame.display.set_mode((800, 800))
clock = pygame.time.Clock()
bloddsprite = pygame.sprite.Group()
bloddsprite.add(blood)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
bloddsprite.update()
window.fill(0)
bloddsprite.draw(window)
pygame.display.flip()
pygame.quit()
exit()
I tried using get_bounding_rect() but it didn't seem to change anything. I'm not sure exactly how to fix this.

How do I keep objects inside pygame surface when changing squared shape to a rectangle? [duplicate]

This question already has answers here:
Setting up an invisible boundary for my sprite
(1 answer)
Use vector2 in pygame. Collide with the window frame and restrict the ball to the rectangular area
(1 answer)
Create a border in PyGame
(1 answer)
Not letting the character move out of the window
(2 answers)
Closed 13 days ago.
In playing around with pygame capabilities I prepare to code a game of my own. While most of pygame's examples display surfaces like squares, I'd like to run with a rectangular shape resembling that of a cell phone screen. Initially, I'd expect that simply reshaping a GfG example picked up on the internet would do the job, yet I realize that objects do not stay inside the new rectangular shape when moving a sprite around with keyboard arrows.
I attempted to adjust width and height of surface (changed from (500, 500)):
# Global Variables
COLOR = (255, 100, 98)
SURFACE_COLOR = (167, 255, 100)
WIDTH = 580
HEIGHT = 250
But the squared object that I can control keeps continuing outside the new rect shape.
Any suggestions on how to proceed?
My playground code picked up on www.geeksforgeeks.org looks as follows:
import random
import pygame
# Global Variables
COLOR = (255, 100, 98)
SURFACE_COLOR = (167, 255, 100)
WIDTH = 580
HEIGHT = 250
# Object class
class Sprite(pygame.sprite.Sprite):
def __init__(self, color, height, width):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(SURFACE_COLOR)
self.image.set_colorkey(COLOR)
pygame.draw.rect(self.image,
color,
pygame.Rect(0, 0, width, height))
self.rect = self.image.get_rect()
def moveRight(self, pixels):
self.rect.x += pixels
def moveLeft(self, pixels):
self.rect.x -= pixels
def moveForward(self, speed):
self.rect.y += speed * speed/10
def moveBack(self, speed):
self.rect.y -= speed * speed/10
pygame.init()
RED = (255, 0, 0)
size = (WIDTH, HEIGHT)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Controlling Sprite")
all_sprites_list = pygame.sprite.Group()
playerCar = Sprite(RED, 20, 30)
playerCar.rect.x = 150
playerCar.rect.y = 150
all_sprites_list.add(playerCar)
exit = True
clock = pygame.time.Clock()
while exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
exit = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
playerCar.moveLeft(5)
if keys[pygame.K_RIGHT]:
playerCar.moveRight(5)
if keys[pygame.K_DOWN]:
playerCar.moveForward(5)
if keys[pygame.K_UP]:
playerCar.moveBack(5)
all_sprites_list.update()
screen.fill(SURFACE_COLOR)
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()

Make enemy go backward

I am making a space invaders game where the enemy hits the left or right side of the screen it will go down. However, I am struggling to figure out how to do the same thing but in reverse. So when it hits the end of the screen it will move left/right. Here is the code for the enemy.
import pygame
import random
# Initialize Pygame
pygame.init()
# Creates the screen for pygame
screen = pygame.display.set_mode((1000, 800))
#Enemy1
enemy1image = pygame.image.load('Enemy1.png')
enemy1image = pygame.transform.scale(enemy1image, (80, 80))
#Make it appear in a random cordinate
enemy1X = random.randint (0,1000)
enemy1y = random.randint(40,300)
enemy1X_change = 3
enemy1Y_change = 30
enemy1y_change_reverse = -30
def enemy1(x,y):
#Draws Enemy1 on screen
screen.blit(enemy1image,(x,y))
#Enemy1 Movement/boundaries
enemy1X += enemy1X_change
enemy1(enemy1X, enemy1y)
#Every time the enemy hits the boundary, it moves down
if enemy1X <= 0:
enemy1X_change = 4
enemy1y += enemy1Y_change
elif enemy1X >= 917:
enemy1X_change = -4
enemy1y += enemy1Y_change
It is difficult to answer what is specifically wrong with your code without a Minimal, Reproducible Example. Your concept appears valid, when you hit the boundary, change direction, move down and increase speed.
Here is an example that creates sprites that exhibit space-invader style movement. It it a little more effort to create sprites, but they make handling multiple game entities much easier.
import pygame
import random
screen = pygame.display.set_mode((800, 800))
pygame.init()
sprite_list = pygame.sprite.Group()
class Block(pygame.sprite.Sprite):
"""A block that moves like a space invader"""
def __init__(self, size, pos):
pygame.sprite.Sprite.__init__(self)
self.size = size
self.image = pygame.Surface([size[0], size[1]])
self.image.fill(pygame.color.Color("blueviolet"))
self.rect = self.image.get_rect()
self.rect.x = pos[0]
self.rect.y = pos[1]
self.speedx = random.randint(-5, 5) # note: includes zero
self.speedy = size[1] # this only changes on edge collission
def update(self):
"""move across the screen, skip down a row when at the edge"""
width, height = screen.get_size()
if not 0 < self.rect.x < (width - self.size[0]):
self.speedx *= -1 # reverse direction
self.rect.y += self.speedy
self.rect.x += self.speedx
if self.rect.y > (height - self.size[1]):
self.kill()
# Create some random blocks in random positions
for _ in range(5):
invader = Block(
(random.randint(80, 100), random.randint(80, 100)), # size
(random.randint(0, 800), random.randint(0, 800)), # position
)
sprite_list.add(invader)
run = True
clock = pygame.time.Clock()
while run:
## Handle Events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONUP:
# create block on mouse click
invader = Block((random.randint(80, 100), random.randint(80, 100)), event.pos)
sprite_list.add(invader)
## Clear background
screen.fill("white")
## Update Sprites
sprite_list.update()
## Draw Sprites
sprite_list.draw(screen)
## Update Screen
pygame.display.update()
clock.tick(60) # limit to 60 FPS
pygame.quit()

TypeError: pygame.sprite.Sprite.add() argument after * must be an iterable, not Game [duplicate]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I am trying to learn Python and wanted to practice with Pygame. I am currently using Python 3.6.5 and running the code in Atom 1.27.2 and installed the atom-runner package. I have been following the KidsCanCode tutorial for Pygame on Youtube.
I wanted to change the code around so I am not just copying the tutorial. At the moment everything works until I try to spawn a bullet from my ship. The bullet is supposed to go from the left to right, spawning from the ship on the left side of the screen. Once the program loads all ships are moving as expected with collisions working, however when I hit space bar the game crashes with the following error:
TypeError: add() argument after * must be an iterable, not int
I thought it has to do with my player.shoot function but if I remove the function and try to spawn the bullet under...
if event.key == pg.K_SPACE:
It still doesn't work.
I have the code similar to the code on the video but it still doesn't seem to work. Maybe it has to do with my .rect positions for the bullet, but at this point I am not really sure. Any help would be appreciated.
import pygame as pg
import random
import os
WIDTH = 1200
HEIGHT = 700
FPS = 60
#-----define colors-----
WHITE = (255,255,255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# set up assets folders
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, 'graphics')
pg.init()
pg.mixer.init()
screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption('First Game')
clock = pg.time.Clock()
# ------Load graphics-------------
player_img = pg.image.load(os.path.join(img_folder, 'blueship1.png')).convert()
enemy1_img = pg.image.load(os.path.join(img_folder, 'enemy1.png')).convert()
# ------------ Sprite for the player---------
class Player(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.transform.scale(player_img, (80, 60))
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.midleft = (0, HEIGHT / 2)
self.speedx = 0
self.speedy = 0
def update(self):
self.rect.x += self.speedx
self.speedy = 0
keystate = pg.key.get_pressed()
if keystate[pg.K_UP]:
self.speedy = -5
if keystate[pg.K_DOWN]:
self.speedy = 5
self.rect.y += self.speedy
if self.rect.bottom > HEIGHT:
self.rect.bottom = HEIGHT
if self.rect.top < 0:
self.rect.top = 0
def shoot(self):
laser = laser1(self.rect.midright, self.rect.centery)
all_sprites.add(laser)
lasers.add(laser)
class Enemy1(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.transform.scale(enemy1_img, (80, 60))
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.rect.x = random.randrange(WIDTH + 40, WIDTH + 100)
self.speedx = random.randrange(-8, -1)
def update(self):
self.rect.x += self.speedx
if self.rect.right < 0:
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.rect.x = random.randrange(WIDTH + 40, WIDTH + 100)
self.speedx = random.randrange(-8, -1)
class laser1(pg.sprite.Sprite):
def __int__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((10, 5))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.centery = y
self.rect.left = x
self.speedx = 15
def update(self):
self.rect.x += self.speedx
#kill at right side of screen
if self.rect.left > WIDTH:
self.kill()
# ---initializes pygame and creates window---
all_sprites = pg.sprite.Group()
mobs = pg.sprite.Group()
lasers = pg.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
m = Enemy1()
all_sprites.add(m)
mobs.add(m)
# --------------Game loop-----------------
running = True
while running:
# ------keep loop running at right speed-----
clock.tick(FPS)
# ------Process input (events)--------
for event in pg.event.get():
#check for closing window
if event.type == pg.QUIT:
running = False
elif event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
player.shoot()
# ----------Update---------------
all_sprites.update()
# --------------Checking for Collisions----------------
hits = pg.sprite.spritecollide(player, mobs, False)
if hits:
running = False
# ---------Draw / render----------------
screen.fill(BLACK)
all_sprites.draw(screen)
# flip after drawing
pg.display.flip()
The issue is caused by a typo. The name of the constructor is __init__ rather than __int__
def __int__(self, x, y):
def __init__(self, x, y):

Why is my pygame application loop not working properly?

I am working on a very rough topdown 2d adventure game after skimming around the pygame documentation. However, I have hit a bit of a roadblock after not being able to find anything on a camera system and found that most tutorials for a camera are 5+ years old and don't seem to work anymore. Can anybody help me build a camera?
This is my main executed script
import sys, pygame
from PlayerObject import Player
pygame.init()
screen_height = 180
screen_width = 320
map_height = 1080
map_width = 1920
num_objects = 5
screen = pygame.display.set_mode((screen_width, screen_height))
player_image = pygame.image.load('models/hero.bmp').convert()
background = pygame.image.load('models/lobby.bmp').convert()
screen.blit(background, (0, 0))
objects = []
# randomly generates 5 entities with the 1st one being the controlled character
for i in range(num_objects):
o = Player(player_image, random.randint(0, screen_width), random.randint(0, screen_height), 10)
objects.append(o)
while 1:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_left()
screen.blit(objects[0].image, objects[0].pos)
if keys[pygame.K_RIGHT]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_right()
screen.blit(objects[0].image, objects[0].pos)
if keys[pygame.K_UP]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_up()
screen.blit(objects[0].image, objects[0].pos)
if keys[pygame.K_DOWN]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_down()
screen.blit(objects[0].image, objects[0].pos)
screen.blit(background)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
for o in objects:
screen.blit(background, o.pos, o.pos)
for num in range(num_objects - 1):
objects[num + 1].rand_move()
for o in objects:
screen.blit(o.image, o.pos)
pygame.display.update()
pygame.time.delay(100)
This is my Player class
import random
map_height = 180
map_width = 320
class Player:
def __init__(self, image, width, height, speed):
self.speed = speed
self.image = image
self.pos = image.get_rect().move(width, height)
self.image = image
def set_speed(self, speed):
self.speed = speed
def rand_move(self):
x = random.randint(-self.speed, self.speed)
y = random.randint(-self.speed, self.speed)
self.pos = self.pos.move(x, y)
# keeps player in boundaries
if self.pos.left < 0:
self.pos.left = 0
if self.pos.right > map_width:
self.pos.right = map_width
if self.pos.top < 0:
self.pos.top = 0
if self.pos.bottom > map_height:
self.pos.bottom = map_height
def move_left(self):
speed = self.speed
self.pos = self.pos.move(-speed, 0)
if self.pos.left < 0:
self.pos.left = 0
def move_right(self):
speed = self.speed
self.pos = self.pos.move(speed, 0)
if self.pos.right > map_width:
self.pos.right = map_width
def move_up(self):
speed = self.speed
self.pos = self.pos.move(0, -speed)
if self.pos.top < 0:
self.pos.top = 0
def move_down(self):
speed = self.speed
self.pos = self.pos.move(0, speed)
if self.pos.bottom > map_height:
self.pos.bottom = map_height
Your basic misunderstanding, is that you try to draw the background at the position of an object, then you move the object and blit it finally on its new position. That all is not necessary.
In common the entire scene is drawn in each frame in the main application loop. It is sufficient to draw the background to the entire window and blit each object on top of it. Note, you do not see the changes of the window surface immediately. The changes become visible, when the display is updated by pygame.display.update() or pygame.display.flip():
The main application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
e.g.:
while 1:
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# update objects (depends on input events and frames)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
objects[0].move_left()
if keys[pygame.K_RIGHT]:
objects[0].move_right()
if keys[pygame.K_UP]:
objects[0].move_up()
if keys[pygame.K_DOWN]:
objects[0].move_down()
for num in range(num_objects - 1):
objects[num + 1].rand_move()
# draw background
screen.blit(background, (0, 0))
# draw scene
for o in objects:
screen.blit(o.image, o.pos)
# update dispaly
pygame.display.update()
pygame.time.delay(100)
Minimal example: repl.it/#Rabbid76/PyGame-MinimalApplicationLoop

Categories