Esempio n. 1
0
class Text(Billboard):
    def __init__(self,
                 name,
                 nodePath,
                 offset,
                 text,
                 stencilId,
                 scale=0.025000000000000001,
                 *args,
                 **kwargs):
        Billboard.__init__(self, name, nodePath, *args, **kwargs)
        self.setBin('fixed', 110)
        self.scale = scale
        self.textNode = OnscreenText(text=text,
                                     fg=Vec4(0, 0, 0, 1),
                                     scale=scale,
                                     shadow=Vec4(0, 0, 0, 0),
                                     mayChange=True,
                                     font=PiratesGlobals.getPirateFont())
        self.textNode.detachNode()
        sNode = self.attachNewNode('stencil')
        sNode.setY(-offset)
        self.textNode.instanceTo(sNode)
        sNode.setDepthTest(False)

    def setBold(self, bold):
        self.textNode.setShadow(Vec4(0, 0, 0, bold))

    def setTextScale(self, scale):
        self.textNode.setScale(self.scale * scale)
Esempio n. 2
0
class HUD():
    def __init__(self):
        self.speedometer = OnscreenImage(image = 'img/speedometerDial.png', pos = (-1, 0, -.7) )
        self.speedometer.setScale(.25)
        self.speedometer.setTransparency(TransparencyAttrib.MAlpha)
        self.speedPin = OnscreenImage(image = 'img/speedometerNeedle.png', pos = (-1, 0, -.7))
        self.speedPin.setScale(.10)
        self.speedPin.setTransparency(TransparencyAttrib.MAlpha)
        self.speedPin.setHpr(0, 0, 0)
        
        self.minimap = OnscreenImage(image = 'img/minimap.png', pos = (1.05, 0, -.65))
        self.minimap.setScale(.19, .19, .3)
        self.dot = OnscreenImage(image = 'img/dot.png', pos = (1.01, 0, -.55))
        self.dot.setScale(.025)
        

        font1 = loader.loadFont('img/goodfish.ttf')
        self.lapText = OnscreenText(text = "0/10", font = font1, pos = (1, -.1, 0), fg = (1, 1, 1, 1) )
        self.lapText.setScale(.05)
        self.placeText = OnscreenText(text = "", font = font1, pos = (1, -.2, 0), fg = (1, 1, 1, 1))
        self.placeText.setScale(.05)
        self.timerText = OnscreenText(text = "Time: ", font = font1, pos = (1, -.3, 0), fg = (1, 1, 1, 1))

        
    def update(self, velocity, x, y, laps, place, time):
        if velocity < 0:
            velocity = -velocity


        self.dot.setPos(1.01+(x/4250), 0, -.55+(y/4250))
        self.lapText.setText("Laps: " + str(laps)+"/3")


        self.speedPin.setHpr(0, 0, 4*velocity)



        self.placeText.setText("Position: "+str(place))
        self.timerText.setText("Time: "+ str(round(time)))
    
    """def getDist(self, x, y, checkpoint):
        cx = checkpoint[0]
        cy = checkpoint[1]
        dist = math.sqrt((cx-x)**2 + (cy-y)**2)
        
        rotAngle = math.atan2(-y,x)
        
        newX = x*math.cos(rotAngle) - y*math.sin(rotAngle)
        
        dToCheckpoint = dist - newX
        return dToCheckpoint"""
    
    """def updateMiniMap(self, x, y):
        self.dot.setPos(1+(x/1000), 0, -.7+(y/1000))"""
        
        
Esempio n. 3
0
 def sign_cb(parent):
     text = '\n\n'.join(ThanksNames.get_thanks(3, 4))
     txt = OnscreenText(text, parent=parent, scale=.2, fg=(0, 0, 0, 1),
                        pos=(.245, 0))
     bounds = lambda: txt.get_tight_bounds()
     while bounds()[1].x - bounds()[0].x > .48:
         scale = txt.getScale()[0]
         # NB getScale is OnscreenText's meth; it doesn't have swizzle
         txt.setScale(scale - .01, scale - .01)
     bounds = txt.get_tight_bounds()
     height = bounds[1].z - bounds[0].z
     txt.set_z(.06 + height / 2)
Esempio n. 4
0
 def sign_cb(parent):
     text = '\n\n'.join(ThanksNames.get_thanks(3, 4))
     txt = OnscreenText(text, parent=parent, scale=.2, fg=(0, 0, 0, 1),
                        pos=(.245, 0))
     bounds = lambda: txt.get_tight_bounds()
     while bounds()[1].x - bounds()[0].x > .48:
         scale = txt.getScale()[0]
         # NB getScale is OnscreenText's meth; it doesn't have swizzle
         txt.setScale(scale - .01, scale - .01)
     bounds = txt.get_tight_bounds()
     height = bounds[1].z - bounds[0].z
     txt.set_z(.06 + height / 2)
Esempio n. 5
0
def test_onscreentext_text_scale():
    text = OnscreenText(scale=(1, 2))
    assert text['scale'] == (1, 2)
    assert text.scale == (1, 2)
    assert text.getScale() == (1, 2)
    assert text.text_scale == (1, 2)
    assert text.getTextScale() == (1, 2)
    assert text.get_scale() == (1, 1, 1)

    text.setTextScale(3, 4)
    assert text['scale'] == (3, 4)
    assert text.scale == (3, 4)
    assert text.getScale() == (3, 4)
    assert text.text_scale == (3, 4)
    assert text.getTextScale() == (3, 4)
    assert text.get_scale() == (1, 1, 1)

    text.text_scale = (7, 8)
    assert text['scale'] == (7, 8)
    assert text.scale == (7, 8)
    assert text.getScale() == (7, 8)
    assert text.text_scale == (7, 8)
    assert text.getTextScale() == (7, 8)
    assert text.get_scale() == (1, 1, 1)

    text.setScale(9, 10)
    assert text['scale'] == (9, 10)
    assert text.scale == (9, 10)
    assert text.getScale() == (9, 10)
    assert text.text_scale == (9, 10)
    assert text.getTextScale() == (9, 10)
    assert text.get_scale() == (1, 1, 1)

    text['scale'] = (11, 12)
    assert text['scale'] == (11, 12)
    assert text.scale == (11, 12)
    assert text.getScale() == (11, 12)
    assert text.text_scale == (11, 12)
    assert text.getTextScale() == (11, 12)
    assert text.get_scale() == (1, 1, 1)

    text.scale = 13
    assert text['scale'] == (13, 13)
    assert text.scale == (13, 13)
    assert text.getScale() == (13, 13)
    assert text.text_scale == (13, 13)
    assert text.getTextScale() == (13, 13)
    assert text.get_scale() == (1, 1, 1)
