Lightning Function Python - python

I am currently working on writing a function as part of a functions assignment. I am using python 2.7.5 and pygame. We are supposed to write a recursive function that draws lighting. I am currently having an error with my code but I do not know what it is. Here is my code:
from math import *
from pygame import *
from random import *
screen=display.set_mode((800,600))
def lightning(screen,x,y,size,ang):
if size > 5:
rang = radians(ang)
x2 = x-size*cos(rang)
y2 = y+size*sin(rang)
draw.line(screen,(200,180,0),(x,y),(x2,y2))
lightning(screen,x2,y2,size-randint(1,10),ang-randint(-20,10))
lightning(screen,x2,y2,size-randint(1,10),ang+randint(-10,30))
lightning(screen,400,0,100,randint(60,100))
running=True
while running:
for evt in event.get():
if evt.type==QUIT:
runnning=False
screen.fill((0,0,0))
lightning(screen,400,0,100,randint(60,100))
time.wait(500)
display.flip()
quit()
Currently, when I try to add another line of lightning (the "lightning(...)") it does not display any error in the shell and also does not display anything in the pygame window. When I have only one line, the lightning functions properly. I would just like to know where my error is and reasons to why it is causing the error. Any help is appreciated. Thanks.

For size=100 function ligthning() is call 800 000 to 3 500 000 times.
If you add another line of lightning it gives you even 7 000 000 calls.
Maybe You don't see result because it works too long. Try your code for smaller size.
My code to count ligthning() calls.
from math import *
from pygame import *
from random import *
#---------------------------------------------------------------------
def lightning(screen, x, y, size, ang, count):
if size > 5:
rang = radians(ang)
x2 = x-size*cos(rang)
y2 = y+size*sin(rang)
draw.line(screen,(200,180,0),(x,y),(x2,y2))
count = lightning(screen,x2,y2,size-randint(1,10),ang-randint(-20,10), count)
count = lightning(screen,x2,y2,size-randint(1,10),ang+randint(-10,30), count)
return count + 1
#---------------------------------------------------------------------
screen = display.set_mode((800,600))
#lightning(screen,400, 0, 100, randint(60,100))
running = True
while running:
for evt in event.get():
if evt.type == QUIT:
running = False
elif evt.type == KEYDOWN:
if evt.key == K_ESCAPE:
running = False
screen.fill((0,0,0))
print 'count: ', lightning(screen, 400, 0, 100, randint(60,100), 0)
display.flip()
#time.wait(500)
quit()
EDIT:
Theoretically radint(1,10) can always give 1 so you can always have lightning(...,size-1, ...) and for size=100it can give 2**95 calls.
2**95 = 39 614 081 257 132 168 796 771 975 168L

Related

Generative Art in Python- Upstream Logic causing "Invalid Literal for int()"

I'm a novice coder working on a small generative art exercise to make space-invader sprites, have been stuck on this for a while even though it's probably a trivial problem. The goal of the code is to allow the user to define their own inputs in the command line for a grid of sprite characters, like this:
python spritething.py [SPRITE_DIMENSIONS] [NUMBER] [IMAGE_SIZE]
'''
import PIL, sys, random
from PIL import Image, ImageDraw
origDimension = 1500
r = lambda: random.randint(50,255)
rc = lambda: ('#%02X%02X%02X' % (r(),r(),r()))
listSym = []
def create_square(border, draw, randColor, element, size):
if (element == int(size/2)):
draw.rectangle(border, randColor)
elif (len(listSym) == element+1):
draw.rectangle(border,listSym.pop())
else:
listSym.append(randColor)
draw.rectangle(border, randColor)
def create_invader(border, draw, size):
x0, y0, x1, y1 = border
squareSize = (x1-x0)/size
randColors = [rc(), rc(), rc(), (0,0,0), (0,0,0), (0,0,0)]
i = 1
for y in range(0, size):
i *= -1
element = 0
for x in range(0, size):
topLeftX = x*squareSize + x0
topLeftY = y*squareSize + y0
botRightX = topLeftX + squareSize
botRightY = topLeftY + squareSize
create_square((topLeftX, topLeftY, botRightX, botRightY), draw, random.choice(randColors), element, size)
if (element == int(size/2) or element == 0):
i *= -1;
element += i
def main(size, invaders, imgSize):
origDimension = imgSize
origImage = Image.new('RGB', (origDimension, origDimension))
draw = ImageDraw.Draw(origImage)
invaderSize = origDimension/invaders
padding = invaderSize/size
for x in range(0, invaders):
for y in range(0, invaders):
topLeftX = x*invaderSize + padding/2
topLeftY = y*invaderSize + padding/2
botRightX = topLeftX + invaderSize - padding
botRightY = topLeftY + invaderSize - padding
create_invader((topLeftX, topLeftY, botRightX, botRightY), draw, size)
origImage.save("Examples/Example-"+str(size)+"x"+str(size)+"-"+str(invaders)+"-"+str(imgSize)+".jpg")
if __name__ == "__main__":
main(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
'''
When I run this code I get a value error from the last line where the argv's are soposed to go. but I'm not sure where I'm going wrong upstream. Any help greatly appreciated.
'''
---------------------------------------------------------------------------
ValueError Traceback (most recent call
15
16 if __name__ == "__main__":
---> 17 main(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
ValueError: invalid literal for int() with base 10: '--ip=127.0.0.1'
'''
Assuming you've got a Python script script.py:
import sys
print(sys.argv)
And you run it from the terminal via:
python script.py firstarg 123 thirdarg
The output will be:
['script.py', 'firstarg', '123', 'thirdarg']
Notice: sys.argv is a list of strings, where each string represents one of the command line arguments passed in when the script was initially executed. Also notice that the first command line argument will always be a string with the script file's name. Even if you run the same script with no "custom" command line arguments, your program will always get at least one command line argument by default (the script's name.)
EDIT - Here is the image that's generated when I run your script (no changes):

