#! /usr/bin/env python
# -*- coding: Utf-8 -*-

#####################################
# Mozgó célpont bombázása           #
# (C) G. Swinnen - Avril 2004 - GPL #
#####################################

from Tkinter import *
from math import sin, cos, pi
from random import randrange
from threading import Thread

class Canon:
    """Ágyúrajz"""
    def __init__(self, boss, num, x, y, irany):
        self.boss = boss            # a vászon hivatkozása
        self.num = num              # az ágyú száma a listában
        self.x1, self.y1 = x, y     # ágyú forgástengelye
        self.irany = irany            # lövés iránya (-1:balra, +1:jobbra)
        self.lagyucso = 30               # ágyúcsõ hossza
        # ágyúcsõ rajzolása (vízszintes) :
        self.x2, self.y2 = x + self.lagyucso * irany, y
        self.cso = boss.create_line(self.x1, self.y1,
                                     self.x2, self.y2, width =10)
        # ágyútest rajzolása (színes kör) :
        self.rc = 15                # a kör sugara
        self.test = boss.create_oval(x -self.rc, y -self.rc, x +self.rc,
                                      y +self.rc, fill ='black')
        # egy lövedék elõrajzolása (kiinduláskor egy pont) :
        self.lovedek = boss.create_oval(x, y, x, y, fill='red')
        self.anim = 0
        # a vászon szélességének és magasságának meghatározása :
        self.xMax = int(boss.cget('width'))
        self.yMax = int(boss.cget('height'))

    def orienter(self, angle):
        "ágyú dõlésszögének beállítása"
        # rem : az <angle> (szög) paramétert stringként kapja.
        # át kell alakítani valós számmá, majd radiánná :
        self.angle = float(angle)*2*pi/360      
        self.x2 = self.x1 + self.lagyucso * cos(self.angle) * self.irany
        self.y2 = self.y1 - self.lagyucso * sin(self.angle)
        self.boss.coords(self.cso, self.x1, self.y1, self.x2, self.y2)
        
    def feu(self):
        "golyó kilövésének indítása"
        # céltárgy hivatkozása :
        self.celtargy = self.boss.master.celtargy
        if self.anim ==0:
            self.anim =1
            # lövedék kezdõ pozíciója (ez az ágyú torka)) :
            self.xo, self.yo = self.x2, self.y2
            v = 20              # kezdõ sebesség
            # ennek a sebességnek a függõleges és vízszintes komponensei :
            self.vy = -v *sin(self.angle)
            self.vx = v *cos(self.angle) *self.irany
            self.animacio_lovedek()
    
    def animacio_lovedek(self):
        "lövedék animációja (ballisztikus pálya)"
        # lövedék pozícionálása koordinátái újradefiniálásával :
        self.boss.coords(self.lovedek, self.xo -3, self.yo -3,
                                    self.xo +3, self.yo +3)
        if self.anim >0:
            # a következõ pozíció számolása :
            self.xo += self.vx
            self.yo += self.vy
            self.vy += .5
            self.test_akadaly()        # akadályba ütközött ?
            self.boss.after(1, self.animacio_lovedek)
        else:
            # animáció vége :
            self.boss.coords(self.lovedek, self.x1, self.y1, self.x1, self.y1) 
   
    def test_akadaly(self):
        "Eldöntjük: a lövedék célba talált-e vagy elérte-e a játéktér határát"
        if self.yo >self.yMax or self.xo <0 or self.xo >self.xMax:
            self.anim =0
            return
        if self.yo > self.celtargy.y -3 and self.yo < self.celtargy.y +18 \
        and self.xo > self.celtargy.x -3 and self.xo < self.celtargy.x +43:
            # megrajzoljuk a lövedék robbanását (narancssárga kör) :
            self.robbanas = self.boss.create_oval(self.xo -10,
                         self.yo -10, self.xo +10, self.yo +10,
                         fill ='orange', width =0)
            self.boss.after(150, self.robbanas_vege)
            self.anim =0
   
    def robbanas_vege(self):
        "a robbanási kör törlése - a pontszám kezelése"
        self.boss.delete(self.robbanas)
        # a siker jelzése a master-ablaknak :
        self.boss.master.goal()        

