|
|
|
Return to Showcase
by martan3d » Thu Feb 24, 2011 11:06 am
Well, not sure I would call it 'showcase' material, it's my first attempt. But it was great fun and thanks to everyone for helping me learn the basics. I'm sure there are bugs and I do lose a die now and then so my ODE and frame rate and all that need some work but it does work pretty good considering.
I 'packpanda'd the whole thing and put it up if you would care to try it out-
http://www.virginiahelicopter.net/game/dice.exe
-
martan3d
-
- Posts: 33
- Joined: Mon Dec 27, 2010 7:16 pm
by coppertop » Thu Feb 24, 2011 11:09 am
Is it possible for you to provide it in a system-neutral form? I.e. source code? Many people don't use Windows but would still like to check it out.
-

coppertop
-
- Posts: 526
- Joined: Sat Apr 18, 2009 5:48 am
by Inkaster » Thu Feb 24, 2011 12:18 pm
You can use Winrar to compress the folder "game" inside your Panda3d folder. Those who have panda3d will be able to play the game with the main.py.
-
Inkaster
-
- Posts: 12
- Joined: Tue Dec 14, 2010 5:06 pm
by martan3d » Thu Feb 24, 2011 12:25 pm
Sorry about that. Here is the code:
- Code: Select all
from pandac.PandaModules import NodePath, DirectionalLight, AmbientLight, VBase4, Vec4, Vec3 from pandac.PandaModules import OdeWorld, OdeBody, OdeMass, Quat, OdePlaneGeom, BitMask32 from pandac.PandaModules import OdeSimpleSpace, OdeJointGroup, OdeBoxGeom from direct.showbase.ShowBase import ShowBase from direct.gui.OnscreenText import OnscreenText from direct.gui.DirectGui import * from pandac.PandaModules import TextNode from direct.task import Task import random, sys, time
FRAMESKIP = 4
# Panda Render Window class PandaApp(ShowBase): def __init__(self): ShowBase.__init__(self)
# global things to do base.disableMouse() # turn off internal camera control base.setBackgroundColor(0.2, 0.2, 0.2) # not that we care really, can't see it
# std random startup stuff random.seed()
# main physics world lives here, set the gravity to earth std self.myWorld = OdeWorld() self.myWorld.setGravity(0, 0, -9.81)
# Create a space and add a contactgroup for our physics system self.space = OdeSimpleSpace() self.space.enable() self.space.setAutoCollideWorld(self.myWorld) self.contactgroup = OdeJointGroup() self.space.setAutoCollideJointGroup(self.contactgroup)
# The surface table is needed for autoCollide self.myWorld.initSurfaceTable(1) self.myWorld.setSurfaceEntry(0, 0, 20, 3.8, 1.1, 0.9, 0.00001, 0.0, 0.002)
# Load Sounds (notes) for dice models self.loadSounds()
# load dice models and set them for dynamics self.LoadModels()
# load the room we bounce in, set the physics floor and walls self.LoadRoom() # setup global collision system callback self.space.setCollisionEvent("ode-collision") base.accept("ode-collision", self.onCollision)
# add a directional light dlight = DirectionalLight('dlight') dlight.setColor(VBase4(0.9, 0.9, 0.9, 1)) dlnp = render.attachNewNode(dlight) dlnp.setHpr(0, -60, 0) render.setLight(dlnp)
# and an ambient light too alight = AmbientLight('alight') alight.setColor(VBase4(0.15, 0.15, 0.15, 1)) alnp = render.attachNewNode(alight) render.setLight(alnp)
# camera coords self.cameraX = 0 self.cameraY = -25 self.cameraZ = 11 self.cameraH = 0 self.cameraP = -16 self.cameraR = 0
# fix the camera here self.camera.setPos(self.cameraX, self.cameraY, self.cameraZ) self.camera.setHpr(self.cameraH, self.cameraP, self.cameraR)
# add keyboard controls self.accept('space', self.throwDice) self.accept('escape', sys.exit) self.accept('c', self.addCredits) self.accept('b', self.addBet) # setup some flags and things self.frame = 0 self.computedWin = True self.addForce = False self.runSimulation = False self.inSimulation = False self.rotationRunning = False self.collision = False self.winlist = {} self.positionlist = {} self.prevlist = {}
# money and such self.credits = 10 self.bet = 1 self.winnings = 0
# wins per face self.ones = 0 self.twos = 0 self.threes = 0 self.fours = 0 self.fives = 0 self.sixes = 0
# setup the screen text displays and cute little dice button self.drawScreenText()
# start everything and we are done with initialize taskMgr.doMethodLater(0.1, self.startRot, "StartRotation") taskMgr.doMethodLater(0.7, self.startGrav, "StartGravity")
def loadSounds(self): f0 = loader.loadSfx("models/f.wav") g0 = loader.loadSfx("models/g.wav") b0 = loader.loadSfx("models/bb.wav") c0 = loader.loadSfx("models/c.wav") e0 = loader.loadSfx("models/eb.wav") f1 = loader.loadSfx("models/f1.wav") g1 = loader.loadSfx("models/g1.wav") b0 = loader.loadSfx("models/bb1.wav") c1 = loader.loadSfx("models/c1.wav") self.sounds = [f0, g0, c0, f1, g1, c1, f0, g0, c1 ] self.soundIndex = 0
# Text on the Screen def drawScreenText(self): text = "" self.textObject = OnscreenText(text=text, \ pos=(-1.05,-0.95), \ scale = 0.10, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1) text = "Credits:" self.CreditsText = OnscreenText(text=text, \ pos=(-1.3, 0.9), \ scale = 0.1, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1) text = "%d" % self.credits self.CreditsNum = OnscreenText(text=text, \ pos=(-0.9, 0.9), \ scale = 0.13, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1) text = "Bet:" self.BetText = OnscreenText(text=text, \ pos=(.94, 0.9), \ scale = 0.1, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1) text = "%d" % self.bet self.BetNum = OnscreenText(text=text, \ pos=(1.14, 0.9), \ scale = 0.13, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1) text = "Win: 0" self.textWin = OnscreenText(text=text, \ pos=(.94,-0.95), \ scale = 0.10, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1) text = "Idle" self.textStatus = OnscreenText(text=text, \ pos=(.94,-0.85), \ scale = 0.04, \ fg=(1, 1, 1, 1), \ align=TextNode.ALeft, \ mayChange=1)
# Add button buttonText = ("", "", "Throw", "") self.bDie = DirectButton(text = buttonText, \ geom = self.displayDie, \ geom_pos = (0,0,0), \ geom_scale = (0.1, 0.1, 0.1), \ geom_hpr = (0, 0, 0), \ relief = None, \ text_fg = (1, 1, 1, 1), \ text_scale = (0.3, 0.3), \ text_shadow = (0, 0, 0, 1), \ text_style = ScreenTitle, \ frameColor = (1, 1, 1, 1), \ borderWidth = (0.05, 0.05), \ #image = 'symbols\symbol_1.png', \ pos = (-1.2, 0, -.90), \ scale = 0.3, \ hpr = (0,0,0), \ command=self.throwDice)
#start up the physics task def startGrav(self, task): self.startGravitySim()
# spin the dice weirdly rotate task def startRot(self, task): self.startRotation()
# add some credits to our pot def addCredits(self): self.credits = self.credits + 1 s = "%d" % self.credits self.CreditsNum.setText(s)
# bet some credits on this spin def addBet(self): self.bet = self.bet + 1 if self.bet > 5: self.bet = 1 s = "%d" % self.bet self.BetNum.setText(s)
# spin the models randomly def rotateModels(self, task): self.frame = self.frame + 1 if self.frame >= FRAMESKIP: self.frame = 0 for die in self.dice: x = random.randint(0,359) y = random.randint(0,359) z = random.randint(0,359) die[0].setHpr(x,y,z) die[3].setPosition(die[0].getPos(render)) die[3].setQuaternion(die[0].getQuat(render)) if self.collision == False: return Task.cont else: return Task.done
# start the dice rotating def startRotation(self): if self.rotationRunning == False: self.rotationRunning = True self.inSimulation = False self.taskMgr.add(self.rotateModels, "rotateModels")
# force (explode) the dice def forceDie(self): for i in range(0,9): body = self.dice[i][3] a = random.randint(-17000000,17000000) b = random.randint(-17000000,17000000) c = random.randint(10000000,33000000) # up is always big to overcome gravity body.setForce(Vec3(a, b, c))
# do a throw def throwDice(self): if self.credits - self.bet < 0: return
if self.computedWin == False: return
self.computedWin = False
self.textStatus.setText("Throw Dice") #print "THROW DICE" self.credits = self.credits - self.bet s = "%d" % self.credits self.CreditsNum.setText(s)
self.winnings = 0 w = "Win: %d" % self.winnings self.textWin.setText(w)
for i in range(0,9): self.prevlist[i] = (0.0, 0.0, 0.0) self.moving = 0 self.forceDie() taskMgr.doMethodLater(0.2, self.evaluateWinList, "EvaluateWinList")
def checkMotion(self): moving = False for d in self.winlist.keys(): (l,m,n) = self.winlist[d] a = "%03.0f" % l b = "%03.0f" % m c = "%03.0f" % n (o,p,q) = self.prevlist[d] e = "%03.0f" % o f = "%03.0f" % p g = "%03.0f" % q
if a != e: moving = True if b != f: moving = True if c != g: moving = True
for d in self.winlist.keys(): self.prevlist[d] = self.winlist[d]
return moving
# evaluate (count up faces) dice as they come to rest on the floor, a task that runs every frame def evaluateWinList(self, task):
if self.checkMotion() == False: self.moving = self.moving + 1 else: self.moving = 0 ones = 0 twos = 0 threes = 0 fours = 0 fives = 0 sixes = 0
a = b = c = 0
for d in self.winlist.keys(): l, m, n = self.winlist[d] a = int(l+0.5) b = int(m+0.5) c = int(n+0.5) if b == 0 and c == -89: ones = ones + 1 elif b == 0 and c == 0: twos = twos + 1 elif b == 90: threes = threes + 1 elif b < -88: fours = fours + 1 elif b == 0 and c != 90: fives = fives + 1 elif b == 0 and c == 90: sixes = sixes + 1
if self.ones == ones and self.twos == twos and self.threes == threes \ and self.fours == fours and self.fives == fives and self.sixes == sixes:
t = "" if ones > 3: t = t + "%d ones " % ones if twos > 3: t = t + "%d twos " % twos if threes > 3: t = t + "%d threes " % threes if fours > 3: t = t + "%d fours " % fours if fives > 3: t = t + "%d fives " % fives if sixes > 3: t = t + "%d sixes " % sixes if ones > 0 and twos > 0 and threes > 0 and fours > 0 and fives > 0 and sixes > 0: t = t + "six sequence" self.textObject.setText(t)
else: self.ones = ones self.twos = twos self.threes = threes self.fours = fours self.fives = fives self.sixes = sixes
self.bDie["geom_hpr"] = (a,b,c) if self.moving > 5: taskMgr.doMethodLater(0.1, self.computeTotals, "compute total wins") return Task.done return Task.cont
def computeTotals(self, task): self.textStatus.setText("Compute win") self.winnings = 0 # five of a kind or greater pays bet * number of a kind if self.ones > 3: self.winnings = self.winnings + (self.ones * self.bet) if self.twos > 3: self.winnings = self.winnings + self.twos * self.bet
if self.threes > 3: self.winnings = self.winnings + (self.threes * self.bet) if self.fours > 3: self.winnings = self.winnings + self.fours * self.bet if self.fives > 3: self.winnings = self.winnings + self.fives * self.bet if self.sixes > 3: self.winnings = self.winnings + self.sixes * self.bet
if self.ones > 0 and self.twos > 0 and self.threes > 0 and self.fours > 0 and self.fives > 0 and self.sixes > 0: self.winnings = self.winnings + (2 * self.bet)
w = "Win: %d" % self.winnings self.textWin.setText(w)
self.credits = self.credits + self.winnings s = "%d" % self.credits self.CreditsNum.setText(s)
self.computedWin = True
return Task.done
# start the gravity/collision simulation def startGravitySim(self): self.addForce = False if self.runSimulation == False: self.deltaTimeAccumulator = 0.0 self.stepSize = 1.0 / 90.0 self.runSimulation = True taskMgr.doMethodLater(0.1, self.simulationTask, "Physics Simulation")
# callback for collisions of the dice def onCollision(self, entry): geom1 = entry.getGeom1() geom2 = entry.getGeom2() body1 = entry.getBody1() body2 = entry.getBody2()
for np, geom, sound, body in self.dice: if geom == geom1 or geom == geom2: velocity = body1.getAngularVel() if velocity[0] > 2.0 and sound.status != sound.PLAYING: sound.setVolume(velocity[0] / 80.0) sound.play() self.collision = True # run the gravity/collision simulation task def simulationTask(self, task): self.inSimulation = True self.space.autoCollide() #self.myWorld.quickStep(globalClock.getDt()) self.myWorld.quickStep(0.016) i = 0 for np, geom, sound, body in self.dice: self.positionlist[i] = np.getPos() self.winlist[i] = np.getHpr() i = i + 1 if not np.isEmpty(): np.setPosQuat(render, geom.getBody().getPosition(), Quat(geom.getBody().getQuaternion())) self.contactgroup.empty() # Clear the contact joints if self.runSimulation == True: return task.cont
# set already existing models to standard places def setModels(self): i = 0 z = 2.0 for x in [-1.0, 0.0, 1.0]: die = self.dice[i][0] die.setPos(x, 0.4, z) die.setHpr(0,0,0) body = self.dice[i][3] body.setPosition(die.getPos(render)) body.setQuaternion(die.getQuat(render)) i = i + 1 z = 3.0 for x in [-1.0, 0.0, 1.0]: die = self.dice[i][0] die.setPos(x, 0.0, z) die.setHpr(0,0,0) body = self.dice[i][3] body.setPosition(die.getPos(render)) body.setQuaternion(die.getQuat(render)) i = i + 1 z = 4.0 for x in [-1.0, 0.0, 1.0]: die = self.dice[i][0] die.setPos(x, 0.4, z) die.setHpr(0,0,0) body = self.dice[i][3] body.setPosition(die.getPos(render)) body.setQuaternion(die.getQuat(render)) i = i + 1
# build individual die, set mass, collision and physics def buildModel(self, x, y, modelDice): die = modelDice.copyTo(self.root) die.setPos(x, 0.0, y) die.setScale(0.25, 0.25, 0.25) diceBody = OdeBody(self.myWorld) mass = OdeMass() wt = random.randint(10000, 14240) mass.setBox(wt, 1, 1, 1) diceBody.setMass(mass) diceBody.setPosition(die.getPos(render)) diceBody.setQuaternion(die.getQuat(render)) diceBody.enable() diceGeom = OdeBoxGeom(self.space, 1, 1, 1) diceGeom.setCollideBits(BitMask32(0x00000001)) diceGeom.setCategoryBits(BitMask32(0x00000001)) diceGeom.setBody(diceBody) Sound = self.sounds[self.soundIndex] self.soundIndex = self.soundIndex + 1 return die, diceGeom, Sound, diceBody
# import the dice model base and build all nine def LoadModels(self): self.displayDie = loader.loadModel("models/die") # for button self.displayDie.setDepthTest(True) self.displayDie.setDepthWrite(True)
modelDice = loader.loadModel("models/die") self.root = render.attachNewNode("Root") self.dice = []
y = 2.0 for x in [-1.0, -0.4, 1.0]: die, diceGeom, Sound, body = self.buildModel(x, y, modelDice) self.dice.append((die, diceGeom, Sound, body))
y = 3.0 for x in [-1.0, 0.0, 1.0]: die, diceGeom, Sound, body = self.buildModel(x, y, modelDice) self.dice.append((die, diceGeom, Sound, body))
y = 4.0 for x in [-1.0, 0.4, 1.0]: die, diceGeom, Sound, body = self.buildModel(x, y, modelDice) self.dice.append((die, diceGeom, Sound, body))
def LoadRoom(self): # put dice in a box, model only room = loader.loadModel("models/room") room.reparentTo(render) room.setScale(1, 2, 1) room.setPos(0, -1, 0) room.setTwoSided(True)
# install physics - floor groundGeom = OdeBoxGeom(self.space, (2000, 2000, 1)) groundGeom.setCollideBits(BitMask32( 0xffffffff)) groundGeom.setCategoryBits(BitMask32(0xffffffff))
# wall left wall0Geom = OdeBoxGeom(self.space, (1, 2000, 2000)) wall0Geom.setPosition(-6.5,0,0) wall0Geom.setCollideBits(BitMask32(0xffffffff)) wall0Geom.setCategoryBits(BitMask32(0xffffffff))
# wall right wall1Geom = OdeBoxGeom(self.space, (1, 2000, 2000)) wall1Geom.setPosition(6.5,0,0) wall1Geom.setCollideBits(BitMask32(0xffffffff)) wall1Geom.setCategoryBits(BitMask32(0xffffffff))
# wall back wall2Geom = OdeBoxGeom(self.space, (2000, 1, 2000)) wall2Geom.setPosition(0,6.5,0) wall2Geom.setCollideBits(BitMask32(0xffffffff)) wall2Geom.setCategoryBits(BitMask32(0xffffffff))
# wall behind cam wall3Geom = OdeBoxGeom(self.space, (2000, 1, 2000)) wall3Geom.setPosition(0,-6.8,0) wall3Geom.setCollideBits(BitMask32(0xffffffff)) wall3Geom.setCategoryBits(BitMask32(0xffffffff))
# ceiling wall4Geom = OdeBoxGeom(self.space, (2000, 2000, 1)) wall4Geom.setPosition(0,0,11) wall4Geom.setCollideBits(BitMask32(0xffffffff)) wall4Geom.setCategoryBits(BitMask32(0xffffffff))
# MAIN - start everything panda = PandaApp() run()
-
martan3d
-
- Posts: 33
- Joined: Mon Dec 27, 2010 7:16 pm
by martan3d » Thu Feb 24, 2011 12:37 pm
The models are a die from turbosquid which I had to tweak, and a simple box. I used the free SoftImageModTool for those. I exported to .x format then used x2egg to convert them.
I put the egg and one jpg file in the same place:
http://www.virginiahelicopter.net/game/
Code reviews and suggestions welcome, just don't bash me too hard
There are some things I don't like, particularly how I determine that the dice have quit moving and the scoring is way too easy, the house needs to keep more!
-
martan3d
-
- Posts: 33
- Joined: Mon Dec 27, 2010 7:16 pm
by AnimateDream » Thu Mar 03, 2011 9:48 pm
I had a chance to check this out. I like what you did with the sound. Its a great at what it does. I've been working on games in my spare time for a decade, and I still have a hard time dialing back my ambition enough to make make something simple, but polished like this.
-
AnimateDream
-
- Posts: 89
- Joined: Tue Feb 16, 2010 2:36 am
by martan3d » Fri Mar 04, 2011 2:19 pm
Thanks! It was a lot of fun.
-
martan3d
-
- Posts: 33
- Joined: Mon Dec 27, 2010 7:16 pm
by enc » Fri Mar 04, 2011 5:38 pm
Nice and clean.
You need to clean up ode stuff before you sys.exit or it will throw and error on exiting.
-
enc
-
- Posts: 166
- Joined: Wed May 27, 2009 3:35 am
- Location: Estonia, Tartu
by martan3d » Sat Mar 05, 2011 9:59 pm
I'm going to revisit it soon and try to put it on a web page. And refactor as I can. I have another little game I'm working on too.
-
martan3d
-
- Posts: 33
- Joined: Mon Dec 27, 2010 7:16 pm
Return to Showcase
Who is online
Users browsing this forum: No registered users and 1 guest
| | |