Esempio n. 6
0
 def sign_cb(parent):
     thanks = open(eng.curr_path + 'assets/thanks.txt').readlines()
     shuffle(thanks)
     text = '\n\n'.join(thanks[:3])
     txt = OnscreenText(text,
                        parent=parent,
                        scale=.2,
                        fg=(0, 0, 0, 1),
                        pos=(.245, 0))
     bounds = lambda: txt.getTightBounds()
     while bounds()[1][0] - bounds()[0][0] > .48:
         scale = txt.getScale()[0]
         txt.setScale(scale - .01, scale - .01)
     bounds = txt.getTightBounds()
     height = bounds[1][2] - bounds[0][2]
     txt.setZ(.06 + height / 2)
Esempio n. 7
0
class Text(Billboard):

    def __init__(self, name, nodePath, offset, text, stencilId, scale = 0.025000000000000001, *args, **kwargs):
        Billboard.__init__(self, name, nodePath, *args, **kwargs)
        self.setBin('fixed', 110)
        self.scale = scale
        self.textNode = OnscreenText(text = text, fg = Vec4(0, 0, 0, 1), scale = scale, shadow = Vec4(0, 0, 0, 0), mayChange = True, font = PiratesGlobals.getPirateFont())
        self.textNode.detachNode()
        sNode = self.attachNewNode('stencil')
        sNode.setY(-offset)
        self.textNode.instanceTo(sNode)
        sNode.setDepthTest(False)


    def setBold(self, bold):
        self.textNode.setShadow(Vec4(0, 0, 0, bold))


    def setTextScale(self, scale):
        self.textNode.setScale(self.scale * scale)
Esempio n. 8
0
class SeaMonster(UsesAnimationMixer, Avatar.Avatar, UsesEffectNode):
    FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0), ('idle', 1.0))
    SfxNames = {
        'death': SoundGlobals.SFX_MONSTER_DEATH }
    sfx = { }
    actor = None
    animInfo = { }
    
    class AnimationMixer(AnimationMixer):
        LOOP = AnimationMixer.LOOP
        ACTION = dict(AnimationMixer.ACTION)
        ACTION['MOVIE'] = AnimationMixer.ACTION_INDEX + 1

    
    def __init__(self, animationMixer = None):
        Avatar.Avatar.__init__(self)
        UsesEffectNode.__init__(self)
        self.setPickable(0)
        self.shadowFileName = 'models/misc/drop_shadow'
        self.nameText = None
        self.avatarType = None
        if not SeaMonster.sfx:
            for name in SeaMonster.SfxNames:
                SeaMonster.sfx[name] = loadSfx(SeaMonster.SfxNames[name])
            
        
        OTPRender.renderReflection(False, self, 'p_creature', None)
        animationMixer = self.AnimationMixer
        UsesAnimationMixer.__init__(self, animationMixer)

    
    def delete(self):
        Avatar.Avatar.delete(self)

    
    def forceLoadAnimDict(self):
        for anim in self.animDict:
            self.getAnimControls(anim)
        

    
    def generateSeaMonster(self):
        if self.actor:
            self.copyActor(self.actor)
        

    
    def setAvatarType(self, avatarType):
        if self.avatarType:
            self.initializeNametag3d()
            return None
        else:
            self.avatarType = avatarType
            self.height = EnemyGlobals.getHeight(avatarType)
            self.initializeDropShadow()
            self.initializeNametag3d()

    
    def initializeNametag3d(self):
        if self.avatarType.isA(AvatarType(base = AvatarTypes.Animal)):
            return None
        
        Avatar.Avatar.initializeNametag3d(self)
        self.nametag3d.setH(self.getGeomNode().getH())
        self.nametag3d.setFogOff()
        self.nametag3d.setLightOff()
        self.nametag3d.setColorScaleOff(100)
        self.nametag.setFont(PiratesGlobals.getPirateBoldOutlineFont())
        self.iconNodePath = self.nametag.getNameIcon()
        if self.iconNodePath.isEmpty():
            self.notify.warning('empty iconNodePath in initializeNametag3d')
            return 0
        
        if not self.nameText:
            self.nameText = OnscreenText(fg = Vec4(1, 1, 1, 1), bg = Vec4(0, 0, 0, 0), scale = 1.1000000000000001, align = TextNode.ACenter, mayChange = 1, font = PiratesGlobals.getPirateBoldOutlineFont())
            self.nameText.reparentTo(self.iconNodePath)
            self.nameText.setTransparency(TransparencyAttrib.MDual, 2)
            self.nameText.setColorScaleOff(100)
            self.nameText.setLightOff()
            self.nameText.setFogOff()
            scale = self.nametag3d.getScale(render)
            self.nameText.setScale(1.0 / scale[0])
        

    
    def scaleAnimRate(self, forwardSpeed):
        rate = 1.0
        myMaxSpeed = self.getMaxSpeed()
        if myMaxSpeed > 0 and forwardSpeed > 0:
            currTime = globalClockDelta.globalClock.getFrameTime()
            maxSpeed = myMaxSpeed * (currTime - self.prevSpeedClock)
            prevTime = self.prevSpeedClock
            self.prevSpeedClock = currTime
            rate = min(1.25, forwardSpeed / maxSpeed)
        
        return rate

    
    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle('modelRoot', lodName)
            joint = bundle.findChild('name_tag')
            if joint:
                joints.append(joint)
                continue
        
        return joints

    
    def getAirborneHeight(self):
        return 0.0

    
    def getMaxSpeed(self):
        return 0

    
    def getRadius(self):
        return self.battleTubeRadius

    
    def play(self, *args, **kwArgs):
        UsesAnimationMixer.play(self, *args, **args)

    
    def loop(self, *args, **kwArgs):
        UsesAnimationMixer.loop(self, *args, **args)

    
    def pingpong(self, *args, **kwArgs):
        UsesAnimationMixer.pingpong(self, *args, **args)

    
    def pose(self, *args, **kwArgs):
        UsesAnimationMixer.pose(self, *args, **args)

    
    def stop(self, *args, **kwArgs):
        UsesAnimationMixer.stop(self, *args, **args)

    
    def getDeathAnimName(self, animNum = None):
        animStrings = [
            'death']
        if animNum not in range(len(animStrings)):
            animNum = random.choice([
                0])
        
        return animStrings[animNum]

    
    def getAnimInfo(self, state):
        return self.animInfo.get(state, self.FailsafeAnims)

    
    def setupAnimInfoState(cls, state, info):
        if len(info) < len(cls.FailsafeAnims):
            info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):]
        
        cls.animInfo[state] = info

    setupAnimInfoState = classmethod(setupAnimInfoState)
    
    def setupAnimInfo(cls):
        cls.setupAnimInfoState('LandRoam', cls.FailsafeAnims)
        cls.setupAnimInfoState('WaterRoam', cls.FailsafeAnims)

    setupAnimInfo = classmethod(setupAnimInfo)
    
    def setupAnims(cls):
        cls.animInfo = copy.copy(SeaMonster.animInfo)
        cls.setupAnimInfo()
        filePrefix = cls.ModelInfo[1]
        animList = cls.AnimList
        animDict = { }
        for anim in animList:
            animDict[anim[0]] = filePrefix + anim[1]
        
        cls.animDict = animDict

    setupAnims = classmethod(setupAnims)
    
    def setLODs(self):
        avatarDetail = base.config.GetString('avatar-detail', 'high')
        if avatarDetail == 'high':
            dist = [
                0,
                20,
                80,
                280]
        elif avatarDetail == 'med':
            dist = [
                0,
                10,
                40,
                280]
        elif avatarDetail == 'low':
            dist = [
                0,
                6,
                20,
                280]
        else:
            raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail
        self.addLOD('low', dist[3], dist[2])
        self.addLOD('med', dist[2], dist[1])
        self.addLOD('hi', dist[1], dist[0])

    
    def setupAssets(cls):
        cls.animInfo = copy.copy(SeaMonster.animInfo)
        cls.setupAnimInfo()
        filePrefix = cls.ModelInfo[1]
        animList = cls.AnimList
        animDict = { }
        for anim in animList:
            animDict[anim[0]] = filePrefix + anim[1]
        
        cls.animDict = animDict
        filePrefix = cls.ModelInfo[1]
        for name in cls.SfxNames:
            cls.sfx[name] = loadSfx(cls.SfxNames[name])
        
        cls.actor = Actor.Actor()
        if loader.loadModel(filePrefix + 'med') != None:
            avatarDetail = base.config.GetString('avatar-detail', 'high')
            if avatarDetail == 'high':
                dist = [
                    0,
                    200,
                    800,
                    2800]
            elif avatarDetail == 'med':
                dist = [
                    0,
                    100,
                    400,
                    2800]
            elif avatarDetail == 'low':
                dist = [
                    0,
                    60,
                    200,
                    2800]
            else:
                raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail
            cls.actor.setLODNode()
            cls.actor.addLOD('low', dist[3], dist[2])
            cls.actor.addLOD('med', dist[2], dist[1])
            cls.actor.addLOD('hi', dist[1], dist[0])
            cls.actor.loadModel(filePrefix + 'hi', 'modelRoot', 'hi')
            cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'med')
            cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'low')
            cls.actor.loadAnims(cls.animDict, 'modelRoot', 'all')
        else:
            cls.actor.loadModel(cls.ModelInfo[0])
            cls.actor.loadAnims(cls.animDict)
        cls.actor.getGeomNode().setH(180)

    setupAssets = classmethod(setupAssets)