Is there a way to control the FPS in Pygame Zero?

I'm working on a simple project using pygame zero and so far I've been able to display a group of images to form a very simple animation. I rendered the video out into a .png sequence at 60 fps. It seems like pygame zero is rendering them out a bit faster than that and I was just wondering if there was a way to lock the FPS to 60 so everything would render as I'd expect it to. I have some sound files that I'd like to sync up with the image sequence, so having them render at a constant FPS would be very helpful.
I've also noticed that the sound keeps looping after it's played, so I tried to stop it after it's played, but the sound cuts off at the end because the animation seems to be finishing too early.
Here's the code I have so far:
import pgzrun
WIDTH = 480
HEIGHT = 360
# boot1 graphics
boot1 = Actor('boot1_1')
boot1.frame = 1
boot1.active = True
# boot2 graphics
boot2 = Actor('boot2_1')
boot2.frame = 1
boot2.active = False
# overlay
overlay = Actor("overlay_a")
def update_boot1():
if boot1.active:
boot1.x = WIDTH/2
boot1.image = "boot1_{}".format(boot1.frame)
boot1.frame += 1
else:
boot1.x = 1000
if boot1.frame > 59:
#boot1.frame = 1
boot2.active = True
update_boot2()
boot1.active = False
def update_boot2():
if boot2.active:
boot2.x = WIDTH/2
sounds.boot1.play()
boot2.image = "boot2_{}".format(boot2.frame)
boot2.frame += 1
else:
boot2.x = 1000
if boot2.frame > 233:
boot2.frame = 233
boot2.active = False
sounds.boot1.stop()
def draw():
screen.clear
screen.fill((0, 75, 0))
boot2.draw()
boot1.draw()
overlay.draw()
# running the animation
def update(dt):
update_boot1()
update_boot2()
pgzrun.go()
I also haven't found a way to "unload" the image sequences, or make them not visible when I'm done with them, so I just throw them off to the side with ".x = 1000".
in your running loop, just use:
just use clock.tick(60)#or whatever fps you want

TypeError: argument 1 must be pygame.Surface, not str [Pygame using buttons]

