0

I thought I'd play around with vPython so I wrote a 3D breakout game (I used to have one on my Amiga and I haven't seen one for Windows). Everything is done except for one wee problem. I want to idle while waiting for the user to click the left mouse button. Because the user must still be able to move the paddle (to position the shot for a new ball), I can't just do a getclick or getevent (which pauses the loop). I tried

if newball:

  if myscene.mouse.clicked:
      do stuff

because events are not being cleared from the queue even if I do
myscene.mouse.events = 0
which is supposed to clear out any queued mouse events

Similarly I can't just idle until myscene.mouse.button = "left" because this attribute never seems to be updated as the following program will show

from visual import *

myscene = display(title="test",width=500,height=320)

status = label(text="test",color=(1,0,0))

while True:
    rate(100)
    if myscene.mouse.button is None:
        status.text = "None"
    else:
        status.text = myscene.mouse.button

On my machine (Windows 7 Pro, Active Python 2.7.2.5, vPython 5.71) the status stays frozen on "None". Is this a bug in vPython? Does anyone have a suggestion on either what I am doing wrong or how to work around the bug if I am not?

2
Contributors
4
Replies
5
Views
6 Years
Discussion Span
Last Post by Reverend Jim
0

I got this way also right mouse event visible, but mouse wheel still not and middle event came from 'chord middle' ie both left and right down simultanously:

from visual import *

myscene = display(title="test",width=500,height=320)
myscene.userspin = myscene.userzoom = False

status = label(text="test",color=(1,0,0))

while True:
    rate(100)
    for count in range(myscene.mouse.events):
        m = myscene.mouse.getevent()
        status.text = "%s %s %s: %s" % (m.button, m.drag, m.drop, m.pos)
0

It seems the mouse.button not updating thing is a bug, however, I have a workaround.

def EmptyBuffer (myscene):
    while myscene.mouse.clicked > 0:
        temp = myscene,mouse.getclick()
.
.
.
while True:
.
.
.
    if gameover:
    
        if myscene.mouse.clicked > 0:
            numbricks = Reset(brickLeft+brickRight+brickTop+brickBack)
            numballs  = 3
            gameover  = False
            UpdateStatus(status,numballs,numbricks)

as long as the section of code that sets gameover to True also calls EmptyBuffer then everything works fine.

0

If anyone is interested here is the complete 3D Breakout code. Constructive comments are always appreciated.

#########################################################################################
#                                                                                       #
#  Name:                                                                                #
#                                                                                       #
#    Breakout3D.py                                                                      #
#                                                                                       #
#  Description:                                                                         #
#                                                                                       #
#    A 3D version of Breakout (requires red/cyan glasses). Black out the bricks on 4    #
#    walls to win.                                                                      #
#                                                                                       #
#  Future:                                                                              #
#                                                                                       #
#    Change velocity vector depending on what part of the paddle is hit.                #
#                                                                                       #
#  Audit:                                                                               #
#                                                                                       #
#    2011-09-04  R J de Graff original code                                             #
#                                                                                       #
#########################################################################################

from visual import *

def SideBrick(bricks,y,z):      #check if a left or right side brick was hit

    halfy = bricks[0].height / 2
    halfz = bricks[0].width  / 2
    
    for brick in bricks:
        if brick.visible:
            if brick.y-halfy <= y <= brick.y+halfy and brick.z-halfz <= z <= brick.z+halfz:
                return True,brick
    return False,""

def TopBrick(bricks,x,z):       #check if a top brick was hit               

    halfx = bricks[0].width  / 2
    halfz = bricks[0].length / 2

    for brick in bricks:
        if brick.visible:
            if brick.x-halfx <= x <= brick.x+halfx and brick.z-halfz <= z <= brick.z+halfz:
                return True,brick
    return False,""

def BackBrick(bricks,x,y):      #check if a back brick was hit              

    halfx = bricks[0].length / 2
    halfy = bricks[0].height / 2

    for brick in bricks:
        if brick.visible:
            if brick.x-halfx <= x <= brick.x+halfx and brick.y-halfy <= y <= brick.y+halfy:
                return True,brick
    return False,""

def UpdateStatus(status,numballs,numbricks):

    status.text = "Balls=%d  Bricks=%d" % (numballs,numbricks)

def Reset(bricks):              #set all bricks visible                     

    for brick in bricks:
        brick.visible = True
    return len(bricks)

def EmptyBuffer(myscene):       #flush all buffered left clicks             

    while myscene.mouse.clicked > 0:
        temp = myscene.mouse.getclick()

brickLeft  = []                 #all bricks on the left wall                
brickRight = []                 #all bricks on the right wall               
brickTop   = []                 #all bricks on the top wall                 
brickBack  = []                 #all bricks on the back wall                

myscene = display(title="3D Breakout",width=1000,height=640,fullscreen=True)
myscene.select()
myscene.autoscale = True
myscene.userzoom  = True
myscene.userspin  = False
myscene.range     = 360
myscene.cursor.visible = False
myscene.stereo = 'redcyan'

