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)