0
\$\begingroup\$

I have 148 lines of code...

from tkinter import *
from math import sqrt
from random import shuffle
HEIGHT = 768
WIDTH = 1366
window = Tk()
colors = ["darkred", "green", "blue", "purple", "pink", "lime"]
health = {
    "ammount" : 3,
    "color": "green"
}
window.title("Bubble Blaster")
c = Canvas(window, width=WIDTH, height=HEIGHT, bg="darkblue")
c.pack()
ship_id = c.create_polygon(5, 5, 5, 25, 30, 15, fill="green")
ship_id2 = c.create_oval(0, 0, 30, 30, outline="red")
SHIP_R = 15
MID_X = WIDTH / 2
MID_Y = HEIGHT / 2
c.move(ship_id, MID_X, MID_Y)
c.move(ship_id2, MID_X, MID_Y)
ship_spd = 10
score = 0
def move_ship(event):
    if event.keysym == "Up":
        c.move(ship_id, 0, -ship_spd)
        c.move(ship_id2, 0, -ship_spd)
    elif event.keysym == "Down":
        c.move(ship_id, 0, ship_spd)
        c.move(ship_id2, 0, ship_spd)
    elif event.keysym == "Left":
        c.move(ship_id, -ship_spd, 0)
        c.move(ship_id2,  -ship_spd, 0)
    elif event.keysym == "Right":
        c.move(ship_id, ship_spd, 0)
        c.move(ship_id2,  ship_spd, 0)
    elif event.keysym == "P":
        score += 10000
c.bind_all('<Key>', move_ship)
from random import randint
bub_id = list()
bub_r = list()
bub_speed = list()
bub_id_e = list()
bub_r_e = list()
bub_speed_e = list()
min_bub_r = 10
max_bub_r = 30
max_bub_spd = 10
gap = 100
def create_bubble():
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline="white", fill="lightblue")
    bub_id.append(id1)
    bub_r.append(r)
    bub_speed.append(randint(5, max_bub_spd))
def create_bubble_e():
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline="black", fill="red")
    bub_id_e.append(id1)
    bub_r_e.append(r)
    bub_speed_e.append(randint(6, max_bub_spd))
def create_bubble_r():
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline="white", fill=colors[0])
    bub_id.append(id1)
    bub_r.append(r)
    bub_speed.append(randint(6, max_bub_spd))
def move_bubbles():
    for i in range(len(bub_id)):
        c.move(bub_id[i], -bub_speed[i], 0)
    for i in range(len(bub_id_e)):
        c.move(bub_id_e[i], -bub_speed_e[i], 0)
from time import sleep, time
bub_chance = 30
def get_coords(id_num):
    pos = c.coords(id_num)
    x = (pos[0] + pos[2]) / 2
    y = (pos[1] + pos[3]) / 2
    return x, y
def del_bubble(i):
    del bub_r[i]
    del bub_speed[i]
    c.delete(bub_id[i])
    del bub_id[i]
def clean():
    for i in range(len(bub_id) -1, -1, -1):
        x, y = get_coords(bub_id[i])
        if x < -gap:
            del_bubble(i)
def distance(id1, id2):
    x1, y1 = get_coords(id1)
    x2, y2 = get_coords(id2)
    return sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
def  collision():
    points = 0
    for bub in range(len(bub_id) -1, -1, -1):
        if distance(ship_id2, bub_id[bub]) < (SHIP_R + bub_r[bub]):
            points += (bub_r[bub] + bub_speed[bub])
            del_bubble(bub)
    return points
def cleanAll():
    for i in range(len(bub_id) -1, -1, -1):
        x, y = get_coords(bub_id[i])
        del_bubble(i)
def  collision_e():
    for bub in range(len(bub_id_e) -1, -1, -1):
        if distance(ship_id2, bub_id_e[bub]) < (SHIP_R + bub_r_e[bub]):
            window.destroy()
            print("You were killed by a red bubble...")
            print("You got ", score, " score!")
            sleep(100)            
c.create_text(50, 30, text="SCORE", fill="white")
st = c.create_text(50, 50, fill="white")
c.create_text(100, 30, text="TIME", fill="white")
tt = c.create_text(100, 50, fill="white")
def show(score):
    c.itemconfig(st, text=str(score))
evil_bub = 50
#MAIN GAME LOOP
while True:
    if randint(1, bub_chance) == 1:
        create_bubble()
    if randint(1, evil_bub) == 1:
        create_bubble_e()
    if randint(1, 100) == 1:
        create_bubble_r()
    move_bubbles()
    collision_e()
    clean()
    score += collision()
    if score >= 400:
        evil_bub = 40
        bub_chance = 25
        if score >= 1000:
            evil_bub = 30
            bub_chance = 20
    show(score)
    window.update()
    shuffle(colors)
    sleep(0.01)

I would like to know if there is any way to make this better.