class SeaMonster(UsesAnimationMixer, Avatar.Avatar, UsesEffectNode):
    FailsafeAnims = (('idle', 1.0), ('idle', 1.0), ('idle', 1.0),
                     ('idle', 1.0), ('idle', 1.0), ('idle', 1.0),
                     ('idle', 1.0), ('idle', 1.0), ('idle', 1.0),
                     ('idle', 1.0), ('idle', 1.0), ('idle', 1.0),
                     ('idle', 1.0), ('idle', 1.0))
    SfxNames = {'death': SoundGlobals.SFX_MONSTER_DEATH}
    sfx = {}
    actor = None
    animInfo = {}

    class AnimationMixer(AnimationMixer):
        LOOP = AnimationMixer.LOOP
        ACTION = dict(AnimationMixer.ACTION)
        ACTION['MOVIE'] = AnimationMixer.ACTION_INDEX + 1

    def __init__(self, animationMixer=None):
        Avatar.Avatar.__init__(self)
        UsesEffectNode.__init__(self)
        self.setPickable(0)
        self.shadowFileName = 'models/misc/drop_shadow'
        self.nameText = None
        self.avatarType = None
        if not SeaMonster.sfx:
            for name in SeaMonster.SfxNames:
                SeaMonster.sfx[name] = loadSfx(SeaMonster.SfxNames[name])

        OTPRender.renderReflection(False, self, 'p_creature', None)
        animationMixer = self.AnimationMixer
        UsesAnimationMixer.__init__(self, animationMixer)
        return

    def delete(self):
        Avatar.Avatar.delete(self)

    def forceLoadAnimDict(self):
        for anim in self.animDict:
            self.getAnimControls(anim)

    def generateSeaMonster(self):
        if self.actor:
            self.copyActor(self.actor)

    def setAvatarType(self, avatarType):
        if self.avatarType:
            self.initializeNametag3d()
            return
        else:
            self.avatarType = avatarType
            self.height = EnemyGlobals.getHeight(avatarType)
            self.initializeDropShadow()
            self.initializeNametag3d()

    def initializeNametag3d(self):
        if self.avatarType.isA(AvatarType(base=AvatarTypes.Animal)):
            return
        Avatar.Avatar.initializeNametag3d(self)
        self.nametag3d.setH(self.getGeomNode().getH())
        self.nametag3d.setFogOff()
        self.nametag3d.setLightOff()
        self.nametag3d.setColorScaleOff(100)
        self.nametag.setFont(PiratesGlobals.getPirateBoldOutlineFont())
        self.iconNodePath = self.nametag.getNameIcon()
        if self.iconNodePath.isEmpty():
            self.notify.warning('empty iconNodePath in initializeNametag3d')
            return 0
        if not self.nameText:
            self.nameText = OnscreenText(
                fg=Vec4(1, 1, 1, 1),
                bg=Vec4(0, 0, 0, 0),
                scale=1.1,
                align=TextNode.ACenter,
                mayChange=1,
                font=PiratesGlobals.getPirateBoldOutlineFont())
            self.nameText.reparentTo(self.iconNodePath)
            self.nameText.setTransparency(TransparencyAttrib.MDual, 2)
            self.nameText.setColorScaleOff(100)
            self.nameText.setLightOff()
            self.nameText.setFogOff()
            scale = self.nametag3d.getScale(render)
            self.nameText.setScale(1.0 / scale[0])

    def scaleAnimRate(self, forwardSpeed):
        rate = 1.0
        myMaxSpeed = self.getMaxSpeed()
        if myMaxSpeed > 0 and forwardSpeed > 0:
            currTime = globalClockDelta.globalClock.getFrameTime()
            maxSpeed = myMaxSpeed * (currTime - self.prevSpeedClock)
            prevTime = self.prevSpeedClock
            self.prevSpeedClock = currTime
            rate = min(1.25, forwardSpeed / maxSpeed)
        return rate

    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle('modelRoot', lodName)
            joint = bundle.findChild('name_tag')
            if joint:
                joints.append(joint)

        return joints

    def getAirborneHeight(self):
        return 0.0

    def getMaxSpeed(self):
        return 0

    def getRadius(self):
        return self.battleTubeRadius

    def play(self, *args, **kwArgs):
        UsesAnimationMixer.play(self, *args, **kwArgs)

    def loop(self, *args, **kwArgs):
        UsesAnimationMixer.loop(self, *args, **kwArgs)

    def pingpong(self, *args, **kwArgs):
        UsesAnimationMixer.pingpong(self, *args, **kwArgs)

    def pose(self, *args, **kwArgs):
        UsesAnimationMixer.pose(self, *args, **kwArgs)

    def stop(self, *args, **kwArgs):
        UsesAnimationMixer.stop(self, *args, **kwArgs)

    def getDeathAnimName(self, animNum=None):
        animStrings = ['death']
        if animNum not in range(len(animStrings)):
            animNum = random.choice([0])
        return animStrings[animNum]

    def getAnimInfo(self, state):
        return self.animInfo.get(state, self.FailsafeAnims)

    @classmethod
    def setupAnimInfoState(cls, state, info):
        if len(info) < len(cls.FailsafeAnims):
            info += cls.FailsafeAnims[len(info) - len(cls.FailsafeAnims):]
        cls.animInfo[state] = info

    @classmethod
    def setupAnimInfo(cls):
        cls.setupAnimInfoState('LandRoam', cls.FailsafeAnims)
        cls.setupAnimInfoState('WaterRoam', cls.FailsafeAnims)

    @classmethod
    def setupAnims(cls):
        cls.animInfo = copy.copy(SeaMonster.animInfo)
        cls.setupAnimInfo()
        filePrefix = cls.ModelInfo[1]
        animList = cls.AnimList
        animDict = {}
        for anim in animList:
            animDict[anim[0]] = filePrefix + anim[1]

        cls.animDict = animDict

    def setLODs(self):
        avatarDetail = base.config.GetString('avatar-detail', 'high')
        if avatarDetail == 'high':
            dist = [0, 20, 80, 280]
        elif avatarDetail == 'med':
            dist = [0, 10, 40, 280]
        elif avatarDetail == 'low':
            dist = [0, 6, 20, 280]
        else:
            raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail
        self.addLOD('low', dist[3], dist[2])
        self.addLOD('med', dist[2], dist[1])
        self.addLOD('hi', dist[1], dist[0])

    @classmethod
    def setupAssets(cls):
        cls.animInfo = copy.copy(SeaMonster.animInfo)
        cls.setupAnimInfo()
        filePrefix = cls.ModelInfo[1]
        animList = cls.AnimList
        animDict = {}
        for anim in animList:
            animDict[anim[0]] = filePrefix + anim[1]

        cls.animDict = animDict
        filePrefix = cls.ModelInfo[1]
        for name in cls.SfxNames:
            cls.sfx[name] = loadSfx(cls.SfxNames[name])

        cls.actor = Actor.Actor()
        if loader.loadModel(filePrefix + 'med') != None:
            avatarDetail = base.config.GetString('avatar-detail', 'high')
            if avatarDetail == 'high':
                dist = [0, 200, 800, 2800]
            elif avatarDetail == 'med':
                dist = [0, 100, 400, 2800]
            elif avatarDetail == 'low':
                dist = [0, 60, 200, 2800]
            else:
                raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail
            cls.actor.setLODNode()
            cls.actor.addLOD('low', dist[3], dist[2])
            cls.actor.addLOD('med', dist[2], dist[1])
            cls.actor.addLOD('hi', dist[1], dist[0])
            cls.actor.loadModel(filePrefix + 'hi', 'modelRoot', 'hi')
            cls.actor.loadModel(filePrefix + 'med', 'modelRoot', 'med')
            cls.actor.loadModel(filePrefix + 'low', 'modelRoot', 'low')
            cls.actor.loadAnims(cls.animDict, 'modelRoot', 'all')
        else:
            cls.actor.loadModel(cls.ModelInfo[0])
            cls.actor.loadAnims(cls.animDict)
        cls.actor.getGeomNode().setH(180)
        return
