Stanley Roy Chilton
Stanley Roy Chilton

Reputation: 71

appending code to create multiple random moving sprites - python tkinter

Below is the code I am trying to get working, i currently have it creating the sprites although once the second sprite is created the movement for the first is stopped.

Say there are 2 sprites both of them should be moving individually, completely random from each other.

The code creates a new sprite every 3 seconds(for testing purposes once the code is working it will be set to 10 seconds)

class enemymove(object):
    def create():
        global enemy, radiusenemy, xenemy, yenemy
        amount = 0
        enemy = list()
        xenemy = list()
        yenemy = list()
        enemypositionx = list()
        enemypositiony = list()
        lastop = len(enemy)
        enemy.append(amount)
        xenemy.append(amount)
        yenemy.append(amount)
        enemypositionx.append(amount)
        enemypositiony.append(amount)
        amount = amount + 1
        radiusenemy = 12.5
        enemypositionx[lastop] = random.uniform(12.5, resX-12.5)
        enemypositiony[lastop] = random.uniform(12.5, resY-12.5)
        print(lastop)
        enemy[lastop] = canvas.create_oval((enemypositionx[lastop]) + radiusenemy ,(enemypositiony[lastop]) - radiusenemy ,(enemypositionx[lastop]) - radiusenemy ,(enemypositiony[lastop]) + radiusenemy, fill="black", outline="black")
        xenemy[lastop] = (canvas.coords(enemy[lastop])[2])  - 12.5
        yenemy[lastop] = (canvas.coords(enemy[lastop])[3])  - 12.5
        Thread(target = spawntime.timer).start()
        enemymove.movement(lastop);

    def movement(lastop):
        global timer
        timer = random.randint(150,3000)
        count = random.randint(1, 4)
        print(count)
        if count == 1:
            enemymove.up(lastop);
        if count == 2:
            enemymove.downward(lastop);
        if count == 3:
            enemymove.rightran(lastop);
        if count == 4:
            enemymove.leftran(lastop);

    def up(lastop):
        global xenemy, yenemy
        print ("forward")
        yenemy[lastop] = (canvas.coords(enemy[lastop])[1])
        canvas.coords(enemy[lastop], xenemy[lastop] + radiusenemy, yenemy[lastop] + radiusenemy, xenemy[lastop] - radiusenemy, yenemy[lastop] - radiusenemy)
        print(yenemy)
        print(xenemy)
        canvas.after(timer, enemymove.movement, lastop)

    def downward(lastop):
        global xenemy, yenemy
        print("back")
        yenemy[lastop] = (canvas.coords(enemy[lastop])[3]) 
        canvas.coords(enemy[lastop], xenemy[lastop] - radiusenemy, yenemy[lastop] + radiusenemy, xenemy[lastop] + radiusenemy, yenemy[lastop] - radiusenemy)
        print(yenemy)
        print(xenemy)
        canvas.after(timer, enemymove.movement, lastop)

    def rightran(lastop):
        global xenemy, yenemy
        print("right")
        xenemy[lastop] = (canvas.coords(enemy[lastop])[2]) 
           canvas.coords(enemy[lastop], xenemy[lastop] - radiusenemy, yenemy[lastop] - radiusenemy, xenemy[lastop] + radiusenemy, yenemy[lastop] + radiusenemy)
        print(yenemy)
        print(xenemy)
        canvas.after(timer, enemymove.movement, lastop)

    def leftran(lastop):
        global xenemy, yenemy
        print("left")
        xenemy[lastop] = (canvas.coords(enemy[lastop])[0])
        canvas.coords(enemy[lastop], xenemy[lastop] - radiusenemy, yenemy[lastop] - radiusenemy, xenemy[lastop] + radiusenemy, yenemy[lastop] + radiusenemy)
        print(yenemy)
        print(xenemy)
        canvas.after(timer, enemymove.movement, lastop)

class spawntime():
    def timer():
        global timeset
        timeset = 3
        spawntime.calculation()

    def calculation():
        global timeset
        print ('The count is: ', timeset)
        if timeset <= 0:
            enemymove.create()
        else:
            timeset -= 1
            canvas.after(1000, spawntime.calculation)

    #runs the main code
    def main():
        global root, canvas
        root.title("")
        canvas = Canvas(root, width= resX, height=resY, bg = "white")
        canvas.pack()
        Thread(target = spawntime.timer).start()  
        root.mainloop()

    main()

I'm reasonably new to appending, so making multiple different appended sprites move all together is out of my range, and so I am unsure of how to get this to work.

Upvotes: 0

Views: 791

Answers (1)

furas
furas

Reputation: 142641

I don't understand your code so I create own version. Now every enemy moves after random time. After random time I add new enemy

I keep enemies on list but I don't need this list.

import random

import tkinter as tk