class VezerloPult(Frame):
    """Egy ágyúhoz asszociált vezérlõpult""" 
    def __init__(self, boss, canon):
        Frame.__init__(self, bd =3, relief =GROOVE)
        self.score =0
        s =Scale(self, from_ =88, to =65,
                 troughcolor ='dark grey',
                 command =canon.orienter)
        s.set(45)                       # a lövés kezdõ szöge
        s.pack(side =LEFT)
        Label(self, text ='Dõlésszög').pack(side =TOP, anchor =W, pady =5)        
        Button(self, text ='Tûz !', command =canon.feu).\
                                    pack(side =BOTTOM, padx =5, pady =5)
        Label(self, text ="pont").pack()
        self.pontok =Label(self, text=' 0 ', bg ='white')
        self.pontok.pack()
        # az agyu iranyanak megfeleloen belra vagy jobbra pozicional :
        gd =(LEFT, RIGHT)[canon.irany == -1]
        self.pack(padx =3, pady =5, side =gd)

    def pontHozzaadasa(self, p):
        "a pontszám növelése vagy csökkentése"
        self.score += p
        self.pontok.config(text = ' %s ' % self.score)

class Celtargy:
    """céltárgyként szolgáló grafikus objektum"""
    def __init__(self, can, x, y):
        self.can = can             # a vászon hivatkozása
        self.x, self.y = x, y
        self.celtargy = can.create_oval(x, y, x+40, y+15, fill ='purple')
        
    def elmozditas(self, dx, dy):
        "a céltárgy dx,dy elmozdulása" 
        self.can.move(self.celtargy, dx, dy)
        self.x += dx
        self.y += dy
        return self.x, self.y

class Thread_celtargy(Thread):
    """a céltárgy animációját irányító thread-objektum"""
    def __init__(self, app, celtargy):
        Thread.__init__(self)
        self.celtargy = celtargy          # az elmozdítandó objektum
        self.app = app              # az alkalmazásablak hivatkozása
        self.sx, self.sy = 6, 3     # távolság- és idõnövekmények
        self.dt =300                # az animációhoz (ms)
   
    def run(self):
        "animálás, amíg az alkalmazásablak létezik" 
        x, y = self.celtargy.elmozditas(self.sx, self.sy)
        if x > self.app.xm -50 or x < self.app.xm /5:
                self.sx = -self.sx
        if y < self.app.ym /2 or y > self.app.ym -20:
                self.sy = -self.sy
        if self.app != None:
            self.app.after(int(self.dt), self.run)

    def stop(self):
        "a thread zárása, ha az alkalmazásablak zárva van"
        self.app =None
        
    def gyorsit(self):
        "a mozgás gyorsítása"
        self.dt /= 1.5
        self.app.bell()

class Application(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.master.title('<<< Lövés mozgó céltárgyra >>>')
        self.pack()
        self.xm, self.ym = 600, 500
        self.jeu = Canvas(self, width =self.xm, height =self.ym,
                          bg ='ivory', bd =3, relief =SUNKEN)
        self.jeu.pack(padx =4, pady =4, side =TOP)

        # Egy ágyú és egy vezérlõ pult objektum létrehozása :
        x, y = 30, self.ym -20
        self.gun =Canon(self.jeu, 1, x, y, 1)
        self.pult =VezerloPult(self, self.gun)
        
        # mozgó célpont létrehozása :
        self.celtargy = Celtargy(self.jeu, self.xm/2, self.ym -25)
        # mozgó célpont animálása saját thread-del :
        self.tc = Thread_celtargy(self, self.celtargy)
        self.tc.start()
        # az összes thread leállítása amikor zárjuk az ablakot :
        self.bind('<Destroy>',self.zaras_threadek)

    def goal(self):
        "a célpontot eltaláltuk"
        self.pult.pontHozzaadasa(1)
        self.tc.gyorsit()
        
    def zaras_threadek(self, evt):
        "a célpont animációs thread-jének leállítása"
        self.tc.stop()

if __name__ =='__main__':
    Application().mainloop()
