historical/toontown-classic.git/panda/samples/music-box/main.py

176 lines
7.6 KiB
Python
Raw Normal View History

2024-01-16 11:20:27 -06:00
#!/usr/bin/env python
# Author: Shao Zhang, Phil Saltzman, and Elan Ruskin
# Last Updated: 2015-03-13
#
# This tutorial shows how to load, play, and manipulate sounds
# and sound intervals in a panda project.
from direct.showbase.ShowBase import ShowBase
from panda3d.core import NodePath, TextNode
from panda3d.core import PointLight, AmbientLight
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
from direct.interval.SoundInterval import SoundInterval
from direct.gui.DirectSlider import DirectSlider
from direct.gui.DirectButton import DirectButton
from direct.interval.MetaInterval import Parallel
from direct.interval.LerpInterval import LerpHprInterval
import sys
# Create an instance of ShowBase, which will open a window and set up a
# scene graph and camera.
base = ShowBase()
class MusicBox(DirectObject):
def __init__(self):
# Our standard title and instructions text
self.title = OnscreenText(text="Panda3D: Tutorial - Music Box",
parent=base.a2dBottomCenter,
pos=(0, 0.08), scale=0.08,
fg=(1, 1, 1, 1), shadow=(0, 0, 0, .5))
self.escapeText = OnscreenText(text="ESC: Quit", parent=base.a2dTopLeft,
fg=(1, 1, 1, 1), pos=(0.06, -0.1),
align=TextNode.ALeft, scale=.05)
# Set up the key input
self.accept('escape', sys.exit)
# Fix the camera position
base.disableMouse()
# Loading sounds is done in a similar way to loading other things
# Loading the main music box song
self.musicBoxSound = loader.loadMusic('music/musicbox.ogg')
self.musicBoxSound.setVolume(.5) # Volume is a percentage from 0 to 1
# 0 means loop forever, 1 (default) means
# play once. 2 or higher means play that many times
self.musicBoxSound.setLoopCount(0)
# Set up a simple light.
self.plight = PointLight("light")
self.plight.setColor((0.7, 0.7, 0.5, 1))
light_path = base.render.attachNewNode(self.plight)
light_path.setPos(0, 0, 20)
base.render.setLight(light_path)
alight = AmbientLight("ambient")
alight.setColor((0.3, 0.3, 0.4, 1))
base.render.setLight(base.render.attachNewNode(alight))
# Enable per-pixel lighting
base.render.setShaderAuto()
# Sound objects do not have a pause function, just play and stop. So we will
# Use this variable to keep track of where the sound is at when it was stoped
# to impliment pausing
self.musicTime = 0
# Loading the open/close effect
# loadSFX and loadMusic are identical. They are often used for organization
#(loadMusic is used for background music, loadSfx is used for other effects)
self.lidSfx = loader.loadSfx('music/openclose.ogg')
# The open/close file has both effects in it. Fortunatly we can use intervals
# to easily define parts of a sound file to play
self.lidOpenSfx = SoundInterval(self.lidSfx, duration=2, startTime=0)
self.lidCloseSfx = SoundInterval(self.lidSfx, startTime=5)
# For this tutorial, it seemed appropriate to have on screen controls.
# The following code creates them.
# This is a label for a slider
self.sliderText = OnscreenText("Volume", pos=(-0.1, 0.87), scale=.07,
fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1))
# The slider itself. It calls self.setMusicBoxVolume when changed
self.slider = DirectSlider(pos=(-0.1, 0, .75), scale=0.8, value=.50,
command=self.setMusicBoxVolume)
# A button that calls self.toggleMusicBox when pressed
self.button = DirectButton(pos=(.9, 0, .75), text="Open",
scale=.1, pad=(.2, .2),
rolloverSound=None, clickSound=None,
command=self.toggleMusicBox)
# A variable to represent the state of the simulation. It starts closed
self.boxOpen = False
# Here we load and set up the music box. It was modeled in a complex way, so
# setting it up will be complicated
self.musicBox = loader.loadModel('models/MusicBox')
self.musicBox.setPos(0, 60, -9)
self.musicBox.reparentTo(render)
# Just like the scene graph contains hierarchies of nodes, so can
# models. You can get the NodePath for the node using the find
# function, and then you can animate the model by moving its parts
# To see the hierarchy of a model, use, the ls function
# self.musicBox.ls() prints out the entire hierarchy of the model
# Finding pieces of the model
self.Lid = self.musicBox.find('**/lid')
self.Panda = self.musicBox.find('**/turningthing')
# This model was made with the hinge in the wrong place
# this is here so we have something to turn
self.HingeNode = self.musicBox.find(
'**/box').attachNewNode('nHingeNode')
self.HingeNode.setPos(.8659, 6.5, 5.4)
# WRT - ie with respect to. Reparents the object without changing
# its position, size, or orientation
self.Lid.wrtReparentTo(self.HingeNode)
self.HingeNode.setHpr(0, 90, 0)
# This sets up an interval to play the close sound and actually close the box
# at the same time.
self.lidClose = Parallel(
self.lidCloseSfx,
LerpHprInterval(self.HingeNode, 2.0, (0, 90, 0), blendType='easeInOut'))
# Same thing for opening the box
self.lidOpen = Parallel(
self.lidOpenSfx,
LerpHprInterval(self.HingeNode, 2.0, (0, 0, 0), blendType='easeInOut'))
# The interval for turning the panda
self.PandaTurn = self.Panda.hprInterval(7, (360, 0, 0))
# Do a quick loop and pause to set it as a looping interval so it can be
# started with resume and loop properly
self.PandaTurn.loop()
self.PandaTurn.pause()
def setMusicBoxVolume(self):
# Simply reads the current value from the slider and sets it in the
# sound
newVol = self.slider.guiItem.getValue()
self.musicBoxSound.setVolume(newVol)
def toggleMusicBox(self):
#if self.lidOpen.isPlaying() or self.lidClose.isPlaying():
# # It's currently already opening or closing
# return
if self.boxOpen:
self.lidOpen.pause()
self.lidClose.start() # Start the close box interval
self.PandaTurn.pause() # Pause the figurine turning
# Save the current time of the music
self.musicTime = self.musicBoxSound.getTime()
self.musicBoxSound.stop() # Stop the music
self.button['text'] = "Open" # Prepare to change button label
else:
self.lidClose.pause()
self.lidOpen.start() # Start the open box interval
self.PandaTurn.resume() # Resume the figuring turning
# Reset the time of the music so it starts where it left off
self.musicBoxSound.setTime(self.musicTime)
self.musicBoxSound.play() # Play the music
self.button['text'] = "Close" # Prepare to change button label
self.button.setText() # Actually change the button label
# Set our state to opposite what it was
self.boxOpen = not self.boxOpen
#(closed to open or open to closed)
# and we can run!
mb = MusicBox()
base.run()