# --- constants --- # UPPERCASE name

RES_X = 800
RES_Y = 600

# --- classes --- # CamelCase name 

class Enemies(object):

    def __init__(self, canvas):

        # access to canvas
        self.canvas = canvas

        # started amount of enemies
        self.amount = 5

        # list for all enemies
        self.enemies = list()

        # create enemies
        for _ in range(self.amount):
            self.create_one_enemy()

    def create_one_enemy(self):
        radius = 12.5 # random

        x = random.uniform(radius, RES_X-radius)
        y = random.uniform(radius, RES_Y-radius)

        oval = self.canvas.create_oval(x-radius, y-radius, x+radius, y+radius, fill="black", outline="black")

        # one enemy
        enemy = [x, y, radius, oval]

        # apped to list - but I don't need this list 
        self.enemies.append(enemy)

        # move this enemy after random time
        random_time = random.randint(150, 3000)
        root.after(random_time, self.move_one_enemy, enemy)

    def move_one_enemy(self, enemy):

        #print('moving:', enemy)

        # get old values
        x, y, radius, oval = enemy

        direction = random.randint(1,4)

        if direction == 1: # up
            y -= radius
        elif direction == 2: # down
            y += radius
        elif direction == 3: # left
            x -= radius
        elif direction == 4: # right
            x += radius

        self.canvas.coords(oval, x-radius, y-radius, x+radius, y+radius)

        # remember new values
        enemy[0] = x
        enemy[1] = y

        # move this enemy after random time
        random_time = random.randint(150, 3000)
        root.after(random_time, self.move_one_enemy, enemy)

# --- functions --- # lower_case name 

def add_new_enemy():

    enemies.create_one_enemy()

    # add next enemy after random time
    timer = random.randint(150, 3000)
    root.after(random_time, add_new_enemy)

# --- main ---

root = tk.Tk()
root.title("")

canvas = tk.Canvas(root, width=RES_X, height=RES_Y, bg="white")
canvas.pack()

# create enemies and move it using `root.after`
enemies = Enemies(canvas)

# add new enemy after random time
random_time = random.randint(150, 3000)
root.after(random_time, add_new_enemy)

root.mainloop()

EDIT: but rather I would create class Enemy for single enemy and then list enemies to keep all Enemy instances.

import random

import tkinter as tk

# --- constants --- # UPPERCASE name

RES_X = 800
RES_Y = 600

# --- classes --- # CamelCase name 

class Enemy(object):
    '''single enemy'''

    def __init__(self, canvas):

        # access to canvas
        self.canvas = canvas

        self.radius = 12.5 # random

        self.color = random.choice( ('black', 'red', 'green', 'blue', 'yellow') )

        self.x = random.uniform(self.radius, RES_X-self.radius)
        self.y = random.uniform(self.radius, RES_Y-self.radius)

        self.x1 = self.x-self.radius
        self.y1 = self.y-self.radius

        self.x2 = self.x+self.radius
        self.y2 = self.y+self.radius

        self.oval = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill=self.color, outline=self.color)

        self.moving = True

        self.start()


    def start(self):
        '''start moving'''

        self.moving = True

        # move this enemy after random time
        random_time = random.randint(150, 3000)
        root.after(random_time, self.move)


    def stop(self):
        '''stop moving'''

        self.moving = False


    def move(self):

        if self.moving: # to stop root.after

            direction = random.randint(1,4)

            if direction == 1: # up
                self.y -= self.radius
                self.y1 -= self.radius
                self.y2 -= self.radius
            elif direction == 2: # down
                self.y += self.radius
                self.y1 += self.radius
                self.y2 += self.radius
            elif direction == 3: # left
                self.x -= self.radius
                self.x1 -= self.radius
                self.x2 -= self.radius
            elif direction == 4: # right
                self.x += self.radius
                self.x1 += self.radius
                self.x2 += self.radius

            self.canvas.coords(self.oval, self.x1, self.y1, self.x2, self.y2)
            # move this enemy after random time
            random_time = random.randint(150, 3000)
            root.after(random_time, self.move)

# --- functions --- # lower_case name 

def add_new_enemy():

    enemies.append(Enemy(canvas))

    # add next enemy after random time
    timer = random.randint(150, 3000)
    root.after(random_time, add_new_enemy)

# --- main ---

root = tk.Tk()
root.title("")

canvas = tk.Canvas(root, width=RES_X, height=RES_Y, bg="white")
canvas.pack()

# 5 enemies at the beginning
enemies = list()

for _ in range(5):
    enemies.append(Enemy(canvas))

# add new enemy after random time
random_time = random.randint(150, 3000)
root.after(random_time, add_new_enemy)

root.mainloop()

And now you can use list to stop/start enemies

for one_enemy in enemies:
    one_enemy.stop()

