So I am trying to fade my screen out and back in after completing a level using PyGame. My problem is that only the fadeout() works and not the fadein(). When calling the fadein() the screen turns black for a few seconds then suddenly shows the next level. I can't find the problem, any ideas?
def fadeout():
fadeout = pg.Surface((screen_width, screen_height))
fadeout = fadeout.convert()
fadeout.fill(black)
for i in range(255):
fadeout.set_alpha(i)
screen.blit(fadeout, (0, 0))
pg.display.update()
def fadein():
fadein = pg.Surface((screen_width, screen_height))
fadein = fadein.convert()
fadein.fill(black)
for i in range(255):
fadein.set_alpha(255-i)
screen.blit(fadein, (0, 0))
pg.display.update()
Your problem is that you fade in to a black screen, so you don't see any effect. A black screen with a black half-translucent Surface drawn on top is still a black Surface.
You should render the first frame of your level, and blit that Surface to the screen before blitting the fadein surface onto the screen.
Here's a simple example that I hacked together. Press a key to switch from one scene to the next.
import pygame
import random
from itertools import cycle
class Cloud(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((50, 20))
self.image.set_colorkey((11, 12, 13))
self.image.fill((11, 12, 13))
pygame.draw.ellipse(self.image, pygame.Color('white'), self.image.get_rect())
self.rect = self.image.get_rect(topleft=(x,y))
def update(self, dt, events):
self.rect.move_ip(dt/10, 0)
if self.rect.left >= pygame.display.get_surface().get_rect().width:
self.rect.right = 0
class DayScene:
def __init__(self):
self.clouds = pygame.sprite.Group(Cloud(0, 30), Cloud(100, 40), Cloud(400, 50))
def draw(self, screen):
screen.fill(pygame.Color('lightblue'))
self.clouds.draw(screen)
def update(self, dt, events):
self.clouds.update(dt, events)
class NightScene:
def __init__(self):
sr = pygame.display.get_surface().get_rect()
self.sky = pygame.Surface(sr.size)
self.sky.fill((50,0,50))
for x in random.sample(range(sr.width), 50):
pygame.draw.circle(self.sky, (200, 200, 0), (x, random.randint(0, sr.height)), 1)
self.clouds = pygame.sprite.Group(Cloud(70, 70), Cloud(60, 40), Cloud(0, 50), Cloud(140, 10), Cloud(100, 20))
def draw(self, screen):
screen.blit(self.sky, (0, 0))
self.clouds.draw(screen)
def update(self, dt, events):
self.clouds.update(dt, events)
class Fader:
def __init__(self, scenes):
self.scenes = cycle(scenes)
self.scene = next(self.scenes)
self.fading = None
self.alpha = 0
sr = pygame.display.get_surface().get_rect()
self.veil = pygame.Surface(sr.size)
self.veil.fill((0, 0, 0))
def next(self):
if not self.fading:
self.fading = 'OUT'
self.alpha = 0
def draw(self, screen):
self.scene.draw(screen)
if self.fading:
self.veil.set_alpha(self.alpha)
screen.blit(self.veil, (0, 0))
def update(self, dt, events):
self.scene.update(dt, events)
if self.fading == 'OUT':
self.alpha += 8
if self.alpha >= 255:
self.fading = 'IN'
self.scene = next(self.scenes)
else:
self.alpha -= 8
if self.alpha <= 0:
self.fading = None
def main():
screen_width, screen_height = 300, 300
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()
dt = 0
fader = Fader([DayScene(), NightScene()])
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.KEYDOWN:
fader.next()
fader.draw(screen)
fader.update(dt, events)
pygame.display.flip()
dt = clock.tick(30)
main()
By abstracting each scene into it's own class and delegating the scene change to the Fader class, we're able to let the scenes continue (or add a simple if statement to prevent that) and to handle events while fading.
Related
I am developing a game in python 3.10.4 using pygame but I am struggling to generate a flow of user class objects in the main loop from a list using random.choice.
def run_game(self):
"""Start the main loop for the game."""
list_of_particles = [Particle__SO2(self),Particle__H20(self),Particle__CO2(self),Particle__H2S(self), Particle__CO2(self)]
while True:
self._check_events()
self.clock.tick(25)
new_particle = random.choice(list_of_particles)
self.particles.add(new_particle)
self._update_particles()
The code works but the list seemingly exhausts itself after generating each object exactly once and I am at a loss to see why. Full code below:
import sys
import pygame
from pygame.sprite import Sprite
import random
class Volcano_game:
"""Overall class to manage game assets and behavior."""
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.screen = pygame.display.set_mode((1920, 1080))
self.particles = pygame.sprite.Group()
self.vent_location_xy = (952, 881)
self.io_surface_y = 950
self.gravity = 1
self.clock = pygame.time.Clock()
self.alpha_surf = pygame.Surface(self.screen.get_size(), pygame.SRCALPHA)
def run_game(self):
"""Start the main loop for the game."""
list_of_particles = [Particle__SO2(self),Particle__H20(self),Particle__CO2(self),Particle__H2S(self), Particle__CO2(self)]
while True:
self._check_events()
self.clock.tick(25)
new_particle = random.choice(list_of_particles)
self.particles.add(new_particle)
self._update_particles()
self.update_screen()
self.alpha_surf.fill((255, 255, 255, 250),
special_flags=pygame.BLEND_RGBA_MULT)
def _update_particles(self):
"""Update position of particles and get rid of old particles."""
# Update bullet positions.
self.particles.update()
# Get rid of particles that have landed or gone off screen.
for particle in self.particles.copy():
if particle.y > self.io_surface_y:
self.particles.remove(particle)
elif particle.y < 0:
self.particles.remove(particle)
elif particle.x < 0:
self.particles.romove(particle)
elif particle.x > 1920:
self.particles.remove(particle)
def update_screen(self):
"""Update images on the screen, and flip to the new screen."""
self.screen.fill((0, 0, 0))
self.screen.blit(self.alpha_surf, (0, 0))
for particle in self.particles.sprites():
particle.draw_particle()
pygame.display.flip()
def _check_events(self):
"""Respond to keypresses and mouse events."""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
class Particle(Sprite):
"""a class to manage sprites fired from the volcano"""
def __init__(self, vg_game):
super().__init__()
self.screen = vg_game.alpha_surf
self.colour = (60, 255, 60)
self.rect_x = 952
self.rect_y = 881
self.y = self.rect_y
self.x = self.rect_x
self.speed_y = -15
self.speed_x = (random.randint(-11, 11))
self.gravity = vg_game.gravity
def update(self):
"""move the particle around the screen"""
# update the decimal position of the particle
self.y += self.speed_y
self.x += self.speed_x
self.speed_y += self.gravity
self.rect_y = self.y
self.rect_x = self.x
def draw_particle(self):
"""draw the particle on the screen"""
pygame.draw.circle(self.screen, self.colour,
(self.rect_x, self.rect_y), 2)
class Particle__SO2(Particle):
def __init__(self, vg_game):
super().__init__(vg_game)
self.colour = (255, 255, 255)
self.speed_y = -17
class Particle__H20(Particle):
def __init__(self, vg_game):
super().__init__(vg_game)
self.colour = (0, 0, 255)
self.speed_y = -52.5
class Particle__CO2(Particle):
def __init__(self, vg_game):
super().__init__(vg_game)
self.colour = (255, 0, 0)
self.speed_y = -24.72
class Particle__H2S(Particle):
def __init__(self, vg_game):
super().__init__(vg_game)
self.colour = (255, 255, 0)
self.speed_y = -31.9
if __name__ == '__main__':
# Make a game instance, and run the game.
vg = Volcano_game()
vg.run_game()
You just create 4 particle objects. You need to choose a random particle type (class) and create a new instance object of that type in each iteration of the loop:
class Volcano_game:
"""Overall class to manage game assets and behavior."""
# [...]
def run_game(self):
"""Start the main loop for the game."""
# EDIT:
# list_of_particles = [Particle__SO2(self),Particle__H20(self),Particle__CO2(self),Particle__H2S(self), Particle__CO2(self)]
list_of_particles = [Particle__SO2, Particle__H20, Particle__CO2, Particle__H2S, Particle__CO2]
while True:
self._check_events()
self.clock.tick(25)
# EDIT:
# new_particle = random.choice(list_of_particles)
new_particle = random.choice(list_of_particles)(self)
self.particles.add(new_particle)
self._update_particles()
self.update_screen()
self.alpha_surf.fill((255, 255, 255, 250), special_flags=pygame.BLEND_RGBA_MULT)
The list isn't being "exhausted". The problem is that you only have five particle objects - the ones you defined in list_of_particles. Once a given particle is no longer within your desired bounds you remove it from the volcano game's tracked list of particles (which is fine), but the particle instance itself doesn't get deleted or reset. Your main loop will happily pick a particle instance it has seen before, update its position (which will now be even further outside of your desired bounds), add it to the volcano game's list of tracked particles, and then immediately remove it.
I would suggest instead to randomly pick a type of particle, and then to instantiate that type, so that you have a brand new particle object each time. Something like:
particle_types = [Particle__SO2, Particle__H20, Particle__CO2, Particle__H2S] # Note: We are not instantiating any particle objects. We're creating a list of particle types - referring to the particle classes directly.
ParticleType = random.choice(particle_types)
particle = ParticleType(self)
self.particles.add(particle)
self._update_particles()
I have been following a guide to make my game. However, when I try to run the program I get a syntax Error with the Class Circle and not sure why? I can't figure out the reason and I'm sure there are more issue afterward the Class Circle but can't fix it.
import pygame
from pygame.locals import *
from uagame import Window
import time
import random
def main():
window = Window('Pong', 500, 400)
window.set_auto_update(False)
game = Game(window)
game.play()
window.close()
class Rect:
def __init__(self, center, radius, color, window):
self.center = center
self.radius = radius
self.color = color
self.window = window
def draw(self):
pygame.draw.rect(self.window.get_surface(), self.color, Rect((100, 200), (20, 30))
class Circle: # Syntax Error: class Circle:: <string>, line 28, pos 5
def __init__(self, center, radius, color, window):
self.center = center
self.radius = radius
self.color = color
self.window = window
def draw(self):
pygame.draw.circle(self.window.get_surface(), self.color, self.center,self.radius)
def get_color(self):
return self.color
def move(self):
window_size = (self.window.get_width() , self.window.get_height())
for index in range(0,2):
self.center[index] = (self.center[index] + 1) % window_size[index]
def enlarge(self,increment):
self.radius = self.radius + increment
class Game:
def __init__(self, window):
self.window = window
self.bg_color = pygame.Color('black')
self.fg_color = 'green'
self.rect_color = 'green'
self.pause_time = 0.02
self.close_clicked = False
self.continue_game = True
self.circle = Ball([200,200], 20, pygame.Color(self.fg_color),window)
self.rect = Rect([100,200], 50 , pygame.Color(self.fg_color),window)
self.radius_increment = 5
def play(self):
while not self.close_clicked:
self.handle_event()
self.draw()
if self.continue_game:
self.update()
self.decide_continue()
time.sleep(self.pause_time)
def handle_event(self):
event = pygame.event.poll()
if event.type == QUIT:
self.close_clicked = True
elif event.type == MOUSEBUTTONUP and self.continue_game:
self.handle_mouse_up()
def handle_mouse_up(self):
self.circle.enlarge(self.radius_increment)
def draw(self):
self.window.clear()
self.circle.draw()
self.rect.draw()
if not self.continue_game:
self.window.set_bg_color(self.fg_color)
self.window.clear()
self.window.update()
def update(self):
self.circle.move()
def decide_continue(self):
pass
main()
Your error actually lies in the line above. See that your code is missing a parenthesis to close the rect() function. Always remember to count the parenthesis on long functions like this.
def draw(self):
pygame.draw.rect(self.window.get_surface(), self.color, Rect((100, 200), (20, 30))) #<-
I must be able to move both: green and red (pair) by clicking and dragging one of them, while keeping their position relative to each other. I am not sure how to do it with the code I already have. Should I create another class for red rectangles or use Parent Child classes? Help greatly appreciated.
import pygame as pg
WHITE = (255, 255, 255)
GREEN = (33, 133, 33)
RED = (255, 0, 0)
SCREEN = pg.display.set_mode((700, 500))
clock = pg.time.Clock()
cT = 140 # cycle time
cNum = 3 # cyle number
class Rectangle(pg.sprite.Sprite):
def __init__(self, color, width, height, x, y):
super().__init__()
self.height = height
self.color = color
self.image = pg.Surface((width, height))
self.image.fill(color)
self.rect = self.image.get_rect(topleft=(x, y))
def move(self, rel_x, rel_y):
self.rect.move_ip(rel_x, rel_y)
def collidepoint(self, pos):
return self.rect.collidepoint(pos)
class Rect1():
def __init__(self, color, width, height, x, y, all_sprites):
self.height = height
self.selected1 = False
self.rect = pg.Rect((x, y, width, height))
self.rectangles = []
for z in range(0, cNum * cT, cT):
rect = Rectangle(color, width, height, x, self.rect.y - z + cT)
self.rectangles.append(rect)
all_sprites.add(rect)
def move(self, rel_x, rel_y):
self.rect.move_ip(rel_x, rel_y)
for r in self.rectangles:
r.move(rel_x, rel_y)
def collidepoint(self, pos):
for r in self.rectangles:
if r.rect.collidepoint(pos):
return True
def handle_event(self, event):
if event.type == pg.MOUSEBUTTONDOWN:
if self.collidepoint(event.pos):
self.selected1 = True
elif event.type == pg.MOUSEBUTTONUP:
self.selected1 = False
elif event.type == pg.MOUSEMOTION:
if self.selected1 :
self.move(0, event.rel[1])
class Connection():
def __init__(self, rect_1, rect_2, vel):
self.rect_1 = rect_1
self.rect_2 = rect_2
self.vel = vel
def draw(self, screen):
for r_1 in self.rect_1.rectangles:
for r_2 in self.rect_2.rectangles:
dist1 = r_2.rect.x - r_1.rect.x
velocity = int(dist1 * self.vel) # green wave angle
A_start_x, A_start_y = r_1.rect.topright
A_end_x, A_end_y = r_1.rect.bottomright
B_start_x, B_start_y = r_2.rect.topleft
B_end_x, B_end_y = r_2.rect.bottomleft
if B_start_y < A_start_y - velocity and B_end_y > A_start_y - velocity:
start_pos = (A_start_x, A_start_y)
end_pos = (B_start_x, A_start_y - velocity) # minus 50
pg.draw.aaline(screen, GREEN, start_pos, end_pos, 1)
if B_end_y > A_end_y - velocity and B_start_y < A_end_y - velocity:
start_pos = (A_end_x, A_end_y-1)
end_pos = (B_end_x, A_end_y - 1 - velocity) # minus 50
pg.draw.aaline(screen, RED, start_pos, end_pos, 1)
def main():
pg.init()
all_sprites = pg.sprite.Group()
objects = [
Rect1(GREEN, 10, 58, 55, 244, all_sprites ),
Rect1(GREEN, 10, 111, 188, 226, all_sprites ),
Rect1(RED, 10, 68, 69, 222, all_sprites),
Rect1(RED, 10, 121, 211, 202, all_sprites),]
conns = [
Connection(objects[0], objects[1], 0.1),
Connection(objects[2], objects[3], -0.1),]
done = False
clock = pg.time.Clock()
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
for o in objects:
o.handle_event(event)
SCREEN.fill(WHITE)
all_sprites.draw(SCREEN)
for c in conns:
c.draw(SCREEN)
pg.display.update()
clock.tick(60)
pg.quit()
if __name__ == '__main__':
main()
You could associate the rectangles by storing a reference to the other rectangle as an attribute (e.g. self.associated) and then update the associated rects as well in the handle_event method: self.associated.move(0, event.rel[1])
class Rect1():
def __init__(self, color, width, height, x, y, all_sprites, associated=None):
self.associated = associated
# Snip ...
def handle_event(self, event):
# Snip ...
elif event.type == pg.MOUSEMOTION:
if self.selected1 :
self.move(0, event.rel[1])
self.associated.move(0, event.rel[1])
def main():
# Snip ...
green_short = Rect1(GREEN, 10, 58, 55, 244, all_sprites)
red_short = Rect1(RED, 10, 68, 69, 222, all_sprites, green_short)
green_short.associated = red_short
green_long = Rect1(GREEN, 10, 111, 188, 226, all_sprites)
red_long = Rect1(RED, 10, 121, 211, 202, all_sprites, green_long)
green_long.associated = red_long
objects = [green_short, green_long, red_short, red_long]
Hey guys am developing a game with pygame. The idea of the game is that when a user click on start button on the menu(which appear on the first before starting a game) he must see the two balls bouncing on the pygame window.
For this i have two python files.
bounceball.py
This python file makes the two ball bounce on the pygame window which is made by me.The code of bounceball.py is
here.(Sorry for pasting it on pastebin since its a long code)
menu.py
This python file creates a menu which i have found from the internet and this also works fine.The code of menu.py is here
But the Problem is that when a user clicks on the Start button from the menu it didnt do anything .The thing i want is when a user clicks on start button from menu he must see the ball boucing which i have coded in bounceball.py on the pygame window.How can i link my bounceball.py to the menu.
I have tried to acheive this by many methods but it didnt helped me ..
Hope you guys can help me in acheieving this ..Any help would be appreciated ..Thanks in advance
It could be done better but at least it works.
menu.py
#!/usr/bin/python
import sys
import pygame
import bounceball
#----------------------------------------------------------------------
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
#----------------------------------------------------------------------
class MenuItem(pygame.font.Font):
def __init__(self, text, font=None, font_size=30,
font_color=WHITE, (pos_x, pos_y)=(0, 0)):
pygame.font.Font.__init__(self, font, font_size)
self.text = text
self.font_size = font_size
self.font_color = font_color
self.label = self.render(self.text, 1, self.font_color)
self.width = self.label.get_rect().width
self.height = self.label.get_rect().height
self.dimensions = (self.width, self.height)
self.pos_x = pos_x
self.pos_y = pos_y
self.position = pos_x, pos_y
def is_mouse_selection(self, (posx, posy)):
if (posx >= self.pos_x and posx <= self.pos_x + self.width) and \
(posy >= self.pos_y and posy <= self.pos_y + self.height):
return True
return False
def set_position(self, x, y):
self.position = (x, y)
self.pos_x = x
self.pos_y = y
def set_font_color(self, rgb_tuple):
self.font_color = rgb_tuple
self.label = self.render(self.text, 1, self.font_color)
#----------------------------------------------------------------------
class GameMenu():
def __init__(self, screen, items, funcs, bg_color=BLACK, font=None, font_size=30,
font_color=WHITE):
self.screen = screen
self.scr_width = self.screen.get_rect().width
self.scr_height = self.screen.get_rect().height
self.bg_color = bg_color
self.clock = pygame.time.Clock()
self.funcs = funcs
self.items = []
for index, item in enumerate(items):
menu_item = MenuItem(item, font, font_size, font_color)
# t_h: total height of text block
t_h = len(items) * menu_item.height
pos_x = (self.scr_width / 2) - (menu_item.width / 2)
pos_y = (self.scr_height / 2) - (t_h / 2) + (index * menu_item.height)
menu_item.set_position(pos_x, pos_y)
self.items.append(menu_item)
self.mouse_is_visible = True
self.cur_item = None
def set_mouse_visibility(self):
if self.mouse_is_visible:
pygame.mouse.set_visible(True)
else:
pygame.mouse.set_visible(False)
def set_keyboard_selection(self, key):
"""
Marks the MenuItem chosen via up and down keys.
"""
for item in self.items:
# Return all to neutral
item.set_italic(False)
item.set_font_color(WHITE)
if self.cur_item is None:
self.cur_item = 0
else:
# Find the chosen item
if key == pygame.K_UP and \
self.cur_item > 0:
self.cur_item -= 1
elif key == pygame.K_UP and \
self.cur_item == 0:
self.cur_item = len(self.items) - 1
elif key == pygame.K_DOWN and \
self.cur_item < len(self.items) - 1:
self.cur_item += 1
elif key == pygame.K_DOWN and \
self.cur_item == len(self.items) - 1:
self.cur_item = 0
self.items[self.cur_item].set_italic(True)
self.items[self.cur_item].set_font_color(RED)
# Finally check if Enter or Space is pressed
if key == pygame.K_SPACE or key == pygame.K_RETURN:
text = self.items[self.cur_item].text
self.funcs[text]()
def set_mouse_selection(self, item, mpos):
"""Marks the MenuItem the mouse cursor hovers on."""
if item.is_mouse_selection(mpos):
item.set_font_color(RED)
item.set_italic(True)
else:
item.set_font_color(WHITE)
item.set_italic(False)
def run(self):
mainloop = True
while mainloop:
# Limit frame speed to 50 FPS
self.clock.tick(50)
mpos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop = False
if event.type == pygame.KEYDOWN:
self.mouse_is_visible = False
self.set_keyboard_selection(event.key)
if event.type == pygame.MOUSEBUTTONDOWN:
for item in self.items:
if item.is_mouse_selection(mpos):
self.funcs[item.text]()
if pygame.mouse.get_rel() != (0, 0):
self.mouse_is_visible = True
self.cur_item = None
self.set_mouse_visibility()
# Redraw the background
self.screen.fill(self.bg_color)
for item in self.items:
if self.mouse_is_visible:
self.set_mouse_selection(item, mpos)
self.screen.blit(item.label, item.position)
pygame.display.flip()
#----------------------------------------------------------------------
def run_bounceball():
print "run bounceball"
bounceball.run(screen)
#----------------------------------------------------------------------
if __name__ == "__main__":
pygame.init()
# Creating the screen
screen = pygame.display.set_mode((300, 300), 0, 32)
menu_items = ('Start', 'Quit')
funcs = {'Start': run_bounceball,
'Quit': sys.exit}
pygame.display.set_caption('Game Menu')
gm = GameMenu(screen, funcs.keys(), funcs)
gm.run()
bounceball.py
import pygame
import math
from itertools import cycle
#----------------------------------------------------------------------
# some simple vector helper functions, stolen from http://stackoverflow.com/a/4114962/142637
def magnitude(v):
return math.sqrt(sum(v[i]*v[i] for i in range(len(v))))
def add(u, v):
return [ u[i]+v[i] for i in range(len(u)) ]
def sub(u, v):
return [ u[i]-v[i] for i in range(len(u)) ]
def dot(u, v):
return sum(u[i]*v[i] for i in range(len(u)))
def normalize(v):
vmag = magnitude(v)
return [ v[i]/vmag for i in range(len(v)) ]
#----------------------------------------------------------------------
class Ball(object):
def __init__(self, path, screen):
self.x, self.y = (0, 0)
self.speed = 2.5
self.color = (200, 200, 200)
self.path = cycle(path)
self.set_target(next(self.path))
self.screen = screen
#property
def pos(self):
return self.x, self.y
# for drawing, we need the position as tuple of ints
# so lets create a helper property
#property
def int_pos(self):
return map(int, self.pos)
#property
def target(self):
return self.t_x, self.t_y
#property
def int_target(self):
return map(int, self.target)
def next_target(self):
self.set_target(self.pos)
self.set_target(next(self.path))
def set_target(self, pos):
self.t_x, self.t_y = pos
def update(self):
# if we won't move, don't calculate new vectors
if self.int_pos == self.int_target:
return self.next_target()
target_vector = sub(self.target, self.pos)
# a threshold to stop moving if the distance is to small.
# it prevents a 'flickering' between two points
if magnitude(target_vector) < 2:
return self.next_target()
# apply the balls's speed to the vector
move_vector = [c * self.speed for c in normalize(target_vector)]
# update position
self.x, self.y = add(self.pos, move_vector)
def draw(self):
pygame.draw.circle(self.screen, self.color, self.int_pos, 4)
#----------------------------------------------------------------------
def run(screen):
#pygame.init() # no need it - inited in menu.py
#screen = pygame.display.set_mode((300, 300)) # no need it - created in menu.py
clock = pygame.time.Clock()
quit = False
path = [(26, 43),
(105, 110),
(45, 225),
(145, 295),
(266, 211),
(178, 134),
(250, 56),
(147, 12)]
path2 = [(26, 43),
(105, 10),
(45, 125),
(150, 134),
(150, 26),
(107, 12)]
ball = Ball(path, screen)
ball.speed = 1.9
ball2 = Ball(path2, screen)
ball2.color = (200, 200, 0)
balls = [ball, ball2]
while not quit:
quit = pygame.event.get(pygame.QUIT)
pygame.event.poll()
map(Ball.update, balls)
screen.fill((0, 0, 0))
map(Ball.draw, balls)
pygame.display.flip()
clock.tick(60)
Ok, so I am using pygame.draw to make a stick figure in the class called Entity:
class Entity: #Used with default arguments blited on a 600 by 600 pixel screen
def __init__(self, pos=[300, 300]):
self.pos = pos
self.legR = [10, 25]
self.legL = [-10, -25]
self.armR = [0, 0]
self.armL = [0, 0]
self.body = [30, 5]
self.head = [0, 0, 5]
self.size = [60, 110]
self.color = [0, 0, 0]
self.image = pygame.surface.Surface(self.size)
self.image.fill([255, 255, 255])
def render(self, screen, frame):
self.image = pygame.surface.Surface(self.size)
self.image.fill([255, 255, 255])
pygame.draw.line(self.image, self.color, [self.size[0]/2, self.size[1]/2],
[self.size[0]/2+self.legR[0], self.size[0]/2+self.legR[1]], 5)
pygame.draw.line(self.image, self.color, [self.size[0]/2, self.size[1]/2],
[self.size[0]/2+self.legL[0], self.size[0]/2+self.legL[1]], 5)
pygame.draw.line(self.image, self.color, [self.size[0]/2, self.size[1]/2],
[self.size[0]/2+self.body[0], self.size[0]/2+self.body[1]], self.body[1])
pygame.draw.circle(self.image, self.color,
[self.size[0]/2+self.body[0]+self.head[0], self.size[1]/2+self.body[1]+self.head[1]],
self.head[2])
#pygame.draw.line(self.image, self.color, [self.size/2
screen.blit(self.image, self.pos)
So I run this and it gives me this weird messed up image with a bunch of lines in random directions. It seams to me I do not really understand the function well. Could I please have a example of a render able stick figure with configurable joints? If not, could someone please at least tell me my fatal error? Thanks!
I started writing an example based off your code. For now it just draws 2 legs and his spine:
Note:
Using vectors instead of tuples would let you do return
self.pos+offset vs return (self.pos[0]+offset[0],
self.pos[1]+offset[1])
I use offsets relative a local origin to draw.
code:
import pygame
from pygame.locals import *
pygame.init()
# not normally all global, but simplified demo
color_bg = Color("gray20")
color_fg = Color("gray80")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((600,400))
class Entity():
def __init__(self, pos=(300, 300)):
self.pos = pos
self.armR = (10, 10)
self.armL = (-10, 10)
self.body = (0, -20)
self.head_offset = self.offset(self.body)
def offset(self, offset):
# get offset to draw, relative stickman's hips
return (self.pos[0]+offset[0], self.pos[1]+offset[1])
def render(self):
b = self.pos
#pygame.draw.line( screen, color_fg, (10,10), (20,30) )
o = self.offset( self.armL )
pygame.draw.line( screen, color_fg, b, o )
o = self.offset( self.armR )
pygame.draw.line( screen, color_fg, b, o )
o = self.offset( self.body )
pygame.draw.line( screen, Color("red"), b, o )
class Game():
def __init__(self):
self.e = Entity()
def draw(self):
screen.fill( color_bg )
self.e.render()
pygame.display.flip()
clock.tick(80)
def loop(self):
done=False
while not done:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT: done = True
# event: keydown
elif event.type == KEYDOWN:
if event.key == K_ESCAPE or event.key == K_SPACE: done = True
elif event.type == MOUSEMOTION:
self.mouse_loc = event.pos
self.draw()
g = Game()
g.loop()
The main problem I see is that you're using the x-value of your entity's size for the y-value of one of the points on your lines:
pygame.draw.line(self.image, self.color, [self.size[0]/2, self.size[1]/2],
[self.size[0]/2+self.legR[0], self.size[0]/2+self.legR[1]], 5)
The second value in the third argument should be:
self.size[1]/2+self.legR[1]
That will get you want you want rendered, but I would also takes monkey's advice and organize a bit and compartmentalize repeated code into functions.