Esempio n. 10
0
class VisualizerApp(ShowBase):

    FOV = 90
    VIEW_DISTANCE_CHUNKS = 5

    def __init__(self, level, chunks):
        ShowBase.__init__(self)

        self.level = level

        self.disableMouse()

        wp = WindowProperties()
        #wp.setFullscreen(True)
        wp.setCursorHidden(True)
        wp.setMouseMode(WindowProperties.M_relative)
        #wp.setSize(800, 500)
        self.win.requestProperties(wp)

        self.camLens.setFov(VisualizerApp.FOV)

        self.keyMap = {
            'forward': 0,
            'backward': 0,
            'left': 0,
            'right': 0,
            'shift': 0
        }

        self.setBackgroundColor(0.53, 0.80, 0.92, 1)

        self.accept('escape', sys.exit)
        self.accept("a", self.set_key, ["left", True])
        self.accept("d", self.set_key, ["right", True])
        self.accept("w", self.set_key, ["forward", True])
        self.accept("s", self.set_key, ["backward", True])
        self.accept('lshift', self.set_key, ['shift', True])
        self.accept("a-up", self.set_key, ["left", False])
        self.accept("d-up", self.set_key, ["right", False])
        self.accept("w-up", self.set_key, ["forward", False])
        self.accept("s-up", self.set_key, ["backward", False])
        self.accept('lshift-up', self.set_key, ['shift', False])

        self.cameraMovementTask = taskMgr.add(self.camera_movement, "CameraMovement")
        self.cameraRotationTask = taskMgr.add(self.camera_rotation, 'CameraRotation')

        self.position_text = OnscreenText(text="Position: \nChunk: ", align=TextNode.ALeft, parent=self.pixel2d, fg=(1, 1, 1, 1), bg=(0, 0, 0, 0.7))
        self.position_text.setScale(18)
        self.position_text.setPos(5, -20)

        self.taskMgr.setupTaskChain('chunk_loader_chain', numThreads=6)

        self.create_lights()

        self.taskMgr.doMethodLater(0, self.load_chunks, 'Load Chunks', extraArgs=[chunks], appendTask=True)

        self.camera.setPos(-64 * 5, 54 * 5, 100)

    def create_lights(self):

        plight = PointLight('plight')
        plight.setColor((0.2, 0.2, 0.2, 1))
        plight_node = self.render.attachNewNode(plight)
        plight_node.setPos(-64 * 25, 54 * 25, 126)
        self.render.setLight(plight_node)

        alight = AmbientLight('alight')
        alight.setColor((0.2, 0.2, 0.2, 1))
        self.render.setLight(self.render.attachNewNode(alight))

    def set_key(self, key, value):
        self.keyMap[key] = value

    def recenter_mouse(self):
        self.win.movePointer(0,
                             int(self.win.getProperties().getXSize() / 2),
                             int(self.win.getProperties().getYSize() / 2))

    SENSITIVITY_MULTIPLIER = 20

    def camera_rotation(self, task):

        mw = self.mouseWatcherNode

        has_mouse = mw.hasMouse()

        if has_mouse:
            dx, dy = mw.getMouseX(), mw.getMouseY()
        else:
            dx, dy = 0, 0

        camera_h = self.camera.getH() + -dx * VisualizerApp.SENSITIVITY_MULTIPLIER
        camera_p = self.camera.getP() + dy * VisualizerApp.SENSITIVITY_MULTIPLIER

        self.camera.setH(camera_h)
        self.camera.setP(camera_p)

        self.recenter_mouse()
        return task.cont

    MOVE_SPEED = 3
    MOVE_SPEED_MULTIPLIER = 10

    def camera_movement(self, task):

        dt = globalClock.getDt()

        direction = self.render.getRelativeVector(self.camera, (0, 1, 0))
        direction.normalize()

        position = self.camera.getPos()

        move_speed = VisualizerApp.MOVE_SPEED

        if self.keyMap['shift']:
            move_speed *= VisualizerApp.MOVE_SPEED_MULTIPLIER

        if self.keyMap['forward']:
            position += direction * dt * move_speed
        if self.keyMap['backward']:
            position += direction * dt * -move_speed

        self.camera.setPos(position)

        chunk_x = position.x // self.level.chunk_width
        chunk_z = position.y // self.level.chunk_depth

        self.position_text.text = 'Position: (x: %04d, y: %04d, z: %04d)\nChunk (x: %02d, z: %02d)' % (position.x, position.z, position.y, chunk_x, chunk_z)

        return task.cont

    def load_chunks(self, chunks, task):

        for chunk in chunks:
            self.taskMgr.doMethodLater(0, self.load_chunk, 'Load Chunk', extraArgs=[chunk], appendTask=True,
                                       taskChain='chunk_loader_chain')

        return task.done

    def load_chunk(self, chunk, task):

        voxel_real_size = Vec3(self.level.chunk_unit_width / self.level.chunk_width, self.level.chunk_unit_height / self.level.chunk_voxel_height,
                               self.level.chunk_unit_depth / self.level.chunk_depth)

        chunk_size = Vec3(self.level.chunk_width, self.level.chunk_voxel_height, self.level.chunk_depth)

        chunk = VChunk(chunk_size, voxel_real_size, chunk)
        chunk.show(self)

        return task.done
