Столкновение в играх: Пушка, со столкновениями и рикошетами

from random import randrange as rnd, choice
from tkinter import *
import math
import time

root = Tk()
fr = Frame(root)
root.geometry('800x600')
canv = Canvas(root, bg = 'white')
canv.pack(fill=BOTH,expand=1)

colors = ['blue','green','red','brown']

class ball():
    def __init__(self,x=40,y=450):
        self.x = x
        self.y = y
        self.r = 10
        self.color = choice(colors)
        self.points = 3
        self.id = canv.create_oval(self.x-self.r, self.y-self.r, self.x+self.r, self.y+self.r, fill=self.color)
        self.id_points = canv.create_text(self.x,self.y,text = self.points)
        self.live = 200
        self.nature = 1
        
    def paint(self):
        canv.coords(self.id,self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r)
        canv.coords(self.id_points,self.x,self.y)
        canv.itemconfig(self.id_points,text = self.points)
        
        
        
    def move(self):
        if self.y <= 500:
            self.vy += 0.07
            self.y += self.vy
            self.x += self.vx
            self.vx *= 0.999
            self.v = (self.vx**2+self.vy**2)**0.5
            self.an = math.atan(self.vy/self.vx)
            self.paint()
        else:
            if self.vx**2+self.vy**2 > 10:
                self.vy = -self.vy*0.7
                self.vx = self.vx*0.7
                self.y = 499
            if self.live < 0:
                self.kill()
            else:
                self.live -= 1
        if self.x > 780:
            self.vx = - self.vx/2
            self.x = 779
            
    def hittest(self,ob):
        if abs(ob.x - self.x) <= (self.r + ob.r) and abs(ob.y - self.y) <= (self.r + ob.r):
            return True
        else:
            return False
            
    def ricochet(self,w):
        self.v = (self.vx**2 + self.vy**2)**0.5
        self.an = math.atan(self.vy/self.vx)

        if self.x == w.x:
            self.x += 1
                
        if w.x-(self.x+self.vx):
            an_rad = math.atan((w.y-(self.y+self.vy))/(w.x-(self.x+self.vx)))
            an_res = an_rad - (self.an - an_rad )
            
            vx2 = 0.7*self.v*math.cos(an_res)
            vy2 = 0.7*self.v*math.sin(an_res)
            if self.an > 0 and self.vx < 0 and self.vy < 0 or self.an < 0 and self.vx < 0:
                vx2 = -vx2
                vy2 = -vy2
            self.vx = -vx2
            self.vy = -vy2
            self.move()
            self.move()
            self.points += 1
            
    def kill(self):
        global balls
        canv.delete(self.id)
        canv.delete(self.id_points)
        
        try:
            balls.pop(balls.index(self))
        except:
            pass
            
    def bum(self):
        global balls, colors
        for z in range(5):
            new_ball = ball()
            new_ball.r = 5
            new_ball.vx = self.vx + rnd(-5,5)
            new_ball.vy = self.vy - rnd(-5,5)
            new_ball.x = self.x
            new_ball.y = self.y
            new_ball.nature = 0
            new_ball.points = 1
            new_ball.live = 20
            while new_ball.color == 'red':
                new_ball.color = choice(colors)
            balls += [new_ball]
            self.kill()
        

class gun():
    def __init__(self):
        self.f2_power = 10
        self.f2_on = 0
        self.an = 1
        self.points = 0
        self.id = canv.create_line(20,450,50,420,width=7, smooth = 1)
        self.id_points = canv.create_text(30,30,text = self.points,font = '28')
        
    def fire2_start(self,event):
        self.f2_on = 1

    def stop(self):
        self.f2_on = 0

    def fire2_end(self,event):
        global balls, bullet
        bullet += 1
        new_ball = ball()
        new_ball.r += 5
        self.an = math.atan((event.y-new_ball.y)/(event.x-new_ball.x)) 
        new_ball.vx = self.f2_power*math.cos(self.an)/7
        new_ball.vy = self.f2_power*math.sin(self.an)/7
        balls += [new_ball]
        self.f2_on = 0
        self.f2_power = 35


    def targetting (self,event=0):
        if event:
            self.an = math.atan((event.y-450)/(event.x-20))     
        if self.f2_on:
            canv.itemconfig(self.id,fill = 'orange')
        else:
            canv.itemconfig(self.id,fill = 'black')
        canv.coords(self.id, 20, 450, 20 + max(self.f2_power,20) * math.cos(self.an), 450+max(self.f2_power,20) * math.sin(self.an))
        
    def power_up(self):
        if self.f2_on:
            if self.f2_power < 100:
                self.f2_power += 1
            canv.itemconfig(self.id,fill = 'orange')
        else:
            canv.itemconfig(self.id,fill = 'black')
            
    def bum(self, event = 0):
        global balls
        balls[-1].bum()

        
class target():
    def __init__(self):
        self.points = 1
        x = self.x = rnd(600,780)
        y = self.y = rnd(300,500)
        r = self.r = rnd(10,40)
        self.live = 5 + rnd(5)
        color = self.color = 'red'
        self.id = canv.create_oval(x-r,y-r,x+r,y+r, fill = self.color)
        self.id_live = canv.create_text(x,y,text=self.live)
        
    def hit(self):
        canv.itemconfig(self.id_live,text=self.live)
        if self.live < 1:
            self.kill()
        
    def kill(self):
        global targets
        targets.pop(targets.index(self))
        canv.delete(self.id)
        canv.delete(self.id_live)
        
        
balls = []
bullet = 0
targets = []
g1 = gun()
walls = []

while 1:
    for z in range(rnd(3,7)):
        targets += [target()]

    for z in range(rnd(1,8)):
        walls += [target()]
        walls[-1].x = rnd(200,600)
        walls[-1].y = rnd(100,400)
        walls[-1].r = rnd(20,50)
        canv.delete(walls[-1].id_live)
        canv.itemconfig(walls[-1].id, fill = 'gray', width = 0)
        canv.coords(walls[-1].id, walls[-1].x-walls[-1].r, walls[-1].y-walls[-1].r, walls[-1].x+walls[-1].r, walls[-1].y+walls[-1].r)

    canv.bind('<Button-1>',g1.fire2_start)
    canv.bind('<Button-3>',g1.bum)
    canv.bind('<ButtonRelease-1>',g1.fire2_end)
    canv.bind('<Motion>',g1.targetting)

    result = canv.create_text(400,300, text = '', font = "28")
    z = 0.03
    while targets or balls:
        for b in balls:
            b.move()
            if b.nature:
                for w in walls:
                    if b.hittest(w):
                        b.ricochet(w)

            for b_test in balls:
                if b != b_test and b.nature and b_test.nature and  b.hittest(b_test):
                    b.ricochet(b_test)
                    b_test.bum()
                    
            for t in targets:
                if b.hittest(t):
                    b.kill()
                    t.hit()
                    g1.points += 1
                    t.live -= b.points
                    canv.itemconfig(g1.id_points, text = g1.points)
                    
        if not targets:
            canv.bind('<Button-1>','')
            canv.bind('<ButtonRelease-1>','')
            g1.stop()
            canv.itemconfig(result, text = 'Вы уничтожили все цели за ' + str(bullet) + ' выстрелов')
                
        canv.update()
        time.sleep(0.01)
        g1.targetting()
        g1.power_up()
    canv.update()
    time.sleep(0.01)
    canv.delete(result)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *