Esempio n. 1
0
class Player(object):
    """
        Player is the main actor in the fps game
    """
    HP = 100
    EROSION = 0
    updateTime = 0
    speed = 10
    FORWARD = Vec3(0, 2, 0)
    BACK = Vec3(0, -1, 0)
    LEFT = Vec3(-1, 0, 0)
    RIGHT = Vec3(1, 0, 0)
    STOP = Vec3(0)
    walk = STOP
    strafe = STOP
    readyToJump = False
    jump = 0
    state = ''
    cameraState = 1
    visionState = 0
    RightButton = 0
    LeftButton = 0
    goodmanager = None
    isInteractive = False
    SLOW = 1
    End = 0
    Begin = 1
    TaskState = End

    def __init__(self, goodmanager, m, g):
        """ inits the player """
        # 6/17
        self.walksound = loader.loadSfx("res/sounds/footstep.mp3")
        self.goodmanager = goodmanager
        self.menu = m
        self.game = g
        self.loadModel()
        self.setUpCamera()
        self.setMouseIcon()
        self.createCollisions()
        self.attachControls()
        self.initSkill()
        self.shoot = Shoot()
        # init mouse update task
        self.initSave()
        self.initTask()
        self.initMission()

    def initMission(self):
        if self.game.levelName == "tutorial":
            self.mission = Mission(self, self.menu)
        elif self.game.levelName == "levelTwo":
            self.mission = MissionTwo(self, self.menu)
        elif self.game.levelName == "levelThree":
            self.mission = MissionThree(self, self.menu)

    def initSave(self):
        self.erosionFrame = DirectFrame(frameColor=(0, 0, 0, 0),
                                        frameSize=(-1, 1, -1, 1),
                                        pos=(-1.2, 0, 0))
        self.erosionFrame.hide()
        self.erosionFrame.setScale(.02, 1, .4)
        self.background = OnscreenImage('res/erosion_bar.png',
                                        pos=(0, 0, 0),
                                        scale=(1, 1, 1))
        self.background.setTransparency(TransparencyAttrib.MAlpha)
        self.background.reparentTo(self.erosionFrame)
        # self.erosionBar = DirectWaitBar(value=self.EROSION, pos=(0, 0, 0), barTexture='res/erosion_value.png',
        #                                 relief=None)
        # self.erosionBar.setHpr(0, 0, -90)
        # self.erosionBar.setScale(0.98, 1, 10)
        # self.erosionBar.hide()
        # self.erosionBar.reparentTo(self.erosionFrame)
        self.erosionBar = OnscreenImage('res/erosion_value.png',
                                        pos=(0, 0, 0),
                                        scale=(1, 1, 1))
        self.erosionBar.setScale(1)
        self.erosionBar.setTransparency(TransparencyAttrib.MAlpha)
        self.erosionBar.reparentTo(self.erosionFrame)

        self.currentItemFrame = DirectFrame(
            frameColor=(0, 0, 0, 0),
            frameSize=(-2, 2, -2, 2),
            pos=(-1.2, 0, .8),
            image='res/models/items/injection.png',
            scale=(.1))
        self.currentItemFrame.setTransparency(TransparencyAttrib.MAlpha)
        self.currentItemFrame.hide()
        # self.currentItemFrame.show()

    def initTask(self):
        if self.TaskState == self.Begin: return
        self.TaskState = self.Begin
        self.state = ''
        self.game.gameState = ''
        self.mouseIconNormal.show()
        taskMgr.add(self.mouseUpdate, "mouse-task")
        taskMgr.add(self.moveUpdate, "move-task")
        taskMgr.add(self.jumpUpdate, 'jump-task')
        taskMgr.add(self.erosionUpdate, "erosion-task")

    def endTask(self):
        if self.TaskState == self.End: return
        self.TaskState = self.End
        self.state = 'pause'
        self.mouseIconWatch.hide()
        self.mouseIconNormal.hide()
        taskMgr.remove('mouse-task')
        taskMgr.remove('move-task')
        taskMgr.remove('jump-task')
        taskMgr.remove('erosion-task')
        # reset update time
        self.updateTime = 5

    def loadModel(self):
        """ make the nodepath for player """
        # self.playerModel = Actor("res/models/ralph", {"run": "res/models/ralph-run", "walk": "res/models/ralph-walk"})
        self.playerModel = Actor("res/models/hitman-model5", {
            "walk": "res/models/hitman-walk5",
            "stand": "res/models/hitman-stand"
        })
        # self.playerModel = Actor("res/models/hitman2-model", {"walk": "res/models/hitman2-walk", "stand":"res/models/hitman-stand"})
        self.playerModel.setH(180)
        self.playerModel.setZ(0)
        self.playerModel.setScale(1.1)
        # self.playerModel.hide()
        self.node = NodePath("player")
        self.node.reparentTo(render)
        self.playerModel.reparentTo(self.node)
        # self.node.setPos(0, 0, 10)
        self.node.setPos(-250, 265, 0)
        self.node.setHpr(150, 0, 0)
        self.node.setScale(20)
        self.node.hide(BitMask32.bit(0))
        self.node.hide(BitMask32.bit(1))

    def setMouseIcon(self):
        self.mouseIconNormal = OnscreenImage(image="res/mouse/mouse1.png",
                                             pos=(0, 1.1, 0))
        self.mouseIconNormal.setTransparency(TransparencyAttrib.MAlpha)
        self.mouseIconNormal.setScale(0.02)
        self.mouseIconNormal.setLightOff()
        self.mouseIconNormal.setSa(0.5)
        self.mouseIconWatch = OnscreenImage(image="res/mouse/mouse2.png",
                                            pos=(0, 1.1, 0))
        self.mouseIconWatch.setTransparency(TransparencyAttrib.MAlpha)
        self.mouseIconWatch.setScale(0.05)
        self.mouseIconWatch.setSa(0.5)
        self.mouseIconWatch.setLightOff()
        self.mouseIconNormal.reparentTo(base.camera)
        self.mouseIconWatch.reparentTo(base.camera)
        self.mouseIconWatch.hide()

    def SetMouseModeNormal(self, mode):
        if mode == 'Watch':
            self.mouseIconWatch.show()
            self.mouseIconNormal.hide()
        elif mode == 'Normal':
            self.mouseIconNormal.show()
            self.mouseIconWatch.hide()

    def setUpCamera(self):
        """ puts camera at the players node """
        pl = base.cam.node().getLens()
        pl.setFov(70)
        base.cam.node().setLens(pl)
        base.camera.reparentTo(self.node)
        base.cam.node().setCameraMask(BitMask32.bit(3))
        self.oldcameraState = 0
        self.cameranewPos = None
        self.cameranewH = None
        self.changeCamera()

    # 6/17
    def createCollisions(self):
        """ create a collision solid and ray for the player """
        cn = CollisionNode('PlayerCollideNode')
        cn.addSolid(CollisionSphere(0, 0, 4, 1))
        solid = self.node.attachNewNode(cn)
        solid.setScale(1, 1, 1)
        solid.setPos(0, 0, 0)
        # solid.show()
        base.cTrav.addCollider(solid, base.pusher)
        base.pusher.addCollider(solid, self.node, base.drive.node())
        # init players floor collisions
        ray = CollisionRay()
        ray.setOrigin(0, 0, 3)
        ray.setDirection(0, 0, -1)
        cn = CollisionNode('playerRay')
        cn.addSolid(ray)
        cn.setFromCollideMask(BitMask32.bit(0))
        cn.setIntoCollideMask(BitMask32.allOff())
        solid = self.node.attachNewNode(cn)
        # solid.show()
        base.cTrav.setRespectPrevTransform(True)
        self.nodeGroundHandler = CollisionHandlerQueue()
        base.cTrav.addCollider(solid, self.nodeGroundHandler)
        # init players Forward Ray
        ForwardSegment = CollisionSegment(0, 2, 0, 0, 20, 0)
        cn = CollisionNode('playerForwardSegment')
        cn.addSolid(ForwardSegment)
        cn.setFromCollideMask(BitMask32.bit(0))
        cn.setIntoCollideMask(BitMask32.allOff())
        solid = base.camera.attachNewNode(cn)
        # solid.show()
        base.cTrav.addCollider(solid, self.nodeGroundHandler)
        # repair cross wall
        ForwardSegment = CollisionSegment(0, -4, 3, 0, 4, 3)
        cn = CollisionNode('PlayerMoveForwardSegment')
        cn.addSolid(ForwardSegment)
        cn.setFromCollideMask(BitMask32.bit(0))
        cn.setIntoCollideMask(BitMask32.allOff())
        solid = self.node.attachNewNode(cn)
        # solid.show()
        base.cTrav.addCollider(solid, self.nodeGroundHandler)
        # init play Right Ray
        ForwardSegment = CollisionSegment(-2, 0, 3, 2, 0, 3)
        cn = CollisionNode('PlayerMoveRightSegment')
        cn.addSolid(ForwardSegment)
        cn.setFromCollideMask(BitMask32.bit(0))
        cn.setIntoCollideMask(BitMask32.allOff())
        solid = self.node.attachNewNode(cn)
        # solid.show()
        base.cTrav.addCollider(solid, self.nodeGroundHandler)

    def attachControls(self):
        """ attach key events """
        # base.accept("space", self.__setattr__, ["readyToJump", True])
        # base.accept("space-up", self.__setattr__, ["readyToJump", False])
        self.keyEven = [
            "s", "s-up", "w", "w-up", "a", "d", "a-up", "d-up", "c", "o",
            "mouse3", "mouse3-up", "mouse1", "mouse1-up"
        ]
        base.accept("s", self.__setattr__, ["walk", self.STOP])
        base.accept("w", self.__setattr__, ["walk", self.FORWARD])
        base.accept("s", self.__setattr__, ["walk", self.BACK])
        base.accept("s-up", self.__setattr__, ["walk", self.STOP])
        base.accept("w-up", self.__setattr__, ["walk", self.STOP])
        base.accept("a", self.__setattr__, ["strafe", self.LEFT])
        base.accept("d", self.__setattr__, ["strafe", self.RIGHT])
        base.accept("a-up", self.__setattr__, ["strafe", self.STOP])
        base.accept("d-up", self.__setattr__, ["strafe", self.STOP])
        base.accept("c", self.changeCamera)
        base.accept("o", self.doubleVision)
        base.accept("mouse3", self.__setattr__, ["RightButton", 1])
        base.accept("mouse3-up", self.__setattr__, ["RightButton", 0])
        base.accept("mouse1", self.__setattr__, ["LeftButton", 1])
        base.accept("mouse1-up", self.__setattr__, ["LeftButton", 0])

    def IgnoreControls(self):
        for name in self.keyEven:
            base.ignore(name)
        print base.getAllAccepting()

    def initSkill(self):
        self.tex = Texture()
        self.tex.setMinfilter(Texture.FTLinear)
        base.win.addRenderTexture(self.tex,
                                  GraphicsOutput.RTMTriggeredCopyTexture)
        self.tex.setClearColor((0, 0, 0, 1))
        self.tex.clearImage()

        # Create another 2D camera. Tell it to render before the main camera.
        self.backcam = base.makeCamera2d(base.win, sort=-10)
        self.background = NodePath("background")
        self.backcam.reparentTo(self.background)
        self.background.setDepthTest(0)
        self.background.setDepthWrite(0)
        self.backcam.node().getDisplayRegion(0).setClearDepthActive(0)

        self.bcard = base.win.getTextureCard()
        self.bcard.reparentTo(base.render2d)
        self.bcard.setTransparency(1)
        self.fcard = base.win.getTextureCard()
        self.fcard.reparentTo(base.render2d)
        self.fcard.setTransparency(1)

        # Add the task that initiates the screenshots.
        taskMgr.add(self.takeSnapShot, "takeSnapShot")

        if base.win.getGsg().getCopyTextureInverted():
            # print("Copy texture is inverted.")
            self.bcard.setScale(1, 1, -1)
            self.fcard.setScale(1, 1, -1)

        self.bcard.hide()
        self.fcard.hide()
        self.nextclick = 0
        self.clickrate = 10000

    def takeSnapShot(self, task):
        if task.time > self.nextclick:
            self.nextclick += 1.0 / self.clickrate
            if self.nextclick < task.time:
                self.nextclick = task.time
            base.win.triggerCopy()
        return task.cont

    def doubleVision(self):
        self.visionState = 1 - self.visionState
        if self.visionState == 1:
            self.bcard.show()
            self.bcard.setColor(1, 1, 1, 0.60)
            self.bcard.setScale(1.0)
            self.bcard.setPos(-0.05, 0, 0)
            self.bcard.setR(0)
            self.fcard.show()
            self.fcard.setColor(1, 1, 1, 0.60)
            self.fcard.setScale(1.0)
            self.fcard.setPos(0.05, 0, 0)
            self.fcard.setR(0)
            self.clickrate = 10000
            self.nextclick = 0
        else:
            self.bcard.hide()
            self.fcard.hide()

    def changeCamera(self):
        if self.cameraState == 1:
            self.cameraState = 0
        else:
            self.cameraState = 1
        self.setCamera()

    def setCamera(self):
        self.cameraoldPos = base.camera.getPos()
        self.cameraoldNear = base.cam.node().getLens().getNear()
        if self.cameraState == 0:
            self.cameranewPos = Vec3(0, -5, 10)
            pl = base.cam.node().getLens()
            self.cameranewNear = 1
            base.cam.node().setLens(pl)
        elif self.cameraState == 1:
            self.cameranewPos = Vec3(0, -1, 8)
            self.cameranewNear = 1
            # self.playerModel.hide()
            self.playerModel.hide(BitMask32.bit(3))
        elif self.cameraState == 2:
            self.cameranewPos = Vec3(0, -1.5, 8)
            self.cameranewNear = 1
        taskMgr.add(self.updatecamera, "updatecamera")

    def updatecamera(self, task):
        if task.time < 0.2:
            camera.setPos(
                (self.cameraoldPos * (0.2 - task.time) + self.cameranewPos *
                 (task.time)) / 0.2)
            return task.cont
        if self.cameraState == 1:
            self.playerModel.hide(BitMask32.bit(3))
        else:
            self.playerModel.show(BitMask32.bit(3))
        pl = base.cam.node().getLens()
        pl.setNear(self.cameraoldNear)
        base.cam.node().setLens(pl)
        return

    def erosionUpdate(self, task):
        if self.EROSION >= 100:
            self.mission.end("endA")
            return
        if self.EROSION >= 80:
            self.visionState = 0
            self.doubleVision()
        else:
            self.visionState = 1
            self.doubleVision()
        # self.erosionBar['value'] = self.EROSION
        self.erosionBar.setScale(1, 1, self.EROSION / 100)
        self.erosionBar.setPos(0, 0, -1 + self.EROSION / 100)
        if task.time > self.updateTime:
            self.EROSION = math.pow(2,
                                    (self.EROSION / 20 - 1)) / 6 + self.EROSION
            # print task.time, 'time'
            # print self.EROSION
            self.updateTime += 10
            # print self.updateTime
        return task.cont

    def erosionUpdateTemp(self):
        if self.EROSION >= 100:
            if self.game.levelName == 'levelThree':
                self.mission.chessBoard.hide()
            self.mission.end("endA")
            return
        if self.EROSION >= 80:
            self.visionState = 0
            self.doubleVision()
        else:
            self.visionState = 1
            self.doubleVision()
        # self.erosionBar['value'] = self.EROSION
        self.erosionBar.setScale(1, 1, self.EROSION / 100)
        self.erosionBar.setPos(0, 0, -1 + self.EROSION / 100)

    def mouseUpdate(self, task):
        """ this task updates the mouse """
        if self.state == '':
            md = base.win.getPointer(0)
            x = md.getX()
            y = md.getY()
            if base.win.movePointer(0,
                                    base.win.getXSize() / 2,
                                    base.win.getYSize() / 2):
                self.node.setH(self.node.getH() -
                               (x - base.win.getXSize() / 2) * 0.1)
                base.camera.setP(base.camera.getP() -
                                 (y - base.win.getYSize() / 2) * 0.1)
                if (base.camera.getP() < -45.): base.camera.setP(-45)
                if (base.camera.getP() > 45.): base.camera.setP(45)

        if self.RightButton == 1:
            self.shoot.MouseDown(self.node)
            self.EROSION += 5
            self.RightButton = 0

        # check Interactive Goods
        nearest = 1000.0
        goods = None
        for i in range(self.nodeGroundHandler.getNumEntries()):
            entry = self.nodeGroundHandler.getEntry(i)
            IntoName = entry.getIntoNode().getName()
            FromName = entry.getFromNode().getName()
            if FromName == 'playerForwardSegment':
                if entry.getSurfacePoint(base.camera).getY() < nearest:
                    nearest = entry.getSurfacePoint(base.camera).getY()
                    goods = self.goodmanager.GoodsIta.get(IntoName)
        if goods and goods.Interactive == True:
            # print goods.Name
            self.SetMouseModeNormal('Watch')
            self.isInteractive = True
            self.currentInteract = goods
        else:
            self.SetMouseModeNormal('Normal')
            self.isInteractive = False
            self.currentInteract = None

        if self.LeftButton == 1 and self.isInteractive:
            print 'trigger interactive event'
            print goods.Name
            self.mission.interactiveWith(goods)

        return task.cont

    def moveUpdate(self, task):
        """ this task makes the player move """
        # move where the keys set it
        # print self.node.getPos()
        nearestForward = 1000.0
        nearestRight = 1000.0
        RightEntry = None
        ForwardEntry = None
        for i in range(self.nodeGroundHandler.getNumEntries()):
            entry = self.nodeGroundHandler.getEntry(i)
            IntoName = entry.getIntoNode().getName()
            FromName = entry.getFromNode().getName()
            if FromName == 'PlayerMoveForwardSegment' and (
                    IntoName != 'PlayerCollideNode'):
                if entry.getSurfacePoint(self.node).getY() < nearestForward:
                    nearestForward = entry.getSurfacePoint(self.node).getY()
                    ForwardEntry = entry
            if FromName == 'PlayerMoveRightSegment' and (IntoName !=
                                                         'PlayerCollideNode'):
                if abs(entry.getSurfacePoint(self.node).getX()) < nearestRight:
                    nearestRight = abs(entry.getSurfacePoint(self.node).getX())
                    RightEntry = entry
        if nearestForward < 2 and nearestForward > -2:
            self.SLOW = abs(nearestForward) * 0.2
            self.node.setPos(self.node.getPos() +
                             ForwardEntry.getSurfaceNormal(render))
        else:
            self.SLOW = 1
        if nearestRight < 2:
            self.node.setPos(self.node.getPos() +
                             RightEntry.getSurfaceNormal(render))
        if (nearestForward < 0 and nearestForward > -5.) or nearestRight < 5:
            if self.cameraState == 0:
                self.cameraState = 2
                self.setCamera()
        else:
            if self.cameraState == 2:
                self.cameraState = 0
                self.setCamera()

        if self.state == '':
            self.walksound.setLoop(False)
            #self.walksound.stop()
            if ((self.walk == self.FORWARD)
                    and (self.playerModel.getAnimControl('walk').isPlaying()
                         == False)):
                self.walksound.setLoop(True)
                self.walksound.setVolume(0.5)
                self.walksound.play()
                self.playerModel.getAnimControl('walk').play()

            elif self.walk == self.STOP and self.playerModel.getAnimControl(
                    'stand').isPlaying() == False:
                self.playerModel.getAnimControl('stand').play()
                self.playerModel.getAnimControl('walk').stop()
                self.walksound.setLoop(False)
                self.walksound.stop()
                if self.strafe == LVector3f(
                        -1, 0, 0) or self.strafe == LVector3f(1, 0, 0):
                    self.walksound.setLoop(True)
                    # self.walksound.setVolume(0.5)
                    self.walksound.play()
                elif self.strafe == LVector3f(0, 0, 0):
                    self.walksound.setLoop(False)
                    self.walksound.stop()
            #elif self.walk == self.BACK:
            #self.walksound.setLoop(True)
            #self.walksound.setVolume(0.5)
            #self.walksound.play()

            self.node.setFluidPos(
                self.node,
                self.walk * globalClock.getDt() * self.speed * self.SLOW)
            self.node.setFluidPos(
                self.node,
                self.strafe * globalClock.getDt() * self.speed * self.SLOW)
        return task.cont

    # 6/17
    def jumpUpdate(self, task):
        """ this task simulates gravity and makes the player jump """
        # get the highest Z from the down casting ray
        highestZ = -100
        for i in range(self.nodeGroundHandler.getNumEntries()):
            entry = self.nodeGroundHandler.getEntry(i)
            # print entry
            z = entry.getSurfacePoint(render).getZ()
            # if z > highestZ and entry.getFromNode().getName() == 'playerRay' and entry.getIntoNode().getName() != "PlayerCollideNode":
            if z > highestZ and entry.getFromNode().getName(
            ) == 'playerRay' and entry.getIntoNode().getName() == "floor":
                highestZ = z
                # print highestZ
        # gravity effects and jumps
        self.node.setZ(self.node.getZ() +
                       self.jump * globalClock.getDt() * 600)
        self.jump -= 1 * globalClock.getDt()
        if highestZ > self.node.getZ():
            self.jump = 0
            self.node.setZ(highestZ)
            if self.readyToJump:
                self.jump = 1
        return task.cont
class CanvasPanel():
    def __init__(self, parent):
        self.parent = parent
        self.elementHandler = None

        color = (
            (0.8, 0.8, 0.8, 1), # Normal
            (0.9, 0.9, 1, 1), # Click
            (0.8, 0.8, 1, 1), # Hover
            (0.5, 0.5, 0.5, 1)) # Disabled
        # respect menu bar

        self.canvasScale = 1080 # min(base.getSize()[0], base.getSize()[1])

        # we default to a 1920x1080 FHD screen
        self.canvasLeft = -1920/2
        self.canvasRight = 1920/2
        self.canvasTop = 1080/2
        self.canvasBottom = -1080/2

        self.visualEditor = DirectScrolledFrame(
            frameColor=(0.25, 0.25, 0.25, 1),
            canvasSize=(self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop),
            scrollBarWidth=20,

            # vertical scrollbar
            verticalScroll_value=0.5,
            verticalScroll_thumb_relief=DGG.FLAT,
            verticalScroll_incButton_relief=DGG.FLAT,
            verticalScroll_decButton_relief=DGG.FLAT,
            verticalScroll_thumb_frameColor=color,
            verticalScroll_incButton_frameColor=color,
            verticalScroll_decButton_frameColor=color,

            # horizontal scrollbar
            horizontalScroll_value=0.5,
            horizontalScroll_thumb_relief=DGG.FLAT,
            horizontalScroll_incButton_relief=DGG.FLAT,
            horizontalScroll_decButton_relief=DGG.FLAT,
            horizontalScroll_thumb_frameColor=color,
            horizontalScroll_incButton_frameColor=color,
            horizontalScroll_decButton_frameColor=color,
            )

        self.scaleParent = DirectFrame(
            scale=(1,1,1)
            )

        # store which base parent should be used for the elements
        self.currentVisEditorParent = base.aspect2d
        self.visEditorInAspect2D = True

        # Layouting
        self.sizer = DirectAutoSizer(
            updateOnWindowResize=False,
            parent=parent,
            child=self.visualEditor,
            )

        # zoom scale
        self.minScale = DEFAULT_MIN_SCALE
        self.maxScale = DEFAULT_MAX_SCALE
        self.zoomInMultiplyer = 1.1
        self.zoomOutMultiplyer = 0.9

        # This frame will be the base parent for the added GUI elements
        self.elementHolder = DirectFrame(
            #frameColor=(0.25, 0.25, 0.25, 1),
            scale=LVecBase3f(self.canvasScale/2,1,self.canvasScale/2),
            parent=self.scaleParent
            )
        self.elementHolder.bind(DGG.B1RELEASE, base.messenger.send, ["mouse3"])
        # Ensure the holder frame will be streched to fill the parent
        self.scaleParentSizer = DirectAutoSizer(
            parent=self.visualEditor.canvas,
            child=self.scaleParent,
            parentGetSizeFunction=self.visualEditor.cget,
            parentGetSizeExtraArgs=["canvasSize"],
            )

        self.elementHolderSizer = DirectAutoSizer(
            parent=self.scaleParent,
            child=self.elementHolder
            )

        # The designers grid
        self.grid = DirectGrid(gridSize=50.0, gridSpacing=0.05,parent=self.elementHolder)
        self.grid.setP(90)
        self.grid.snapMarker.hide()
        self.snapToGrid = not self.grid.isHidden()

        self.canvasTopCenter = self.elementHolder.attachNewNode("canvasTopCenter")
        self.canvasBottomCenter = self.elementHolder.attachNewNode("canvasBottomCenter")
        self.canvasLeftCenter = self.elementHolder.attachNewNode("canvasLeftCenter")
        self.canvasRightCenter = self.elementHolder.attachNewNode("canvasRightCenter")

        self.canvasTopLeft = self.elementHolder.attachNewNode("canvasTopLeft")
        self.canvasTopRight = self.elementHolder.attachNewNode("canvasTopRight")
        self.canvasBottomLeft = self.elementHolder.attachNewNode("canvasBottomLeft")
        self.canvasBottomRight = self.elementHolder.attachNewNode("canvasBottomRight")

        # default to Aspect2D
        self.setVisualEditorParent(False)

        base.taskMgr.add(self.watchCanvasProps, "watch-canvas-properties", sort=50, priority=0)

    def getEditorCanvasSize(self):
        cs = self.elementHolder["frameSize"]

        if self.currentVisEditorParent == base.pixel2d:
            cs = self.visualEditor["canvasSize"]

        return cs

    def getEditorRootCanvas(self):
        return self.elementHolder

    def watchCanvasProps(self, task):
        """Watch for all properties that can be changed on the canvas and won't
        directly propagate down to the actual background, which is the element
        holder."""

        self.sizer.refresh()

        sizeChanged = False
        cs = self.getEditorCanvasSize()
        if self.canvasLeft != cs[0]:
            sizeChanged = True
        elif self.canvasRight != cs[1]:
            sizeChanged = True
        elif self.canvasBottom != cs[2]:
            sizeChanged = True
        elif self.canvasTop != cs[3]:
            sizeChanged = True

        if sizeChanged:
            width = cs[1] - cs[0]
            height = cs[3] - cs[2]

            self.canvasScale = min(width, height)

            if self.currentVisEditorParent == base.pixel2d:
                if width > height:
                    self.canvasScale *= self.visualEditor.getScale()[2]
                else:
                    self.canvasScale *= self.visualEditor.getScale()[0]
            else:
                if width > height:
                    self.canvasScale *= self.elementHolder.getScale()[2]
                else:
                    self.canvasScale *= self.elementHolder.getScale()[0]

            #TODO: the scale probably needs to be calculated dependent on the users screen size
            self.elementHolder["scale"]= LVecBase3f(self.canvasScale/2,1,self.canvasScale/2),

            self.elementHolderSizer.refresh()
            self.scaleParentSizer.refresh()
            self.setCanvasPlacers()

        if self.visualEditor["frameColor"] != self.elementHolder["frameColor"]:
            fc = self.visualEditor["frameColor"]
            self.elementHolder["frameColor"] = fc
            self.elementHolderSizer["frameColor"] = fc
            self.scaleParentSizer["frameColor"] = fc
            self.scaleParent["frameColor"] = fc
        self.visualEditor

        return task.cont

    def setCanvasPlacers(self):
        cs = self.getEditorCanvasSize()
        self.canvasLeft = cs[0]
        self.canvasRight = cs[1]
        self.canvasBottom = cs[2]
        self.canvasTop = cs[3]

        # Put the nodes in their places
        self.canvasTopCenter.setPos(0, 0, self.canvasTop)
        self.canvasBottomCenter.setPos(0, 0, self.canvasBottom)
        self.canvasLeftCenter.setPos(self.canvasLeft, 0, 0)
        self.canvasRightCenter.setPos(self.canvasRight, 0, 0)

        self.canvasTopLeft.setPos(self.canvasLeft, 0, self.canvasTop)
        self.canvasTopRight.setPos(self.canvasRight, 0, self.canvasTop)
        self.canvasBottomLeft.setPos(self.canvasLeft, 0, self.canvasBottom)
        self.canvasBottomRight.setPos(self.canvasRight, 0, self.canvasBottom)

    def getEditorPlacer(self, placerName):
        placerName = placerName.lower()
        placerName = placerName.replace("a2d", "canvas")
        if placerName == "canvasTopCenter".lower():
            return self.canvasTopCenter
        elif placerName == "canvasBottomCenter".lower():
            return self.canvasBottomCenter
        elif placerName == "canvasLeftCenter".lower():
            return self.canvasLeftCenter
        elif placerName == "canvasRightCenter".lower():
            return self.canvasRightCenter
        elif placerName == "canvasTopLeft".lower():
            return self.canvasTopLeft
        elif placerName == "canvasTopRight".lower():
            return self.canvasTopRight
        elif placerName == "canvasBottomLeft".lower():
            return self.canvasBottomLeft
        elif placerName == "canvasBottomRight".lower():
            return self.canvasBottomRight

    def setElementHandler(self, elementHandler):
        self.elementHandler = elementHandler

    def setVisualEditorCanvasSize(self, newCanvasSize):
        self.visualEditor["canvasSize"] = newCanvasSize
        self.elementHolderSizer.refresh()
        self.scaleParentSizer.refresh()
        self.setCanvasPlacers()

    def setVisualEditorParent(self, toPixel2D):
        if toPixel2D:
            # change to pixel2d
            # we default to a 1920x1080 FHD screen
            self.canvasLeft = 0
            self.canvasRight = 1920
            self.canvasBottom = -1080
            self.canvasTop = 0

            self.setVisualEditorCanvasSize((self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop))
            self.currentVisEditorParent = base.pixel2d

            # Speed up the setGridSpacing call by setting the size to 1
            self.grid.setGridSize(1)
            self.grid.setGridSpacing(0.05 * (self.canvasScale / 2))
            self.grid.setGridSize(1920*4)
            self.visEditorInAspect2D = False
            if self.elementHandler is not None:
                self.elementHandler.setEditorParentType(self.visEditorInAspect2D)
                self.elementHandler.setEditorCenter((self.visualEditor.getWidth()/2, 0, -self.visualEditor.getHeight()/2))
        else:
            # change to aspect2d
            # we default to a 1920x1080 FHD screen
            self.canvasLeft = -1920/2
            self.canvasRight = 1920/2
            self.canvasTop = 1080/2
            self.canvasBottom = -1080/2

            self.scaleParent.setScale(1, 1, 1)

            self.setVisualEditorCanvasSize((self.canvasLeft, self.canvasRight, self.canvasBottom, self.canvasTop))
            self.currentVisEditorParent = base.aspect2d

            # Speed up the setGridSpacing call by setting the size to 1
            self.grid.setGridSize(1)
            self.grid.setGridSpacing(0.05)
            self.grid.setGridSize(50)
            self.visEditorInAspect2D = True
            if self.elementHandler is not None:
                self.elementHandler.setEditorParentType(self.visEditorInAspect2D)
                self.elementHandler.setEditorCenter((0, 0, 0))

        # reset the zoom value
        self.resetZoom()

        self.setCanvasPlacers()

    def toggleVisualEditorParent(self):
        if self.currentVisEditorParent == base.aspect2d:
            self.setVisualEditorParent(True)
        elif self.currentVisEditorParent != base.aspect2d:
            self.setVisualEditorParent(False)

    def resizeFrame(self):
        self.sizer.refresh()

    def toggleGrid(self, enable):
        if enable:
            self.grid.show()
            self.snapToGrid = True
        else:
            self.grid.hide()
            self.snapToGrid = False

    def resetZoom(self):
        self.visualEditor["verticalScroll_range"] = (0, 1)
        self.visualEditor["horizontalScroll_range"] = (0, 1)
        if self.currentVisEditorParent != base.aspect2d:
            # we are in pixel2d
            self.getEditorRootCanvas().setScale(1,1,1)
            self.visualEditor.verticalScroll["value"] = 0
            self.visualEditor.horizontalScroll["value"] = 0

            posParentScaleX = DGH.getRealWidth(self.parent)
            self.minScale = DEFAULT_MIN_SCALE
            self.maxScale = DEFAULT_MAX_SCALE
            base.messenger.send("setZoomValeMinMax", [self.minScale, self.maxScale])
            base.messenger.send("setZoomValue", [1])
        else:
            # we are in aspect2d
            self.getEditorRootCanvas().setScale(self.canvasScale/2,1,self.canvasScale/2)
            self.visualEditor.verticalScroll["value"] = 0.5
            self.visualEditor.horizontalScroll["value"] = 0.5

            posParentScaleX = DGH.getRealWidth(self.parent)
            self.minScale = posParentScaleX * DEFAULT_MIN_SCALE
            self.maxScale = posParentScaleX * DEFAULT_MAX_SCALE
            base.messenger.send("setZoomValeMinMax", [self.minScale, self.maxScale])
            base.messenger.send("setZoomValue", [self.canvasScale/2])

    def setZoom(self, zoomValue):
        z = zoomValue
        s = self.getEditorRootCanvas().getScale()

        self.getEditorRootCanvas().setScale(z, s[1], z)

        # update scroll bars
        vr = self.visualEditor["verticalScroll_range"]
        vv = self.visualEditor.verticalScroll["value"]
        hr = self.visualEditor["horizontalScroll_range"]
        hv = self.visualEditor.horizontalScroll["value"]

        vw = vr[1] - vr[0]
        hw = hr[1] - hr[0]

        curPosVer = vv / vw * 100
        curPosHor = hv / hw * 100

        self.visualEditor["verticalScroll_range"] = (vr[0]*(z/s[0]), vr[1]*(z/s[2]))
        self.visualEditor["horizontalScroll_range"] = (hr[0]*(z/s[0]), hr[1]*(z/s[2]))

        vr = self.visualEditor["verticalScroll_range"]
        hr = self.visualEditor["horizontalScroll_range"]

        self.visualEditor.verticalScroll["value"] = (vr[1] - vr[0]) / 100 * curPosVer
        self.visualEditor.horizontalScroll["value"] = (hr[1] - hr[0]) / 100 * curPosHor

        self.elementHolderSizer.refresh()


    def zoom(self, direction):
        z = 1
        s = self.getEditorRootCanvas().getScale()
        if direction < 0 and self.getEditorRootCanvas().getScale()[0] > self.minScale:
            z = self.zoomOutMultiplyer
        elif direction > 0 and self.getEditorRootCanvas().getScale()[0] < self.maxScale:
            z = self.zoomInMultiplyer

        self.getEditorRootCanvas().setScale(s[0]*z, s[1], s[2]*z)

        base.messenger.send("setZoomValue", [self.getEditorRootCanvas().getScale()[0]])
        #print(self.getEditorRootCanvas().getScale())

        # update scroll bars
        vr = self.visualEditor["verticalScroll_range"]
        vv = self.visualEditor.verticalScroll["value"]
        hr = self.visualEditor["horizontalScroll_range"]
        hv = self.visualEditor.horizontalScroll["value"]

        vw = vr[1] - vr[0]
        hw = hr[1] - hr[0]

        curPosVer = vv / vw * 100
        curPosHor = hv / hw * 100

        self.visualEditor["verticalScroll_range"] = (vr[0]*z, vr[1]*z)
        self.visualEditor["horizontalScroll_range"] = (hr[0]*z, hr[1]*z)

        vr = self.visualEditor["verticalScroll_range"]
        hr = self.visualEditor["horizontalScroll_range"]

        self.visualEditor.verticalScroll["value"] = (vr[1] - vr[0]) / 100 * curPosVer
        self.visualEditor.horizontalScroll["value"] = (hr[1] - hr[0]) / 100 * curPosHor

        self.elementHolderSizer.refresh()

    def dragEditorFrame(self, dragEnabled):
        taskMgr.remove("dragEditorFrameTask")
        mwn = base.mouseWatcherNode
        if dragEnabled:
            t = taskMgr.add(self.dragEditorFrameTask, "dragEditorFrameTask")
            t.vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])

    def dragEditorFrameTask(self, t):
        mwn = base.mouseWatcherNode
        if mwn.hasMouse():
            vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
            moveVec = t.vMouse2render2d - vMouse2render2d
            t.vMouse2render2d = vMouse2render2d
            newValue = self.visualEditor["verticalScroll_value"] - moveVec.getZ()
            if newValue <= 1 and newValue >= 0:
                self.visualEditor["verticalScroll_value"] = newValue
            elif newValue > 1:
                self.visualEditor["verticalScroll_value"] = 1
            elif newValue < 0:
                self.visualEditor["verticalScroll_value"] = 0

            newValue = self.visualEditor["horizontalScroll_value"] + moveVec.getX()
            if newValue <= 1 and newValue >= 0:
                self.visualEditor["horizontalScroll_value"] = newValue
            elif newValue > 1:
                self.visualEditor["horizontalScroll_value"] = 1
            elif newValue < 0:
                self.visualEditor["horizontalScroll_value"] = 0

        return t.cont