I am currently thinking about working on a small game where the player has to get rid of mob waves in an arena. The game is going to be 2D top-down.
What I want from this game is the player to be able to use the terrain and combine spells to his advantage.
Example of spell/spell interaction: if the player casts an ice wall and then the player fires a fire ball I want the fireball to disappear and the ice wall to melt into a water puddle. Then if the player sends a lightning bolt on the puddle, I want the water puddle to become electrified and affect all the mobs currently on it with some damage.
Example of spell/terrain interaction: If a player sends a fireball on a tree, I want the tree start burning (i.e dealing dmg to nearby mobs) and eventually die (i.e unable to burn anymore). If the player then sends a water jet on the tree I want the tree to be able to grow back again (and potentially be able to burn down again).
Now that you have an idea of what I want, I'll tell you what I've done so far.
I've created a Cast class which represent my spells. This class has three key attributes to govern the interactions with other spells:
1 - attributes: a list of which contains the properties relevant for the Cast (eg: 'flammable' or 'conductive') 2 - states: a dictionary which contains keys which are: 'ablaze', 'frozen', 'conductive', 'blooming' 3 - col-lvl: the collision level, to prevent things on the ground interacting with things mid-air.
for the moment I call the following function at every frame of my game, in order to update the states of each cast in the game:
def update_states(casts_group): '''make cast attribute lists''' flammables = [] freezables = [] fertiles =[] conductives = [] for c in casts_group: if 'flammable' in c.attributes: flammables.append(c) if 'freezable' in c.attributes: freezables.append(c) if 'fetile' in c.attributes: fertiles.append(c) if 'conductive' in c.attributes: conductives.append(c) '''resolve cast states''' '''for flammables''' for f in flammables: for c in flammables: if c.col_lvl == f.col_lvl: if c is not f and f.states['ablaze']: c.states['ablaze'] = True for c in freezables: if c.col_lvl == f.col_lvl: if f.states['ablaze']: if c.states['frozen']: c.states['frozen'] = False f.states['ablaze'] = False for c in fertiles: if c.col_lvl == f.col_lvl: if f.states['ablaze'] and c.states['fertile']: c.states['fertile'] = False '''for freezables''' for w in freezables: for c in freezables: if c.col_lvl == w.col_lvl: if c is not w and w.states['frozen']: c.states['frozen'] = True for c in fertiles: if c.col_lvl == w.col_lvl: if w.states['frozen']: c.states['blooming'] = False elif not w.states['frozen']: c.states['blooming'] = True for c in conductives: if c.col_lvl == w.col_lvl: if not w.states['frozen'] and c.states['conductive']: w.states['conductive'] = True elif w.states['frozen']: w.states['conductive'] = False '''for fertiles''' for f in fertiles: for c in fertiles: if f is not c and c.col_lvl == f.col_lvl: if f.states['blooming']: c.states['blooming'] = True for c in conductives: if c.col_lvl == f.col_lvl: if f.states['blooming'] and c.states['conductive']: f.states['blooming'] = False '''for conductives''' for e in conductives: for c in conductives: if c.col_lvl == e.col_lvl: if e is not c and e.states['conductive']: c.states['conductive'] = True Each cast will then have a series of method which will dictate what should happen based on which states are currently active.
My question to you is : How can I improve this ??
When I run the following test my computer takes 0.8 seconds to solve for about 2000 Cast. That will never hold if I want a decent FPS. I am worried because this is just one function of the game and it already uses up a lot of time. Although I don't expect to have that many casts at any one time in the game, I will have to add a similar step to deal with Terrain/Spell interactions ... and the whole remainder of the game.
Thank you for your help,
BTW if you think this is a question best suited for the CodeReview community let me know, I wasn't quite sure.
TEST:
setup = """ class Cast(): def __init__(self, attr, states): self.attributes = attr self.states = states self.col_lvl = 0 def update_states(casts_group): #for c in casts_group: print c.states '''make cast attribute lists''' flammables = [] freezables = [] fertiles =[] conductives = [] for c in casts_group: if 'flammable' in c.attributes: flammables.append(c) if 'freezable' in c.attributes: freezables.append(c) if 'fetile' in c.attributes: fertiles.append(c) if 'conductive' in c.attributes: conductives.append(c) '''resolve cast states''' '''for flammables''' for f in flammables: for c in flammables: if c.col_lvl == f.col_lvl: if c is not f and f.states['ablaze']: c.states['ablaze'] = True for c in freezables: if c.col_lvl == f.col_lvl: if f.states['ablaze']: if c.states['frozen']: c.states['frozen'] = False f.states['ablaze'] = False for c in fertiles: if c.col_lvl == f.col_lvl: if f.states['ablaze'] and c.states['fertile']: c.states['fertile'] = False '''for freezables''' for w in freezables: for c in freezables: if c.col_lvl == w.col_lvl: if c is not w and w.states['frozen']: c.states['frozen'] = True for c in fertiles: if c.col_lvl == w.col_lvl: if w.states['frozen']: c.states['blooming'] = False elif not w.states['frozen']: c.states['blooming'] = True for c in conductives: if c.col_lvl == w.col_lvl: if not w.states['frozen'] and c.states['conductive']: w.states['conductive'] = True elif w.states['frozen']: w.states['conductive'] = False '''for fertiles''' for f in fertiles: for c in fertiles: if f is not c and c.col_lvl == f.col_lvl: if f.states['blooming']: c.states['blooming'] = True for c in conductives: if c.col_lvl == f.col_lvl: if f.states['blooming'] and c.states['conductive']: f.states['blooming'] = False '''for conductives''' for e in conductives: for c in conductives: if c.col_lvl == e.col_lvl: if e is not c and e.states['conductive']: c.states['conductive'] = True #for c in casts_group: print c.states c_group = [ Cast(['flammable'], {'ablaze' : True, 'frozen' : False, 'blooming' : False, 'conductive': False}), Cast(['freezable','conductive'], {'ablaze' : False, 'frozen' : True, 'blooming' : False, 'conductive': False}), Cast(['conductive'], {'ablaze' : False, 'frozen' : False, 'blooming' : False, 'conductive': True})] d_group = [] for x in range(667): d_group += c_group """ test = """update_states(d_group)""" from timeit import timeit n = 1 print timeit(stmt = test, setup = setup, number = n)