Help with two issues, buttons and second class object
Peter Otten
__peter__ at web.de
Thu Nov 24 09:53:26 EST 2016
Thomas Grops via Python-list wrote:
> Hi I have created some code, which moves a rectangle around and when it
> hits the edge it picks a random new direction. It does this by the count
> function within my class. I am wanting to create a button to randomly
> change count but I my class seems to be getting errors.
>
> I also wanted to create a second class object tank2 but it doesn't seem to
> move when I create it with tank2.Tank(x,y,vx,vy) and call tank1.move()
>
> Can anyone help me many thanks.
It may take some time to get it, but don't use time.sleep() in a tkinter
script!
> def right(self):
> canvas.move(self.id,+5,0)#move right
>
> #reposition x,vx,y,vy values
> self.x+=5
> self.vx+=5
>
> #Update canvas
> canvas.update()
> time.sleep(0.1)
When you have to repeat the same code with small variations (the
canvas.move() arguments) make these variations arguments of the function.
> def move(self):
>
> # Loop for steps in movement
> for t in range(1, 10000):
> #Move direction depending on count value
> if self.count==0:
> self.left()
So 0 means "left" and 6 means "down and right". If a value's meaning is not
obvious use a name instead
LEFT = 42 # also have a look at the enum module in the stdlib
if self.count == LEFT:
self.left()
> if self.count==1:
> self.right()
> if self.count==2:
> self.up()
> if self.count==3:
> self.down()
> if self.count==4:
> self.upLeft()
> if self.count==5:
> self.upRight()
> if self.count==6:
> self.downRight()
> if self.count==7:
> self.downLeft()
That's quite a lot of if-s. It might be better to use a table.
> #Left border
> if self.x <= 0:
> #banned directions
> excludedNumbers = [0,4,7]
> #define random integer to be selected
> randomNumber = random.randint(0,8)
> #nested while loop so that the banned directions are not
> #selected
> while randomNumber in excludedNumbers:
> randomNumber = random.randint(0,8)
> #feed allowed random direction back to the count
> self.count=randomNumber
>
> #Right border
> elif self.vx >= 1000:
> #banned directions
> excludedNumbers = [1,5,6]
> #define random integer to be selected
> randomNumber = random.randint(0,8)
> #nested while loop so that the banned directions are not
> #selected
> while randomNumber in excludedNumbers:
> randomNumber = random.randint(0,8)
> #feed allowed random direction back to the count
Instead of repeating your code with copy-and-past make a helper function
like the randx() posted by Larry Hudson.
By the way, randint(min, max) may return max so there are 9 possible
outcomes while you handle only 8. To be consistent with Python's half-open
ranges use
random.randrange(8) # may return 0, 1, 2, 3, 4, 5, 6, 7, but not 8
Below is what became of your code when I messed with it. Don't copy it, try
to pick up ideas, and have fun!
import tkinter as tk
import random
#Canvas size
WIDTH = 1000
HEIGHT = 700
BUTTONS_PER_ROW = 6
MRIGHT = 0
MLEFT = 1
MUP = 2
MDOWN = 3
MLEFTUP = 4
MRIGHTUP = 5
MRIGHTDOWN = 6
MLEFTDOWN = 7
class Tank():
def __init__(self, root, canvas, name, x, y, width, height, color):
self.root = root
self.canvas = canvas
self.color = color
self.name = name
self.__life = 10
self.speed = 1
self.x = x
self.y = y
self.width = width
self.height = height
self.direction = MRIGHT
self.id = canvas.create_rectangle(
x, y, self.right, self.bottom, fill=color
)
self.moves = [
(5, 0), # right
(-5, 0), # left
(0, -2), # up
(0, 2), # down
(-1, -1), # left-up
(1, -1), # right-up
(1, 1), # right-down
(-1, 1) # left-down
]
@property
def right(self):
return self.x + self.width
@property
def bottom(self):
return self.y + self.height
def attack(self):
print('ouch!')
self.__life -= 1
def checkLife(self):
if self.__life <= 0:
print('dead')
else:
print(str(self.__life) + " life left")
def medic(self):
self.__life += 5
def move_tank(self, dx, dy):
self.x += dx
self.y += dy
self.canvas.move(self.id, dx, dy)
def move(self):
self.move_tank(*self.moves[self.direction])
# If a boundary has been crossed, pick a direction randomly
directions = set(range(8))
if self.x <= 0:
directions -= {MLEFT, MLEFTUP, MLEFTDOWN}
elif self.right >= WIDTH:
directions -= {MRIGHT, MRIGHTUP, MRIGHTDOWN}
if self.y <= 0:
directions -= {MUP, MLEFTUP, MRIGHTUP}
elif self.bottom >= HEIGHT:
directions -= {MDOWN, MLEFTDOWN, MRIGHTDOWN}
assert directions, "nowhere to go!"
if len(directions) < 8:
print(self, "hit wall, changing direction")
self.direction = random.choice(list(directions))
self.root.after(10, self.move)
def changeDirection(self):
print(self, "changing direction on user request")
self.direction = random.randrange(8)
def __str__(self):
return self.name
def random_color():
colors = [
random.randrange(128),
random.randrange(128, 256),
random.randrange(128)
]
random.shuffle(colors)
return "#{:02x}{:02x}{:02x}".format(*colors)
def main():
root = tk.Tk()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg='khaki')
canvas.grid(row=0, column=0, columnspan=BUTTONS_PER_ROW)
tanks = [
Tank(
root, canvas, "Tank #{}".format(i),
x, 650, 40, 40,
random_color())
for i, x in enumerate(range(0, WIDTH, 80), 1)
]
for i, tank in enumerate(tanks):
tank.move()
button = tk.Button(
root,
text=tank.name,
command=tank.changeDirection,
bg=tank.color
)
button.grid(row=1+i // BUTTONS_PER_ROW, column=i % BUTTONS_PER_ROW)
root.mainloop()
if __name__ == "__main__":
main()
PS:
> #life, speed, starting position, vectors, size of tank
> def __init__(self, x, y, vx, vy):
Python has docstrings. Use them!
More information about the Python-list
mailing list