-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathworld.py
135 lines (122 loc) · 5.46 KB
/
world.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
##import psyco
##psyco.full()
import math, time, sys
import stackless
import pygame, pygame.locals
from util import log, myvars, roundtup
from actor import Actor
import collide
import util_pygame
class WorldState:
"""A snapshot of the world sent to all actors, both local and remote"""
def __init__(self,updateRate,time):
self.updateRate = updateRate
self.time = time
self.actors = []
class World(Actor):
"""The playground that runs the business.
Respon:
Make all actors tick()
Make sure every frame (tick) takes the same time to do.
Scan actors collisions amongst themeselves and with the World boundaries.
Collab:
All actors JOIN World.
Sends actors snapshots of the world.
Forward INPUT msgs to player (usually gotten from server).
"""
def __init__(self):
World._singleton= self
Actor.__init__(self)
print "world id=",self.id
self.registeredActors = {}
self.updateRate = 30
self.maxupdateRate = 30
self.checkpoint = 0
self.height= 496
self.width= 496
self.collide= collide.get_dispatcher()
stackless.tasklet(self.runFrame)()
def killDeadActors(self):
for id in self.registeredActors.keys():
_actor= self.registeredActors[id]
if hasattr(_actor,'hitpoints'):
if _actor.hitpoints <= 0:
print "ACTOR", id, "DIED, hitpoints=", self.registeredActors[id].hitpoints
_actor.channel.send_exception(TaskletExit)
del self.registeredActors[id]
del Actor.actors[id]
def testCollisionWithActor(self, _actor):
x, y = roundtup(_actor.location)
w,h = _actor.rect.size
left, right= (x < 0), (x + w > self.width)
top, bottom= (y < 0), (y + h > self.height)
return left, right, top, bottom
def scanActorImpacts(self):
util_pygame.SpriteActor.sprite_group.update(self.updateRate)
coll_group= pygame.sprite.Group()
for id in self.registeredActors.keys():
_actor = self.registeredActors[id]
if _actor.public and _actor.physical:
where=self.testCollisionWithActor(_actor)
if True in where: #with world boundaries
self.collide(_actor, self, where)
#return sprite-list, don't kill (=coll_group.remove) colliding
collisions = util_pygame.spritecollide(_actor, coll_group, False)
coll_group.add(_actor)
for c in collisions:
print ' ** collision', c.__class__.__name__, c.rect, _actor.__class__.__name__, _actor.rect
self.collide(_actor,c)
def sendStateToActors(self,starttime):
worldState = WorldState(self.updateRate,starttime)
for id, _actor in self.registeredActors.items():
if _actor.public:
#print 'adding', id, self.registeredActors[id]
worldState.actors.append( (id,myvars(_actor)) )
for id,_actor in self.registeredActors.items():
if not _actor.public: #only to Server and Display
#print "sending state to %s" % _actor.name
_actor.channel.send( (self.id,"WORLD_STATE",worldState, self.checkpoint) )
self.checkpoint = 0
def actorsTick(self):
for id,_actor in self.registeredActors.items():
_actor.tick(self.updateRate)
def runFrame(self):
initialStartTime = time.time()
startTime = time.time()
while 1:
self.killDeadActors()
self.actorsTick()
self.scanActorImpacts()
self.sendStateToActors(startTime)
#wait
calculatedEndTime = startTime + 1.0/self.updateRate
doneProcessingTime = time.time()
percentUtilized = (doneProcessingTime - startTime) / (1.0/self.updateRate)
if percentUtilized >= 1:
self.updateRate -= 1
print "TOO MUCH PROCESSING, LOWERING FRAME RATE: " , self.updateRate
elif percentUtilized <= 0.6 and self.updateRate < self.maxupdateRate:
self.updateRate += 1
print "TOO MUCH FREETIME, RAISING FRAME RATE: " , self.updateRate
while time.time() < calculatedEndTime:
stackless.schedule()
startTime = calculatedEndTime
stackless.schedule()
def defaultMessageAction(self,args):
sentFrom, msg, msgArgs = args[0],args[1],args[2:]
if msg == "INPUT":
#usually gotten from server, so fwd to player
self.checkpoint = time.time()
#print "World INPUT", time.time()-self.checkpoint, self.registeredActors.items()[1][1].angle
#if self.registeredActors.has_key(sentFrom):
Actor.actors[sentFrom].channel.send((self.id, "INPUT")+ msgArgs)
elif msg == "JOIN":
#props= msgArgs[0] #myvar dict instance
#print "joined:", sentFrom, props['name'], str(props)
self.registeredActors[sentFrom] = Actor.actors[sentFrom]
elif msg == "COLLISION":
pass # known, but we don't do anything
elif msg == "KILLME":
self.registeredActors[sentFrom].hitpoints = 0
else:
print '!!!! WORLD GOT UNKNOWN MESSAGE ' , msg, msgArgs