or check some information

for one_enemy in enemies:
    print("x:", one_enemy.x)
    print("y:", one_enemy.y)

btw: and then you can create EnemiesGroup class


EDIT: EnemiesGroup and buttons to control group

import random

import tkinter as tk

# --- constants --- # UPPERCASE name

RES_X = 800
RES_Y = 600

# --- classes --- # CamelCase name 

class Enemy(object):
    '''single enemy'''

    def __init__(self, canvas):

        # access to canvas
        self.canvas = canvas

        self.radius = 12.5 # random

        self.color = random.choice( ('black', 'red', 'green', 'blue', 'yellow') )

        self.x = random.uniform(self.radius, RES_X-self.radius)
        self.y = random.uniform(self.radius, RES_Y-self.radius)

        self.x1 = self.x-self.radius
        self.y1 = self.y-self.radius

        self.x2 = self.x+self.radius
        self.y2 = self.y+self.radius

        self.oval = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill=self.color, outline=self.color)

        self.moving = True

        self.start()


    def start(self):
        '''start moving'''

        self.moving = True

        # move this enemy after random time
        random_time = random.randint(150, 3000)
        root.after(random_time, self.move)


    def stop(self):
        '''stop moving'''

        self.moving = False


    def move(self):

        if self.moving: # to stop root.after
            direction = random.randint(1,4)

            if direction == 1: # up
                self.y -= self.radius
                self.y1 -= self.radius
                self.y2 -= self.radius
            elif direction == 2: # down
                self.y += self.radius
                self.y1 += self.radius
                self.y2 += self.radius
            elif direction == 3: # left
                self.x -= self.radius
                self.x1 -= self.radius
                self.x2 -= self.radius
            elif direction == 4: # right
                self.x += self.radius
                self.x1 += self.radius
                self.x2 += self.radius

            self.canvas.coords(self.oval, self.x1, self.y1, self.x2, self.y2)

            # move this enemy after random time
            random_time = random.randint(150, 3000)
            root.after(random_time, self.move)

class EnemiesGroup(object):

    def __init__(self, canvas):

        self.canvas = canvas

        self.enemies = list()

        self.moving = True


    def add_new_enemy(self):

        # can be only 5 enemies 
        if len(self.enemies) < 5:
            e = Enemy(self.canvas)

            # stop new enemy if all enemies are stoped
            e.moving = self.moving

            self.enemies.append(e)
        else:
            print("You have 5 enemies - I can't add more.")

    def stop_all_enemies(self):
        for e in self.enemies:
            e.stop()

        # all enemies are stoped
        self.moving = False


    def start_all_enemies(self):
        for e in self.enemies:
            e.start()

        # all enemies are moving
        self.moving = True

# --- functions --- # lower_case name

def add_new_enemy():

    enemies_group.add_new_enemy()

    # add next enemy after random time
    timer = random.randint(150, 3000)
    root.after(random_time, add_new_enemy)

# --- main ---

root = tk.Tk()
root.title("")

canvas = tk.Canvas(root, width=RES_X, height=RES_Y, bg="white")
canvas.pack()

# enemies

enemies_group = EnemiesGroup(canvas)

for _ in range(5):
    enemies_group.add_new_enemy()

# add new enemy after random time
random_time = random.randint(150, 3000)
root.after(random_time, add_new_enemy)

# buttons to control all enemies

button_stop = tk.Button(root, text='STOP', command=enemies_group.stop_all_enemies)
button_stop.pack()

button_start = tk.Button(root, text='START', command=enemies_group.start_all_enemies)
button_start.pack()

button_add = tk.Button(root, text='ADD NEW ENEMY', command=enemies_group.add_new_enemy)
button_add.pack()

root.mainloop()

EDIT: removing enemy by clicking oval.

In add_new_enemy I bind to oval event <Button-1> and function clicked (with enemy object).

Function clicked removes oval from canvas and removes enemy from enemies group.

class EnemiesGroup(object):

    # ... other functions ...    

    def clicked(self, event, enemy):
        print('clicked:', enemy),

        # remove oval from canvas        
        self.canvas.delete(enemy.oval)

        # remove enemy from list
        self.enemies.remove(enemy)

        # create new enemy after 10s
        root.after(10000, self.add_new_enemy)


    def add_new_enemy(self):

        # can be only 5 enemies 
        if len(self.enemies) < 5:
            print('create new enemy')
            e = Enemy(self.canvas)

            # stop new enemy if all enemies are stoped
            e.moving = self.moving

            # bind mouse button to enemy
            self.canvas.tag_bind(e.oval, '<Button-1>', lambda event:self.clicked(event, e))

            self.enemies.append(e)
        else:
            print("You have 5 enemies - I can't add more.")


    # ... other functions ...

Upvotes: 1

Related Questions