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)
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))"""
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)
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)
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)
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)
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)
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
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
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
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
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