\$\endgroup\$
  • 1
    \$\begingroup\$ Please describe what your code does in a bit of detail in the question. \$\endgroup\$ – Nic Hartley Aug 27 '17 at 11:54
  • \$\begingroup\$ Your question currently leaves some things to be desired. I'd recommend taking a look at Simon's Guide to posting a good question. In particular, you could improve your description about the code, and add screenshots if possible. \$\endgroup\$ – Simon Forsberg Dec 10 '17 at 16:15
5
\$\begingroup\$

Don't use a wildcard import

Wildcard imports are discouraged by PEP8. Instead, I recommend doing imports like this:

import tkinter as tk

You will then have to change all of the code that references classes, functions, and constance to include the prefix tk. (eg: window = tk.Tk())

Put all imports at the top of the file

You have this stuck in the middle of the code, which needs to be moved to the top:

from random import randint

Don't create your own event loop

Tkinter comes with an efficient event loop called mainloop. You can run your game loop with it using the after method common to all widgets.

What you should do is move everything necessary for one iteration of a loop into a function. You then call that function periodically using after. So, for example, instead of this:

while True:
    ...
    window.update()
    sleep(0.01)

... you do something like this:

def do_update():
    # all your code except the call to `update` and `sleep`

def call_periodically():
    do_update()
    window.after(100, call_periodically)

There are two advantages:

  1. you eliminate the use of sleep. sleep does exactly that, making your entire application go to sleep. That means that while it is sleeping (even if it's just for a short period of time), your application won't be able to respond to any events, including requests to redraw the window

  2. you can speed up or slow down the game by simply changing the first value to the call to after.

For more information, see:

\$\endgroup\$
1
\$\begingroup\$

This part of your code

if event.keysym == "Up":
    c.move(ship_id, 0, -ship_spd)
    c.move(ship_id2, 0, -ship_spd)
elif event.keysym == "Down":
    c.move(ship_id, 0, ship_spd)
    c.move(ship_id2, 0, ship_spd)
elif event.keysym == "Left":
    c.move(ship_id, -ship_spd, 0)
    c.move(ship_id2,  -ship_spd, 0)
elif event.keysym == "Right":
    c.move(ship_id, ship_spd, 0)
    c.move(ship_id2,  ship_spd, 0)
elif event.keysym == "P":

may become shorter and more readable, too, if you will employ a dictionary for your four directions:

directions = dict(Up=(0, -1), Down=(0, +1), Left=(-1, 0), Right=(1, 0))

direction = event.keysym                       # for better readability only 
if  direction in directions:
    x_fact, y_fact = directions[direction]     # unpacking tuple
    cx = x_fact * ship_spd
    cy = y_fact * ship_spd
    c.move(ship_id,  cx, cy)
    c.move(ship_id2, cx, cy)

Note the construction of that dictionary (using keywords to avoid typing quotes).

\$\endgroup\$
0
\$\begingroup\$

To follow the DRY principle (Don't Repeat Yourself) consider refactoring this part of your code

def create_bubble():
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline="white", fill="lightblue")
    bub_id.append(id1)
    bub_r.append(r)
    bub_speed.append(randint(5, max_bub_spd))
def create_bubble_e():
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline="black", fill="red")
    bub_id_e.append(id1)
    bub_r_e.append(r)
    bub_speed_e.append(randint(6, max_bub_spd))
def create_bubble_r():
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline="white", fill=colors[0])
    bub_id.append(id1)
    bub_r.append(r)
    bub_speed.append(randint(6, max_bub_spd))

(BTW. why not follow PEP 8 - Style Guide about surrounding top-level function with two blank lines?)

Those 3 function definitions are almost the same - so pick out the differences and you may endup with something as

def create_bubble_common(rand_speed_min, outline, fill):
    x = WIDTH + gap
    y = randint(0, HEIGHT)
    r = randint(min_bub_r, max_bub_r)
    id1 = c.create_oval(x - r, y - r, x + r, y + r, outline=outline, fill=fill)
    bub_id.append(id1)
    bub_r.append(r)
    bub_speed.append(randint(rand_speed_min, max_bub_spd))


def create_bubble():
    create_bubble_common(5, 'white', 'lightblue')


def create_bubble_e():
    create_bubble_common(6, 'black', 'red')


def create_bubble_r():
    create_bubble_common(6, 'white', colors[0])

or instead of last 3 definition directly use

create_bubble_common(5, 'white', 'lightblue')

(and other two) at the appropriate places as you use every of them only once.

\$\endgroup\$
0
\$\begingroup\$

Your ship have 2 parts - ship_id and ship_id2.

First tip - why not use something as part1 and part2 instead such ugly names?


But now I'll keep your names in the sake to not break your current code.

As you always move these 2 parts simultaneously, e. g. in this part of your code

c.move(ship_id, MID_X, MID_Y)
c.move(ship_id2, MID_X, MID_Y)

you may first construct the whole ship

ship = (ship_id, ship_id2)

and then use

for part in ship:
    c.move(part, MID_X, MID_Y)

or - even better - create a function for the ship moving

def move_ship(cx, cy):
    for part in ship:
        c.move(part, MID_X, MID_Y)

and then use it in all parts of your code - for example as

move_ship(MID_X, MID_Y)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.