Hello I'm creating a game using pygame and I had some problems. I create some buttons (using images)and depending in some actions the Image of this buttons will change.I will show you the the part of the code where there is the Error.
And sorry, but I'm Spanish, and my English is bad. This is the code:
import pygame
from pygame.locals import *
import time
pygame.init()
display_weight = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_weight, display_height), pygame.RESIZABLE)
pygame.display.set_caption("I NEED HELP :d")
clock = pygame.time.Clock()
#BUTTONS IMAGE
default_ap = pygame.image.load('button_menu_ap.png')
default_ip = pygame.image.load('button_menu_ip.png')
chewbacca_ip = pygame.image.load('button_select_GalaxyWars_chewbacca_ip.png')
chewbacca_ap = pygame.image.load('button_select_GalaxyWars_chewbacca_ap.png')
def button_img(x,y,w,h,ip,ap,action=None,especific1=None,especific2=None,especific3=None,especific4=None,especific5=None,especific6=None\
,especific7=None,especific8=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse [1] > y:
gameDisplay.blit(ap, (x,y))
if click [0] == 1 and action != None:
if especific1 != None:
if especific2 != None:
if especific2 != None and especific3 != None and especific4 != None and especific5 != None and especific6 != None \
and especific7 != None and especific8 != None:
action(especific1, especific2, especific3, especific4, especific5, especific6, especific7, especific8)
else:
action(especific1, especific2)
else:
action(especific1)
else:
action()
else:
gameDisplay.blit(ip, (x,y))
pygame.display.update()
def select_p1(nombre):
nombre_ip = (nombre + '_ip')
nombre_ap = (nombre + '_ap')
return button_img(display_weight/2-300,display_height/2-250,100,100,nombre_ip,nombre_ap,select_categoria,1,nombre)
pygame.display.update()
def select_categoria(num):
global gameDisplay, display_weight,display_height
select_categoria = True
gameDisplay.fill((255,255,255))
while select_categoria:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
# Este es el código que redimensiona la ventana
if event.type == VIDEORESIZE:
# Recrea la ventana con el nuevo tamaño
display_weight = event.w
display_height = event.h
gameDisplay = pygame.display.set_mode((display_weight, display_height),
pygame.RESIZABLE)
button_img(display_weight/2-125,display_weight/2-125,250,60,button_select_categoria_ip,button_select_categoria_ap, select_GalaxyWars, num)
pygame.display.update()
clock.tick(15)
clock.tick(15)
select_p1 ('default')
Then the Error is that one:
Traceback (most recent call last):
File "C:/Users/win/Desktop/MARCOS/PYTHON/PROYECTO HGA/HELP.py", line 73,
in <module>
select_p1 ('default')
File "C:/Users/win/Desktop/MARCOS/PYTHON/PROYECTO HGA/HELP.py", line 46,
in select_p1
return button_img(display_weight/2-300,display_height/2-
250,100,100,nombre_ip,nombre_ap,select_categoria,1,nombre)
File "C:/Users/win/Desktop/MARCOS/PYTHON/PROYECTO HGA/HELP.py", line 39,
in button_img
gameDisplay.blit(ip, (x,y))
TypeError: argument 1 must be pygame.Surface, not str
For Example in the last line of the code:
select_p1 ('default')
If I put 'default', the images be the ones call default_ap and default_ip, those ones:
default_ap = pygame.image.load('button_menu_ap.png')
default_ip = pygame.image.load('button_menu_ip.png')
And if I put chewbacca, the images will be the ones call chewbacca_ap and chewbacca_ip.
Please, is someone knows a way to solve my problem, please tell me.
The error is self explanatory:
gameDisplay.blit(ip, (x,y))
TypeError: argument 1 must be pygame.Surface, not str
The object ip should be a pygame.Surface, instead it is an str. Perhaps you want to create a dictionary:
button_image_dict = {'default_ip': default_ip,
'default_ap': default_ap,
'chewbacca_ip': chewbacca_ip,
'chewbacca_ap': chewbacca_ap}
And then use this dictionary to find the object from the string:
gameDisplay.blit(button_image_dict[ip], (x,y))
I have a dictionary of characters: cheracters = {'default':0,'chewbacca':1,'Stormsoldier':2}
First, I think that should be a list. All you're storing is item positions.
If I understand what you're trying to do, you want a dictionary for the images
For example
ap = {
'default' : 'button_menu_ap.png',
'chewbacca' : 'button_select_GalaxyWars_chewbacca_ap.png'
}
nombre = 'chewbacca'
chewbacca_ap = pygame.image.load(ap[nombre])

I have trouble, j = pygame.joystick.Joystick()

My example code from google.
#!/usr/bin/env python
import pygame
from pygame import
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
# Initialise the pygame library
pygame.init()
# Connect to the first JoyStick16:11:10:05:0B:1C
j = pygame.joystick.Joystick(0)
j.init()
print 'Initialized Joystick : %s' % j.get_name()
# Setup the various GPIO values, using the BCM numbers for now
MotorA0 = 16
MotorA1 = 18
MotorAE = 22
MotorB0 = 23
MotorB1 = 21
MotorBE = 19
16:11:10:05:0B:1C
A0 = False
A1 = False
B0 = False
B1 = False
GPIO.setup(MotorA0,GPIO.OUT)
GPIO.setup(MotorA1,GPIO.OUT)
GPIO.setup(MotorAE,GPIO.OUT)
GPIO.setup(MotorB0,GPIO.OUT)
GPIO.setup(MotorB1,GPIO.OUT)
GPIO.setup(MotorBE,GPIO.OUT)
# Set all the Motors to 'off'
GPIO.output(MotorA0, A0)
GPIO.output(MotorA1, A1)
GPIO.output(MotorAE, False)
GPIO.output(MotorBE, False)
GPIO.output(MotorB0, B0)
GPIO.output(MotorB1, B1)
# Only start the motors when the inputs go above the following threshold
threshold = 0.60
LeftTrack = 0
RightTrack = 0
# Configure the motors to match the current settings.
def setmotors():
GPIO.output(MotorA0, A0)
GPIO.output(MotorA1, A1)
GPIO.output(MotorAE, True)
GPIO.output(MotorBE, True)
GPIO.output(MotorB0, B0)
GPIO.output(MotorB1, B1)
# Try and run the main code, and in case of failure we can stop the motors
try:
# Turn on the motors
GPIO.output(MotorAE, True)
GPIO.output(MotorBE, True)
# This is the main loop
while True:
# Check for any queued events and then process each one
events = pygame.event.get()
for event in events:
UpdateMotors = 0
# Check if one of the joysticks has moved
if event.type == pygame.JOYAXISMOTION:
if event.axis == 1:
LeftTrack = event.value
UpdateMotors = 1
elif event.axis == 3:
RightTrack = event.value
UpdateMotors = 1
# Check if we need to update what the motors are doing
if UpdateMotors:
# Check how to configure the left motor
# Move forwards
if (RightTrack > threshold):
A0 = False
A1 = True
# Move backwards
elif (RightTrack < -threshold):
A0 = True
A1 = False
# Stopping
else:
A0 = False
A1 = False
# And do the same for the right motor
if (LeftTrack > threshold):
B0 = False
B1 = True
# Move backwards
elif (LeftTrack < -threshold):
B0 = True
B1 = False
# Otherwise stop
else:
B0 = False
B1 = False
# Now we've worked out what is going on we can tell the
# motors what they need to do
setmotors()
except KeyboardInterrupt:
# Turn off the motors
GPIO.output(MotorAE, False)
GPIO.output(MotorBE, False)
j.quit()#!/usr/bin/env python
GPIO.cleanup()
When i run this code, i have a troubleshoot.
Traceback (most recent call last):
File "control.py", line 13, in
j = pygame.joystick.Joystick()
TypeError: function takes exactly 1 argument (0 given)
Your issue is that the command line j=pygame.joystick.Joystick(0) is calling the first ps3 controller that is available and paired to your raspberry pi (or whatever device you are using).
With that said, if you do not have a ps3 controller paired with the device, it will never work, because the next command line calls the Ps3controller 0 , and in your case, seems not to be any installed or paired.
Also some other issues with your code:
Line 4: Erase this line completely
Line 26: This was suppose to have a # hashtag before it, used only for notation. You can actually delete this line because it was notes from someone else's project anyway.
Line 78: The indentation is incorrect. it has to follow the indentation of the "while True" loop above it. So to fix it, make sure to backspace the command in line 78 all the way to the left, then press spacebar 8 times, or press TAB key 2 times, same thing. that will fix it!
Now your code works. actually one last thing, make sure to install pygame library as well, type this in the Xterminal(im using raspberry pi with raspbian) if u don't have it yet: sudo apt-get install python-pygame
I hope this all helped. I know you will have more questions, this code used to piss me off!lol

How do perform time-based audio with Pygame?

This is my first question on StackOverflow, so here goes:
Edit: I have edited this a few times, just fixing typing mistakes and updating the code. Even after adding various changes to the code, the issue still remains the exact same.
Also, pygame.mixer.music.fadeout() is not what I'm looking for. This code will also be for when I want to lower music volume to perhaps 50% on, say, pausing the game or entering a talk scene.
With Pygame, I am trying to perform music volume manipulation based on how much time has passed. I already have some decent code created, but it's not performing how I thought it intuitively should. Also, I should note that I am using the component-based EBS system I ripped from PySDL2. Here is the link to the EBS module: https://bitbucket.org/marcusva/py-sdl2/src/02a4bc4f79d9440fe98e372e0ffaadacaefaa5c6/sdl2/ext/ebs.py?at=default
This is my initial block of code:
import pygame
from pygame.locals import *
# Setup import paths for module.
pkg_dir = os.path.split(os.path.abspath(__file__))[0]
parent_dir, pkg_name = os.path.split(pkg_dir)
sys.path.insert(0, parent_dir)
sys.path.insert(0, os.path.join(parent_dir, "Game"))
import Game
from Porting.sdl2.ext import ebs
pygame.display.quit()
print("Counting down...")
for n in range(5):
print(str(n + 1))
pygame.time.delay(1000)
appworld = ebs.World()
audio_system = Game.audio.AudioSystem(44100, -16, 2, 4096)
appworld.add_system(audio_system)
test1 = Game.sprites.AudioSprite(appworld)
test2 = Game.sprites.AudioSprite(appworld)
test1.audio = Game.audio.Audio(database["BGMusic0"], True)
test2.audio = Game.audio.Audio(database["BGMusic1"], True)
game_clock = pygame.time.Clock()
volume_change_clock = pygame.time.Clock()
loop = True
time_passed = 0
while loop:
game_clock.tick(60)
appworld.process()
time_passed += volume_change_clock.tick(60)
if time_passed > (10 * 1000):
print(time_passed)
if not audio_system.music_volume_changed:
audio_system.set_music_volume(0, True)
My next block of code:
import pygame
from Porting.sdl2.ext import ebs
class AudioSystem(ebs.System):
def __init__(self, frequency, bit_size, channels, buffer):
super(AudioSystem, self).__init__()
self.componenttypes = Audio,
pygame.mixer.init(frequency, bit_size, channels, buffer)
pygame.mixer.set_num_channels(200)
self.frequency = frequency
self.bit_size = bit_size
self.channels = channels
self.buffer = buffer
self.music_volume_change_clock = None
self.music_volume_changed = False
self.music_volume_current = 0
self.music_volume_new = 0
self.music_fade = False
self.music_change_speed = 0
self.time_passed_total = 0
self.time_passed_remainder = 0
def process(self, world, componentsets):
for audio in componentsets:
if audio.is_music:
music = pygame.mixer.music
if not pygame.mixer.music.get_busy():
music.load(audio.file)
music.play()
if self.music_volume_changed:
self.music_volume_current = music.get_volume() * 100
if self.music_volume_current != self.music_volume_new and self.music_fade:
time_passed = self.music_volume_change_clock.tick(60)
self.time_passed_total += time_passed
self.time_passed_total += self.time_passed_remainder
self.time_passed_remainder = 0
if self.time_passed_total > self.music_change_speed:
self.time_passed_remainder = self.time_passed_total % self.music_change_speed
volume_change_amount = int(self.time_passed_total / self.music_change_speed)
self.time_passed_total = 0
if self.music_volume_current > self.music_volume_new:
self.music_volume_current -= volume_change_amount
music.set_volume(self.music_volume_current / 100)
elif self.music_current_volume < self.music_volume_new:
self.music_volume_current += volume_change_amount
music.set_volume(self.music_volume_current / 100)
elif self.music_volume_current != self.music_volume_new:
music.set_volume(self.music_volume_current / 100)
else:
self.music_volume_changed = False
self.music_fade = False
else:
if not audio.channel:
audio.channel = pygame.mixer.find_channel()
audio.channel.play()
def set_music_volume(self, percent, fade = False, change_speed = 50):
self.music_volume_changed = True
self.music_volume_new = percent
self.music_fade = fade
self.music_change_speed = change_speed
self.music_volume_change_clock = pygame.time.Clock()
class Audio(object):
def __init__(self, file, is_music = False):
self.is_music = is_music
if self.is_music:
self.file = file
else:
self.channel = None
self.file = pygame.mixer.Sound(file)
My testing has shown that manipulating the parameter of Clock.tick() in my Game.audio module in various ways influences how quickly the audio playing falls from 100 to 0. Leaving it blank causes it to stop almost instantaneously. At 60, it falls to 0 in around 2 seconds, which baffles me. At 30, in 1 second. At 5, it falls slowly, with the volume never seeming to reach 0. I want to completely desynchronize my audio volume manipulation completely from my game's frame-rate, but I am unsure of how I would accomplish that. I want to avoid threading and multiprocessing if possible.
Thanks in advance! :)
Clock.tick()'s parameter is used to call the SDL sleep function to limit how many times the loop runs per second.
Calling it with Clock.tick(5) limits it to five loops per second.
I've also never used two clocks in the same code, especially with the multiple ticks (all of which will calculate their sleep time individually). Instead of that, consider using the return value of tick (the time in ms since the last call), and use that to track time through the whole application.
Example:
timer = 0
Do things
timer += main_clock.tick(FPS)

Categories

Resources