wallLeft   = -250               #x coordinate of the left wall              
wallRight  =  250               #x coordinate of the right wall             
wallTop    =  150               #y coordinate of the ceiling                
wallBottom = -150               #y coordinate of the floor                  
wallBack   = -300               #z coordinate of the back wall              
wallFront  =  200               #z coordinate of the front wall             

brickColor = (0.7,0.7,1)

for x in range(-200,201,100):   #draw the bricks on the top                 
    for z in range(-260,141,100):
        brickTop.append(box(pos=(x,wallTop,z),size=(95,0.1,95),color=brickColor))

for y in range(-120,121,60):    #draw the bricks on the left and right      
    for z in range(-260,141,100):
        brickLeft.append (box(pos=(wallLeft ,y,z),size=(0.1,55,95),color=brickColor))
        brickRight.append(box(pos=(wallRight,y,z),size=(0.1,55,95),color=brickColor))

for x in range(-200,201,100):   #draw the bricks on the back                
    for y in range(-120,121,60):
        brickBack.append(box(pos=(x,y,wallBack),size=(95,55,0.1),color=brickColor))

paddle = box(pos=(0,wallBottom,0),size=(90,.1,90),color=(1,1,1))
status = label(text="",pos=(0,wallBottom+5,wallFront),height=20)

ball = sphere (material=materials.shiny, radius = 5.0)
ball.mass = 1.0
ball.velocity = vector(0.15, 0.23, 0.27)
ball.visible = False
#ball.trail = curve(color=(1,0,1))          #uncomment to see ball path

dt = 1.0

numbricks = Reset(brickLeft+brickRight+brickTop+brickBack)
numballs  = 3

status.text = "Left Click to launch or ESC to exit"

newball  = True
hitfound = False
gameover = False

while true:

    rate(400)

    #update paddle position based on mouse position

    px =  min(max(2*myscene.mouse.pos[0],wallLeft+20),wallRight-20)
    pz = -min(max(2*myscene.mouse.pos[1],wallBack),wallFront)-100
    paddle.pos = (px,wallBottom,pz)

    #If waiting to launch a new ball then idle until keypress. We have to poll rather than
    #pause or we won't be able to move the paddle while we wait.

    if gameover:
    
        if myscene.mouse.clicked > 0:
            numbricks = Reset(brickLeft+brickRight+brickTop+brickBack)
            numballs  = 3
            newball   = True
            gameover  = False
            UpdateStatus(status,numballs,numbricks)
            
    elif newball:

        if myscene.mouse.clicked > 0:
            newball = False
            paddle.color = (1,1,1)
            ball.pos = paddle.pos
            ball.velocity = vector(0.15, 0.23, 0.27)
            ball.visible = True     
            UpdateStatus(status,numballs,numbricks)
            
    else:

        ball.pos = ball.pos + ball.velocity * dt
        #ball.trail.append(pos=ball.pos)        #uncomment to see ball path

        #check for hit on a visible brick

        if ball.x <= wallLeft:
            ball.velocity.x = -ball.velocity.x
            hitfound,brick = SideBrick(brickLeft,ball.y,ball.z)

        if ball.x >= wallRight:
            ball.velocity.x = -ball.velocity.x
            hitfound,brick = SideBrick(brickRight,ball.y,ball.z)

        if ball.z <= wallBack:
            ball.velocity.z = -ball.velocity.z
            hitfound,brick = BackBrick(brickBack,ball.x,ball.y)

        if ball.z >= wallFront:
            ball.velocity.z = -ball.velocity.z

        if ball.y >= wallTop:
            ball.velocity.y = -ball.velocity.y
            hitfound,brick = TopBrick(brickTop,ball.x,ball.z)

        #if hit then clear brick

        if hitfound:
            brick.visible = False
            hitfound   = false
            numbricks -= 1
            UpdateStatus(status,numballs,numbricks)

        #check if paddle hit or miss

        if ball.y <= wallBottom and numballs > 0:
            if paddle.x-45 <= ball.x <= paddle.x+45 and paddle.z-45 <= ball.z <= paddle.z+45 and wallBottom - ball.y <= 1:
                ball.velocity.y = -ball.velocity.y
            elif wallBottom - ball.y > 50:
                numballs -= 1
                newball = (numballs > 0)
                EmptyBuffer(myscene)
                paddle.color = (1,1,0)
                ball.visible = False
                status.text = "Left Click to launch or ESC to exit"
 
        #check if out of bricks (win) or balls (lose)

        if not gameover and (numbricks == 0 or numballs == 0):
            gameover = True
            EmptyBuffer(myscene)
            if numbricks == 0:
                status.text = "Congratulations - You Win - Left Click for new game or ESC to exit"
            else:
                status.text = "Sorry - You've got no balls - Left Click for new game or ESC to exit"
0

If anyone cares it turns out that the problem is that the documentation is wrong. It should say to get the event, E = scene.mouse.getevent(), then look at E.button.

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.