I'm working on a sort of a 2D Minecraft clone for my first in depth Pyglet project and I've run across a problem. Whenever I have a decent number of blocks on screen, the frame rate drops dramatically.
Here is my rendering method:
I use a dictionary with the key being a tuple(which represents the coordinate for the block) and the item being a texture.
I loop through the entire dictionary and render each block:
for key in self.blocks:
self.blocks[key].blit(key[0] * 40 + sx,key[1] * 40+ sy)
P.S. sx and sy are coordinate offsets for screen scrolling
I would like to know if there is a way to more efficiently render each block.
I'm going to do my best to explain why and how to optemize your code without actually knowing what you code looks like.
I will assume you have something along the lines of:
self.blocks['monster001'] = pyglet.image.load('./roar.png')
This is all fine and dandy, if you want to load a static image that you don't want to do much with. However, you're making a game and you are going to use a hell of a lot more sprites and objects than just one simple image file.
Now this is where shared objects, batches and sprites come in handy.
First off, input your image into a sprite, it's a good start.
sprite = pyglet.sprite.Sprite(pyglet.image.load('./roar.png'))
sprite.draw() # This is instead of blit. Position is done via sprite.x = ...
Now, draw is a hell of a lot quicker than .blit() for numerous of reasons, but we'll skip why for now and just stick with blazing speed upgrades.
Again, this is just one small step towards successful framerates (other than having limited hardware ofc.. duh).
Anyway, back to pew pew your code with upgrades.
Now you also want to add sprites to a batch so you can simultaneously render a LOT of things on one go (read: batch) instead of manually pushing things to the graphics card. Graphic cards soul purpose was designed to be able to handle gigabits of throughput in calculations in one insanely fast go rather than handle multiple of small I/O's.
To do this, you need to create a batch container. And add "layers" to it.
It's quite simple really, all you need to do is:
main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
# stuff_above_background = pyglet.graphics.OrderedGroup(1)
# ...
We'll stick one with batch for now, you probably don't need more for this learning purpose.
Ok so you got your batch, now what? Well now we try our hardest to choke that living hell out of your graphics card and see if we can even buckle it under pressure (No graphic cars were harmed in this process, and please don't choke things..)
Oh one more thing, remember the note about shared objects? well, we'll create a shared image object here that we push into the sprite, instead of loading one new image every.. single... time.. monster_image we'll call it.
monster_image = pyglet.image.load('./roar.png')
for i in range(100): # We'll create 100 test monsters
self.blocks['monster'+str(i)] = pyglet.sprite.Sprite(imgage=monster_image, x=0, y=0, batch=main_batch, group=background)
Now you have 100 monsters created and added to the batch main_batch into the sub-group background. Simple as pie.
Here's the kicker, instead of calling self.blocks[key].blit() or .draw(), we can now call main_batch.draw() and it will fire away every single monster onto the graphics card and produce wonders.
Ok, so now you've optimized the speed of your code, but really that won't help you in the long run if you're making a game. Or in this case, a graphics engine for your game. What you want to do is step up into the big league and use classes. If you were amazed before you'll probably loose your marbles of how awesome your code will look once you've done with it.
Ok so first, you want to create a base class for your objects on the screen, lets called in baseSprite.
Now there are some kinks and stuff you need to work around with Pyglet, for one, when inheriting Sprite objects trying to set image will cause all sorts of iffy glitches and bugs when working with stuff so we'll set self.texture directly which is basically the same thing but we hook into the pyglet libraries variables instead ;D pew pew hehe.
class baseSprite(pyglet.sprite.Sprite):
def __init__(self, texture, x, y, batch, subgroup):
self.texture = texture
super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
self.x = x
self.y = y
def move(self, x, y):
""" This function is just to show you
how you could improve your base class
even further """
self.x += x
self.y += y
def _draw(self):
"""
Normally we call _draw() instead of .draw() on sprites
because _draw() will contains so much more than simply
drawing the object, it might check for interactions or
update inline data (and most likely positioning objects).
"""
self.draw()
Now that's your base, you can now create monsters by doing:
main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
monster_image = pyglet.image.load('./roar.png')
self.blocks['monster001'] = baseSprite(monster_image, 10, 50, main_batch, background)
self.blocks['monster002'] = baseSprite(monster_image, 70, 20, main_batch, background)
...
main_batch.draw()
How, you probably use the default #on_window_draw() example that everyone else is using and that's fine, but I find it slow, ugly and just not practical in the long run. You want to do Object Oriented Programming.. Right?
That's what it's called, I call it readable code that you like to watch all day long. RCTYLTWADL for short.
To do this, we'll need to create a class that mimics the behavior of Pyglet and call it's subsequent functions in order and poll the event handler otherwise sh** will get stuck, trust me.. Done it a couple of times and bottle necks are easy to create.
But enough of my mistakes, here's a basic main class that you can use that uses poll-based event handling and thus limiting the refresh rate to your programming rather than built in behavior in Pyglet.
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False)
self.x, self.y = 0, 0
self.sprites = {}
self.batches = {}
self.subgroups = {}
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def render(self):
self.clear()
for batch_name, batch in self.batches.items():
batch.draw()
for sprite_name, sprite in self.sprites.items():
sprite._draw()
self.flip() # This updates the screen, very much important.
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze.
# Basically it flushes the event pool that otherwise
# fill up and block the buffers and hangs stuff.
event = self.dispatch_events()
x = main()
x.run()
Now this is again just a basic main class that does nothing other than render a black background and anything put into self.sprites and self.batches.
Do note! we call ._draw() on the sprites because we created our own sprite class earlier? Yea that's the awesome base sprite class that you can hook in your own stuff before draw() is done on each individual sprite.
Anywho, This all boils down to a couple of things.
Use sprites when making games, your life will be easier
Use batches, your GPU will love you and the refreshrates will be amazing
Use classes and stuff, your eyes and code mojo will love you in the end.
Here's a fully working example of all the pieces puzzled together:
import pyglet
from pyglet.gl import *
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE)
pyglet.clock.set_fps_limit(60)
class baseSprite(pyglet.sprite.Sprite):
def __init__(self, texture, x, y, batch, subgroup):
self.texture = texture
super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
self.x = x
self.y = y
def move(self, x, y):
""" This function is just to show you
how you could improve your base class
even further """
self.x += x
self.y += y
def _draw(self):
"""
Normally we call _draw() instead of .draw() on sprites
because _draw() will contains so much more than simply
drawing the object, it might check for interactions or
update inline data (and most likely positioning objects).
"""
self.draw()
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False)
self.x, self.y = 0, 0
self.sprites = {}
self.batches = {}
self.subgroups = {}
self._handles = {}
self.batches['main'] = pyglet.graphics.Batch()
self.subgroups['base'] = pyglet.graphics.OrderedGroup(0)
monster_image = pyglet.image.load('./roar.png')
for i in range(100):
self._handles['monster'+str(i)] = baseSprite(monster_image, randint(0, 50), randint(0, 50), self.batches['main'], self.subgroups['base'])
# Note: We put the sprites in `_handles` because they will be rendered via
# the `self.batches['main']` batch, and placing them in `self.sprites` will render
# them twice. But we need to keep the handle so we can use `.move` and stuff
# on the items later on in the game making process ;)
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def render(self):
self.clear()
for batch_name, batch in self.batches.items():
batch.draw()
for sprite_name, sprite in self.sprites.items():
sprite._draw()
self.flip() # This updates the screen, very much important.
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze.
# Basically it flushes the event pool that otherwise
# fill up and block the buffers and hangs stuff.
event = self.dispatch_events()
# Fun fact:
# If you want to limit your FPS, this is where you do it
# For a good example check out this SO link:
# http://stackoverflow.com/questions/16548833/pyglet-not-running-properly-on-amd-hd4250/16548990#16548990
x = main()
x.run()
Some bonus stuff, I added GL options that usually does some benefitial stuff for you.
I also added sa FPS limiter that you can tinker and play with.
Edit:
Batched updates
Since the sprite object can be used to do massive renderings in one go by sending it all to the graphics card, similarly you'd want to do batched updates.
For instance if you want to update every objects position, color or whatever it might be.
This is where clever programming comes into play rather than nifty little tools.
See, everything i relevant in programming.. If you want it to be.
Assume you have (at the top of your code) a variable called:
global_settings = {'player position' : (50, 50)}
# The player is at X cord 50 and Y cord 50.
In your base sprite you could simply do the following:
class baseSprite(pyglet.sprite.Sprite):
def __init__(self, texture, x, y, batch, subgroup):
self.texture = texture
super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
self.x = x + global_settings['player position'][0]#X
self.y = y + global_settings['player position'][1]#Y
Note that you'd have to tweak the draw() (note, not _draw() since batched rendering will call upon draw and not _draw) function a little bit to honor and update position updates per rendering sequence. That or you could create a new class that inherits baseSprite and have only those types of sprite updated:
class monster(baseSprite):
def __init__(self, monster_image, main_batch, background):
super(monster, self).__init__(imgage=monster_image, x=0, y=0, batch=main_batch, group=background)
def update(self):
self.x = x + global_settings['player position'][0]#X
self.y = y + global_settings['player position'][1]#Y
And thus only call .update() on monster type classes/sprites.
It's a bit tricky to get it optimal and there's ways to solve it and still use batched rendering, but somewhere along these lines is probably a good start.
IMPORTANT NOTE I just wrote a lot of this from the top of my head (not the first time I've written a GUI class in Pyglet) and for whatever reason this *Nix instance of mine doesn't find my X-server.. So can't test the code.
I'll give it a test in an hour when I get off work, but this gives you a general Idea of what to do and what to think for when making games in Pyglet. Remember, have fun while doing it or you're quit before you even started because games take time to make ^^
Pew pew lazors and stuff, best of luck!
Related
I am developing an image viewer using pyqt.
I want the image to be fixed when the box moved.
However, the image is pushed when the box tries to reach the viewer's side like this.
It was implemented using QGraphicsView, QGraphicsScene, and QGraphicsitem.
This is part of main class
self.scene_r = GraphicsScene()
self.scene_r.addPixmap(pix_resized)
self.resizedView.setScene(self.scene_r)
self.resizedView.centerOn(128,128)
This is QGraphicScene Class
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
QGraphicsScene.__init__(self)
rect_item = recItem(QRectF(0, 0, 100, 100))
rect_item.setFlag(QGraphicsItem.ItemIsMovable, True)
rect_item.setZValue(1)
rect_item.setPen(Qt.green)
self.addItem(rect_item)
I tried to override mouseMoveEvent() of QGraphicsRectItem class, but it failed.
That happens for two reasons:
Since you are making the item movable, you can move it freely, anywhere you want.
When the scene rectangle is smaller than the one visible in the view, the view tries to ensure that the whole scene rectangle stays visible, possibly by scrolling its contents.
Note that, unless explicitly set using setSceneRect() (on the scene or on the view, the results might differ), Qt automatically sets the scene rect implicitly to the bigger QRect that contains all visible graphics items.
There at least two possible solutions to your problem, which one to choose depends on what you need, and you can also decide to use both of them.
Explicitly set the sceneRect
You can set the sceneRect to a specific rectangle, an item, or all existing items. Note that, while in your case it won't change much if you set the rectangle for the scene or the view, in more complex cases (for example, multiple views showing the same scene) the result might differ.
# on the view
self.setSceneRect(self.scene_r.itemsBoundingRect())
# alternativaly, on the scene
self.setSceneRect(self.itemsBoundingRect())
Limit the area in which the item can be moved
In this case you can intercept the itemChange ItemPositionChange (note that the ItemSendsGeometryChanges flag must be set) and return an adjusted value before it is actually applied:
class RecItem(QGraphicsRectItem):
def __init__(self, *args):
super().__init__(*args)
self.setFlags(self.ItemSendsGeometryChanges)
def itemChange(self, change, value):
if change == self.ItemPositionChange:
sceneRect = self.scene().sceneRect()
newGeometry = self.boundingRect().translated(value)
# the item pen must be taken into account
halfPen = self.pen().width() / 2
if value.x() < sceneRect.x():
value.setX(sceneRect.x() + halfPen)
if value.y() < sceneRect.y():
value.setY(sceneRect.y() + halfPen)
if newGeometry.right() + halfPen > sceneRect.right():
value.setX(sceneRect.right() - newGeometry.width())
if newGeometry.bottom() + halfPen > sceneRect.bottom():
value.setY(sceneRect.bottom() - newGeometry.height())
return value
return super().itemChange(change, value)
Hey I've been stuck on this issue for quite a while and was hoping someone could help me out:
I'm using pyglet and have got all of the code working in my project (even what I was having the issue with) then I restarted my computer and suddenly it didn't work...
This is the loop that is instantiating my 'Letter' objects:
main_st = ut.makeString("EXNXYXAXDAADUXMDXLGEQTAQXDDQSVXUTSXKHXHRXYFUXLXJUTHXYVADSUXKHUQUIXSJHXHDPKXFQUXILNXORMXRPL")
letter_list = []
for i in range(len(main_st)):
letter_list.append(l.Letter(pyglet.resource.image("Letters/" + main_st[i] + ".png"),main_st[i],10,10))
And this is the Letter class constructor Letter is a subclass of pyglet.sprite.Sprite:
def __init__(self,im,iden,xx,yy):
super(Letter,self).__init__(img=im,x=xx,y=yy)
At no point in the program do I modify the x and y coordinates of sprite but when I go to draw them, no matter what I put in for xx and yy they're always drawn in the same place on the window UNLESS I do a very large number for yy, and in those cases it simply disappears (I assume it's outside of the window).
I'm having each letter flash on the screen for 1 second and in order to do that here's my on_draw method
def on_draw():
background.draw()
if not key_manager.cur_letter == None:
key_manager.cur_letter.draw()
(only key_manager.cur_letter gets drawn and that switches every second).
The problem might be related to older versions.
But after calling super(Letter, self)... you could do:
def __init__(self,im,iden,xx,yy):
super(Letter,self).__init__(img=im,x=xx,y=yy)
self.x = xx
self.y = yy
And that should do the trick.
I'm new to python and relatively new to programming in general and I'm trying to write a side scrolling arcade game using the pygame and random modules. However I have hit a stumbling block in the way that the game is populated with enemies. What I am trying to achieve to make it so that for every enemy that leaves the left hand side of the window a new one is spawned somewhere beyond the right hand edge of the window.
However when an enemy leaves the left hand side of the screen and my respawn function is called I get an "typeerror" that the plane object it is trying to add to the enemies list is not callable - I cannot figure out why this is.
To begin with. I have defined a class for each type of enemy in my game. I have tried to get the planes to respawn the way i want them to first and then plan to do the same for the others. so I will only include relevant code to this class of enemies.
class plane(object):
def __init__(self, start_x, start_y, speed):
self.start_x = start_x
self.start_y = start_y
self.speed = speed
self.width = 200
self.height = 60
self.Hitbox = (self.start_x, self.start_y, self.width,
self.height)
def draw(self, win):
pygame.draw.rect(win, (0,0,0), (self.start_x, self.start_y,
self.width, self.height),0)
self.Hitbox = (self.start_x, self.start_y, self.width,
self.height)
pygame.draw.rect(win, (0,255,0), self.Hitbox, 1)
I can create an initial list of enemies by using the following create level function before entering the main loop of the game and i have defined another function called Respawn() It's this Respawn() function that won't work in the way i hoped:
turrets = []
towers = []
planes = []
def createLevel():
for r in range(left_turret_number):
turrets.append(turret(random.randint(1,2651), "Diag_left"))
for r in range(right_turret_number):
turrets.append(turret(random.randint(1,2651), "up"))
for r in range(tower_number):
towers.append(tower(random.randint(150,2651),random.randint(1,450),
50))
for r in range(plane_number):
planes.append(plane(random.randint(500,2651), random.randint(1,
450), random.randint(10, 20)))
def Respawn():
random_plane_x = random.randint(500,2651)
random_plane_y = random.randint(1, 450)
random_plane_speed = random.randint(10, 20)
random_plane = plane(random_plane_x, random_plane_y,
random_plane_speed)
print(random_plane_x, random_plane_y, random_plane_speed)
planes.append(random_plane)
In my main loop the pertinent following things happen in this order:
1.) each plane is moved by their speed towards the left of the window
for plane in planes:
plane.start_x -= plane.speed
2.) each plane is checked to see whether it has completely left the left hand side of the window, and if it has, it is removed from the list and the respawn counter increases by one - I have done it this way in case two planes by chance leave the screen at the same time.
for plane in planes:
plane.start_x -= plane.speed
3.) for the number of respawn counters, the respawn function is called that many times. (this is after collisons have been detected and keyboard input checked for ect.). finally the respawn counter is reset and the game window redrawn.
if plane_respawn_counter > 0:
for r in range(plane_respawn_counter):
Respawn()
plane_respawn_counter = 0
redrawGameWindow()
When a plane leaves the left hand side of the screen and the respawn function is triggered the program simply crashes and I get the error message "TypeError: "plane" object is not callable".
Thank you for your attention - I hope someone can tell me why the object is not callable and hopefully also how I can fix it :) I hope the information I have provided is sufficient - please let me know if you need any more details or need to see any further code from my program.
You should rename your variable in your for loop from planes--planes is the name of your class. Here is where I'm talking about:
for plane in planes:
plane.start_x -= plane.speed
In your respawn function, you call plane,
random_plane = plane(random_plane_x, random_plane_y, random_plane_speed)
but planes has been redefined as an instance of your class plane, therefore your error object not callable. Try just changing your for-loop variable to something else or renaming your class to Plane (it's pretty standard for them to start with an uppercase letter).
I'm making a 2-d game using Pygame.
I want to add particle effects into the game I'm working on. I want to do things like spawn smoke, fire, blood, etc. I'm curious is there an easy way to do this? I don't really know even where to start.
I just need a base case I could expand upon..
Pls Help.
You might want to just make a class made of rects that go up and randomly go to the right or left each time it is updated for the smoke. Then make a ton of them whenever you want it. I'll try to make an example code below, but I can't guarntee it will work. You can make similar classes for the other particle effects.
class classsmoke(pygame.Rect):
'classsmoke(location)'
def __init__(self, location):
self.width=1
self.height=1
self.center=location
def update(self):
self.centery-=3#You might want to increase or decrease this
self.centerx+=random.randint(-2, 2)#You might want to raise or lower this as well
#use this to create smoke
smoke=[]
for i in range(20):
smoke.append(classsmoke(insert location here))
#put this somewhere within your game loop
for i in smoke:
i.update()
if i.centery<0:
smoke.remove(i)
else:
pygame.draw.rect(screen, GREY, i)
Another option would be to make the class just a tuple, like this:
class classsmoke():
'classsmoke(location)'
def __init__(self, location):
self.center=location
def update(self):
self.center[1]-=3
self.center[0]+=random.randint(-2, 2)
#to create smoke
smoke=[]
for i in range(20):
smoke.append(classsmoke(insert location here))
#put inside game loop
for i in smoke:
i.update()
if i.centery<0:
smoke.remove(i)
else:
pygame.draw.rect(screen, GREY, (i.center[0], i.center[1], 1, 1))
Or, to avoid classes completly:
#to create smoke:
smoke=[]
for i in range(20):
smoke.append(insert location here)
#put within your game loop
for i in smoke:
i[1]-=3
i[0]+=random.randint(-2, 2)
if i[1]<0:
smoke.remove(i)
else:
pygame.draw.rect(screen, GREY, (i[0], i[1], 1, 1))
Pick your preference, and do something similar for other particle effects.
Check the Library for particle effects PyIgnition
I have tried a for loop with the blit and draw methods and using different variables for " PlayerSprite " and " Treegroup "
for PlayerSprite in Treegroup:
surface.blit(PlayerSprite,(random.randrange(100,500),random.randrange(100,600)))
also tried
SPRITES=[]
for Sprites in range(10):
Sprites= PlayerSprite
SPRITES.append(Sprites)
all I get are errors
screen=pygame.display.set_mode((640,480))
background1=pygame.image.load("C:\Pygame-Docs\examples\data\Random Map.bmp")
class Tree1(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load('C:\Pygame-Docs\examples\data\Tree 1.bmp')
self.image=self.image.convert()
self.rect=self.image.get_rect()
self.rect.centerx=random.randrange(10,100)
self.rect.centery=random.randrange(10,100)
# Makes a group of trees
Howmanytrees=random.randrange(5,10)
Trees=[]
for tree in range(Howmanytrees):
trees=Tree1()
Trees.append(trees)
# Howmany groups
for Treegroup in range(10):
Treegroup=Trees
# Places groups
PlayerSprite=pygame.sprite.Group(Treegroup)
# keeps loop ( game ) going until canceled
keepgoing=True
while keepgoing:
for event in pygame.event.get():
if event.type==pygame.QUIT:
keepgoing=False
# actually draws screen
screen.blit(background1,(0,0))
PlayerSprite.draw(screen)
pygame.display.flip()
This code only displays 5 to 10 trees " Trees=[] "
and nothing else. I have worked on this problem for over a week , read many tutorials, looked on many websites, nothing seems to work. I must be overlooking or missing somethig. I thought this would be easy!
Thanks so much!
As far as I understand what you want to achieve, the below code should help you. I kept it very very simple regarding python syntax, as you seems to be a newbie (for experienced programmers: yes, what I wrote below is horrible python code, but I believe the OP can understand it and it may help).
The key is that if you want to get several groups of trees, you must have a loop within a loop. The inner loop put the trees inside the group, and the outer loop put several groups. Of course you can (and should) certainly hide the inner loop behind some function or class.
# Howmany groups ? say 3
trees_groups = []
number_of_groups = 3
for _ in range(number_of_groups):
# Choose a base position for my group of trees
base_x = random.randrange(0,530)
base_y = random.randrange(0,370)
# Makes a group of trees
trees=[]
number_of_trees = random.randrange(5,10)
for _ in range(number_of_trees):
one_tree = Tree1()
trees.append(one_tree)
for tree in trees:
tree.rect.centerx += base_x
tree.rect.centery += base_y
trees_groups.append(tree)
# Places groups
PlayerSprite=pygame.sprite.Group(trees_groups)
Some after notes:
And as other posters said, you should not use capitalized variables as you do. The python usage is to keep them for classes
Also looping using range when the base variant is not used is bad practice. I emphasized this by using underline as a variable name for the loop variant when it is not used.
I would use randint and move_ip to get what you want. Here is a code snippet from my own game that works just as well:
self.rect.move_ip(random.randint(minX, maxX), random.randint(minY, maxY))
the four variables minX, maxX, minY, maxY form a rectangle where the sprite can be placed. In your case, the trees would be placed along the entire screen, but with a reduced max X and Y range so trees won't clip through the bottom of the screen.
Also, use a Group class to store your trees rather than a list. A list stops the spawning of multiple trees, while a Group does. Here is how to call it:
Treegroup = pygame.sprite.Group
and to add a sprite to the group:
Treegroup.add(Tree1(screen))
Make sure the class itself has screen in its init, like so:
def __init__(self, screen)
Once that's done, your code should look something like this:
for Treegroup in range(10):
Treegroup.add(Tree(screen))
[...]
class Tree(pygame.sprite.Sprite):
def __init__(self, screen):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image('tree.png', -1)
self.rect.move_ip(random.randint(0, 800), random.randint(0, 600))
self.area = screen.get_rect()
It doesn't really make much sense to me.
for tree in range(Howmanytrees):
trees=Tree1()
Trees.append(trees)
Your loop here is doing nothing at all. tree should be a number between 0 and Howmanytrees. Again, the following block isn't indented so it's not part of the loop. Even so, the block still wouldn't work. Also, you're confusing yourself and us with variable names. Trees is the object? trees is the list? Don't do this. Seriously.
No idea what the following code is up to.
# Howmany groups
for Treegroup in range(10):
Treegroup=Trees
Create your SpriteGroup passing in the aforementioned trees list? Or am I missing something :) TreeGroup = Trees 10 times is just going to do that 10 times. You are not using the loop variant. The only thing that modifies during the loop. Even so, this entire block of code is useless.
while keepgoing:
for event in pygame.event.get():
if event.type==pygame.QUIT:
keepgoing=False
This is going to cause a nice infinite loop. It is evaluating the keepgoing variable constantly. This will never get set to false unless the user quits, but also it will never display anything on the screen. Lose this. Use this instead:
for event in pygame.event.get():
if event.type == QUIT:
return
This will not cause an infinite loop as there are only so many events to be processed per tick. Then the program will loop around and do the process or updating, rendering and getting input again.