Posts: 1,145
Threads: 114
Joined: Sep 2019
Taking the following snippet, is it possible to create a pygame.Rect() and add it to a sprite group?
Been looking for awhile and not really found anything. Maybe just tired. lol.
In the following example, I can get func1 to display but, not sure how to add func2 to a sprites group.
Any help would be great.
import pygame
import sys
# Initiate pygame
pygame.init()
# Create some settings
size = (1280, 720)
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Shmup')
clock = pygame.time.Clock()
hud = pygame.sprite.Group()
def func1():
arect = pygame.Rect(30,10,125,25)
pygame.draw.rect(screen, 'green', arect)
def func2():
arect = pygame.Rect(30, 35, 125, 25)
hud.add(arect)
while True:
event = pygame.event.poll()
if event.type == pygame.QUIT:
sys.exit()
hud.update()
hud.draw(screen)
func1()
pygame.display.update()
clock.tick(60)
pygame.quit()
Posts: 6,825
Threads: 20
Joined: Feb 2020
Oct-25-2023, 01:34 PM
(This post was last modified: Oct-25-2023, 01:34 PM by deanhystad.)
Things in a sprite group must act like sprites. A sprite must have a rectangle attribute, not be a rectangle. A sprite must have an image (a surface), though I think you can get around that one by supplying your own update and draw methods. A function is not going to satisfy the requirements of being sprite-like.
Posts: 544
Threads: 15
Joined: Oct 2016
(Oct-25-2023, 04:25 AM)menator01 Wrote: Taking the following snippet, is it possible to create a pygame.Rect() and add it to a sprite group?
Been looking for awhile and not really found anything. Maybe just tired. lol.
In the following example, I can get func1 to display but, not sure how to add func2 to a sprites group.
Any help would be great.
import pygame
import sys
# Initiate pygame
pygame.init()
# Create some settings
size = (1280, 720)
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Shmup')
clock = pygame.time.Clock()
hud = pygame.sprite.Group()
def func1():
arect = pygame.Rect(30,10,125,25)
pygame.draw.rect(screen, 'green', arect)
def func2():
arect = pygame.Rect(30, 35, 125, 25)
hud.add(arect)
while True:
event = pygame.event.poll()
if event.type == pygame.QUIT:
sys.exit()
hud.update()
hud.draw(screen)
func1()
pygame.display.update()
clock.tick(60)
pygame.quit()
pygame.sprite.Group only except sprites.
sprite = pygame.sprite.Sprite()
# Sprite must have image and a rect variable.
sprite.rect = pygame.Rect(30, 35, 125, 25)
sprite.image = pygame.Surface(sprite.rect.size)
sprite.image.fill('green')
hud.add(sprite) When you learn classes.
class MySprite(pygame.sprite.Sprite):
def __init__(self, color, x, y, w, h):
super().__init__()
self.rect = pygame.Rect(x, y, w, h)
self.image = pygame.Surface(self.rect.size)
self.image.fill(color)
hud.add(MySprite('green', 30, 35, 125, 25))
99 percent of computer problems exists between chair and keyboard.
Posts: 1,145
Threads: 114
Joined: Sep 2019
I figured out how to do it but, took another route as I wasn't able to figure out how to make the bar decrease and change colors the lower it got.
Posts: 6,825
Threads: 20
Joined: Feb 2020
Something like this?
import pygame
import sys
import math
class StatusBar(pygame.sprite.Sprite):
def __init__(
self,
rect=(0, 0, 100, 10),
max_=1,
min_=0,
fg="white",
bg="black",
center=None,
colormap=None,
):
super().__init__()
self.rect = pygame.Rect(rect)
self.bar = pygame.Rect(0, 0, self.rect.width, self.rect.height)
self.image = pygame.Surface(self.rect.size)
self.colormap = dict(sorted(colormap.items())) if colormap else {}
self.fg = fg
self.bg = bg
self.max = max_
self.min = min_
self.range = self.max - self.min
self.center = center
self._value = 0
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
self._value = max(self.min, min(new_value, self.max))
def update(self):
if self.center is None:
self.bar.width = int(
self.rect.width * (self.value - self.min) / (self.max - self.min)
)
else:
a = self.rect.width * (self._value - self.min) / self.range
b = self.rect.width * (self.center - self.min) / self.range
self.bar.x = min(a, b)
self.bar.width = abs(a - b)
self.image.fill(self.bg)
fg = self.fg
for value, color in self.colormap.items():
if value <= self._value:
fg = color
else:
break
pygame.draw.rect(self.image, fg, self.bar)
pygame.init()
screen = pygame.display.set_mode((220, 90))
b1 = StatusBar((10, 10, 200, 10), min_=-1)
b2 = StatusBar(
(10, 30, 200, 10), min_=-1, colormap={-1: "green", 0: "yellow", 0.5: "red"}
)
b3 = StatusBar((10, 50, 200, 10), min_=-1, center=0)
b4 = StatusBar(
(10, 70, 200, 10),
min_=-1,
center=0,
colormap={
-1: "red",
-0.75: "orange",
-0.5: "yellow",
-0.25: "green",
0.25: "yellow",
0.5: "orange",
0.75: "red",
},
)
group = pygame.sprite.Group()
group.add((b1, b2, b3, b4))
clock = pygame.time.Clock()
for i in range(1000):
event = pygame.event.poll()
if event.type == pygame.QUIT:
sys.exit()
b1.value = math.sin(math.radians(i))
b2.value = math.cos(math.radians(i))
b3.value = math.sin(math.radians(i))
b4.value = math.cos(math.radians(i))
group.update()
group.draw(screen)
pygame.display.update()
clock.tick(60)
pygame.quit()
Posts: 1,145
Threads: 114
Joined: Sep 2019
@ deanhystad That looks good. I will have to study the math module. I'm not really familiar with cos and sin. Your example will help a great deal. Thanks.
Posts: 1,145
Threads: 114
Joined: Sep 2019
Oct-28-2023, 03:59 PM
(This post was last modified: Oct-28-2023, 03:59 PM by menator01.)
I've uploaded the files to git if anyone wants to check it out. Other than some unknown bugs I haven't come across yet, only thing left is for me too add the form to enter scores.
https://github.com/menator01/shmup2
I've finished the re-write.
The old script had everything in one file. The re-writes has modules that are imported. I broke down the classes into modules.
Depending on what that class does. There still may be some bugs that I've not found.
I've added some things too.
On the powerups that fall, if you catch one (there are only two - laser and shield), icons will apprear in the bottom right of the game window. They will disappear when done. Example - if you catch the shield icon and it gets destroyed, the icon will disappear. The laser is a timed powerup. To keep them, just have to keep catching them when they fall.
Requirements:- python 3.12
- pygame 2.5.2
- sqlite3
I welcome any feedback.
I've changed the shmup.py. Added a couple variables to set the range of mobs spawned. Had it hard coded so to speak to 8 - 10 mobs.
Now it just can be set the min_mob and max_mob right before the while loop starts.
import pygame
from modules import abient, pages, character, mysprites, display
from modules.character import player_sprite, mob_sprite, weapon_sprite
from modules.powerups import PowerUp, power_sprite, Shield, shield_sprite
from modules.effects import Explosion
import os
from random import random, randrange
# Initiate pygame
pygame.init()
# pygame clock
clock = pygame.time.Clock()
# Get the working directory path
path = os.path.realpath(os.path.dirname(__file__))
# Setup screen window
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption('Shmup')
# Background music and image
music = abient.Music(path)
bgimg = pygame.image.load(f'{path}/media/images/backgrounds/space.png')
bgimg_rect = bgimg.get_rect()
# Set some variables
gameover = True
doform = False
# range of mobs to spawn
min_mob = 10
max_mob = 15
# Start the game loop
while True:
# Start the background music
if not pygame.mixer.music.get_busy():
music.play()
# Display the background image
screen.blit(bgimg, bgimg_rect)
# Poll pygame events
event = pygame.event.poll()
# Ways to exit the game
if event.type == pygame.QUIT:
break
# Has a key been pressed
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
break
# Fire weapons
if event.key == pygame.K_m:
player.missile()
# We don't want the laser to fire without catching the icon first
if player.laser_fire:
if event.key == pygame.K_l:
player.laser()
else:
player.laser_fire = False
# We are not playing yet. Go to start title page
if gameover:
pages.Title(screen)
gameover = False
player = character.Player(path)
shield = Shield(path)
# Create some starting mobs
for i in range(randrange(min_mob, max_mob)):
mob = character.Mob(path)
# Used for displaying the three life ships
col = 0
for i in range(3):
ship = display.Hud(path, 1120+col)
col += 60
ship.newship()
# Is the game over? Do we need to go to the form
if doform:
pages.Form(screen, player)
doform = False
gameover = True
# Statusbars - Displays the info across the top including the life ships
display.StatusBar(screen, 100, 15, player.life, text='Life')
display.StatusBar(screen, 100, 45, shield.strength, text='Shield')
ship.hud_sprites.update()
ship.hud_sprites.draw(screen)
display.Score(screen, player.score)
display.Tips(screen, 880, 680)
# If player looses a life, remove ship from top
for item in ship.hud_sprites:
if len(ship.hud_sprites) > player.lives:
ship.hud_sprites.remove(item)
# Draw and update all the sprites
mysprites.allsprites.update()
mysprites.allsprites.draw(screen)
# Having to keep these seperate from allsprites to detect collisions
mob_sprite.update()
mob_sprite.draw(screen)
display.show_sprite.update()
display.show_sprite.draw(screen)
# Set weapon to True will get destroyed
weapon = True
# Loop through weapon_sprite if weapon type is laser,
# set weapon to True. laser will not be destroyed
for weapons in weapon_sprite:
weapon = True if weapons.type == 'missile' else False
# Check for weapon hitting mob
weaponhits = pygame.sprite.groupcollide(weapon_sprite, mob_sprite, weapon, True)
for weaponhit in weaponhits:
character.Mob(path)
player.score += int(mob.radius * random())
Explosion(path, weaponhit.rect.center)
if random() > 0.8:
PowerUp(path, weaponhit.rect.center)
#Detect powerup hit
powerhits = pygame.sprite.groupcollide(power_sprite, player_sprite, True, False)
# Loop through the powerup and apply accordingly
for powerhit in powerhits:
# Caught a shield icon
if powerhit.type == 'shield':
for shield in shield_sprite:
shield.kill()
shield = Shield(path)
shield.strength = 100
shield.raise_shield(player.rect.centerx, player.rect.top)
show_shield = display.Show(path, 'shield.png', 1195, 690)
display.show_sprite.add(show_shield)
# Caught a partial heal icon
if powerhit.type == 'heal':
sound = pygame.mixer.Sound(f'{path}/media/sounds/partial_heal.wav')
sound.set_volume(0.9)
sound.play()
if player.life == 100:
player.score += int(player.life * random())
else:
player.life += int(player.life * random())
if player.life > 100:
player.life = 100
# Caught a laser icon
if powerhit.type == 'laser':
player.laser_timer = pygame.time.get_ticks()
player.laser_fire = True
laser = display.Show(path, 'laser2.png', 1165, 690)
display.show_sprite.add(laser)
# Caught a full heal icon
if powerhit.type == 'fullheal':
sound = pygame.mixer.Sound(f'{path}/media/sounds/full_heal.wav')
sound.set_volume(0.9)
sound.play()
if player.life == 100:
player.score += int(randrange(10, 50) * random())
else:
player.life = 100
# Timer for laser. Laser ends after 10 seconds unless another
# laser powerup is caught
if player.laser_timer:
if pygame.time.get_ticks() - player.laser_timer > 10000:
player.laser_fire = False
player.laser_timer = None
# Laser end remove from icon from game screen
for item in display.show_sprite:
if item.type == 'laser2':
item.kill()
# Checking for mobs hitting the shield
shieldhits = pygame.sprite.groupcollide(mob_sprite, shield_sprite, True, False)
for shieldhit in shieldhits:
mob = character.Mob(path)
Explosion(path, shieldhit.rect.center)
# Shield was hit, remove some of the strength
shield.strength -= int(shield.radius *0.3)
# Shield strength reached 0, remove it
if shield.strength <= 1:
shield.strength = 0
for item in shield_sprite:
item.kill()
shield.hidden = True
# Lost shield remove icon from the game screen
for item in display.show_sprite:
if item.type == 'shield':
item.kill()
# Player takes hits from mobs
ship_destroy = False
if player.life <= 0:
ship_destroy = True
player.lives -= 1
player.life = 100
player.hide()
player.laser_fire = False
player.laser_timer = None
display.show_sprite.empty()
# If player looses all lifes, reset everything and go to form
if player.lives <= 0 and not player.explosion.alive():
mysprites.allsprites.empty()
display.show_sprite.empty()
mob_sprite.empty()
shield_sprite.empty()
ship.hud_sprites.empty()
doform = True
# Detect if any mobs has hit the player. We need to create a newmob for the one killed
mobhits = pygame.sprite.groupcollide(mob_sprite, player_sprite, True, False)
for mobhit in mobhits:
Explosion(path, mobhit.rect.center)
player.life -= int(mobhit.radius)
character.Mob(path)
# Update the display
pygame.display.update()
clock.tick(60)
pygame.quit()
Posts: 544
Threads: 15
Joined: Oct 2016
Oct-31-2023, 06:53 AM
(This post was last modified: Oct-31-2023, 07:00 AM by Windspar.)
Why are you using pygame.event.poll ? That does 1 event per frame. This will give you unwanted side effects.
running = True
while running:
# Event Loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Get Key States
keys = pygame.key.get_pressed()
if keys[pygame.K_m]:
# Fire Missle. Would need a timer for a refresh rate.
99 percent of computer problems exists between chair and keyboard.
Posts: 1,145
Threads: 114
Joined: Sep 2019
Perhaps but, it satisfies the need for the game. I've not found any side effects yet.
Posts: 544
Threads: 15
Joined: Oct 2016
Nov-01-2023, 03:23 AM
(This post was last modified: Nov-01-2023, 03:24 AM by Windspar.)
You probably don't know what side effects it will cause.
If you had more events trigger. You would notice lag on input.
99 percent of computer problems exists between chair and keyboard.
|