My son asked me if I could write a small program to have a ball bounce around the screen then have me explain it. Spotting a neat father-son opportunity I said "Yes!, no problem". S开发者_开发百科o I dug out my python skills and wrote this..
#!/usr/bin/python
#
# We have to tell python what stuff we're
# going to use. We do this by asking to import
# the code we'll be making use of
#
import curses
import random
import time
#
# We'll be using a screen handling
# package called "curses" so we need
# to initialise the screen
stdscr = curses.initscr()
# We need to make sure that
# keys we type will not show up
# on the screen spoiling the
# stuff we're drawing
curses.noecho()
# We need to tell curses that we don't
# want to wait when we ask for keys from
# the user, if there's non there then
# we want curses to carry on
stdscr.nodelay( True )
# This ones a bit tricky to explain.
# Basically it puts the keyboard into
# a mode which allows curses to do
# things with it...
curses.cbreak()
# Ok, now we can do the fun stuff
# First thing we need to do is to
# find out how big our screen is
max_y, max_x = stdscr.getmaxyx()
stdscr.box()
min_x = 1
min_y = 1
max_y = max_y - 2
max_x = max_x - 2
stdscr.addstr( min_y, min_x, "1" )
stdscr.addstr( min_y, max_x, "2" )
stdscr.addstr( max_y, min_x, "3" )
stdscr.addstr( max_y, max_x, "4" )
dir_x = 1
dir_y = 1
# Then we can pick a random point on the
# screen in both the y (up-down) and x
# (left-right) directions
y = random.randint( 0, max_y )
x = random.randint( 0, max_x )
# Ok, this basically says, while trying to
# get a key from the user keeps coming back
# with an error, meaning there aren't any keys
# to return, do the code inside the loop
while( stdscr.getch() == curses.ERR ):
# Ok, at the location we got, put a "0"
stdscr.addstr( y, x, "O" )
# stdscr.addstr( str( (y, x) ) )
# this just moves the cursor to a new location so we can see the "O" better
stdscr.move( 0, 0 )
# have the screen update
stdscr.refresh()
# now choose a new location
x = x + dir_x
y = y + dir_y
# have we gone too far
if x > max_x or x < min_x:
# change direction
dir_x = -dir_x
x = x + dir_x
if y > max_y or y < min_y:
# change direction
dir_y = -dir_y
y = y + dir_y
# wait a bit so we can see the screen we've drawn.
time.sleep( 0.05 )
# Ok, we're finished. Tidy up
curses.nocbreak()
stdscr.keypad( False )
curses.echo()
curses.endwin()
I ran the program and was quite pleased. However, when the ball hits the edge, it seems to "slide" and not bounce cleanly.
It's quite late in the evening so I couldn't get my head around it and I thought I'd throw it out there and see if anyone could explain why. I'm not after fixing the code, I'm pretty sure that with <= or >= the tests would work. I just can't understand what it does what it does...
Thx Mark.
You need to add twice dir_* in the "change direction" code.
You are figuring out a new x and y coordinate before you are testing. So, say the ball is at 20, 1 and is drawn, and assume the dir is North East with slope 1. The next position will be calculated at 21, 0. Here you see the y is out of range now. So you set it back to 1 when what you really want is 2, so you get a slide across the edge. Usually, what I do is test for the next conditions first, then add the new offsets. So...
if x + dir_x > max_x or x - dir_x < min_x:
Getting this kind of simulation to work properly at the edges is tricky. I ran it here and it looks nice to me (OS X). When it hits the edge you'll get two O's in a row at the edge but then it comes back. At a guess, this has to do with how far your virtual x,y point has to penetrate before reversal happens, which depends on how fast it's moving.
Took me a while to work out what you're meaning. You mean the double 'OO' on the wall when it changes direction? Seems to me the conditional allows the ball to go over (not up to) the line and then pulls it back again. I changed this bit:
# have we gone too far
if x >= max_x or x <= min_x:
# change direction
dir_x = -dir_x
#x = x + dir_x
if y >= max_y or y <= min_y:
# change direction
dir_y = -dir_y
#y = y + dir_y
(Note I changed > to >= and same with < and I also commented out the second increment - if you catch it on the line you don't need it.)
Nice little example by the way.
Not really too familiar with python, but is
dir_x = -dir_x
Acceptable? Maybe try
dir_x *= -1
or
dir_x = dir_x * -1
?
精彩评论