Esempio n. 11
0
class MyApp(ShowBase):
    """Test class for the all the uses cases for the EasingMgr class."""

    def __init__(self):
        ShowBase.__init__(self)

        base.disableMouse()
        base.setBackgroundColor(.2, .2, .2)

        camera.setPos(0, 0, 45)
        camera.setHpr(0, -90, 0)

        self.curr_ease = [(easeClass[8], easeType[1]),
                          (easeClass[8], easeType[1]),
                          (easeClass[8], easeType[1])]
        self.curr_param = easeParam[2]

        self._labs = []

        self.param_lab = OnscreenText(text=self.curr_param,
                                      pos=(-1.3, .9),
                                      scale=0.07,
                                      fg=(0.8, 0.8, 0.8, 1),
                                      align=TextNode.ALeft,
                                      mayChange=1)

        self.controls = OnscreenText(text='Controls: \n' +
          '   [p] Change paramter. \n' +
          '   [q, a, z] Change ease mode (x, y, z).\n' +
          '   [w, s, x] Change ease type (x,y, z).\n' +
          '   [spacebar] Start the transition.\n' +
          '   [esc] Quit.',
                                     pos=(-1.3, -.7),
                                     scale=0.055,
                                     fg=(0.8, 0.8, 0.8, 1),
                                     align=TextNode.ALeft)

        for i in range(3):
            row = []
            row.append(OnscreenText(text=axis[i],
                                    pos=(-.9, .9 - (i*.1)),
                                    scale=0.07,
                                    fg=(0.8, 0.8, 0.8, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1))
            row.append(OnscreenText(text=self.curr_ease[i][0],
                                    pos=(-.8, .9 - (i*.1)),
                                    scale=0.07,
                                    fg=(0.8, 0.8, 0.8, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1))

            row.append(OnscreenText(text=self.curr_ease[i][1],
                                    pos=(-.6, .9 - (i*.1)),
                                    scale=0.07,
                                    fg=(0.8, 0.8, 0.8, 1),
                                    align=TextNode.ALeft,
                                    mayChange=1))
            self._labs.append(row)

        self._node = None

        self._ease_values = {'position3D': [(-8.0, -3.0, 10.0),
                                            (15.0, 3.0, -20.0)],
                             'position2D': [(-.7, -.3), (.7, .3)],
                             'scale1D': [[.08], [.20]],
                             'scale3D': [(1.0, 1.0, 1.0), (4.0, 4.0, 4.0)]}

        self.end_time = 1.0

        self.accept('escape', sys.exit, [0])
        self.input_setup(True)

        self.__easingMgr = EasingMgr()
        self.__curr_tr = None

        self.__change_param(0)

    def input_setup(self, activate):
        if activate:
            self.accept('q-up', self.__change_class, extraArgs=[0, 1])
            self.accept('a-up', self.__change_class, extraArgs=[1, 1])
            self.accept('z-up', self.__change_class, extraArgs=[2, 1])
            self.accept('w-up', self.__change_type, extraArgs=[0, 1])
            self.accept('s-up', self.__change_type, extraArgs=[1, 1])
            self.accept('x-up', self.__change_type, extraArgs=[2, 1])

            self.accept('p-up', self.__change_param, extraArgs=[1])
            self.accept('space-up', self.start_ease)
            self.accept('escape', sys.exit, [0])
        else:
            self.ignoreAll()

    def start_ease(self):
        self.input_setup(False)
        self.__easingMgr.start_transition(self.__curr_tr)

    def check_finished(self):
        if not self.__curr_tr.is_updating:
            self.input_setup(True)

    def __change_class(self, row, incr):
        self.curr_ease[row] = (easeClass[
            (easeClass.index(self.curr_ease[row][0]) + incr) % len(easeClass)],
            self.curr_ease[row][1])
        self._labs[row][1].setText(self.curr_ease[row][0])
        self.change_transition()

    def __change_type(self, row, incr):
        self.curr_ease[row] = (self.curr_ease[row][0], easeType[
            (easeType.index(self.curr_ease[row][1]) + incr) % len(easeType)])
        self._labs[row][2].setText(self.curr_ease[row][1])
        self.change_transition()

    def __change_param(self, incr):
        self.curr_param = easeParam[
            (easeParam.index(self.curr_param) + incr) % len(easeParam)]
        self.param_lab.setText(self.curr_param)
        self.release_nodes()
        if self.curr_param in ['position2D', 'scale1D']:
            self.load_text()
        if self.curr_param in ['position3D', 'scale3D']:
            self.load_sphere()
        if '1D' in self.curr_param:
            for i, row in enumerate(self._labs):
                if i < 1:
                    for lab in row:
                        lab.show()
                else:
                    for lab in row:
                        lab.hide()

        if '2D' in self.curr_param:
            for i, row in enumerate(self._labs):
                if i < 2:
                    for lab in row:
                        lab.show()
                else:
                    for lab in row:
                        lab.hide()
        if '3D' in self.curr_param:
            for i, row in enumerate(self._labs):
                for lab in row:
                    lab.show()
        self.change_transition()

    def change_transition(self):
        if self.__curr_tr:
            self.__easingMgr.remove_transition(self.__curr_tr)

        values = self._ease_values[self.curr_param]
        self.__curr_tr = self.__easingMgr.add_transition(self._node,
                                                         self.curr_param,
                                                         self.curr_ease,
                                                         self.end_time,
                                                         values,
                                                         self.check_finished)

    def load_text(self):
        self._node = OnscreenText(text='Fantastic text',
                                  pos=(self._ease_values['position2D'][0]),
                                  scale=self._ease_values['scale1D'][0][0])

    def load_sphere(self):
        self._node = loader.loadModel("assets/planet_sphere")
        self._node.reparentTo(render)
        self._node.setScale(self._ease_values['scale3D'][0][0],
                            self._ease_values['scale3D'][0][1],
                            self._ease_values['scale3D'][0][2])
        self._node.setPos(self._ease_values['position3D'][0][0],
                          self._ease_values['position3D'][0][1],
                          self._ease_values['position3D'][0][2])
        self._node_tex = loader.loadTexture("assets/earth.jpg")
        self._node.setTexture(self._node_tex, 1)

    def release_nodes(self):
        if self._node:
            self._node.removeNode()
            self._node = None
Esempio n. 12
0
File: Game.py Progetto: ajh123/game
class GameApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.viewDistanceChunks = 4
        self.viewDistance = (self.viewDistanceChunks + 0.5) * CHUNK_SIDE

        self.visibleChunksXY = set()
        self.visibleChunks = {}
        self.chunksForLoader = {}

        # Disable the camera trackball controls.
        self.disableMouse()

        self.camAngleA = 0
        self.camAngleB = 0

        self.currChunkXY = (None, None)
        self.currChunk = None

        self.accept('arrow_left', self.evtArrowLeft)
        self.accept('arrow_left-repeat', self.evtArrowLeft)
        self.accept('arrow_right', self.evtArrowRight)
        self.accept('arrow_right-repeat', self.evtArrowRight)
        self.accept('arrow_up', self.evtArrowUp)
        self.accept('arrow_up-repeat', self.evtArrowUp)
        self.accept('arrow_down', self.evtArrowDown)
        self.accept('arrow_down-repeat', self.evtArrowDown)
        self.accept('w', self.evtForward)
        self.accept('w-repeat', self.evtForward)
        self.accept('s', self.evtBack)
        self.accept('s-repeat', self.evtBack)
        self.accept('i', self.render.analyze)

        self.dirtTexture = self.loader.loadTexture("textures/blocks/dirt.png")
        self.dirtTexture.setMagfilter(Texture.FTNearest)
        self.dirtTexture.setMinfilter(Texture.FTLinearMipmapLinear)

        self.waterTexture = self.loader.loadTexture(
            "textures/blocks/water.jpg")
        self.waterTexture.setMagfilter(Texture.FTNearest)
        self.waterTexture.setMinfilter(Texture.FTLinearMipmapLinear)

        self.xyzInfo = OnscreenText(text="text",
                                    align=TextNode.ALeft,
                                    parent=pixel2d,
                                    fg=(1, 1, 1, 1),
                                    bg=(0, 0, 0, 0.7))
        self.xyzInfo.setScale(18, 20)
        self.xyzInfo.setPos(5, -20)

        #self.messenger.toggleVerbose()

        self.setFrameRateMeter(True)
        #self.chunkLoaderThread = threading.Thread(target=chunkLoader)
        #self.chunkLoaderThread.start()

        taskMgr.doMethodLater(0.01, self.refreshChunksTask,
                              'refreshChunksTask')
        taskMgr.setupTaskChain('chunkLoaderTaskChain', numThreads=1)

        bgColor = (0.3, 0.5, 1)
        self.setBackgroundColor(*bgColor)
        self.initFog(bgColor)
        self.camLens.setFar(self.viewDistance)

        self.setCamPos(CHUNK_SIDE / 2, CHUNK_SIDE / 2, 32)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(-30, -60, 0)
        render.setLight(dlnp)

        alight = AmbientLight('alight')
        alight.setColor(VBase4(0.4, 0.4, 0.4, 1))
        alnp = render.attachNewNode(alight)
        render.setLight(alnp)

    def initFog(self, color):
        self.fog = Fog("fog")
        self.fog.setColor(*color)
        self.fog.setLinearRange(self.viewDistance * 0.8, self.viewDistance)
        self.render.setFog(self.fog)

    @staticmethod
    def coordConvert(angA, angB, l):
        angA = radians(90 + angA)
        angB = radians(90 - angB)
        x = sin(angB) * cos(angA) * l
        y = sin(angB) * sin(angA) * l
        z = cos(angB) * l
        return x, y, z

    #----------Events--------------
    def evtArrowLeft(self):
        self.camAngleA += 1

        if self.camAngleA > 180:
            self.camAngleA = -179

        self.camera.setH(self.camAngleA)

    def evtArrowRight(self):
        self.camAngleA -= 1

        if self.camAngleA < -179:
            self.camAngleA = 180

        self.camera.setH(self.camAngleA)

    def evtArrowUp(self):
        self.camAngleB += 1

        if self.camAngleB > 90:
            self.camAngleB = 90

        self.camera.setP(self.camAngleB)

    def evtArrowDown(self):
        self.camAngleB -= 1

        if self.camAngleB < -90:
            self.camAngleB = -90

        self.camera.setP(self.camAngleB)

    def evtForward(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, 0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    def evtBack(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, -0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    #------------------------------
    def setCamPos(self, x, y, z):
        self.camera.setPos(x, y, z)

        chunkXY = (int(floor(x / CHUNK_SIDE)), int(floor(y / CHUNK_SIDE)))
        if chunkXY != self.currChunkXY:
            self.setCurrChunk(chunkXY)

        self.xyzInfo.setText("x=%2.2f\ny=%2.2f\nz=%2.2f" % (x, y, z))

    def setCurrChunk(self, chunkXY):
        print chunkXY
        self.currChunkXY = chunkXY
        self.updateVisibleChunkSet()

    @staticmethod
    def loadChunk(chunkXY):
        return Chunk(chunkXY)

    def createVisibleChunkList(self):

        currChunkX, currChunkY = self.currChunkXY

        viewDistSquare = (self.viewDistanceChunks + 1)**2
        #chunkList = filter( lambda xy : xy[0]**2 + xy[1]**2 <=  viewDistSquare,
        #                    product(xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
        #                            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1)))
        chunkList = product(
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1))

        def maxXY(xy1, xy2):
            x1, y1 = xy1
            x2, y2 = xy2
            max1 = max(abs(x1), abs(y1))
            max2 = max(abs(x2), abs(y2))
            return cmp(max1, max2)

        chunkList = [(x + currChunkX, y + currChunkY)
                     for x, y in sorted(chunkList, maxXY)]

        return chunkList

    def updateVisibleChunkSet(self):
        self.visibleChunksXY = self.createVisibleChunkList()
        self.chunkRefreshNeeded = True

    def refreshChunksTask(self, task):
        if not self.chunkRefreshNeeded:
            return task.again

        if taskMgr.hasTaskNamed('chunkLoaderTask'):
            return task.again

        self.chunkRefreshNeeded = False

        print "thinking..."

        chunksToUnload = {}
        oldVisibleChunks = self.visibleChunks
        self.visibleChunks = {}

        for xy, chunk in oldVisibleChunks.iteritems():
            if isinstance(chunk, Chunk):
                if xy in self.visibleChunksXY:
                    self.visibleChunks[xy] = chunk
                else:
                    chunksToUnload[xy] = chunk
                    chunk.hide()
                    chunk.setFree(True)

        chunksToLoadXY = set()

        for xy in self.visibleChunksXY:
            if not self.visibleChunks.has_key(xy):
                chunk = self.chunksForLoader.get(xy, None)
                if isinstance(chunk, Chunk):
                    chunk.show(self)
                    self.visibleChunks[xy] = chunk
                    del self.chunksForLoader[xy]
                else:
                    if len(chunksToLoadXY) <= 2:
                        chunksToLoadXY.add(xy)

        for xy, chunk in self.chunksForLoader.iteritems():
            chunk.setFree(True)

        for xy, chunk in chunksToUnload.iteritems():
            self.chunksForLoader[xy] = chunk

        for xy in chunksToLoadXY:

            self.chunksForLoader[xy] = True

        taskMgr.add(self.chunkLoaderTask,
                    'chunkLoaderTask',
                    taskChain='chunkLoaderTaskChain')

        print "end of thinking"

        return task.again

    def chunkLoaderTask(self, task):
        print "loader Task"

        for xy, chunk in self.chunksForLoader.items():
            if chunk == True:
                newChunk = Chunk(xy)
                self.chunksForLoader[xy] = newChunk
                self.chunkRefreshNeeded = True
            elif isinstance(chunk, Chunk) and chunk.getFree():
                chunk.unload()
                del self.chunksForLoader[xy]
            else:
                print "chunkLoaderTask:unexpected chunk"

        print "loader Task end"
        return Task.done
Esempio n. 13
0
class KubikiApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.viewDistanceChunks = 4
        self.viewDistance = (self.viewDistanceChunks + 0.5) * CHUNK_SIDE

        self.visibleChunksXY = set()
        self.visibleChunks = {}
        self.chunksForLoader = {}

        # Disable the camera trackball controls.
        self.disableMouse()

        self.camAngleA = 0
        self.camAngleB = 0

        self.currChunkXY = (None, None)
        self.currChunk = None

        self.accept('arrow_left', self.evtArrowLeft)
        self.accept('arrow_left-repeat', self.evtArrowLeft)
        self.accept('arrow_right', self.evtArrowRight)
        self.accept('arrow_right-repeat', self.evtArrowRight)
        self.accept('arrow_up', self.evtArrowUp)
        self.accept('arrow_up-repeat', self.evtArrowUp)
        self.accept('arrow_down', self.evtArrowDown)
        self.accept('arrow_down-repeat', self.evtArrowDown)
        self.accept('w', self.evtForward)
        self.accept('w-repeat', self.evtForward)
        self.accept('s', self.evtBack)
        self.accept('s-repeat', self.evtBack)
        self.accept('i', self.render.analyze)

        self.texture = self.loader.loadTexture("dirt.png")
        self.texture.setMagfilter(Texture.FTNearest)
        self.texture.setMinfilter(Texture.FTLinearMipmapLinear)

        self.xyzInfo = OnscreenText(text="text",
                                    align=TextNode.ALeft,
                                    parent=pixel2d,
                                    fg=(1, 1, 1, 1),
                                    bg=(0, 0, 0, 0.7))
        self.xyzInfo.setScale(18, 20)
        self.xyzInfo.setPos(5, -20)

        #self.messenger.toggleVerbose()

        self.setFrameRateMeter(True)
        #self.chunkLoaderThread = threading.Thread(target=chunkLoader)
        #self.chunkLoaderThread.start()

        taskMgr.doMethodLater(0.01, self.refreshChunksTask,
                              'refreshChunksTask')
        taskMgr.setupTaskChain('chunkLoaderTaskChain', numThreads=1)

        bgColor = (0.3, 0.5, 1)
        self.setBackgroundColor(*bgColor)
        self.initFog(bgColor)
        self.camLens.setFar(self.viewDistance)

        self.setCamPos(CHUNK_SIDE / 2, CHUNK_SIDE / 2, 32)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(-30, -60, 0)
        render.setLight(dlnp)

        alight = AmbientLight('alight')
        alight.setColor(VBase4(0.4, 0.4, 0.4, 1))
        alnp = render.attachNewNode(alight)
        render.setLight(alnp)

    def initFog(self, color):
        self.fog = Fog("fog")
        self.fog.setColor(*color)
        self.fog.setLinearRange(self.viewDistance * 0.8, self.viewDistance)
        self.render.setFog(self.fog)

    @staticmethod
    def coordConvert(angA, angB, l):
        #Преобразование из системы коородинат Panda3d в координаты для формулы
        angA = radians(90 + angA)
        angB = radians(90 - angB)
        x = sin(angB) * cos(angA) * l
        y = sin(angB) * sin(angA) * l
        z = cos(angB) * l
        return x, y, z

    #----------Events--------------
    def evtArrowLeft(self):
        self.camAngleA += 1

        if self.camAngleA > 180:
            self.camAngleA = -179

        self.camera.setH(self.camAngleA)

    def evtArrowRight(self):
        self.camAngleA -= 1

        if self.camAngleA < -179:
            self.camAngleA = 180

        self.camera.setH(self.camAngleA)

    def evtArrowUp(self):
        self.camAngleB += 1

        if self.camAngleB > 90:
            self.camAngleB = 90

        self.camera.setP(self.camAngleB)

    def evtArrowDown(self):
        self.camAngleB -= 1

        if self.camAngleB < -90:
            self.camAngleB = -90

        self.camera.setP(self.camAngleB)

    def evtForward(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, 0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    def evtBack(self):
        dx, dy, dz = self.coordConvert(self.camAngleA, self.camAngleB, -0.2)
        x, y, z = self.camera.getPos()
        self.setCamPos(x + dx, y + dy, z + dz)

    #------------------------------
    def setCamPos(self, x, y, z):
        self.camera.setPos(x, y, z)

        chunkXY = (int(floor(x / CHUNK_SIDE)), int(floor(y / CHUNK_SIDE)))
        if chunkXY != self.currChunkXY:
            self.setCurrChunk(chunkXY)

        self.xyzInfo.setText("x=%2.2f\ny=%2.2f\nz=%2.2f" % (x, y, z))

    def setCurrChunk(self, chunkXY):
        print chunkXY
        self.currChunkXY = chunkXY
        self.updateVisibleChunkSet()

    @staticmethod
    def loadChunk(chunkXY):
        return Chunk(chunkXY)

    def createVisibleChunkList(self):

        currChunkX, currChunkY = self.currChunkXY

        #Создаём список смещений чанков от текущего, и фильтруем его через функцию чтобы скруглить
        #слишком удалённые углы
        viewDistSquare = (self.viewDistanceChunks + 1)**2
        #chunkList = filter( lambda xy : xy[0]**2 + xy[1]**2 <=  viewDistSquare,
        #                    product(xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
        #                            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1)))
        chunkList = product(
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1),
            xrange(-self.viewDistanceChunks, self.viewDistanceChunks + 1))

        def maxXY(xy1, xy2):
            x1, y1 = xy1
            x2, y2 = xy2
            max1 = max(abs(x1), abs(y1))
            max2 = max(abs(x2), abs(y2))
            return cmp(max1, max2)

        chunkList = [(x + currChunkX, y + currChunkY)
                     for x, y in sorted(chunkList, maxXY)]

        return chunkList

    def updateVisibleChunkSet(self):
        #Новый массив с видимыми чанками
        self.visibleChunksXY = self.createVisibleChunkList()
        self.chunkRefreshNeeded = True

    def refreshChunksTask(self, task):
        if not self.chunkRefreshNeeded:
            return task.again

        if taskMgr.hasTaskNamed('chunkLoaderTask'):
            return task.again

        self.chunkRefreshNeeded = False

        print "thinking..."

        chunksToUnload = {}
        oldVisibleChunks = self.visibleChunks
        self.visibleChunks = {}

        #Старые видимые чанки переносим в новые или готовим к выгрузке
        for xy, chunk in oldVisibleChunks.iteritems():
            if isinstance(chunk, Chunk):
                if xy in self.visibleChunksXY:
                    self.visibleChunks[xy] = chunk
                else:
                    chunksToUnload[xy] = chunk
                    chunk.hide()
                    chunk.setFree(True)

        chunksToLoadXY = set()

        #Недостающие чанки получаем из загруженных или готовим задание на загрузку
        for xy in self.visibleChunksXY:
            if not self.visibleChunks.has_key(xy):
                chunk = self.chunksForLoader.get(xy, None)
                if isinstance(chunk, Chunk):
                    chunk.show(self)
                    self.visibleChunks[xy] = chunk
                    del self.chunksForLoader[xy]
                else:
                    if len(chunksToLoadXY) <= 2:
                        chunksToLoadXY.add(xy)

        #Загруженные, но ненужные чанки - на выгрузку

        for xy, chunk in self.chunksForLoader.iteritems():
            chunk.setFree(True)

        #Задание на выгрузку
        for xy, chunk in chunksToUnload.iteritems():
            self.chunksForLoader[xy] = chunk

        #Задание на загрузку
        for xy in chunksToLoadXY:

            self.chunksForLoader[xy] = True

        #Запускаем задачу загрузки-выгрузки
        taskMgr.add(self.chunkLoaderTask,
                    'chunkLoaderTask',
                    taskChain='chunkLoaderTaskChain')

        print "end of thinking"

        return task.again

    def chunkLoaderTask(self, task):
        """
        Запускается при необходимости загрузить-выгрузить чанки.
        Выполняется в отдельном потоке
        """
        print "loader Task"

        for xy, chunk in self.chunksForLoader.items():
            if chunk == True:
                #Грузим новый чанк
                newChunk = Chunk(xy)
                self.chunksForLoader[xy] = newChunk
                self.chunkRefreshNeeded = True
            elif isinstance(chunk, Chunk) and chunk.getFree():
                #Выгружаем ненужный чанк
                chunk.unload()
                del self.chunksForLoader[xy]
            else:
                print "chunkLoaderTask:unexpected chunk"

        print "loader Task end"
        return Task.done