Droid Game 3D - Third Person Shooter!

Hello all :slight_smile:
About 5.0.0 :
Add the shader of the fire.
Screenshot this :

Directory 5.0.0 :
/models :
./models/world :frowning: Now, download panda3d art from https://www.panda3d.org/download/noversion/art-gallery.zip
Go to the cat-environment folder. In it you will see a millenium falcon folder. Take all the files from it and put it in the directory ./models/world)
./models/block : block.zip (269.6 KB)
./models/enemies : enemies.zip (381.4 KB)
./models/fighter : fighter.zip (36.9 KB)
./models/player : player.zip (644.6 KB)
./models/sky : sky.zip (12.5 KB)
./models/weapon : weapon.zip (234.3 KB)
./models/whishlyflash : whishlyflash.zip

./fonts : fonts.zip (192.5 KB)
./sounds : sounds.zip (1.8 MB)
./special_effects : special_effects.zip (19.3 KB)
./tex : tex.zip (95.1 KB)
./shaders : shaders.zip (22.2 KB)

droid.py :

#!/usr/bin/env python
# -*- coding: utf_8 -*-

# Π‘ΠΎΠ·Π΄Π°Π½ΠΎ : 22 число, ΡΠ½Π²Π°Ρ€ΡŒ, 2021 Π³ΠΎΠ΄

# Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ инструмСнты
from direct.showbase.ShowBase import ShowBase
from direct.particles.ParticleEffect import ParticleEffect
from direct.gui.OnscreenImage import OnscreenImage
from direct.interval.IntervalGlobal import *
from panda3d.core import *
from marconit_engine import *
import random
import sys
import time
import os
import math


VERSION = '5.0.0'


settings = ['window-title Droid Game release ' +  VERSION,
            'fullscreen 0',
            'win-size 1440 900']
            

loadPrcFileData('', settings[0]) # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π½Π΅ стандартный Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ (Π²ΠΎΠ·ΠΌΡ‘ΠΌ Π΅Π³ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ settings)
loadPrcFileData('', settings[1]) # Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ полноэкранный Ρ€Π΅ΠΆΠΈΠΌ
loadPrcFileData('', settings[2]) # Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠ½Π°

# Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π³Π»Π°Π²Π½Ρ‹ΠΉ класс нашСй ΠΈΠ³Ρ€Ρ‹
class DroidShooter(ShowBase):
    def __init__(self):
        ShowBase.__init__(self) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ всС сСлфы ΠΈΠ· direct
        self.speed = 1800 # ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двигатСля
        self.GB = False # НЕ Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ
        self.EN = False # НС Π±ΡƒΠ΄Π΅ΠΌ Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ английский язык
        self.pro_machine = False # НС Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.menu() # звпуск мСню
        
    def menu(self):
        
        base.enableParticles() # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ эффСкт Π΄Ρ‹ΠΌΠ°

        self.win.setClearColor((0, 0.2, 0.2, 1)) # Π—Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΌ. Π”Π΅Π»ΠΎ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π² этом ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΌ Π΄Π²ΠΈΠΆΠΊΠ΅ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Π·Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ сСрым.
        self.font = loader.loadFont('./fonts/doom_font.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ ΠΈΠ· ΠΈΠ³Ρ€Ρ‹ doom
        self.inst_font = loader.loadFont('./fonts/arial.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ arial

        self.crackSound = GameApi.sound(self, './sounds/crack.wav', 1) # Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π° корабля
        self.shotSound = GameApi.sound(self, './sounds/shot.wav', 1) # Π·Π²ΡƒΠΊ выстрСла
        self.startSound = GameApi.sound(self, './sounds/started.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.errorSound = GameApi.sound(self, './sounds/error.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.click_sound = GameApi.sound(self, './sounds/GUI_click.wav', 1) # Π·Π²ΡƒΠΊ наТатия
        
        self.startSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ запуска ΠΈΠ³Ρ€Ρ‹

        # МСню-эффСкты

        MenuApi.menu_effect(self)

        self.button_start = MenuApi.button(self, pos=(0.7, 0, 0.4), text="CTAPT",
                                   scale=.2, pad=(.2, .2),
                                   command=self.load_game) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹

        self.gb_start = MenuApi.button(self, pos=(0.7, 0, 0.1), text="GB",
                                   scale=.2, pad=(.2, .2),
                                   command=self.gb_mode) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹  Π² Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΠ΅

        self.en = MenuApi.button(self, pos=(0.7, 0, -0.2), text='EN',
                                 scale=.2, pad=(.2, .2),
                                 command=self.en_lang)
        self.pro_button = MenuApi.button(self, pos=(0.7, 0, -0.5), text='PRO',
                                 scale=.2, pad=(.2, .2),
                                 command=self.pro_system)

        self.slider_sun = MenuApi.slider(self, pos=(0.1, 0, .75), scale=0.8, value=0.5,
                                    command=self.set_sun_interval)


        self.title = MenuApi.addTitle(self, "Droid game Ρ€Π΅Π»ΠΈΠ· " + VERSION, self.font)
        
        # НапСчатаСм ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.inst1 = MenuApi.addInstruction(self, 0.95, u"[ESC]: Π’Ρ‹Ρ…ΠΎΠ΄", self.inst_font)
        self.inst2 = MenuApi.addInstruction(self, 0.90, u"[Left Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst3 = MenuApi.addInstruction(self, 0.85, u"[Right Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst4 = MenuApi.addInstruction(self, 0.80, u"[Up Arrow]: Π’ΠΏΠ΅Ρ€Π΅Π΄", self.inst_font)
        self.inst5 = MenuApi.addInstruction(self, 0.75, u"[a]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst6 = MenuApi.addInstruction(self, 0.70, u"[d]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst7 = MenuApi.addInstruction(self, 0.65, u"[Left Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst8 = MenuApi.addInstruction(self, 0.60, u"[Right Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst9 = MenuApi.addInstruction(self, 0.55, u"[a + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst10 = MenuApi.addInstruction(self, 0.50, u"[d + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst11 = MenuApi.addInstruction(self, 0.45, u"[space]: ΡΡ‚Ρ€Π΅Π»ΡŒΠ±Π°", self.inst_font)
        self.inst12 = MenuApi.addInstruction(self, 0.40, u"[s]: Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ", self.inst_font)
        self.inst13 = MenuApi.addInstruction(self, 0.35, u"[w]: ΡƒΠ±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅", self.inst_font)
        self.inst14 = MenuApi.addInstruction(self, 0.30, u"[f]: ΠΏΠΎΠ»Π½Ρ‹ΠΉ Ρ€Π°Π·Π³ΠΎΠ½(ОПАБНО!)", self.inst_font)
        self.inst15 = MenuApi.addInstruction(self, 0.25, u"[0]: ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ систСма", self.inst_font)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.

    def set_sun_interval(self):
        self.sun_interval = self.slider_sun.guiItem.getValue() * 100 # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ слайдСрноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΎΠ΅ Π½Π° 500, Π΄Π° Ρ‚Ρ€Π°Ρ‡Ρƒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ Π½ΠΎ ΠΌΠ½Π΅ каТСтся ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΠ»Π΅Π²Π°Ρ‚ΡŒ Π½Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ мСню, ΠΈΠ±ΠΎ Ρ‚Π°ΠΊΠΎΠ³ΠΎ понятия просто Π½Π΅Ρ‚Ρƒ :)

    def gb_mode(self):
        '''Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.GB = True

    def en_lang(self):
        '''ИзмСнСниС языка Π½Π° английский'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.EN = True

    def pro_system(self):
        '''ΠŸΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.pro_machine = True # Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅

    def load_game(self):
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.button_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ старта
        self.gb_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ Ρ‡Ρ‘Ρ€Π½ΠΎ Π±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°.
        self.title.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΈΠ³Ρ€Ρ‹
        self.en.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π°Π½Π³ΠΎΡΠ·Ρ‹Ρ‡Π½ΡƒΡŽ ΠΊΠ½ΠΎΠΏΠΊΡƒ
        self.pro_button.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ упрвлСния
        # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΠΈ управлСния
        self.inst1.destroy()
        self.inst2.destroy()
        self.inst3.destroy()
        self.inst4.destroy()
        self.inst5.destroy()
        self.inst6.destroy()
        self.inst7.destroy()
        self.inst8.destroy()
        self.inst9.destroy()
        self.inst10.destroy()
        self.inst11.destroy()
        self.inst12.destroy()
        self.inst13.destroy()
        self.inst14.destroy()
        self.inst15.destroy()
        self.slider_sun.destroy() # удаляСм слайдСр солнца
        
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ ΠΊΠ½ΠΎΠΏΠΎΠΊ, ΠΏΠΎ ΠΈΡ… Π½Π°ΠΆΠ°Ρ‚ΠΈΡŽ        

        # РисуСм Π·Π²Ρ‘Π·Π΄Ρ‹

        self.sky = loader.loadModel("./models/sky/solar_sky_sphere") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ модСль космоса(это сфСра)

        self.sky_tex = loader.loadTexture("./tex/stars_1k_tex.jpg") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ тСкстуру
        self.sky.setTexture(self.sky_tex, 1) # Π·Π°Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠΌ тСкстуру Π½Π° Π½Π΅Π±ΠΎ
        self.sky.reparentTo(render) # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π½Π΅Π±ΠΎ
        self.sky.setScale(40000) # Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠΌ Π½Π΅Π±ΠΎ Π΄ΠΎ максимальной Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Ρ‹ panda3d

        self.environ = loader.loadModel("models/world/falcon.egg") # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡƒΠΆΠ΅ созданный Π² blender ΠΌΠΈΡ€.
        self.environ.reparentTo(render) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΌΠΈΡ€Π° Π² ΠΎΠΊΠ½ΠΎ

        droidStartPos = (-1, 0, 1.5 ) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΡΡ‚Π°Ρ€Ρ‚ΠΎΠ²ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π² ΠΌΠΈΡ€Π΅.
        enemyStartPos = (-6, 1, 0.5) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°-Π΄Ρ€ΠΎΠΈΠ΄Π°.

        self.droid = GameApi.object(self, "models/player/seeker.egg", 1, droidStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΈΠ³Ρ€ΠΎΠΊΠ° (созданная Π² blender)
        self.enemy = GameApi.object(self, "models/enemies/r2d2/r2d2.egg", 1, enemyStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° (созданная Π² blender)

        self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 1 # ΠŸΠΎΠ·ΠΈΡ†ΠΈΡ ΠΏΡƒΡˆΠΊΠΈ
        
        self.weapon = GameApi.object(self, 'models/weapon/lightsaber.egg', .5, self.weapon_pos) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.bullet = GameApi.object(self, 'models/weapon/bullet/bullet.egg.pz', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΏΡƒΠ»ΡŽ
        self.flash = GameApi.object(self, 'models/whishlyflash/handlamp.egg', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
               
        self.bullet.reparentTo(render) # пСрСмСстим ΠΏΡƒΠ»ΡŽ Π² ΠΌΠΈΡ€ Π½ΠΎ появится ΠΎΠ½Π° сама Π½Π΅ скоро
        self.flash.reparentTo(render) # пСрСмСстим Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ Π² наш ΠΌΠΈΡ€
        self.bullet.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΏΡƒΠ»ΠΈ
        self.flash.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°

        # враТСский ΠΈΡΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΡŒ
        self.fighter = GameApi.object(self, 'models/fighter/fighter.egg', 1, (0, 90 , 0)) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»ΡŒΠΊΡƒ истрСбитСля
                

        self.cube = GameApi.object(self, 'models/block/crate.egg', .7, (0, 0, 0)) # Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π±Π»ΠΎΠΊ
        self.cube.hprInterval(1.5, (0, 360, 360)).loop()

        self.Intervalcube = self.cube.posInterval(13,
                                                   Point3(0, -500, 0),
                                                   startPos=Point3(0, 10, 0))

        self.Intervalcube.loop()
        
        self.spotlight = camera.attachNewNode(Spotlight("spotlight")) # ΠšΠΎΠ½Ρ„ΠΈΠ³ΠΈ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°
        self.spotlight.node().setColor((.3, .3, .3, 1))
        self.spotlight.node().setSpecularColor((0, 0, 0, 1))

        self.floater = NodePath(PandaNode("floater")) 
        self.floater.reparentTo(self.droid)
        self.floater.setZ(2.0)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.
        
        self.accept("arrow_left", self.setKey, ["left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ
        self.accept("arrow_right", self.setKey, ["right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ
        self.accept("arrow_up", self.setKey, ["forward", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a", self.setKey, ["cam-left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("d", self.setKey, ["cam-right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("arrow_left-up", self.setKey, ["left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_right-up", self.setKey, ["right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_up-up", self.setKey, ["forward", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π²Π΅Ρ€ΡŠ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a-up", self.setKey, ["cam-left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("d-up", self.setKey, ["cam-right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄

        self.accept("space", self.shot) # ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ±Π΅Π»Π΅ стрСляСм
        self.accept("s", self.toggleLights, [[self.spotlight]]) # Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
        self.accept("w", self.weapon_hide) # ΠΏΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ w - ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅.

        base.enableParticles() # Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π΄Ρ‹ΠΌΠ°
        self.p = ParticleEffect() # Π’ΠΊΠ»ΡŽΡ‡ΠΈΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.accept('f', self.particle_start) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f(ΠΎΡ‚ force) -  Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„Π°ΠΉΠ» Π΄Ρ‹ΠΌΠ° ΠΈ пСрСмСстим Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Π½Π½ΠΎ эта анимация стала ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π΄Ρ‹ΠΌΠ°
        self.accept('0', self.fountain) # ΠΏΡ€ΠΈ  Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΎΠΊ f+o(fountain) Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ систСму
        self.accept('f3', self.toggleWireframe) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f3 - Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠΎΠ»ΠΈΠ³ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ

        taskMgr.add(self.move, "moveTask") # ДобавляСм Π·Π°Π΄Π°Ρ‡Ρƒ Π² наш Π΄Π²ΠΈΠΆΠΎΠΊ

        self.isMoving = False # Π‘Ρ‚Π°Π²ΠΈΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ isMoving Π½Π° False(Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΌΠ΅Π½ΡΡ‚ΡŒ это Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅) Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ³Ρ€ΠΎΠΊ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ стоял.
        # Π”Π΅Π»Π°Π΅ΠΌ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ свСт Π±Ρ‹Π» ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½.
        self.disableMouse() # ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΌΡ‹ΡˆΠΊΡƒ
        self.camera.setPos(self.droid.getX(), self.droid.getY() + 1, 3) # Π‘Ρ‚Π°Π²ΠΈΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Ρ‡ΡƒΡ‚ΡŒ большС ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        self.state = 10 # БостояниС корабля

        if not self.EN : # Ссли язык Π½Π΅ английский
            self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else : # Ссли янглийский язык
            self.state_info = MenuApi.text(self, text='machine :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
            
                
        self.check_loss() # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
        self.hide_weapon = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ Π½Π΅ ΡƒΠ±Ρ€Π°Π½ΠΎ
        self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)
        self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)

        self.motor_pos1 = 25.238849639892578, 8.962211608886719, 1.5 # позиция ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°
        self.motor_pos2 = -20.676218032836914, 10.55816650390625, 1.5 # позиция Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°

        self.motor1 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos1, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 1
        self.motor2 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos2, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 2

        self.state_info2 = MenuApi.text(self, text='', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        self.force = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π½Π΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

        self.black_light() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Ρ‹ΠΉ свСт
        self.collisions() # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ

        # солнцС(новая ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° освСщСния)
        sun = DirectionalLight("sun")
        sun.set_color_temperature(6000)
        sun.color = sun.color * 4
        sun_path = render.attach_new_node(sun)
        sun_path.set_pos(10, -10, -10)
        sun_path.look_at(0, 0, 0)
        sun_path.hprInterval(self.sun_interval, (sun_path.get_h(), sun_path.get_p() - 360, sun_path.get_r()), bakeInStart=True).loop()
        render.set_light(sun_path)

        #GameApi.fire(self)
        #GameApi.shadows_shader(self)
        #PaintShade(render)
        

        # Если  ΠΈΠ³Ρ€ΠΎΠΊ Π·Π°Ρ…ΠΎΡ‚Π΅Π» ΠΏΠΎΠΈΠ³Ρ€Π°Ρ‚ΡŒ Π² Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΡƒΡŽ ΠΈΠ³Ρ€Ρƒ, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ это
        if self.GB :        
            GameApi.shaders(self, "./shaders/lighting.vert", "./shaders/lighting.frag") # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚!
            #render.set_shader(Shader.load(Shader.SL_GLSL, "./shaders/terrain.vert.glsl", "./shaders/terrain.frag.glsl")) 

    def collisions(self):
        pass

    def light_shader(self):
        '''Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π° горСния'''
        return Shader.make(Shader.SL_GLSL, vertex="""
            #version 120

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            attribute vec2 p3d_MultiTexCoord0;
            attribute vec4 p3d_Vertex;
            attribute vec3 p3d_Normal;

            uniform mat4 p3d_ModelViewProjectionMatrix;

            void main( void )
            {
                gl_Position    = p3d_ModelViewProjectionMatrix * p3d_Vertex;
                gl_TexCoord[0].xy = p3d_MultiTexCoord0;
                
                v_FragmentPosition  = p3d_Vertex.xyz;
                v_FragmentNormal  = p3d_Normal;
            }

            """,

            fragment="""
            #version 120

            uniform sampler2D p3d_Texture0;
            uniform vec3 pos_light;

            uniform mat4 p3d_ViewMatrixInverse;

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            const vec4  k_LightColor = vec4(1.0, 0.6, 0.3, 1.0);
            const float k_Shininess = 64.0;

            const float k_ConstAttenuation = 0.5;
            const float k_LinearAttenuation = 0.05;
            const float k_QuadricAttenuation = 0.001;

            void main( void )
            {
                vec3  L = pos_light - v_FragmentPosition;

                // ** Used in the calculation of light extinction
                float distance = length( L );

                L = normalize( L );
                vec3  N = normalize( v_FragmentNormal );

                // ** The H vector is used to calculate the gloss (specularity) of a fragment
                vec3  E = normalize( p3d_ViewMatrixInverse[3].xyz - v_FragmentPosition );
                vec3  H = normalize( L + E ); // ** Half-vector

                // ** The calculation coefficient. attenuations
                float attenuation = 1.0 / ( k_ConstAttenuation + k_LinearAttenuation * distance + k_QuadricAttenuation * distance * distance );

                float diffuse = clamp( dot( L, N ), 0.0, 1.0 );
                float specular  = pow( clamp( dot( N, H ), 0.0, 1.0 ), k_Shininess );
              
                if( diffuse <= 0.0 ){
                    specular = 0.0; 
                    }
              
                vec4 diffuseColor  = diffuse * k_LightColor * attenuation;
                vec4 specularColor = specular * k_LightColor * attenuation;
                vec4 ambientColor = vec4(0.01, 0.01, 0.01, 0.01);
                vec4 emissionColor = vec4(0.0, 0.0, 0.0, 0.0);

                gl_FragColor = ( diffuseColor + specularColor + ambientColor + emissionColor) * texture2D(p3d_Texture0, gl_TexCoord[0].xy );
            }
            """)

    def particle_start(self):
        if not self.pro_machine :
            self.force = True # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠΆΠ΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

            self.state -= 1 # сдСлаСм мСньшС ΠΎΡ‡ΠΊΠΎΠ²
            self.state_info.hide() # ΡƒΠ΄Π°Π»ΠΈΠΌ тСкстовыС ΠΎΡ‡ΠΊΠΈ
            
            if self.state != 10 and self.state > 10:
                self.state_info.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС ΠΎ Тизнях корабля
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam/steam.ptf', self.steam_pos, self.environ) 
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС
                
                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ нСисправСн', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='motor error', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

                    
            else:
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam_critic/steam.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide()  # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='критичСскоС состояниС', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='critic state', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
        
            if self.state < 10:
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)
                GameApi.make_shader(self, self.environ, self.steam_pos) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ горСния
                GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='ΠΏΠ°Π΄Π°Π΅ΠΌ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='fall!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else :
            if not self.EN :
                self.pro_info = MenuApi.text(self, text='ПРОЀИ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            else :
                self.pro_info = MenuApi.text(self, text='PRO!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            self.pro_machine_engine()

    def pro_machine_engine(self):
        '''ΠŸΡ€ΠΎΡ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½Π°Ρ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° корабля'''
        # Π’ΡƒΡ‚ Π½ΡƒΠΆΠ΅Π½ дТойстик. Если Π΅Π³ΠΎ Ρƒ вас Π½Π΅Ρ‚, ΡƒΠ²Ρ‹ Π²Ρ‹ Π½Π΅ смоТСтС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ€Π΅ΠΆΠΈΠΌ.
        self.mgr = InputDeviceManager.get_global_ptr()
        for device in self.mgr.get_devices():
            self.gamepad = device

        MenuApi.text(self, text=str(self.gamepad), pos=(-1.6, -0.9), scale=0.05, font=self.font) # Π½Π°ΠΉΠ΄Π΅Π½ΠΎΠ΅ устройство
        
        # Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ дТойстиком
        taskMgr.add(self.moveTaskDjoystic, "moveTaskDjoystic")
##            self.accept("gamepad-back", exit)
##            self.accept("gamepad-start", exit)
##            self.accept("gamepad-face_x", self.reset)
##            self.accept("gamepad-face_b", self.action, extraArgs=["face_b"])

    def reset(self):

        self.camera.setPosHpr(0, -200, 10, 0, 0, 0)
        self.environ.setPosHpr(0, -200, 9, 0, 0, 0)

    def moveTaskDjoystic(self, task):
        dt = globalClock.getDt()

        strafe_speed = 85
        vert_speed = 50
        turn_speed = 100

        lstick = self.gamepad.findButton("lstick")
        if lstick.pressed:
            strafe_speed *= 2.0

        strafe = Vec3(0)
        left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
        left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
        strafe.x = left_x.value
        strafe.y = left_y.value

        if strafe.lengthSquared() >= 0.01:
            self.camera.setPos(self.camera, strafe * strafe_speed * dt)

        trigger_l = self.gamepad.findAxis(InputDevice.Axis.left_trigger)
        trigger_r = self.gamepad.findAxis(InputDevice.Axis.right_trigger)
        lift = trigger_r.value - trigger_l.value
        self.camera.setZ(self.camera.getZ() + (lift * vert_speed * dt))

        right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
        right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

        if abs(right_x.value) >= 0.1 or abs(right_y.value) >= 0.1:
            self.camera.setH(self.camera, turn_speed * dt * -right_x.value)
            self.camera.setP(self.camera, turn_speed * dt * right_y.value)

            self.camera.setR(0)

        return task.cont

    def fountain(self):
        self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ тСкст опасности
        if self.force:
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)

        else :
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                #self.state_info = OnscreenText(text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)
        
        
    def black_light(self):
        # Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ΠΉ свСт
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((0, 0, 0, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def weapon_hide(self):
        # Π£Π±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.hide_weapon = True
        self.weapon.hide()

    def toggleLights(self, lights):
        # Π‘ΠΏΠ΅Ρ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ освСщСниС
        if self.hide_weapon:
            for light in lights:
                if render.hasLight(light):
                    render.clearLight(light)
                else:
                    render.setLight(light)
            
            self.flash.setPos(self.weapon_pos)
        else:
            return


    def shot(self):
        dt = globalClock.getDt() + 0.5 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния
        if not self.hide_weapon : # Ссли ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΡƒΠ±Ρ€Π°Π½ΠΎ Ρ‚ΠΎ ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚Ρ€Π΅Π»ΡΡ‚ΡŒ
            self.shotSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ выстрСла
            self.bullet.setPos(self.weapon_pos) # ΠŸΡƒΠ»Ρ Π±ΡƒΠ΄Π΅Ρ‚ спавнится Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΡƒΡˆΠΊΠΈ
            self.bullet.setY(self.bullet, -11 * dt) # Π‘Π΄Π²ΠΈΠ³Π°Π΅ΠΌ ΠΏΡƒΠ»ΡŽ Π½Π° ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ скорости Π²ΠΏΠ΅Ρ€Ρ‘Π΄

    def check_loss(self):
        if self.state == 0: # Ссли ΠΆΠΈΠ·Π½Π΅ΠΉ Ρƒ корабля Π½Π΅ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ
            self.black_light() # Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΉ свСт
            self.weapon_hide() # ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
            if not self.EN :
                self.info = MenuApi.text(self, text='ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            else :
                self.info = MenuApi.text(self, text='LOSS', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            self.crackSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π°


    def setKey(self, key, value):
        self.keyMap[key] = value # Π”Π΅Π»Π°Π΅ΠΌ ΠΌΠ΅Ρ…aΠ½uΠ·ΠΌ наТатия клавиш.



    def move(self, task):

        ''' Π”Π΅Π»Π°Π΅ΠΌ Ρ„ΡƒΡ†Π½ΠΊΡ†ΠΈΡŽ двиТСния ΠΈΠ³Ρ€ΠΎΠΊΠ° '''

        dt = globalClock.getDt() - .005 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния

        # ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π²Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΡ€Π°Π²ΠΎ

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -10 * dt) # МСняСм ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠΊΠ° ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎ икс. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ получаСтся илюзия ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚Π° ΡƒΠ³Π»Π° Π»ΡƒΡ‡Π°. Но Π½Π° самом Π΄Π΅Π»Π΅ ΠΊΠ°ΠΌΠ΅Ρ€Π° просто пСрСмСщаСтся.
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, + 10 * dt) # Π’ΠΎΠΆΠ΅ самоС, Ρ‡Ρ‚ΠΎ ΠΈ Π½Π°Π²Π΅Ρ€Ρ…Ρƒ.

        startpos = self.droid.getPos() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡƒΠ΄ΠΎΠ±Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if self.keyMap["left"]:
            self.droid.setH(self.droid.getH() + 145 * dt)
            self.enemy.setY(self.enemy, 1 * dt)
        if self.keyMap["right"]:
            self.droid.setH(self.droid.getH() - 145 * dt)
            self.enemy.setY(self.enemy, -1 * dt)
        if self.keyMap["forward"]:
            self.droid.setY(self.droid, -25 * dt)
            self.enemy.setX(self.enemy, 1 * dt)
            # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ условиС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΡƒΠ±Ρ€Π°Π½ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΠΈΠ»ΠΈ Π½Π΅Ρ‚
            if not self.hide_weapon:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.weapon.setPos(self.weapon_pos) # ОбновляСм ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΡƒΡˆΠΊΠΈ
            else:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.flash.setPos(self.weapon_pos)


        camvec = self.droid.getPos() - self.camera.getPos() # Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        camvec.setZ(0) # 0 высота Π²Π΅ΠΊΡ‚ΠΎΡ€Π°
        camdist = camvec.length() # дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π°
        camvec.normalize() # Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        if camdist > 10.0: # Ссли дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ большС 10, Ρ‚ΠΎ смСщаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π·Π° Π΄Ρ€ΠΎΠΎΠΈΠ΄ΠΎΠΌ
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0 # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ дистанция Π±ΡƒΠ΄Π΅Ρ‚ снова 10
        if camdist < 5.0: # Ссли дистагцтя ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ мСньшС 5, Ρ‚ΠΎ...
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) # сдвигаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ
            camdist = 5.0 # всё обновляСм
            
        self.camera.lookAt(self.floater) # Π²ΠΎΡ‚ ΠΈ пригодился наш floater


        return task.cont # Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π·Π°Π΄Π°Ρ‡Ρƒ

##    def addInstructions(self, pos, msg):
##        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=self.inst_font, pos=(-1.3, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1)) # Ѐункция ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ
##
##    def addTitle(self, text):
##        return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1), scale=0.2,
##                            parent=base.a2dBottomRight, align=TextNode.ARight,
##                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=self.font) # Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ тСкстового Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° с ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ ΠΈ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠ΅ΠΉ
##    

droid = DroidShooter() # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ экзСмпляр класса нашСй ΠΈΠ³Ρ€Ρ‹
droid.run() # 3апустим ΠΈΠ³Ρ€Ρƒ


# Ρ€Π°Π·Ρ€ΠΎΠ±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ :
# Π“Π»Π°Π²Π½Ρ‹ΠΉ Π°Π²Ρ‚ΠΎΡ€ : ma3rx
# ΠŸΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ : panda3dmastercoder( присоСдСнился ΠΊ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ 31 января, 2021 Π³ΠΎΠ΄Π°, 12:??)
# Π Π΅ΠΊΠ»Π°ΠΌΡ‰ΠΈΠΊ : rdb (написал ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС Π½Π° Ρ„ΠΎΡ€ΡƒΠΌΠ΅ 6 фСвраля 2021 Π³ΠΎΠ΄Π°, 20:11)

marconit_engine.py :

# БамописноС API к direct и panda3d

from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectButton import DirectButton
from direct.gui.DirectSlider import DirectSlider
from direct.actor.Actor import Actor
from direct.particles.Particles import Particles
from direct.particles.ParticleEffect import ParticleEffect
from panda3d.core import *



from array import array
import random


class MenuApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def slider(self, pos, scale, value, command):
        return DirectSlider(pos=pos, scale=scale, value=value,
                                    command=command)
    
    def button(self, pos, text, scale, pad, command):
        return DirectButton(pos=pos, text=text,
                                   scale=scale, pad=pad,
                                   command=command)

    def addInstruction(self, pos, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=font, pos=(-1.6, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1))
        

    def addTitle(self, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=0.2,
                            parent=base.a2dBottomRight, align=TextNode.ARight,
                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=font)

    def text(self, pos, text, font, scale):
        return OnscreenText(text=text, pos=pos, scale=scale, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=font)

    def menu_effect(self):
        NUM_EMBERS = 512 # Колво частиц
    
        floats = []
        # ΠŸΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡΡ Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΈ Π·Π°Π΄Π°Ρ‘ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для частиц
        for i in range(NUM_EMBERS):
            speed = (0.2 + random.random()) * 0.7
            size = 0.5 + random.random() * 0.5
            size = max(size ** 4, 0.1)
            floats += [random.random(), random.random(), random.random(), speed, 0, 0, 0, size]

        initial_data = array('f', floats) # Π°Ρ€Ρ€Π°Π΅ΠΌ наши Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹
        buffer = ShaderBuffer('embers', initial_data.tobytes(), GeomEnums.UH_static) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€

        format = GeomVertexFormat.get_empty()
        vdata = GeomVertexData('embers', format, GeomEnums.UH_static)

        
        tris = GeomTriangles(GeomEnums.UH_static)
        tris.add_next_vertices(NUM_EMBERS * 3)

        
        geom = Geom(vdata)
        geom.add_primitive(tris)
        geom.set_bounds(BoundingBox((0, 0, 0), (1, 1, 1)))

        node = GeomNode("node")
        node.add_geom(geom)

        embertex = loader.load_texture("./shaders/menu/ember.png")
        embertex.wrap_u = SamplerState.WM_clamp
        embertex.wrap_v = SamplerState.WM_clamp

        shader = Shader.load(Shader.SL_GLSL, "./shaders/menu/embers.vert", "./shaders/menu/embers.frag")
        path = base.render.attach_new_node(node)
        path.set_shader(shader)
        path.set_shader_input("EmberBuffer", buffer)
        path.set_texture(embertex)
        path.set_two_sided(True)
        path.set_attrib(ColorBlendAttrib.make(ColorBlendAttrib.M_add, ColorBlendAttrib.O_incoming_alpha, ColorBlendAttrib.O_one))
        path.set_depth_write(False)
        path.node().set_bounds_type(BoundingVolume.BT_box)

        node = ComputeNode("simulate")
        node.add_dispatch(NUM_EMBERS // 16, 1, 1)
        path = base.render.attach_new_node(node)
        path.set_shader(Shader.load_compute(Shader.SL_GLSL, "./shaders/menu/simulate.comp"))
        path.set_shader_input("windmap", loader.load_texture("./shaders/menu/wind.png"))
        path.set_shader_input("EmberBuffer", buffer)

        base.cam.set_x(0.5)
        base.cam.set_y(-2)
        base.cam.set_z(0.5)

class GameApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def light(self):
        sun = DirectionalLight("sun")
        sun.set_color_temperature(6000)
        sun.color = sun.color * 4
        sun_path = render.attach_new_node(sun)
        sun_path.set_pos(10, -10, -10)
        sun_path.look_at(0, 0, 0)
        sun_path.hprInterval(self.sun_interval, (sun_path.get_h(), sun_path.get_p() - 360, sun_path.get_r()), bakeInStart=True).loop()
        render.set_light(sun_path)

    def object(self, path, scale, pos):
        self.object = Actor(path)
        self.object.reparentTo(render)
        self.object.setScale(scale)
        self.object.setPos(pos)

        return self.object

    def sound(self, path, volume):
        self.sound = loader.loadMusic(path)
        self.sound.setVolume(volume)

        return self.sound

    def shaders(self, vert, frag):
        render.set_shader(Shader.load(Shader.SL_GLSL, vert, frag))

    def loadParticleConfig(self, filename, pos, object):
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(filename))

        self.p.start(object)
        self.p.setPos(pos)

    def make_shader(self, object, pos):
        '''ΠŸΡ€ΠΎ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€'''
        object.set_shader(self.light_shader())
        object.set_shader_input('pos_light', pos)

Thank all for this shader. Its really cool :slight_smile: :grin:

5.0.1 - more realistic with this shader!!!

Directory 5.0.1 :
/models :
./models/world :frowning: Now, download panda3d art from https://www.panda3d.org/download/noversion/art-gallery.zip
Go to the cat-environment folder. In it you will see a millenium falcon folder. Take all the files from it and put it in the directory ./models/world)
./models/block : block.zip (269.6 KB)
./models/enemies : enemies.zip (381.4 KB)
./models/fighter : fighter.zip (36.9 KB)
./models/player : player.zip (644.6 KB)
./models/sky : sky.zip (12.5 KB)
./models/weapon : weapon.zip (234.3 KB)
./models/whishlyflash : whishlyflash.zip

./fonts : fonts.zip (192.5 KB)
./sounds : sounds.zip (1.8 MB)
./special_effects : special_effects.zip (19.3 KB)
./tex : tex.zip (95.1 KB)
./shaders : shaders.zip (22.2 KB)

droid.py :

#!/usr/bin/env python
# -*- coding: utf_8 -*-

# Π‘ΠΎΠ·Π΄Π°Π½ΠΎ : 22 число, ΡΠ½Π²Π°Ρ€ΡŒ, 2021 Π³ΠΎΠ΄

# Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ инструмСнты
from direct.showbase.ShowBase import ShowBase
from direct.particles.ParticleEffect import ParticleEffect
from direct.gui.OnscreenImage import OnscreenImage
from direct.interval.IntervalGlobal import *
from panda3d.core import *
from marconit_engine import *
import random
import sys
import time
import os
import math


VERSION = '5.0.1'


settings = ['window-title Droid Game release ' +  VERSION,
            'fullscreen 0',
            'win-size 1440 900']
            

loadPrcFileData('', settings[0]) # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π½Π΅ стандартный Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ (Π²ΠΎΠ·ΠΌΡ‘ΠΌ Π΅Π³ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ settings)
loadPrcFileData('', settings[1]) # Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ полноэкранный Ρ€Π΅ΠΆΠΈΠΌ
loadPrcFileData('', settings[2]) # Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠ½Π°

# Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π³Π»Π°Π²Π½Ρ‹ΠΉ класс нашСй ΠΈΠ³Ρ€Ρ‹
class DroidShooter(ShowBase):
    def __init__(self):
        ShowBase.__init__(self) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ всС сСлфы ΠΈΠ· direct
        self.speed = 1800 # ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двигатСля
        self.GB = False # НЕ Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ
        self.EN = False # НС Π±ΡƒΠ΄Π΅ΠΌ Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ английский язык
        self.pro_machine = False # НС Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.sun_interval = 100 # Π˜Π½Ρ‚Π΅Ρ€Π²Π°Π» солнца
        self.menu() # звпуск мСню
        
    def menu(self):
        
        base.enableParticles() # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.disableMouse() # ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΌΡ‹ΡˆΠΊΡƒ

        self.win.setClearColor((0, 0.2, 0.2, 1)) # Π—Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΌ. Π”Π΅Π»ΠΎ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π² этом ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΌ Π΄Π²ΠΈΠΆΠΊΠ΅ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Π·Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ сСрым.
        self.font = loader.loadFont('./fonts/doom_font.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ ΠΈΠ· ΠΈΠ³Ρ€Ρ‹ doom
        self.inst_font = loader.loadFont('./fonts/arial.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ arial

        self.crackSound = GameApi.sound(self, './sounds/crack.wav', 1) # Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π° корабля
        self.shotSound = GameApi.sound(self, './sounds/shot.wav', 1) # Π·Π²ΡƒΠΊ выстрСла
        self.startSound = GameApi.sound(self, './sounds/started.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.errorSound = GameApi.sound(self, './sounds/error.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.click_sound = GameApi.sound(self, './sounds/GUI_click.wav', 1) # Π·Π²ΡƒΠΊ наТатия
        
        self.startSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ запуска ΠΈΠ³Ρ€Ρ‹

        # МСню-эффСкты

        MenuApi.menu_effect(self)

        self.button_start = MenuApi.button(self, pos=(0.7, 0, 0.4), text="CTAPT",
                                   scale=.2, pad=(.2, .2),
                                   command=self.load_game) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹

        self.gb_start = MenuApi.button(self, pos=(0.7, 0, 0.1), text="GB",
                                   scale=.2, pad=(.2, .2),
                                   command=self.gb_mode) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹  Π² Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΠ΅

        self.en = MenuApi.button(self, pos=(0.7, 0, -0.2), text='EN',
                                 scale=.2, pad=(.2, .2),
                                 command=self.en_lang)
        self.pro_button = MenuApi.button(self, pos=(0.7, 0, -0.5), text='PRO',
                                 scale=.2, pad=(.2, .2),
                                 command=self.pro_system)

        self.slider_life = MenuApi.slider(self, pos=(0.1, 0, .75), scale=0.8, value=0.5,
                                    command=self.set_lifes)


        self.title = MenuApi.addTitle(self, "Droid game Ρ€Π΅Π»ΠΈΠ· " + VERSION, self.font)
        
        # НапСчатаСм ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.inst1 = MenuApi.addInstruction(self, 0.95, u"[ESC]: Π’Ρ‹Ρ…ΠΎΠ΄", self.inst_font)
        self.inst2 = MenuApi.addInstruction(self, 0.90, u"[Left Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst3 = MenuApi.addInstruction(self, 0.85, u"[Right Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst4 = MenuApi.addInstruction(self, 0.80, u"[Up Arrow]: Π’ΠΏΠ΅Ρ€Π΅Π΄", self.inst_font)
        self.inst5 = MenuApi.addInstruction(self, 0.75, u"[a]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst6 = MenuApi.addInstruction(self, 0.70, u"[d]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst7 = MenuApi.addInstruction(self, 0.65, u"[Left Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst8 = MenuApi.addInstruction(self, 0.60, u"[Right Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst9 = MenuApi.addInstruction(self, 0.55, u"[a + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst10 = MenuApi.addInstruction(self, 0.50, u"[d + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst11 = MenuApi.addInstruction(self, 0.45, u"[space]: ΡΡ‚Ρ€Π΅Π»ΡŒΠ±Π°", self.inst_font)
        self.inst12 = MenuApi.addInstruction(self, 0.40, u"[s]: Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ", self.inst_font)
        self.inst13 = MenuApi.addInstruction(self, 0.35, u"[w]: ΡƒΠ±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅", self.inst_font)
        self.inst14 = MenuApi.addInstruction(self, 0.30, u"[f]: ΠΏΠΎΠ»Π½Ρ‹ΠΉ Ρ€Π°Π·Π³ΠΎΠ½(ОПАБНО!)", self.inst_font)
        self.inst15 = MenuApi.addInstruction(self, 0.25, u"[0]: ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ систСма", self.inst_font)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.

    def set_lifes(self):
        self.state = self.slider_life.guiItem.getValue() * 100 # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ слайдСрноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΎΠ΅ Π½Π° 100, Π΄Π° Ρ‚Ρ€Π°Ρ‡Ρƒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ Π½ΠΎ ΠΌΠ½Π΅ каТСтся ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΠ»Π΅Π²Π°Ρ‚ΡŒ Π½Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ мСню, ΠΈΠ±ΠΎ Ρ‚Π°ΠΊΠΎΠ³ΠΎ понятия просто Π½Π΅Ρ‚Ρƒ :)

    def gb_mode(self):
        '''Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.GB = True

    def en_lang(self):
        '''ИзмСнСниС языка Π½Π° английский'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.EN = True

    def pro_system(self):
        '''ΠŸΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.pro_machine = True # Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅

    def load_game(self):
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.button_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ старта
        self.gb_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ Ρ‡Ρ‘Ρ€Π½ΠΎ Π±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°.
        self.title.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΈΠ³Ρ€Ρ‹
        self.en.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π°Π½Π³ΠΎΡΠ·Ρ‹Ρ‡Π½ΡƒΡŽ ΠΊΠ½ΠΎΠΏΠΊΡƒ
        self.pro_button.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ упрвлСния
        # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΠΈ управлСния
        self.inst1.destroy()
        self.inst2.destroy()
        self.inst3.destroy()
        self.inst4.destroy()
        self.inst5.destroy()
        self.inst6.destroy()
        self.inst7.destroy()
        self.inst8.destroy()
        self.inst9.destroy()
        self.inst10.destroy()
        self.inst11.destroy()
        self.inst12.destroy()
        self.inst13.destroy()
        self.inst14.destroy()
        self.inst15.destroy()
        self.slider_life.destroy() # удаляСм слайдСр ΠΆΠΈΠ·Π½Π΅ΠΉ корабля
        
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ ΠΊΠ½ΠΎΠΏΠΎΠΊ, ΠΏΠΎ ΠΈΡ… Π½Π°ΠΆΠ°Ρ‚ΠΈΡŽ        

        # РисуСм Π·Π²Ρ‘Π·Π΄Ρ‹

        self.sky = loader.loadModel("./models/sky/solar_sky_sphere") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ модСль космоса(это сфСра)

        self.sky_tex = loader.loadTexture("./tex/stars_1k_tex.jpg") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ тСкстуру
        self.sky.setTexture(self.sky_tex, 1) # Π·Π°Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠΌ тСкстуру Π½Π° Π½Π΅Π±ΠΎ
        self.sky.reparentTo(render) # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π½Π΅Π±ΠΎ
        self.sky.setScale(40000) # Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠΌ Π½Π΅Π±ΠΎ Π΄ΠΎ максимальной Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Ρ‹ panda3d

        self.environ = loader.loadModel("models/world/falcon.egg") # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡƒΠΆΠ΅ созданный Π² blender ΠΌΠΈΡ€.
        self.environ.reparentTo(render) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΌΠΈΡ€Π° Π² ΠΎΠΊΠ½ΠΎ

        droidStartPos = (-1, 0, 1.5 ) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΡΡ‚Π°Ρ€Ρ‚ΠΎΠ²ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π² ΠΌΠΈΡ€Π΅.
        enemyStartPos = (-6, 1, 0.5) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°-Π΄Ρ€ΠΎΠΈΠ΄Π°.

        self.droid = GameApi.object(self, "models/player/seeker.egg", 1, droidStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΈΠ³Ρ€ΠΎΠΊΠ° (созданная Π² blender)
        self.enemy = GameApi.object(self, "models/enemies/r2d2/r2d2.egg", 1, enemyStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° (созданная Π² blender)

        self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 1 # ΠŸΠΎΠ·ΠΈΡ†ΠΈΡ ΠΏΡƒΡˆΠΊΠΈ
        
        self.weapon = GameApi.object(self, 'models/weapon/lightsaber.egg', .5, self.weapon_pos) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.bullet = GameApi.object(self, 'models/weapon/bullet/bullet.egg.pz', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΏΡƒΠ»ΡŽ
        self.flash = GameApi.object(self, 'models/whishlyflash/handlamp.egg', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
               
        self.bullet.reparentTo(render) # пСрСмСстим ΠΏΡƒΠ»ΡŽ Π² ΠΌΠΈΡ€ Π½ΠΎ появится ΠΎΠ½Π° сама Π½Π΅ скоро
        self.flash.reparentTo(render) # пСрСмСстим Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ Π² наш ΠΌΠΈΡ€
        self.bullet.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΏΡƒΠ»ΠΈ
        self.flash.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°

        # враТСский ΠΈΡΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΡŒ
        self.fighter = GameApi.object(self, 'models/fighter/fighter.egg', 1, (0, 90 , 0)) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»ΡŒΠΊΡƒ истрСбитСля
                

        self.cube = GameApi.object(self, 'models/block/crate.egg', .7, (0, 0, 0)) # Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π±Π»ΠΎΠΊ
        self.cube.hprInterval(1.5, (0, 360, 360)).loop()

        self.Intervalcube = self.cube.posInterval(13,
                                                   Point3(0, -500, 0),
                                                   startPos=Point3(0, 10, 0))

        self.Intervalcube.loop()
        
        self.spotlight = camera.attachNewNode(Spotlight("spotlight")) # ΠšΠΎΠ½Ρ„ΠΈΠ³ΠΈ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°
        self.spotlight.node().setColor((.3, .3, .3, 1))
        self.spotlight.node().setSpecularColor((0, 0, 0, 1))

        self.floater = NodePath(PandaNode("floater")) 
        self.floater.reparentTo(self.droid)
        self.floater.setZ(2.0)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.
        
        self.accept("arrow_left", self.setKey, ["left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ
        self.accept("arrow_right", self.setKey, ["right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ
        self.accept("arrow_up", self.setKey, ["forward", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a", self.setKey, ["cam-left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("d", self.setKey, ["cam-right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("arrow_left-up", self.setKey, ["left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_right-up", self.setKey, ["right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_up-up", self.setKey, ["forward", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π²Π΅Ρ€ΡŠ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a-up", self.setKey, ["cam-left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("d-up", self.setKey, ["cam-right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄

        self.accept("space", self.shot) # ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ±Π΅Π»Π΅ стрСляСм
        self.accept("s", self.toggleLights, [[self.spotlight]]) # Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
        self.accept("w", self.weapon_hide) # ΠΏΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ w - ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅.

        base.enableParticles() # Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π΄Ρ‹ΠΌΠ°
        self.p = ParticleEffect() # Π’ΠΊΠ»ΡŽΡ‡ΠΈΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.accept('f', self.particle_start) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f(ΠΎΡ‚ force) -  Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„Π°ΠΉΠ» Π΄Ρ‹ΠΌΠ° ΠΈ пСрСмСстим Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Π½Π½ΠΎ эта анимация стала ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π΄Ρ‹ΠΌΠ°
        self.accept('0', self.fountain) # ΠΏΡ€ΠΈ  Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΎΠΊ f+o(fountain) Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ систСму
        self.accept('f3', self.toggleWireframe) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f3 - Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠΎΠ»ΠΈΠ³ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ

        taskMgr.add(self.move, "moveTask") # ДобавляСм Π·Π°Π΄Π°Ρ‡Ρƒ Π² наш Π΄Π²ΠΈΠΆΠΎΠΊ

        self.isMoving = False # Π‘Ρ‚Π°Π²ΠΈΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ isMoving Π½Π° False(Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΌΠ΅Π½ΡΡ‚ΡŒ это Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅) Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ³Ρ€ΠΎΠΊ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ стоял.
        # Π”Π΅Π»Π°Π΅ΠΌ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ свСт Π±Ρ‹Π» ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½.
        self.camera.setPos(self.droid.getX(), self.droid.getY() + 1, 3) # Π‘Ρ‚Π°Π²ΠΈΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Ρ‡ΡƒΡ‚ΡŒ большС ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if not self.EN : # Ссли язык Π½Π΅ английский
            self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else : # Ссли янглийский язык
            self.state_info = MenuApi.text(self, text='machine :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
            
                
        self.check_loss() # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
        self.hide_weapon = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ Π½Π΅ ΡƒΠ±Ρ€Π°Π½ΠΎ
        self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)
        self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)

        self.motor_pos1 = 25.238849639892578, 8.962211608886719, 1.5 # позиция ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°
        self.motor_pos2 = -20.676218032836914, 10.55816650390625, 1.5 # позиция Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°

        self.motor1 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos1, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 1
        self.motor2 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos2, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 2

        self.state_info2 = MenuApi.text(self, text='', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        self.force = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π½Π΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

        self.black_light() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Ρ‹ΠΉ свСт
        self.collisions() # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ

        # солнцС(новая ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° освСщСния)
        GameApi.light(self)
        
        #GameApi.fire(self)
        #GameApi.shadows_shader(self)
        #PaintShade(render)
        

        # Если  ΠΈΠ³Ρ€ΠΎΠΊ Π·Π°Ρ…ΠΎΡ‚Π΅Π» ΠΏΠΎΠΈΠ³Ρ€Π°Ρ‚ΡŒ Π² Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΡƒΡŽ ΠΈΠ³Ρ€Ρƒ, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ это
        if self.GB :        
            GameApi.shaders(self, "./shaders/lighting.vert", "./shaders/lighting.frag") # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚!
            #render.set_shader(Shader.load(Shader.SL_GLSL, "./shaders/terrain.vert.glsl", "./shaders/terrain.frag.glsl")) 

    def collisions(self):
        pass

    def light_shader(self):
        '''Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π° горСния'''
        return Shader.make(Shader.SL_GLSL, vertex="""
            #version 120

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            attribute vec2 p3d_MultiTexCoord0;
            attribute vec4 p3d_Vertex;
            attribute vec3 p3d_Normal;

            uniform mat4 p3d_ModelViewProjectionMatrix;

            void main( void )
            {
                gl_Position    = p3d_ModelViewProjectionMatrix * p3d_Vertex;
                gl_TexCoord[0].xy = p3d_MultiTexCoord0;
                
                v_FragmentPosition  = p3d_Vertex.xyz;
                v_FragmentNormal  = p3d_Normal;
            }

            """,

            fragment="""
            #version 120

            uniform sampler2D p3d_Texture0;
            uniform vec3 pos_light;

            uniform mat4 p3d_ViewMatrixInverse;

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            const vec4  k_LightColor = vec4(1.0, 0.6, 0.3, 1.0);
            const float k_Shininess = 64.0;

            const float k_ConstAttenuation = 0.5;
            const float k_LinearAttenuation = 0.05;
            const float k_QuadricAttenuation = 0.001;

            void main( void )
            {
                vec3  L = pos_light - v_FragmentPosition;

                // ** Used in the calculation of light extinction
                float distance = length( L );

                L = normalize( L );
                vec3  N = normalize( v_FragmentNormal );

                // ** The H vector is used to calculate the gloss (specularity) of a fragment
                vec3  E = normalize( p3d_ViewMatrixInverse[3].xyz - v_FragmentPosition );
                vec3  H = normalize( L + E ); // ** Half-vector

                // ** The calculation coefficient. attenuations
                float attenuation = 1.0 / ( k_ConstAttenuation + k_LinearAttenuation * distance + k_QuadricAttenuation * distance * distance );

                float diffuse = clamp( dot( L, N ), 0.0, 1.0 );
                float specular  = pow( clamp( dot( N, H ), 0.0, 1.0 ), k_Shininess );
              
                if( diffuse <= 0.0 ){
                    specular = 0.0; 
                    }
              
                vec4 diffuseColor  = diffuse * k_LightColor * attenuation;
                vec4 specularColor = specular * k_LightColor * attenuation;
                vec4 ambientColor = vec4(0.01, 0.01, 0.01, 0.01);
                vec4 emissionColor = vec4(0.0, 0.0, 0.0, 0.0);

                gl_FragColor = ( diffuseColor + specularColor + ambientColor + emissionColor) * texture2D(p3d_Texture0, gl_TexCoord[0].xy );
            }
            """)

    def particle_start(self):
        if not self.pro_machine :
            self.force = True # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠΆΠ΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

            self.state -= 1 # сдСлаСм мСньшС ΠΎΡ‡ΠΊΠΎΠ²
            self.state_info.hide() # ΡƒΠ΄Π°Π»ΠΈΠΌ тСкстовыС ΠΎΡ‡ΠΊΠΈ
            
            if self.state != 10 and self.state > 10:
                self.state_info.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС ΠΎ Тизнях корабля
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam/steam.ptf', self.steam_pos, self.environ) 
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС
                
                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ нСисправСн', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='motor error', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

                    
            else:
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam_critic/steam.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide()  # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='критичСскоС состояниС', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='critic state', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
        
            if self.state < 10:
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)
                GameApi.make_shader(self, self.environ, self.steam_pos) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ горСния
                GameApi.make_shader(self, self.droid, (self.droid.getX(), self.droid.getY(), self.droid.getZ()))
                GameApi.make_shader(self, self.enemy, (self.enemy.getX(), self.enemy.getY(), self.enemy.getZ()))
                GameApi.make_shader(self, self.weapon, (self.weapon.getX(), self.weapon.getY(), self.weapon.getZ()))
                GameApi.make_shader(self, self.bullet, (self.bullet.getX(), self.bullet.getY(), self.bullet.getZ()))
                GameApi.make_shader(self, self.flash, (self.flash.getX(), self.flash.getY(), self.flash.getZ()))
                
                GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='ΠΏΠ°Π΄Π°Π΅ΠΌ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='fall!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else :
            if not self.EN :
                self.pro_info = MenuApi.text(self, text='ПРОЀИ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            else :
                self.pro_info = MenuApi.text(self, text='PRO!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            self.pro_machine_engine()

    def pro_machine_engine(self):
        '''ΠŸΡ€ΠΎΡ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½Π°Ρ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° корабля'''
        # Π’ΡƒΡ‚ Π½ΡƒΠΆΠ΅Π½ дТойстик. Если Π΅Π³ΠΎ Ρƒ вас Π½Π΅Ρ‚, ΡƒΠ²Ρ‹ Π²Ρ‹ Π½Π΅ смоТСтС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ€Π΅ΠΆΠΈΠΌ.
        self.mgr = InputDeviceManager.get_global_ptr()
        for device in self.mgr.get_devices():
            self.gamepad = device

        MenuApi.text(self, text=str(self.gamepad), pos=(-1.6, -0.9), scale=0.05, font=self.font) # Π½Π°ΠΉΠ΄Π΅Π½ΠΎΠ΅ устройство
        
        # Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ дТойстиком
        taskMgr.add(self.moveTaskDjoystic, "moveTaskDjoystic")
##            self.accept("gamepad-back", exit)
##            self.accept("gamepad-start", exit)
##            self.accept("gamepad-face_x", self.reset)
##            self.accept("gamepad-face_b", self.action, extraArgs=["face_b"])

    def reset(self):

        self.camera.setPosHpr(0, -200, 10, 0, 0, 0)
        self.environ.setPosHpr(0, -200, 9, 0, 0, 0)

    def moveTaskDjoystic(self, task):
        dt = globalClock.getDt()

        strafe_speed = 85
        vert_speed = 50
        turn_speed = 100

        lstick = self.gamepad.findButton("lstick")
        if lstick.pressed:
            strafe_speed *= 2.0

        strafe = Vec3(0)
        left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
        left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
        strafe.x = left_x.value
        strafe.y = left_y.value

        if strafe.lengthSquared() >= 0.01:
            self.camera.setPos(self.camera, strafe * strafe_speed * dt)

        trigger_l = self.gamepad.findAxis(InputDevice.Axis.left_trigger)
        trigger_r = self.gamepad.findAxis(InputDevice.Axis.right_trigger)
        lift = trigger_r.value - trigger_l.value
        self.camera.setZ(self.camera.getZ() + (lift * vert_speed * dt))

        right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
        right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

        if abs(right_x.value) >= 0.1 or abs(right_y.value) >= 0.1:
            self.camera.setH(self.camera, turn_speed * dt * -right_x.value)
            self.camera.setP(self.camera, turn_speed * dt * right_y.value)

            self.camera.setR(0)

        return task.cont

    def fountain(self):
        self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ тСкст опасности
        if self.force:
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)

        else :
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                #self.state_info = OnscreenText(text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)
        
        
    def black_light(self):
        # Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ΠΉ свСт
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((0, 0, 0, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def weapon_hide(self):
        # Π£Π±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.hide_weapon = True
        self.weapon.hide()

    def toggleLights(self, lights):
        # Π‘ΠΏΠ΅Ρ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ освСщСниС
        if self.hide_weapon:
            for light in lights:
                if render.hasLight(light):
                    render.clearLight(light)
                else:
                    render.setLight(light)
            
            self.flash.setPos(self.weapon_pos)
        else:
            return


    def shot(self):
        dt = globalClock.getDt() + 0.5 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния
        if not self.hide_weapon : # Ссли ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΡƒΠ±Ρ€Π°Π½ΠΎ Ρ‚ΠΎ ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚Ρ€Π΅Π»ΡΡ‚ΡŒ
            self.shotSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ выстрСла
            self.bullet.setPos(self.weapon_pos) # ΠŸΡƒΠ»Ρ Π±ΡƒΠ΄Π΅Ρ‚ спавнится Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΡƒΡˆΠΊΠΈ
            self.bullet.setY(self.bullet, -11 * dt) # Π‘Π΄Π²ΠΈΠ³Π°Π΅ΠΌ ΠΏΡƒΠ»ΡŽ Π½Π° ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ скорости Π²ΠΏΠ΅Ρ€Ρ‘Π΄

    def check_loss(self):
        if self.state == 0: # Ссли ΠΆΠΈΠ·Π½Π΅ΠΉ Ρƒ корабля Π½Π΅ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ
            self.black_light() # Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΉ свСт
            self.weapon_hide() # ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
            if not self.EN :
                self.info = MenuApi.text(self, text='ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            else :
                self.info = MenuApi.text(self, text='LOSS', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            self.crackSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π°


    def setKey(self, key, value):
        self.keyMap[key] = value # Π”Π΅Π»Π°Π΅ΠΌ ΠΌΠ΅Ρ…aΠ½uΠ·ΠΌ наТатия клавиш.



    def move(self, task):

        ''' Π”Π΅Π»Π°Π΅ΠΌ Ρ„ΡƒΡ†Π½ΠΊΡ†ΠΈΡŽ двиТСния ΠΈΠ³Ρ€ΠΎΠΊΠ° '''

        dt = globalClock.getDt() - .005 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния

        # ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π²Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΡ€Π°Π²ΠΎ

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -10 * dt) # МСняСм ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠΊΠ° ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎ икс. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ получаСтся илюзия ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚Π° ΡƒΠ³Π»Π° Π»ΡƒΡ‡Π°. Но Π½Π° самом Π΄Π΅Π»Π΅ ΠΊΠ°ΠΌΠ΅Ρ€Π° просто пСрСмСщаСтся.
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, + 10 * dt) # Π’ΠΎΠΆΠ΅ самоС, Ρ‡Ρ‚ΠΎ ΠΈ Π½Π°Π²Π΅Ρ€Ρ…Ρƒ.

        startpos = self.droid.getPos() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡƒΠ΄ΠΎΠ±Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if self.keyMap["left"]:
            self.droid.setH(self.droid.getH() + 145 * dt)
            self.enemy.setY(self.enemy, 1 * dt)
        if self.keyMap["right"]:
            self.droid.setH(self.droid.getH() - 145 * dt)
            self.enemy.setY(self.enemy, -1 * dt)
        if self.keyMap["forward"]:
            self.droid.setY(self.droid, -25 * dt)
            self.enemy.setX(self.enemy, 1 * dt)
            # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ условиС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΡƒΠ±Ρ€Π°Π½ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΠΈΠ»ΠΈ Π½Π΅Ρ‚
            if not self.hide_weapon:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.weapon.setPos(self.weapon_pos) # ОбновляСм ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΡƒΡˆΠΊΠΈ
            else:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.flash.setPos(self.weapon_pos)


        camvec = self.droid.getPos() - self.camera.getPos() # Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        camvec.setZ(0) # 0 высота Π²Π΅ΠΊΡ‚ΠΎΡ€Π°
        camdist = camvec.length() # дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π°
        camvec.normalize() # Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        if camdist > 10.0: # Ссли дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ большС 10, Ρ‚ΠΎ смСщаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π·Π° Π΄Ρ€ΠΎΠΎΠΈΠ΄ΠΎΠΌ
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0 # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ дистанция Π±ΡƒΠ΄Π΅Ρ‚ снова 10
        if camdist < 5.0: # Ссли дистагцтя ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ мСньшС 5, Ρ‚ΠΎ...
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) # сдвигаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ
            camdist = 5.0 # всё обновляСм
            
        self.camera.lookAt(self.floater) # Π²ΠΎΡ‚ ΠΈ пригодился наш floater


        return task.cont # Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π·Π°Π΄Π°Ρ‡Ρƒ

##    def addInstructions(self, pos, msg):
##        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=self.inst_font, pos=(-1.3, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1)) # Ѐункция ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ
##
##    def addTitle(self, text):
##        return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1), scale=0.2,
##                            parent=base.a2dBottomRight, align=TextNode.ARight,
##                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=self.font) # Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ тСкстового Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° с ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ ΠΈ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠ΅ΠΉ
##    

droid = DroidShooter() # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ экзСмпляр класса нашСй ΠΈΠ³Ρ€Ρ‹
droid.run() # 3апустим ΠΈΠ³Ρ€Ρƒ


# Ρ€Π°Π·Ρ€ΠΎΠ±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ :
# Π“Π»Π°Π²Π½Ρ‹ΠΉ Π°Π²Ρ‚ΠΎΡ€ : ma3rx
# ΠŸΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ : panda3dmastercoder( присоСдСнился ΠΊ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ 31 января, 2021 Π³ΠΎΠ΄Π°, 12:??)
# Π Π΅ΠΊΠ»Π°ΠΌΡ‰ΠΈΠΊ : rdb (написал ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС Π½Π° Ρ„ΠΎΡ€ΡƒΠΌΠ΅ 6 фСвраля 2021 Π³ΠΎΠ΄Π°, 20:11)

marconit_engine.py :

# БамописноС API к direct и panda3d

from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectButton import DirectButton
from direct.gui.DirectSlider import DirectSlider
from direct.actor.Actor import Actor
from direct.particles.Particles import Particles
from direct.particles.ParticleEffect import ParticleEffect
from panda3d.core import *

from array import array
import random


class MenuApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def slider(self, pos, scale, value, command):
        return DirectSlider(pos=pos, scale=scale, value=value,
                                    command=command)
    
    def button(self, pos, text, scale, pad, command):
        return DirectButton(pos=pos, text=text,
                                   scale=scale, pad=pad,
                                   command=command)

    def addInstruction(self, pos, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=font, pos=(-1.6, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1))
        

    def addTitle(self, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=0.2,
                            parent=base.a2dBottomRight, align=TextNode.ARight,
                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=font)

    def text(self, pos, text, font, scale):
        return OnscreenText(text=text, pos=pos, scale=scale, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=font)

    def menu_effect(self):
        NUM_EMBERS = 512 # Колво частиц
    
        floats = []
        # ΠŸΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡΡ Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΈ Π·Π°Π΄Π°Ρ‘ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для частиц
        for i in range(NUM_EMBERS):
            speed = (0.2 + random.random()) * 0.7
            size = 0.5 + random.random() * 0.5
            size = max(size ** 4, 0.1)
            floats += [random.random(), random.random(), random.random(), speed, 0, 0, 0, size]

        initial_data = array('f', floats) # Π°Ρ€Ρ€Π°Π΅ΠΌ наши Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹
        buffer = ShaderBuffer('embers', initial_data.tobytes(), GeomEnums.UH_static) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€

        format = GeomVertexFormat.get_empty()
        vdata = GeomVertexData('embers', format, GeomEnums.UH_static)

        
        tris = GeomTriangles(GeomEnums.UH_static)
        tris.add_next_vertices(NUM_EMBERS * 3)

        
        geom = Geom(vdata)
        geom.add_primitive(tris)
        geom.set_bounds(BoundingBox((0, 0, 0), (1, 1, 1)))

        node = GeomNode("node")
        node.add_geom(geom)

        embertex = loader.load_texture("./shaders/menu/ember.png")
        embertex.wrap_u = SamplerState.WM_clamp
        embertex.wrap_v = SamplerState.WM_clamp

        shader = Shader.load(Shader.SL_GLSL, "./shaders/menu/embers.vert", "./shaders/menu/embers.frag")
        path = base.render.attach_new_node(node)
        path.set_shader(shader)
        path.set_shader_input("EmberBuffer", buffer)
        path.set_texture(embertex)
        path.set_two_sided(True)
        path.set_attrib(ColorBlendAttrib.make(ColorBlendAttrib.M_add, ColorBlendAttrib.O_incoming_alpha, ColorBlendAttrib.O_one))
        path.set_depth_write(False)
        path.node().set_bounds_type(BoundingVolume.BT_box)

        node = ComputeNode("simulate")
        node.add_dispatch(NUM_EMBERS // 16, 1, 1)
        path = base.render.attach_new_node(node)
        path.set_shader(Shader.load_compute(Shader.SL_GLSL, "./shaders/menu/simulate.comp"))
        path.set_shader_input("windmap", loader.load_texture("./shaders/menu/wind.png"))
        path.set_shader_input("EmberBuffer", buffer)

        base.cam.set_x(0.5)
        base.cam.set_y(-2)
        base.cam.set_z(0.5)

class GameApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def light(self):
        sun = DirectionalLight("sun")
        sun.set_color_temperature(6000)
        sun.color = sun.color * 4
        sun_path = render.attach_new_node(sun)
        sun_path.set_pos(10, -10, -10)
        sun_path.look_at(0, 0, 0)
        sun_path.hprInterval(self.sun_interval, (sun_path.get_h(), sun_path.get_p() - 360, sun_path.get_r()), bakeInStart=True).loop()
        render.set_light(sun_path)

    def object(self, path, scale, pos):
        self.object = Actor(path)
        self.object.reparentTo(render)
        self.object.setScale(scale)
        self.object.setPos(pos)

        return self.object

    def sound(self, path, volume):
        self.sound = loader.loadMusic(path)
        self.sound.setVolume(volume)

        return self.sound

    def shaders(self, vert, frag):
        render.set_shader(Shader.load(Shader.SL_GLSL, vert, frag))

    def loadParticleConfig(self, filename, pos, object):
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(filename))

        self.p.start(object)
        self.p.setPos(pos)

    def make_shader(self, object, pos):
        '''ΠŸΡ€ΠΎ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€'''
        object.set_shader(self.light_shader())
        object.set_shader_input('pos_light', pos)

5.0.2 update! MORE REALISTIC!
Directory 5.0.2 :
/models :
./models/world :frowning: Now, download panda3d art from https://www.panda3d.org/download/noversion/art-gallery.zip
Go to the cat-environment folder. In it you will see a millenium falcon folder. Take all the files from it and put it in the directory ./models/world)
./models/block : block.zip (269.6 KB)
./models/enemies : enemies.zip (381.4 KB)
./models/fighter : fighter.zip (36.9 KB)
./models/player : player.zip (644.6 KB)
./models/sky : sky.zip (12.5 KB)
./models/weapon : weapon.zip (234.3 KB)
./models/whishlyflash : whishlyflash.zip

./fonts : fonts.zip (192.5 KB)
./sounds : sounds.zip (1.8 MB)
./special_effects : special_effects.zip (19.3 KB)
./tex : tex.zip (95.1 KB)
./shaders : shaders.zip (22.2 KB)

droid.py :

#!/usr/bin/env python
# -*- coding: utf_8 -*-

# Π‘ΠΎΠ·Π΄Π°Π½ΠΎ : 22 число, ΡΠ½Π²Π°Ρ€ΡŒ, 2021 Π³ΠΎΠ΄

# Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ инструмСнты
from direct.showbase.ShowBase import ShowBase
from direct.particles.ParticleEffect import ParticleEffect
from direct.gui.OnscreenImage import OnscreenImage
from direct.interval.IntervalGlobal import *
from panda3d.core import *
from marconit_engine import *
import random
import sys
import time
import os
import math


VERSION = '5.0.2'


settings = ['window-title Droid Game release ' +  VERSION,
            'fullscreen 0',
            'win-size 1440 900']
            

loadPrcFileData('', settings[0]) # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π½Π΅ стандартный Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ (Π²ΠΎΠ·ΠΌΡ‘ΠΌ Π΅Π³ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ settings)
loadPrcFileData('', settings[1]) # Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ полноэкранный Ρ€Π΅ΠΆΠΈΠΌ
loadPrcFileData('', settings[2]) # Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠ½Π°

# Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π³Π»Π°Π²Π½Ρ‹ΠΉ класс нашСй ΠΈΠ³Ρ€Ρ‹
class DroidShooter(ShowBase):
    def __init__(self):
        ShowBase.__init__(self) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ всС сСлфы ΠΈΠ· direct
        self.speed = 1800 # ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двигатСля
        self.GB = False # НЕ Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ
        self.EN = False # НС Π±ΡƒΠ΄Π΅ΠΌ Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ английский язык
        self.pro_machine = False # НС Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.sun_interval = 100 # Π˜Π½Ρ‚Π΅Ρ€Π²Π°Π» солнца
        self.menu() # звпуск мСню
        
    def menu(self):
        
        base.enableParticles() # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.disableMouse() # ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΌΡ‹ΡˆΠΊΡƒ

        self.win.setClearColor((0, 0.2, 0.2, 1)) # Π—Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΌ. Π”Π΅Π»ΠΎ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π² этом ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΌ Π΄Π²ΠΈΠΆΠΊΠ΅ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Π·Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ сСрым.
        self.font = loader.loadFont('./fonts/doom_font.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ ΠΈΠ· ΠΈΠ³Ρ€Ρ‹ doom
        self.inst_font = loader.loadFont('./fonts/arial.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ arial

        self.crackSound = GameApi.sound(self, './sounds/crack.wav', 1) # Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π° корабля
        self.shotSound = GameApi.sound(self, './sounds/shot.wav', 1) # Π·Π²ΡƒΠΊ выстрСла
        self.startSound = GameApi.sound(self, './sounds/started.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.errorSound = GameApi.sound(self, './sounds/error.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.click_sound = GameApi.sound(self, './sounds/GUI_click.wav', 1) # Π·Π²ΡƒΠΊ наТатия
        
        self.startSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ запуска ΠΈΠ³Ρ€Ρ‹

        # МСню-эффСкты

        MenuApi.menu_effect(self)

        self.button_start = MenuApi.button(self, pos=(0.7, 0, 0.4), text="CTAPT",
                                   scale=.2, pad=(.2, .2),
                                   command=self.load_game) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹

        self.gb_start = MenuApi.button(self, pos=(0.7, 0, 0.1), text="GB",
                                   scale=.2, pad=(.2, .2),
                                   command=self.gb_mode) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹  Π² Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΠ΅

        self.en = MenuApi.button(self, pos=(0.7, 0, -0.2), text='EN',
                                 scale=.2, pad=(.2, .2),
                                 command=self.en_lang)
        self.pro_button = MenuApi.button(self, pos=(0.7, 0, -0.5), text='PRO',
                                 scale=.2, pad=(.2, .2),
                                 command=self.pro_system)

        self.slider_life = MenuApi.slider(self, pos=(0.1, 0, .75), scale=0.8, value=0.5,
                                    command=self.set_lifes)


        self.title = MenuApi.addTitle(self, "Droid game Ρ€Π΅Π»ΠΈΠ· " + VERSION, self.font)
        
        # НапСчатаСм ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.inst1 = MenuApi.addInstruction(self, 0.95, u"[ESC]: Π’Ρ‹Ρ…ΠΎΠ΄", self.inst_font)
        self.inst2 = MenuApi.addInstruction(self, 0.90, u"[Left Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst3 = MenuApi.addInstruction(self, 0.85, u"[Right Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst4 = MenuApi.addInstruction(self, 0.80, u"[Up Arrow]: Π’ΠΏΠ΅Ρ€Π΅Π΄", self.inst_font)
        self.inst5 = MenuApi.addInstruction(self, 0.75, u"[a]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst6 = MenuApi.addInstruction(self, 0.70, u"[d]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst7 = MenuApi.addInstruction(self, 0.65, u"[Left Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst8 = MenuApi.addInstruction(self, 0.60, u"[Right Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst9 = MenuApi.addInstruction(self, 0.55, u"[a + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst10 = MenuApi.addInstruction(self, 0.50, u"[d + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst11 = MenuApi.addInstruction(self, 0.45, u"[space]: ΡΡ‚Ρ€Π΅Π»ΡŒΠ±Π°", self.inst_font)
        self.inst12 = MenuApi.addInstruction(self, 0.40, u"[s]: Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ", self.inst_font)
        self.inst13 = MenuApi.addInstruction(self, 0.35, u"[w]: ΡƒΠ±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅", self.inst_font)
        self.inst14 = MenuApi.addInstruction(self, 0.30, u"[f]: ΠΏΠΎΠ»Π½Ρ‹ΠΉ Ρ€Π°Π·Π³ΠΎΠ½(ОПАБНО!)", self.inst_font)
        self.inst15 = MenuApi.addInstruction(self, 0.25, u"[0]: ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ систСма", self.inst_font)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.

    def set_lifes(self):
        self.state = self.slider_life.guiItem.getValue() * 100 # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ слайдСрноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΎΠ΅ Π½Π° 100, Π΄Π° Ρ‚Ρ€Π°Ρ‡Ρƒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ Π½ΠΎ ΠΌΠ½Π΅ каТСтся ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΠ»Π΅Π²Π°Ρ‚ΡŒ Π½Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ мСню, ΠΈΠ±ΠΎ Ρ‚Π°ΠΊΠΎΠ³ΠΎ понятия просто Π½Π΅Ρ‚Ρƒ :)

    def gb_mode(self):
        '''Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.GB = True

    def en_lang(self):
        '''ИзмСнСниС языка Π½Π° английский'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.EN = True

    def pro_system(self):
        '''ΠŸΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.pro_machine = True # Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅

    def load_game(self):
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.button_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ старта
        self.gb_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ Ρ‡Ρ‘Ρ€Π½ΠΎ Π±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°.
        self.title.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΈΠ³Ρ€Ρ‹
        self.en.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π°Π½Π³ΠΎΡΠ·Ρ‹Ρ‡Π½ΡƒΡŽ ΠΊΠ½ΠΎΠΏΠΊΡƒ
        self.pro_button.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ упрвлСния
        # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΠΈ управлСния
        self.inst1.destroy()
        self.inst2.destroy()
        self.inst3.destroy()
        self.inst4.destroy()
        self.inst5.destroy()
        self.inst6.destroy()
        self.inst7.destroy()
        self.inst8.destroy()
        self.inst9.destroy()
        self.inst10.destroy()
        self.inst11.destroy()
        self.inst12.destroy()
        self.inst13.destroy()
        self.inst14.destroy()
        self.inst15.destroy()
        self.slider_life.destroy() # удаляСм слайдСр ΠΆΠΈΠ·Π½Π΅ΠΉ корабля
        
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ ΠΊΠ½ΠΎΠΏΠΎΠΊ, ΠΏΠΎ ΠΈΡ… Π½Π°ΠΆΠ°Ρ‚ΠΈΡŽ        

        # РисуСм Π·Π²Ρ‘Π·Π΄Ρ‹

        self.sky = loader.loadModel("./models/sky/solar_sky_sphere") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ модСль космоса(это сфСра)

        self.sky_tex = loader.loadTexture("./tex/stars_1k_tex.jpg") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ тСкстуру
        self.sky.setTexture(self.sky_tex, 1) # Π·Π°Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠΌ тСкстуру Π½Π° Π½Π΅Π±ΠΎ
        self.sky.reparentTo(render) # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π½Π΅Π±ΠΎ
        self.sky.setScale(40000) # Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠΌ Π½Π΅Π±ΠΎ Π΄ΠΎ максимальной Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Ρ‹ panda3d

        self.environ = loader.loadModel("models/world/falcon.egg") # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡƒΠΆΠ΅ созданный Π² blender ΠΌΠΈΡ€.
        self.environ.reparentTo(render) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΌΠΈΡ€Π° Π² ΠΎΠΊΠ½ΠΎ

        droidStartPos = (-1, 0, 1.5 ) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΡΡ‚Π°Ρ€Ρ‚ΠΎΠ²ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π² ΠΌΠΈΡ€Π΅.
        enemyStartPos = (-6, 1, 0.5) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°-Π΄Ρ€ΠΎΠΈΠ΄Π°.

        self.droid = GameApi.object(self, "models/player/seeker.egg", 1, droidStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΈΠ³Ρ€ΠΎΠΊΠ° (созданная Π² blender)
        self.enemy = GameApi.object(self, "models/enemies/r2d2/r2d2.egg", 1, enemyStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° (созданная Π² blender)

        self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 1 # ΠŸΠΎΠ·ΠΈΡ†ΠΈΡ ΠΏΡƒΡˆΠΊΠΈ
        
        self.weapon = GameApi.object(self, 'models/weapon/lightsaber.egg', .5, self.weapon_pos) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.bullet = GameApi.object(self, 'models/weapon/bullet/bullet.egg.pz', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΏΡƒΠ»ΡŽ
        self.flash = GameApi.object(self, 'models/whishlyflash/handlamp.egg', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
               
        self.bullet.reparentTo(render) # пСрСмСстим ΠΏΡƒΠ»ΡŽ Π² ΠΌΠΈΡ€ Π½ΠΎ появится ΠΎΠ½Π° сама Π½Π΅ скоро
        self.flash.reparentTo(render) # пСрСмСстим Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ Π² наш ΠΌΠΈΡ€
        self.bullet.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΏΡƒΠ»ΠΈ
        self.flash.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°

        # враТСский ΠΈΡΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΡŒ
        self.fighter = GameApi.object(self, 'models/fighter/fighter.egg', 1, (0, 90 , 0)) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»ΡŒΠΊΡƒ истрСбитСля
                

        self.cube = GameApi.object(self, 'models/block/crate.egg', .7, (0, 0, 0)) # Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π±Π»ΠΎΠΊ
        self.cube.hprInterval(1.5, (0, 360, 360)).loop()

        self.Intervalcube = self.cube.posInterval(13,
                                                   Point3(0, -500, 0),
                                                   startPos=Point3(0, 10, 0))

        self.Intervalcube.loop()
        
        self.spotlight = camera.attachNewNode(Spotlight("spotlight")) # ΠšΠΎΠ½Ρ„ΠΈΠ³ΠΈ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°
        self.spotlight.node().setColor((.3, .3, .3, 1))
        self.spotlight.node().setSpecularColor((0, 0, 0, 1))

        self.floater = NodePath(PandaNode("floater")) 
        self.floater.reparentTo(self.droid)
        self.floater.setZ(2.0)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.
        
        self.accept("arrow_left", self.setKey, ["left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ
        self.accept("arrow_right", self.setKey, ["right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ
        self.accept("arrow_up", self.setKey, ["forward", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a", self.setKey, ["cam-left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("d", self.setKey, ["cam-right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("arrow_left-up", self.setKey, ["left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_right-up", self.setKey, ["right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_up-up", self.setKey, ["forward", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π²Π΅Ρ€ΡŠ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a-up", self.setKey, ["cam-left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("d-up", self.setKey, ["cam-right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄

        self.accept("space", self.shot) # ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ±Π΅Π»Π΅ стрСляСм
        self.accept("s", self.toggleLights, [[self.spotlight]]) # Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
        self.accept("w", self.weapon_hide) # ΠΏΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ w - ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅.

        base.enableParticles() # Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π΄Ρ‹ΠΌΠ°
        self.p = ParticleEffect() # Π’ΠΊΠ»ΡŽΡ‡ΠΈΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.accept('f', self.particle_start) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f(ΠΎΡ‚ force) -  Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„Π°ΠΉΠ» Π΄Ρ‹ΠΌΠ° ΠΈ пСрСмСстим Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Π½Π½ΠΎ эта анимация стала ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π΄Ρ‹ΠΌΠ°
        self.accept('0', self.fountain) # ΠΏΡ€ΠΈ  Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΎΠΊ f+o(fountain) Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ систСму
        self.accept('f3', self.toggleWireframe) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f3 - Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠΎΠ»ΠΈΠ³ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ

        taskMgr.add(self.move, "moveTask") # ДобавляСм Π·Π°Π΄Π°Ρ‡Ρƒ Π² наш Π΄Π²ΠΈΠΆΠΎΠΊ

        self.isMoving = False # Π‘Ρ‚Π°Π²ΠΈΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ isMoving Π½Π° False(Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΌΠ΅Π½ΡΡ‚ΡŒ это Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅) Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ³Ρ€ΠΎΠΊ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ стоял.
        # Π”Π΅Π»Π°Π΅ΠΌ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ свСт Π±Ρ‹Π» ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½.
        self.camera.setPos(self.droid.getX(), self.droid.getY() + 1, 3) # Π‘Ρ‚Π°Π²ΠΈΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Ρ‡ΡƒΡ‚ΡŒ большС ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if not self.EN : # Ссли язык Π½Π΅ английский
            self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else : # Ссли янглийский язык
            self.state_info = MenuApi.text(self, text='machine :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
            
                
        self.check_loss() # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
        self.hide_weapon = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ Π½Π΅ ΡƒΠ±Ρ€Π°Π½ΠΎ
        self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)
        self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)

        self.motor_pos1 = 25.238849639892578, 8.962211608886719, 1.5 # позиция ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°
        self.motor_pos2 = -20.676218032836914, 10.55816650390625, 1.5 # позиция Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°

        self.motor1 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos1, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 1
        self.motor2 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos2, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 2

        self.state_info2 = MenuApi.text(self, text='', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        self.force = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π½Π΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

        self.black_light() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Ρ‹ΠΉ свСт
        self.collisions() # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ

        # солнцС(новая ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° освСщСния)
        GameApi.light(self)
        
        #GameApi.fire(self)
        #GameApi.shadows_shader(self)
        #PaintShade(render)

        self.objects = [self.environ, self.droid,
                        self.enemy, self.weapon,
                        self.bullet, self.flash,
                        self.cube, self.fighter]
        

        # Если  ΠΈΠ³Ρ€ΠΎΠΊ Π·Π°Ρ…ΠΎΡ‚Π΅Π» ΠΏΠΎΠΈΠ³Ρ€Π°Ρ‚ΡŒ Π² Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΡƒΡŽ ΠΈΠ³Ρ€Ρƒ, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ это
        if self.GB :        
            GameApi.shaders(self, "./shaders/lighting.vert", "./shaders/lighting.frag") # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚!
            #render.set_shader(Shader.load(Shader.SL_GLSL, "./shaders/terrain.vert.glsl", "./shaders/terrain.frag.glsl")) 

    def collisions(self):
        pass

    def light_shader(self):
        '''Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π° горСния'''
        return Shader.make(Shader.SL_GLSL, vertex="""
            #version 120

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            attribute vec2 p3d_MultiTexCoord0;
            attribute vec4 p3d_Vertex;
            attribute vec3 p3d_Normal;

            uniform mat4 p3d_ModelViewProjectionMatrix;

            void main( void )
            {
                gl_Position    = p3d_ModelViewProjectionMatrix * p3d_Vertex;
                gl_TexCoord[0].xy = p3d_MultiTexCoord0;
                
                v_FragmentPosition  = p3d_Vertex.xyz;
                v_FragmentNormal  = p3d_Normal;
            }

            """,

            fragment="""
            #version 120

            uniform sampler2D p3d_Texture0;
            uniform vec3 pos_light;

            uniform mat4 p3d_ViewMatrixInverse;

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            const vec4  k_LightColor = vec4(1.0, 0.6, 0.3, 1.0);
            const float k_Shininess = 64.0;

            const float k_ConstAttenuation = 0.5;
            const float k_LinearAttenuation = 0.05;
            const float k_QuadricAttenuation = 0.001;

            void main( void )
            {
                vec3  L = pos_light - v_FragmentPosition;

                // ** Used in the calculation of light extinction
                float distance = length( L );

                L = normalize( L );
                vec3  N = normalize( v_FragmentNormal );

                // ** The H vector is used to calculate the gloss (specularity) of a fragment
                vec3  E = normalize( p3d_ViewMatrixInverse[3].xyz - v_FragmentPosition );
                vec3  H = normalize( L + E ); // ** Half-vector

                // ** The calculation coefficient. attenuations
                float attenuation = 1.0 / ( k_ConstAttenuation + k_LinearAttenuation * distance + k_QuadricAttenuation * distance * distance );

                float diffuse = clamp( dot( L, N ), 0.0, 1.0 );
                float specular  = pow( clamp( dot( N, H ), 0.0, 1.0 ), k_Shininess );
              
                if( diffuse <= 0.0 ){
                    specular = 0.0; 
                    }
              
                vec4 diffuseColor  = diffuse * k_LightColor * attenuation;
                vec4 specularColor = specular * k_LightColor * attenuation;
                vec4 ambientColor = vec4(0.01, 0.01, 0.01, 0.01);
                vec4 emissionColor = vec4(0.0, 0.0, 0.0, 0.0);

                gl_FragColor = ( diffuseColor + specularColor + ambientColor + emissionColor) * texture2D(p3d_Texture0, gl_TexCoord[0].xy );
            }
            """)

    def particle_start(self):
        if not self.pro_machine :
            self.force = True # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠΆΠ΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

            self.state -= 1 # сдСлаСм мСньшС ΠΎΡ‡ΠΊΠΎΠ²
            self.state_info.hide() # ΡƒΠ΄Π°Π»ΠΈΠΌ тСкстовыС ΠΎΡ‡ΠΊΠΈ
            
            if self.state != 10 and self.state > 10:
                self.state_info.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС ΠΎ Тизнях корабля
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam/steam.ptf', self.steam_pos, self.environ) 
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС
                
                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ нСисправСн', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='motor error', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

                    
            else:
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam_critic/steam.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide()  # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='критичСскоС состояниС', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='critic state', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
        
            if self.state < 10:
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)

                for i in range(len(self.objects)):

                    self.object = self.objects[i]
                    GameApi.make_shader(self, self.object, (self.object.getX(), self.object.getY(), self.object.getZ())) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ горСния

                GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='ΠΏΠ°Π΄Π°Π΅ΠΌ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='fall!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else :
            if not self.EN :
                self.pro_info = MenuApi.text(self, text='ПРОЀИ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            else :
                self.pro_info = MenuApi.text(self, text='PRO!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            self.pro_machine_engine()

    def pro_machine_engine(self):
        '''ΠŸΡ€ΠΎΡ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½Π°Ρ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° корабля'''
        # Π’ΡƒΡ‚ Π½ΡƒΠΆΠ΅Π½ дТойстик. Если Π΅Π³ΠΎ Ρƒ вас Π½Π΅Ρ‚, ΡƒΠ²Ρ‹ Π²Ρ‹ Π½Π΅ смоТСтС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ€Π΅ΠΆΠΈΠΌ.
        self.mgr = InputDeviceManager.get_global_ptr()
        for device in self.mgr.get_devices():
            self.gamepad = device

        MenuApi.text(self, text=str(self.gamepad), pos=(-1.6, -0.9), scale=0.05, font=self.font) # Π½Π°ΠΉΠ΄Π΅Π½ΠΎΠ΅ устройство
        
        # Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ дТойстиком
        taskMgr.add(self.moveTaskDjoystic, "moveTaskDjoystic")
##            self.accept("gamepad-back", exit)
##            self.accept("gamepad-start", exit)
##            self.accept("gamepad-face_x", self.reset)
##            self.accept("gamepad-face_b", self.action, extraArgs=["face_b"])

    def reset(self):

        self.camera.setPosHpr(0, -200, 10, 0, 0, 0)
        self.environ.setPosHpr(0, -200, 9, 0, 0, 0)

    def moveTaskDjoystic(self, task):
        dt = globalClock.getDt()

        strafe_speed = 85
        vert_speed = 50
        turn_speed = 100

        lstick = self.gamepad.findButton("lstick")
        if lstick.pressed:
            strafe_speed *= 2.0

        strafe = Vec3(0)
        left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
        left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
        strafe.x = left_x.value
        strafe.y = left_y.value

        if strafe.lengthSquared() >= 0.01:
            self.camera.setPos(self.camera, strafe * strafe_speed * dt)

        trigger_l = self.gamepad.findAxis(InputDevice.Axis.left_trigger)
        trigger_r = self.gamepad.findAxis(InputDevice.Axis.right_trigger)
        lift = trigger_r.value - trigger_l.value
        self.camera.setZ(self.camera.getZ() + (lift * vert_speed * dt))

        right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
        right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

        if abs(right_x.value) >= 0.1 or abs(right_y.value) >= 0.1:
            self.camera.setH(self.camera, turn_speed * dt * -right_x.value)
            self.camera.setP(self.camera, turn_speed * dt * right_y.value)

            self.camera.setR(0)

        return task.cont

    def fountain(self):
        self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ тСкст опасности
        if self.force:
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)

        else :
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                #self.state_info = OnscreenText(text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)
        
        
    def black_light(self):
        # Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ΠΉ свСт
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((0, 0, 0, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def weapon_hide(self):
        # Π£Π±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.hide_weapon = True
        self.weapon.hide()

    def toggleLights(self, lights):
        # Π‘ΠΏΠ΅Ρ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ освСщСниС
        if self.hide_weapon:
            for light in lights:
                if render.hasLight(light):
                    render.clearLight(light)
                else:
                    render.setLight(light)
            
            self.flash.setPos(self.weapon_pos)
        else:
            return


    def shot(self):
        dt = globalClock.getDt() + 0.5 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния
        if not self.hide_weapon : # Ссли ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΡƒΠ±Ρ€Π°Π½ΠΎ Ρ‚ΠΎ ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚Ρ€Π΅Π»ΡΡ‚ΡŒ
            self.shotSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ выстрСла
            self.bullet.setPos(self.weapon_pos) # ΠŸΡƒΠ»Ρ Π±ΡƒΠ΄Π΅Ρ‚ спавнится Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΡƒΡˆΠΊΠΈ
            self.bullet.setY(self.bullet, -11 * dt) # Π‘Π΄Π²ΠΈΠ³Π°Π΅ΠΌ ΠΏΡƒΠ»ΡŽ Π½Π° ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ скорости Π²ΠΏΠ΅Ρ€Ρ‘Π΄

    def check_loss(self):
        if self.state == 0: # Ссли ΠΆΠΈΠ·Π½Π΅ΠΉ Ρƒ корабля Π½Π΅ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ
            self.black_light() # Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΉ свСт
            self.weapon_hide() # ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
            if not self.EN :
                self.info = MenuApi.text(self, text='ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            else :
                self.info = MenuApi.text(self, text='LOSS', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            self.crackSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π°


    def setKey(self, key, value):
        self.keyMap[key] = value # Π”Π΅Π»Π°Π΅ΠΌ ΠΌΠ΅Ρ…aΠ½uΠ·ΠΌ наТатия клавиш.



    def move(self, task):

        ''' Π”Π΅Π»Π°Π΅ΠΌ Ρ„ΡƒΡ†Π½ΠΊΡ†ΠΈΡŽ двиТСния ΠΈΠ³Ρ€ΠΎΠΊΠ° '''

        dt = globalClock.getDt() - .005 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния

        # ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π²Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΡ€Π°Π²ΠΎ

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -10 * dt) # МСняСм ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠΊΠ° ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎ икс. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ получаСтся илюзия ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚Π° ΡƒΠ³Π»Π° Π»ΡƒΡ‡Π°. Но Π½Π° самом Π΄Π΅Π»Π΅ ΠΊΠ°ΠΌΠ΅Ρ€Π° просто пСрСмСщаСтся.
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, + 10 * dt) # Π’ΠΎΠΆΠ΅ самоС, Ρ‡Ρ‚ΠΎ ΠΈ Π½Π°Π²Π΅Ρ€Ρ…Ρƒ.

        startpos = self.droid.getPos() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡƒΠ΄ΠΎΠ±Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if self.keyMap["left"]:
            self.droid.setH(self.droid.getH() + 145 * dt)
            self.enemy.setY(self.enemy, 1 * dt)
        if self.keyMap["right"]:
            self.droid.setH(self.droid.getH() - 145 * dt)
            self.enemy.setY(self.enemy, -1 * dt)
        if self.keyMap["forward"]:
            self.droid.setY(self.droid, -25 * dt)
            self.enemy.setX(self.enemy, 1 * dt)
            # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ условиС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΡƒΠ±Ρ€Π°Π½ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΠΈΠ»ΠΈ Π½Π΅Ρ‚
            if not self.hide_weapon:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.weapon.setPos(self.weapon_pos) # ОбновляСм ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΡƒΡˆΠΊΠΈ
            else:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.flash.setPos(self.weapon_pos)


        camvec = self.droid.getPos() - self.camera.getPos() # Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        camvec.setZ(0) # 0 высота Π²Π΅ΠΊΡ‚ΠΎΡ€Π°
        camdist = camvec.length() # дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π°
        camvec.normalize() # Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        if camdist > 10.0: # Ссли дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ большС 10, Ρ‚ΠΎ смСщаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π·Π° Π΄Ρ€ΠΎΠΎΠΈΠ΄ΠΎΠΌ
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0 # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ дистанция Π±ΡƒΠ΄Π΅Ρ‚ снова 10
        if camdist < 5.0: # Ссли дистагцтя ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ мСньшС 5, Ρ‚ΠΎ...
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) # сдвигаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ
            camdist = 5.0 # всё обновляСм
            
        self.camera.lookAt(self.floater) # Π²ΠΎΡ‚ ΠΈ пригодился наш floater


        return task.cont # Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π·Π°Π΄Π°Ρ‡Ρƒ

##    def addInstructions(self, pos, msg):
##        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=self.inst_font, pos=(-1.3, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1)) # Ѐункция ΠΎ Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ
##
##    def addTitle(self, text):
##        return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1), scale=0.2,
##                            parent=base.a2dBottomRight, align=TextNode.ARight,
##                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=self.font) # Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ тСкстового Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° с ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ ΠΈ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠ΅ΠΉ
##    

droid = DroidShooter() # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ экзСмпляр класса нашСй ΠΈΠ³Ρ€Ρ‹
droid.run() # 3апустим ΠΈΠ³Ρ€Ρƒ


# Ρ€Π°Π·Ρ€ΠΎΠ±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ :
# Π“Π»Π°Π²Π½Ρ‹ΠΉ Π°Π²Ρ‚ΠΎΡ€ : ma3rx
# ΠŸΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ : panda3dmastercoder( присоСдСнился ΠΊ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ 31 января, 2021 Π³ΠΎΠ΄Π°, 12:??)
# Π Π΅ΠΊΠ»Π°ΠΌΡ‰ΠΈΠΊ : rdb (написал ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС Π½Π° Ρ„ΠΎΡ€ΡƒΠΌΠ΅ 6 фСвраля 2021 Π³ΠΎΠ΄Π°, 20:11)

marconit_engine.py :

# БамописноС API к direct и panda3d

from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectButton import DirectButton
from direct.gui.DirectSlider import DirectSlider
from direct.actor.Actor import Actor
from direct.particles.Particles import Particles
from direct.particles.ParticleEffect import ParticleEffect
from panda3d.core import *

from array import array
import random


class MenuApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def slider(self, pos, scale, value, command):
        return DirectSlider(pos=pos, scale=scale, value=value,
                                    command=command)
    
    def button(self, pos, text, scale, pad, command):
        return DirectButton(pos=pos, text=text,
                                   scale=scale, pad=pad,
                                   command=command)

    def addInstruction(self, pos, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=font, pos=(-1.6, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1))
        

    def addTitle(self, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=0.2,
                            parent=base.a2dBottomRight, align=TextNode.ARight,
                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=font)

    def text(self, pos, text, font, scale):
        return OnscreenText(text=text, pos=pos, scale=scale, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=font)

    def menu_effect(self):
        NUM_EMBERS = 512 # Колво частиц
    
        floats = []
        # ΠŸΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡΡ Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΈ Π·Π°Π΄Π°Ρ‘ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для частиц
        for i in range(NUM_EMBERS):
            speed = (0.2 + random.random()) * 0.7
            size = 0.5 + random.random() * 0.5
            size = max(size ** 4, 0.1)
            floats += [random.random(), random.random(), random.random(), speed, 0, 0, 0, size]

        initial_data = array('f', floats) # Π°Ρ€Ρ€Π°Π΅ΠΌ наши Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹
        buffer = ShaderBuffer('embers', initial_data.tobytes(), GeomEnums.UH_static) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€

        format = GeomVertexFormat.get_empty()
        vdata = GeomVertexData('embers', format, GeomEnums.UH_static)

        
        tris = GeomTriangles(GeomEnums.UH_static)
        tris.add_next_vertices(NUM_EMBERS * 3)

        
        geom = Geom(vdata)
        geom.add_primitive(tris)
        geom.set_bounds(BoundingBox((0, 0, 0), (1, 1, 1)))

        node = GeomNode("node")
        node.add_geom(geom)

        embertex = loader.load_texture("./shaders/menu/ember.png")
        embertex.wrap_u = SamplerState.WM_clamp
        embertex.wrap_v = SamplerState.WM_clamp

        shader = Shader.load(Shader.SL_GLSL, "./shaders/menu/embers.vert", "./shaders/menu/embers.frag")
        path = base.render.attach_new_node(node)
        path.set_shader(shader)
        path.set_shader_input("EmberBuffer", buffer)
        path.set_texture(embertex)
        path.set_two_sided(True)
        path.set_attrib(ColorBlendAttrib.make(ColorBlendAttrib.M_add, ColorBlendAttrib.O_incoming_alpha, ColorBlendAttrib.O_one))
        path.set_depth_write(False)
        path.node().set_bounds_type(BoundingVolume.BT_box)

        node = ComputeNode("simulate")
        node.add_dispatch(NUM_EMBERS // 16, 1, 1)
        path = base.render.attach_new_node(node)
        path.set_shader(Shader.load_compute(Shader.SL_GLSL, "./shaders/menu/simulate.comp"))
        path.set_shader_input("windmap", loader.load_texture("./shaders/menu/wind.png"))
        path.set_shader_input("EmberBuffer", buffer)

        base.cam.set_x(0.5)
        base.cam.set_y(-2)
        base.cam.set_z(0.5)

class GameApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def light(self):
        sun = DirectionalLight("sun")
        sun.set_color_temperature(6000)
        sun.color = sun.color * 4
        sun_path = render.attach_new_node(sun)
        sun_path.set_pos(10, -10, -10)
        sun_path.look_at(0, 0, 0)
        sun_path.hprInterval(self.sun_interval, (sun_path.get_h(), sun_path.get_p() - 360, sun_path.get_r()), bakeInStart=True).loop()
        render.set_light(sun_path)

    def object(self, path, scale, pos):
        self.object = Actor(path)
        self.object.reparentTo(render)
        self.object.setScale(scale)
        self.object.setPos(pos)

        return self.object

    def sound(self, path, volume):
        self.sound = loader.loadMusic(path)
        self.sound.setVolume(volume)

        return self.sound

    def shaders(self, vert, frag):
        render.set_shader(Shader.load(Shader.SL_GLSL, vert, frag))

    def loadParticleConfig(self, filename, pos, object):
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(filename))

        self.p.start(object)
        self.p.setPos(pos)

    def make_shader(self, object, pos):
        '''ΠŸΡ€ΠΎ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€'''
        object.set_shader(self.light_shader())
        object.set_shader_input('pos_light', pos)

Hi! I create 5.0.3 update - add sight :slight_smile:

Directory 5.0.3 :
/models :
./models/world :frowning: Now, download panda3d art from https://www.panda3d.org/download/noversion/art-gallery.zip
Go to the cat-environment folder. In it you will see a millenium falcon folder. Take all the files from it and put it in the directory ./models/world)
./models/block : block.zip (269.6 KB)
./models/enemies : enemies.zip (381.4 KB)
./models/fighter : fighter.zip (36.9 KB)
./models/player : player.zip (644.6 KB)
./models/sky : sky.zip (12.5 KB)
./models/weapon : weapon.zip (234.3 KB)
./models/whishlyflash : whishlyflash.zip

./fonts : fonts.zip (192.5 KB)
./sounds : sounds.zip (1.8 MB)
./special_effects : special_effects.zip (19.3 KB)
./tex : tex.zip (95.1 KB)
./shaders : shaders.zip (22.2 KB)

droid.py

#!/usr/bin/env python
# -*- coding: utf_8 -*-

# Π‘ΠΎΠ·Π΄Π°Π½ΠΎ : 22 число, ΡΠ½Π²Π°Ρ€ΡŒ, 2021 Π³ΠΎΠ΄

# Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ инструмСнты
from direct.showbase.ShowBase import ShowBase
from direct.particles.ParticleEffect import ParticleEffect
from direct.gui.OnscreenImage import OnscreenImage
from direct.gui.OnscreenText import OnscreenText
from direct.interval.IntervalGlobal import *
from panda3d.core import *
from marconit_engine import *
import random
import sys
import time
import os
import math


VERSION = '5.0.3'


settings = ['window-title Droid Game release ' +  VERSION,
            'fullscreen 0',
            'win-size 1440 900']
            

loadPrcFileData('', settings[0]) # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π½Π΅ стандартный Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ (Π²ΠΎΠ·ΠΌΡ‘ΠΌ Π΅Π³ΠΎ ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ settings)
loadPrcFileData('', settings[1]) # Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ полноэкранный Ρ€Π΅ΠΆΠΈΠΌ
loadPrcFileData('', settings[2]) # Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠ½Π°

# Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π³Π»Π°Π²Π½Ρ‹ΠΉ класс нашСй ΠΈΠ³Ρ€Ρ‹
class DroidShooter(ShowBase):
    def __init__(self):
        ShowBase.__init__(self) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ всС сСлфы ΠΈΠ· direct
        self.speed = 1800 # ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двигатСля
        self.GB = False # НЕ Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ
        self.EN = False # НС Π±ΡƒΠ΄Π΅ΠΌ Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ английский язык
        self.pro_machine = False # НС Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.sun_interval = 100 # Π˜Π½Ρ‚Π΅Ρ€Π²Π°Π» солнца
        self.menu() # звпуск мСню
        
    def menu(self):
        
        base.enableParticles() # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.disableMouse() # ΠžΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΌΡ‹ΡˆΠΊΡƒ

        self.win.setClearColor((0, 0.2, 0.2, 1)) # Π—Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΌ. Π”Π΅Π»ΠΎ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π² этом ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΌ Π΄Π²ΠΈΠΆΠΊΠ΅ ΠΏΠΎΠ²Π΅Ρ€Ρ…Π½ΠΎΡΡ‚ΡŒ Π·Π°ΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ сСрым.
        self.font = loader.loadFont('./fonts/doom_font.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ ΠΈΠ· ΠΈΠ³Ρ€Ρ‹ doom
        self.inst_font = loader.loadFont('./fonts/arial.ttf') # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡˆΡ€ΠΈΡ„Ρ‚ arial

        self.crackSound = GameApi.sound(self, './sounds/crack.wav', 1) # Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π° корабля
        self.shotSound = GameApi.sound(self, './sounds/shot.wav', 1) # Π·Π²ΡƒΠΊ выстрСла
        self.startSound = GameApi.sound(self, './sounds/started.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.errorSound = GameApi.sound(self, './sounds/error.wav', 1) # Π·Π²ΡƒΠΊ запуска
        self.click_sound = GameApi.sound(self, './sounds/GUI_click.wav', 1) # Π·Π²ΡƒΠΊ наТатия
        
        self.startSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ запуска ΠΈΠ³Ρ€Ρ‹

        # МСню-эффСкты

        MenuApi.menu_effect(self)

        self.button_start = MenuApi.button(self, pos=(0.7, 0, 0.4), text="CTAPT",
                                   scale=.2, pad=(.2, .2),
                                   command=self.load_game) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹

        self.gb_start = MenuApi.button(self, pos=(0.7, 0, 0.1), text="GB",
                                   scale=.2, pad=(.2, .2),
                                   command=self.gb_mode) # ΠΊΠ½ΠΎΠΏΠΊΠ° запуска ΠΈΠ³Ρ€Ρ‹  Π² Ρ‡Ρ‘Ρ€Π½ΠΎ-Π±Π΅Π»ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΠ΅

        self.en = MenuApi.button(self, pos=(0.7, 0, -0.2), text='EN',
                                 scale=.2, pad=(.2, .2),
                                 command=self.en_lang)
        self.pro_button = MenuApi.button(self, pos=(0.7, 0, -0.5), text='PRO',
                                 scale=.2, pad=(.2, .2),
                                 command=self.pro_system)

        self.slider_life = MenuApi.slider(self, pos=(0.1, 0, .75), scale=0.8, value=0.5,
                                    command=self.set_lifes)


        self.title = MenuApi.addTitle(self, "Droid game Ρ€Π΅Π»ΠΈΠ· " + VERSION, self.font)
        
        # НапСчатаСм ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅
        self.inst1 = MenuApi.addInstruction(self, 0.95, u"[ESC]: Π’Ρ‹Ρ…ΠΎΠ΄", self.inst_font)
        self.inst2 = MenuApi.addInstruction(self, 0.90, u"[Left Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst3 = MenuApi.addInstruction(self, 0.85, u"[Right Arrow]: ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst4 = MenuApi.addInstruction(self, 0.80, u"[Up Arrow]: Π’ΠΏΠ΅Ρ€Π΅Π΄", self.inst_font)
        self.inst5 = MenuApi.addInstruction(self, 0.75, u"[a]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ", self.inst_font)
        self.inst6 = MenuApi.addInstruction(self, 0.70, u"[d]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ", self.inst_font)
        self.inst7 = MenuApi.addInstruction(self, 0.65, u"[Left Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst8 = MenuApi.addInstruction(self, 0.60, u"[Right Arrow + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π° Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst9 = MenuApi.addInstruction(self, 0.55, u"[a + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst10 = MenuApi.addInstruction(self, 0.50, u"[d + Up arrow]: ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π² Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΠ΅Ρ€Ρ‘Π΄", self.inst_font)
        self.inst11 = MenuApi.addInstruction(self, 0.45, u"[space]: ΡΡ‚Ρ€Π΅Π»ΡŒΠ±Π°", self.inst_font)
        self.inst12 = MenuApi.addInstruction(self, 0.40, u"[s]: Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ", self.inst_font)
        self.inst13 = MenuApi.addInstruction(self, 0.35, u"[w]: ΡƒΠ±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅", self.inst_font)
        self.inst14 = MenuApi.addInstruction(self, 0.30, u"[f]: ΠΏΠΎΠ»Π½Ρ‹ΠΉ Ρ€Π°Π·Π³ΠΎΠ½(ОПАБНО!)", self.inst_font)
        self.inst15 = MenuApi.addInstruction(self, 0.25, u"[0]: ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ систСма", self.inst_font)
        self.inst16 = MenuApi.addInstruction(self, 0.20, u"[p]: ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΡ†Π΅Π»", self.inst_font)
        

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.

    def set_lifes(self):
        self.state = self.slider_life.guiItem.getValue() * 100 # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ слайдСрноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΡƒΠΌΠ½ΠΎΠΆΠ΅Π½ΠΎΠ΅ Π½Π° 100, Π΄Π° Ρ‚Ρ€Π°Ρ‡Ρƒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ Π½ΠΎ ΠΌΠ½Π΅ каТСтся ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΠ»Π΅Π²Π°Ρ‚ΡŒ Π½Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ мСню, ΠΈΠ±ΠΎ Ρ‚Π°ΠΊΠΎΠ³ΠΎ понятия просто Π½Π΅Ρ‚Ρƒ :)

    def gb_mode(self):
        '''Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.GB = True

    def en_lang(self):
        '''ИзмСнСниС языка Π½Π° английский'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.EN = True

    def pro_system(self):
        '''ΠŸΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅'''
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.pro_machine = True # Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅

    def load_game(self):
        self.click_sound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ΠΊΠ»ΠΈΠΊΠ°
        self.button_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ старта
        self.gb_start.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ Ρ‡Ρ‘Ρ€Π½ΠΎ Π±Π΅Π»ΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ°.
        self.title.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΈΠ³Ρ€Ρ‹
        self.en.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ Π°Π½Π³ΠΎΡΠ·Ρ‹Ρ‡Π½ΡƒΡŽ ΠΊΠ½ΠΎΠΏΠΊΡƒ
        self.pro_button.destroy() # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΡƒ ΠΏΡ€ΠΎΡ„Ρ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ упрвлСния
        # ΡƒΠ΄Π°Π»ΠΈΠΌ ΠΊΠ½ΠΎΠΏΠΊΠΈ управлСния
        self.inst1.destroy()
        self.inst2.destroy()
        self.inst3.destroy()
        self.inst4.destroy()
        self.inst5.destroy()
        self.inst6.destroy()
        self.inst7.destroy()
        self.inst8.destroy()
        self.inst9.destroy()
        self.inst10.destroy()
        self.inst11.destroy()
        self.inst12.destroy()
        self.inst13.destroy()
        self.inst14.destroy()
        self.inst15.destroy()
        self.inst16.destroy()
        self.slider_life.destroy() # удаляСм слайдСр ΠΆΠΈΠ·Π½Π΅ΠΉ корабля
        
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ ΠΊΠ½ΠΎΠΏΠΎΠΊ, ΠΏΠΎ ΠΈΡ… Π½Π°ΠΆΠ°Ρ‚ΠΈΡŽ        

        # РисуСм Π·Π²Ρ‘Π·Π΄Ρ‹

        self.sky = loader.loadModel("./models/sky/solar_sky_sphere") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ модСль космоса(это сфСра)

        self.sky_tex = loader.loadTexture("./tex/stars_1k_tex.jpg") # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ тСкстуру
        self.sky.setTexture(self.sky_tex, 1) # Π·Π°Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠΌ тСкстуру Π½Π° Π½Π΅Π±ΠΎ
        self.sky.reparentTo(render) # ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π½Π΅Π±ΠΎ
        self.sky.setScale(40000) # Ρ€Π°ΡΡˆΠΈΡ€ΠΈΠΌ Π½Π΅Π±ΠΎ Π΄ΠΎ максимальной Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Ρ‹ panda3d

        self.environ = loader.loadModel("models/world/falcon.egg") # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΡƒΠΆΠ΅ созданный Π² blender ΠΌΠΈΡ€.
        self.environ.reparentTo(render) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΌΠΈΡ€Π° Π² ΠΎΠΊΠ½ΠΎ

        droidStartPos = (-1, 0, 1.5 ) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΡΡ‚Π°Ρ€Ρ‚ΠΎΠ²ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π² ΠΌΠΈΡ€Π΅.
        enemyStartPos = (-6, 1, 0.5) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ°-Π΄Ρ€ΠΎΠΈΠ΄Π°.

        self.droid = GameApi.object(self, "models/player/seeker.egg", 1, droidStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΈΠ³Ρ€ΠΎΠΊΠ° (созданная Π² blender)
        self.enemy = GameApi.object(self, "models/enemies/r2d2/r2d2.egg", 1, enemyStartPos) # Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ модСль ΠΏΠΎΠΌΠΎΡ‰Π½ΠΈΠΊΠ° (созданная Π² blender)

        self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 1 # ΠŸΠΎΠ·ΠΈΡ†ΠΈΡ ΠΏΡƒΡˆΠΊΠΈ
        
        self.weapon = GameApi.object(self, 'models/weapon/lightsaber.egg', .5, self.weapon_pos) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.bullet = GameApi.object(self, 'models/weapon/bullet/bullet.egg.pz', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΏΡƒΠ»ΡŽ
        self.flash = GameApi.object(self, 'models/whishlyflash/handlamp.egg', .5, (0, 0, 0)) # Π—Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
               
        self.bullet.reparentTo(render) # пСрСмСстим ΠΏΡƒΠ»ΡŽ Π² ΠΌΠΈΡ€ Π½ΠΎ появится ΠΎΠ½Π° сама Π½Π΅ скоро
        self.flash.reparentTo(render) # пСрСмСстим Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ Π² наш ΠΌΠΈΡ€
        self.bullet.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΏΡƒΠ»ΠΈ
        self.flash.setScale(.5) # Π·Π°Π΄Π°Π΄ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°

        # враТСский ΠΈΡΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΡŒ
        self.fighter = GameApi.object(self, 'models/fighter/fighter.egg', 1, (0, 90 , 0)) # Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»ΡŒΠΊΡƒ истрСбитСля
                

        self.cube = GameApi.object(self, 'models/block/crate.egg', .7, (0, 0, 0)) # Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π±Π»ΠΎΠΊ
        self.cube.hprInterval(1.5, (0, 360, 360)).loop()

        self.Intervalcube = self.cube.posInterval(13,
                                                   Point3(0, -500, 0),
                                                   startPos=Point3(0, 10, 0))

        self.Intervalcube.loop()
        
        self.spotlight = camera.attachNewNode(Spotlight("spotlight")) # ΠšΠΎΠ½Ρ„ΠΈΠ³ΠΈ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊΠ°
        self.spotlight.node().setColor((.3, .3, .3, 1))
        self.spotlight.node().setSpecularColor((0, 0, 0, 1))

        self.floater = NodePath(PandaNode("floater")) 
        self.floater.reparentTo(self.droid)
        self.floater.setZ(2.0)

        self.accept("escape", sys.exit) # ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ клавиши Esc Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ.
        
        self.accept("arrow_left", self.setKey, ["left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ
        self.accept("arrow_right", self.setKey, ["right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ
        self.accept("arrow_up", self.setKey, ["forward", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a", self.setKey, ["cam-left", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("d", self.setKey, ["cam-right", True]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s - Ρ€Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСй модСльки
        self.accept("arrow_left-up", self.setKey, ["left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π»Π΅Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_right-up", self.setKey, ["right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+ΠΏΡ€Π°Π²ΠΎ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΈΠ³Ρ€ΠΎΠΊΠ° Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("arrow_up-up", self.setKey, ["forward", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π²Π²Π΅Ρ€Ρ…+Π²Π²Π΅Ρ€ΡŠ - ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("a-up", self.setKey, ["cam-left", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ a+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²Π»Π΅Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄
        self.accept("d-up", self.setKey, ["cam-right", False]) # ΠŸΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ s+Π²ΠΏΠ΅Ρ€Ρ‘Π΄ - ΠΏΠΎΠ²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π²ΠΏΡ€Π°Π²ΠΎ ΠΈ ΠΈΠ΄Ρ‘ΠΌ Π²ΠΏΠ΅Ρ€Ρ‘Π΄

        self.accept("space", self.shot) # ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ±Π΅Π»Π΅ стрСляСм
        self.accept("s", self.toggleLights, [[self.spotlight]]) # Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„ΠΎΠ½Π°Ρ€ΠΈΠΊ
        self.accept("w", self.weapon_hide) # ΠΏΡ€ΠΈ ΠΊΠ½ΠΎΠΏΠΊΠ΅ w - ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅.
        self.accept("p", self.cursor)

        base.enableParticles() # Π’ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π΄Ρ‹ΠΌΠ°
        self.p = ParticleEffect() # Π’ΠΊΠ»ΡŽΡ‡ΠΈΠΌ эффСкт Π΄Ρ‹ΠΌΠ°
        self.accept('f', self.particle_start) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f(ΠΎΡ‚ force) -  Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠΌ Ρ„Π°ΠΉΠ» Π΄Ρ‹ΠΌΠ° ΠΈ пСрСмСстим Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Π½Π½ΠΎ эта анимация стала ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π΄Ρ‹ΠΌΠ°
        self.accept('0', self.fountain) # ΠΏΡ€ΠΈ  Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΎΠΊ f+o(fountain) Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ ΠΏΠΎΠΆΠ°Ρ€ΠΎΡ‚ΡƒΡˆΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ систСму
        self.accept('f3', self.toggleWireframe) # ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ f3 - Π²ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌ ΠΏΠΎΠ»ΠΈΠ³ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΆΠΈΠΌ

        taskMgr.add(self.move, "moveTask") # ДобавляСм Π·Π°Π΄Π°Ρ‡Ρƒ Π² наш Π΄Π²ΠΈΠΆΠΎΠΊ

        self.isMoving = False # Π‘Ρ‚Π°Π²ΠΈΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ isMoving Π½Π° False(Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΌΠ΅Π½ΡΡ‚ΡŒ это Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅) Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ³Ρ€ΠΎΠΊ ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ стоял.
        # Π”Π΅Π»Π°Π΅ΠΌ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ свСт Π±Ρ‹Π» ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½.
        self.camera.setPos(self.droid.getX(), self.droid.getY() + 1, 3) # Π‘Ρ‚Π°Π²ΠΈΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Ρ‡ΡƒΡ‚ΡŒ большС ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if not self.EN : # Ссли язык Π½Π΅ английский
            self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else : # Ссли янглийский язык
            self.state_info = MenuApi.text(self, text='machine :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
            
                
        self.check_loss() # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
        self.hide_weapon = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ Π½Π΅ ΡƒΠ±Ρ€Π°Π½ΠΎ
        self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)
        self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)

        self.motor_pos1 = 25.238849639892578, 8.962211608886719, 1.5 # позиция ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°
        self.motor_pos2 = -20.676218032836914, 10.55816650390625, 1.5 # позиция Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΠΎΡ‚ΠΎΡ€Π°

        self.motor1 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos1, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 1
        self.motor2 = GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.motor_pos2, self.environ) # ΠΌΠΎΡ‚ΠΎΡ€ 2

        self.state_info2 = MenuApi.text(self, text='', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        self.force = False # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π½Π΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

        self.black_light() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π²Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Ρ‹ΠΉ свСт
        self.collisions() # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΈ

        # солнцС(новая ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° освСщСния)
        GameApi.light(self)
        
        #GameApi.fire(self)
        #GameApi.shadows_shader(self)
        #PaintShade(render)

        self.objects = [self.environ, self.droid,
                        self.enemy, self.weapon,
                        self.bullet, self.flash,
                        self.cube, self.fighter]
        

        # Если  ΠΈΠ³Ρ€ΠΎΠΊ Π·Π°Ρ…ΠΎΡ‚Π΅Π» ΠΏΠΎΠΈΠ³Ρ€Π°Ρ‚ΡŒ Π² Ρ‡Ρ‘Ρ€Π½ΠΎΠ±Π΅Π»ΡƒΡŽ ΠΈΠ³Ρ€Ρƒ, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΠΌ это
        if self.GB :        
            GameApi.shaders(self, "./shaders/lighting.vert", "./shaders/lighting.frag") # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚!
            #render.set_shader(Shader.load(Shader.SL_GLSL, "./shaders/terrain.vert.glsl", "./shaders/terrain.frag.glsl")) 

    def collisions(self):
        pass

    def light_shader(self):
        '''Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€Π° горСния'''
        return Shader.make(Shader.SL_GLSL, vertex="""
            #version 120

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            attribute vec2 p3d_MultiTexCoord0;
            attribute vec4 p3d_Vertex;
            attribute vec3 p3d_Normal;

            uniform mat4 p3d_ModelViewProjectionMatrix;

            void main( void )
            {
                gl_Position    = p3d_ModelViewProjectionMatrix * p3d_Vertex;
                gl_TexCoord[0].xy = p3d_MultiTexCoord0;
                
                v_FragmentPosition  = p3d_Vertex.xyz;
                v_FragmentNormal  = p3d_Normal;
            }

            """,

            fragment="""
            #version 120

            uniform sampler2D p3d_Texture0;
            uniform vec3 pos_light;

            uniform mat4 p3d_ViewMatrixInverse;

            varying vec3 v_FragmentPosition;
            varying vec3 v_FragmentNormal;

            const vec4  k_LightColor = vec4(1.0, 0.6, 0.3, 1.0);
            const float k_Shininess = 64.0;

            const float k_ConstAttenuation = 0.5;
            const float k_LinearAttenuation = 0.05;
            const float k_QuadricAttenuation = 0.001;

            void main( void )
            {
                vec3  L = pos_light - v_FragmentPosition;

                // ** Used in the calculation of light extinction
                float distance = length( L );

                L = normalize( L );
                vec3  N = normalize( v_FragmentNormal );

                // ** The H vector is used to calculate the gloss (specularity) of a fragment
                vec3  E = normalize( p3d_ViewMatrixInverse[3].xyz - v_FragmentPosition );
                vec3  H = normalize( L + E ); // ** Half-vector

                // ** The calculation coefficient. attenuations
                float attenuation = 1.0 / ( k_ConstAttenuation + k_LinearAttenuation * distance + k_QuadricAttenuation * distance * distance );

                float diffuse = clamp( dot( L, N ), 0.0, 1.0 );
                float specular  = pow( clamp( dot( N, H ), 0.0, 1.0 ), k_Shininess );
              
                if( diffuse <= 0.0 ){
                    specular = 0.0; 
                    }
              
                vec4 diffuseColor  = diffuse * k_LightColor * attenuation;
                vec4 specularColor = specular * k_LightColor * attenuation;
                vec4 ambientColor = vec4(0.01, 0.01, 0.01, 0.01);
                vec4 emissionColor = vec4(0.0, 0.0, 0.0, 0.0);

                gl_FragColor = ( diffuseColor + specularColor + ambientColor + emissionColor) * texture2D(p3d_Texture0, gl_TexCoord[0].xy );
            }
            """)

    def particle_start(self):
        if not self.pro_machine :
            self.force = True # ΠŸΠΎΡΡ‚Π°Π²ΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠΆΠ΅ Ρ€Π°Π·Π³ΠΎΠ½ΡΠ»ΠΈΡΡŒ

            self.state -= 1 # сдСлаСм мСньшС ΠΎΡ‡ΠΊΠΎΠ²
            self.state_info.hide() # ΡƒΠ΄Π°Π»ΠΈΠΌ тСкстовыС ΠΎΡ‡ΠΊΠΈ
            
            if self.state != 10 and self.state > 10:
                self.state_info.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС ΠΎ Тизнях корабля
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam/steam.ptf', self.steam_pos, self.environ) 
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС
                
                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ нСисправСн', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='motor error', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

                    
            else:
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)
                GameApi.loadParticleConfig(self, 'special_effects/steam_critic/steam.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide()  # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='критичСскоС состояниС', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='critic state', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
        
            if self.state < 10:
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                self.check_loss() # провСряСм ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅
                self.steam_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 5)

                for i in range(len(self.objects)):

                    self.object = self.objects[i]
                    GameApi.make_shader(self, self.object, (self.object.getX(), self.object.getY(), self.object.getZ())) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€ горСния

                GameApi.loadParticleConfig(self, 'special_effects/steam_critic+/fireish.ptf', self.steam_pos, self.environ)
                self.errorSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ ошибки
                self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ ΠΏΡ€Π΅Π΄Π΅Π΄ΡƒΡ‰Π΅Π΅ сообщСниС

                if not self.EN :
                    self.state_info2 = MenuApi.text(self, text='ΠΏΠ°Π΄Π°Π΅ΠΌ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                else :
                    self.state_info2 = MenuApi.text(self, text='fall!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

        else :
            if not self.EN :
                self.pro_info = MenuApi.text(self, text='ПРОЀИ!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            else :
                self.pro_info = MenuApi.text(self, text='PRO!', pos=(-0.8, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ Ρ‚ΠΎΠΌ Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΠΏΡ€ΠΎΡ„ΠΈ :)
                
            self.pro_machine_engine()

    def pro_machine_engine(self):
        '''ΠŸΡ€ΠΎΡ„Π΅ΡΠΈΠΎΠ½Π°Π»ΡŒΠ½Π°Ρ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ° корабля'''
        # Π’ΡƒΡ‚ Π½ΡƒΠΆΠ΅Π½ дТойстик. Если Π΅Π³ΠΎ Ρƒ вас Π½Π΅Ρ‚, ΡƒΠ²Ρ‹ Π²Ρ‹ Π½Π΅ смоТСтС ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ€Π΅ΠΆΠΈΠΌ.
        self.mgr = InputDeviceManager.get_global_ptr()
        for device in self.mgr.get_devices():
            self.gamepad = device

        MenuApi.text(self, text=str(self.gamepad), pos=(-1.6, -0.9), scale=0.05, font=self.font) # Π½Π°ΠΉΠ΄Π΅Π½ΠΎΠ΅ устройство
        
        # Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ дТойстиком
        taskMgr.add(self.moveTaskDjoystic, "moveTaskDjoystic")
##            self.accept("gamepad-back", exit)
##            self.accept("gamepad-start", exit)
##            self.accept("gamepad-face_x", self.reset)
##            self.accept("gamepad-face_b", self.action, extraArgs=["face_b"])

    def reset(self):

        self.camera.setPosHpr(0, -200, 10, 0, 0, 0)
        self.environ.setPosHpr(0, -200, 9, 0, 0, 0)

    def moveTaskDjoystic(self, task):
        dt = globalClock.getDt()

        strafe_speed = 85
        vert_speed = 50
        turn_speed = 100

        lstick = self.gamepad.findButton("lstick")
        if lstick.pressed:
            strafe_speed *= 2.0

        strafe = Vec3(0)
        left_x = self.gamepad.findAxis(InputDevice.Axis.left_x)
        left_y = self.gamepad.findAxis(InputDevice.Axis.left_y)
        strafe.x = left_x.value
        strafe.y = left_y.value

        if strafe.lengthSquared() >= 0.01:
            self.camera.setPos(self.camera, strafe * strafe_speed * dt)

        trigger_l = self.gamepad.findAxis(InputDevice.Axis.left_trigger)
        trigger_r = self.gamepad.findAxis(InputDevice.Axis.right_trigger)
        lift = trigger_r.value - trigger_l.value
        self.camera.setZ(self.camera.getZ() + (lift * vert_speed * dt))

        right_x = self.gamepad.findAxis(InputDevice.Axis.right_x)
        right_y = self.gamepad.findAxis(InputDevice.Axis.right_y)

        if abs(right_x.value) >= 0.1 or abs(right_y.value) >= 0.1:
            self.camera.setH(self.camera, turn_speed * dt * -right_x.value)
            self.camera.setP(self.camera, turn_speed * dt * right_y.value)

            self.camera.setR(0)

        return task.cont

    def fountain(self):
        self.state_info2.hide() # ΡƒΠ±ΠΈΡ€Π°Π΅ΠΌ тСкст опасности
        if self.force:
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                self.state_info = MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)

        else :
            if self.state != 100:
                self.state += 1
                self.state_info.hide()
                MenuApi.text(self, text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(float(self.state)), pos=(0.5, 0.8), scale=0.1, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля
                #self.state_info = OnscreenText(text='ΠΊΠΎΡ€Π°Π±Π»ΡŒ :' + str(self.state), pos=(0.5, 0.8), scale=0.1, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=self.font) # НапишСм сообщСниС ΠΎ состоянии корабля

            self.fountain_pos = random.randrange(0, 5), random.randrange(0, 5), random.randrange(0, 1)    
            GameApi.loadParticleConfig(self, 'special_effects/fountain/fountain.ptf', self.fountain_pos, self.environ)
        
        
    def black_light(self):
        # Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ΠΉ свСт
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((0, 0, 0, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def weapon_hide(self):
        # Π£Π±Ρ€Π°Ρ‚ΡŒ ΠΎΡ€ΡƒΠΆΠΈΠ΅
        self.hide_weapon = True
        self.weapon.hide()

    def toggleLights(self, lights):
        # Π‘ΠΏΠ΅Ρ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ освСщСниС
        if self.hide_weapon:
            for light in lights:
                if render.hasLight(light):
                    render.clearLight(light)
                else:
                    render.setLight(light)
            
            self.flash.setPos(self.weapon_pos)
        else:
            return


    def shot(self):
        dt = globalClock.getDt() + 0.5 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния
        if not self.hide_weapon : # Ссли ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΡƒΠ±Ρ€Π°Π½ΠΎ Ρ‚ΠΎ ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΡΡ‚Ρ€Π΅Π»ΡΡ‚ΡŒ
            self.shotSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ выстрСла
            self.bullet.setPos(self.weapon_pos) # ΠŸΡƒΠ»Ρ Π±ΡƒΠ΄Π΅Ρ‚ спавнится Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΡƒΡˆΠΊΠΈ
            self.bullet.setY(self.bullet, -500 * dt) # Π‘Π΄Π²ΠΈΠ³Π°Π΅ΠΌ ΠΏΡƒΠ»ΡŽ Π½Π° ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ скорости Π²ΠΏΠ΅Ρ€Ρ‘Π΄

    def check_loss(self):
        if self.state == 0: # Ссли ΠΆΠΈΠ·Π½Π΅ΠΉ Ρƒ корабля Π½Π΅ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ
            self.black_light() # Π²ΠΊΠ»ΡŽΡ‡ΠΈΠΌ Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΉ свСт
            self.weapon_hide() # ΡƒΠ±Π΅Ρ€Ρ‘ΠΌ ΠΎΡ€ΡƒΠΆΠΈΠ΅
            if not self.EN :
                self.info = MenuApi.text(self, text='ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠ΅', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            else :
                self.info = MenuApi.text(self, text='LOSS', font=self.font,
                                pos=(-1.3, -0.5), scale=0.3) # напишСм ΠΎ ΠΏΠΎΡ€Π°ΠΆΠ΅Π½ΠΈΠΈ
            self.crackSound.play() # ΠΈΠ³Ρ€Π°Π΅ΠΌ Π·Π²ΡƒΠΊ Π²Π·Ρ€Ρ‹Π²Π°


    def setKey(self, key, value):
        self.keyMap[key] = value # Π”Π΅Π»Π°Π΅ΠΌ ΠΌΠ΅Ρ…aΠ½uΠ·ΠΌ наТатия клавиш.

    def cursor(self):
        OnscreenText(text="||", style=1, fg=(1,1,1,1),pos=(0.0,0.03) , align=TextNode.ARight, scale = .07)
        OnscreenText(text="||", style=1, fg=(1,1,1,1),pos=(0.0,-0.05), align=TextNode.ARight, scale = .07)
        OnscreenText(text="==", style=1, fg=(1,1,1,1),pos=(-0.03,0.0), align=TextNode.ARight, scale = .07)
        OnscreenText(text="==", style=1, fg=(1,1,1,1),pos=(0.055,0.0), align=TextNode.ARight, scale = .07)


    def move(self, task):

        ''' Π”Π΅Π»Π°Π΅ΠΌ Ρ„ΡƒΡ†Π½ΠΊΡ†ΠΈΡŽ двиТСния ΠΈΠ³Ρ€ΠΎΠΊΠ° '''

        dt = globalClock.getDt() - .005 # CΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ двиТСния

        # ΠŸΠΎΠ²ΠΎΡ€ΠΎΡ‚ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ Π²Π»Π΅Π²ΠΎ ΠΈ Π²ΠΏΡ€Π°Π²ΠΎ

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -10 * dt) # МСняСм ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠΊΠ° ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎ икс. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ получаСтся илюзия ΠΏΠΎΠ²ΠΎΡ€ΠΎΡ‚Π° ΡƒΠ³Π»Π° Π»ΡƒΡ‡Π°. Но Π½Π° самом Π΄Π΅Π»Π΅ ΠΊΠ°ΠΌΠ΅Ρ€Π° просто пСрСмСщаСтся.
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, + 10 * dt) # Π’ΠΎΠΆΠ΅ самоС, Ρ‡Ρ‚ΠΎ ΠΈ Π½Π°Π²Π΅Ρ€Ρ…Ρƒ.

        startpos = self.droid.getPos() # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡƒΠ΄ΠΎΠ±Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ ΠΈΠ³Ρ€ΠΎΠΊΠ°

        if self.keyMap["left"]:
            self.droid.setH(self.droid.getH() + 145 * dt)
            self.enemy.setY(self.enemy, 1 * dt)
        if self.keyMap["right"]:
            self.droid.setH(self.droid.getH() - 145 * dt)
            self.enemy.setY(self.enemy, -1 * dt)
        if self.keyMap["forward"]:
            self.droid.setY(self.droid, -25 * dt)
            self.enemy.setX(self.enemy, 1 * dt)
            # Π‘Π΄Π΅Π»Π°Π΅ΠΌ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ условиС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΡƒΠ±Ρ€Π°Π½ΠΎ ΠΎΡ€ΡƒΠΆΠΈΠ΅ ΠΈΠ»ΠΈ Π½Π΅Ρ‚
            if not self.hide_weapon:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.weapon.setPos(self.weapon_pos) # ОбновляСм ΠΏΠΎΠ·ΠΈΡ†ΠΈΡŽ ΠΏΡƒΡˆΠΊΠΈ
            else:
                self.weapon_pos = self.droid.getX(), self.droid.getY() + 0.7, 3
                self.flash.setPos(self.weapon_pos)


        camvec = self.droid.getPos() - self.camera.getPos() # Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        camvec.setZ(0) # 0 высота Π²Π΅ΠΊΡ‚ΠΎΡ€Π°
        camdist = camvec.length() # дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ ΠΎΡ‚ Π΄Ρ€ΠΎΠΈΠ΄Π°
        camvec.normalize() # Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹
        if camdist > 10.0: # Ссли дистанция ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ большС 10, Ρ‚ΠΎ смСщаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ Π·Π° Π΄Ρ€ΠΎΠΎΠΈΠ΄ΠΎΠΌ
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0 # Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ дистанция Π±ΡƒΠ΄Π΅Ρ‚ снова 10
        if camdist < 5.0: # Ссли дистагцтя ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ мСньшС 5, Ρ‚ΠΎ...
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) # сдвигаСм ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ
            camdist = 5.0 # всё обновляСм
            
        self.camera.lookAt(self.floater) # Π²ΠΎΡ‚ ΠΈ пригодился наш floater


        return task.cont # Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π·Π°Π΄Π°Ρ‡Ρƒ


droid = DroidShooter() # Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ экзСмпляр класса нашСй ΠΈΠ³Ρ€Ρ‹
droid.run() # 3апустим ΠΈΠ³Ρ€Ρƒ


# Ρ€Π°Π·Ρ€ΠΎΠ±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ :
# Π“Π»Π°Π²Π½Ρ‹ΠΉ Π°Π²Ρ‚ΠΎΡ€ : ma3rx
# ΠŸΠΎΠΌΠΎΡ‰Π½ΠΈΠΊ : panda3dmastercoder( присоСдСнился ΠΊ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ 31 января, 2021 Π³ΠΎΠ΄Π°, 12:??)
# Π Π΅ΠΊΠ»Π°ΠΌΡ‰ΠΈΠΊ : rdb (написал ΠΏΠ΅Ρ€Π²ΠΎΠ΅ сообщСниС Π½Π° Ρ„ΠΎΡ€ΡƒΠΌΠ΅ 6 фСвраля 2021 Π³ΠΎΠ΄Π°, 20:11)

marconit_engine.py :

# БамописноС API к direct и panda3d

from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectButton import DirectButton
from direct.gui.DirectSlider import DirectSlider
from direct.actor.Actor import Actor
from direct.particles.Particles import Particles
from direct.particles.ParticleEffect import ParticleEffect
from panda3d.core import *

from array import array
import random


class MenuApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def slider(self, pos, scale, value, command):
        return DirectSlider(pos=pos, scale=scale, value=value,
                                    command=command)
    
    def button(self, pos, text, scale, pad, command):
        return DirectButton(pos=pos, text=text,
                                   scale=scale, pad=pad,
                                   command=command)

    def addInstruction(self, pos, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=font, pos=(-1.6, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1))
        

    def addTitle(self, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=0.2,
                            parent=base.a2dBottomRight, align=TextNode.ARight,
                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=font)

    def text(self, pos, text, font, scale):
        return OnscreenText(text=text, pos=pos, scale=scale, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=font)

    def menu_effect(self):
        NUM_EMBERS = 512 # Колво частиц
    
        floats = []
        # ΠŸΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡΡ Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΈ Π·Π°Π΄Π°Ρ‘ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для частиц
        for i in range(NUM_EMBERS):
            speed = (0.2 + random.random()) * 0.7
            size = 0.5 + random.random() * 0.5
            size = max(size ** 4, 0.1)
            floats += [random.random(), random.random(), random.random(), speed, 0, 0, 0, size]

        initial_data = array('f', floats) # Π°Ρ€Ρ€Π°Π΅ΠΌ наши Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹
        buffer = ShaderBuffer('embers', initial_data.tobytes(), GeomEnums.UH_static) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€

        format = GeomVertexFormat.get_empty()
        vdata = GeomVertexData('embers', format, GeomEnums.UH_static)

        
        tris = GeomTriangles(GeomEnums.UH_static)
        tris.add_next_vertices(NUM_EMBERS * 3)

        
        geom = Geom(vdata)
        geom.add_primitive(tris)
        geom.set_bounds(BoundingBox((0, 0, 0), (1, 1, 1)))

        node = GeomNode("node")
        node.add_geom(geom)

        embertex = loader.load_texture("./shaders/menu/ember.png")
        embertex.wrap_u = SamplerState.WM_clamp
        embertex.wrap_v = SamplerState.WM_clamp

        shader = Shader.load(Shader.SL_GLSL, "./shaders/menu/embers.vert", "./shaders/menu/embers.frag")
        path = base.render.attach_new_node(node)
        path.set_shader(shader)
        path.set_shader_input("EmberBuffer", buffer)
        path.set_texture(embertex)
        path.set_two_sided(True)
        path.set_attrib(ColorBlendAttrib.make(ColorBlendAttrib.M_add, ColorBlendAttrib.O_incoming_alpha, ColorBlendAttrib.O_one))
        path.set_depth_write(False)
        path.node().set_bounds_type(BoundingVolume.BT_box)

        node = ComputeNode("simulate")
        node.add_dispatch(NUM_EMBERS // 16, 1, 1)
        path = base.render.attach_new_node(node)
        path.set_shader(Shader.load_compute(Shader.SL_GLSL, "./shaders/menu/simulate.comp"))
        path.set_shader_input("windmap", loader.load_texture("./shaders/menu/wind.png"))
        path.set_shader_input("EmberBuffer", buffer)

        base.cam.set_x(0.5)
        base.cam.set_y(-2)
        base.cam.set_z(0.5)

class GameApi(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

    def light(self):
        sun = DirectionalLight("sun")
        sun.set_color_temperature(6000)
        sun.color = sun.color * 4
        sun_path = render.attach_new_node(sun)
        sun_path.set_pos(10, -10, -10)
        sun_path.look_at(0, 0, 0)
        sun_path.hprInterval(self.sun_interval, (sun_path.get_h(), sun_path.get_p() - 360, sun_path.get_r()), bakeInStart=True).loop()
        render.set_light(sun_path)

    def object(self, path, scale, pos):
        self.object = Actor(path)
        self.object.reparentTo(render)
        self.object.setScale(scale)
        self.object.setPos(pos)

        return self.object

    def sound(self, path, volume):
        self.sound = loader.loadMusic(path)
        self.sound.setVolume(volume)

        return self.sound

    def shaders(self, vert, frag):
        render.set_shader(Shader.load(Shader.SL_GLSL, vert, frag))

    def loadParticleConfig(self, filename, pos, object):
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(filename))

        self.p.start(object)
        self.p.setPos(pos)

    def make_shader(self, object, pos):
        '''ΠŸΡ€ΠΎ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€'''
        object.set_shader(self.light_shader())
        object.set_shader_input('pos_light', pos)

New marconit_engine.py code:

# БамописноС API к direct и panda3d

from direct.showbase.ShowBase import DirectObject
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectButton import DirectButton
from direct.gui.DirectSlider import DirectSlider
from direct.actor.Actor import Actor
from direct.particles.Particles import Particles
from direct.particles.ParticleEffect import ParticleEffect
from panda3d.core import *

from array import array
import random


class MenuApi(DirectObject):
    def __init__(self):
        ShowBase.__init__(self)

    def slider(self, pos, scale, value, command):
        return DirectSlider(pos=pos, scale=scale, value=value,
                                    command=command)
    
    def button(self, pos, text, scale, pad, command):
        return DirectButton(pos=pos, text=text,
                                   scale=scale, pad=pad,
                                   command=command)

    def addInstruction(self, pos, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1,1,1,1), font=font, pos=(-1.6, pos), align=TextNode.ALeft, scale = .04, shadow=(0,0,0,1))
        

    def addTitle(self, msg, font):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=0.2,
                            parent=base.a2dBottomRight, align=TextNode.ARight,
                            pos=(-0.1, 0.09), shadow=(0, 0, 0, 1), font=font)

    def text(self, pos, text, font, scale):
        return OnscreenText(text=text, pos=pos, scale=scale, fg=(1, 1, 1, 1), align=TextNode.ALeft, font=font)

    def menu_effect(self):
        NUM_EMBERS = 512 # Колво частиц
    
        floats = []
        # ΠŸΡ€ΠΎΡ…ΠΎΠ΄ΠΈΠΌΡΡ Π² Ρ†ΠΈΠΊΠ»Π΅ ΠΈ Π·Π°Π΄Π°Ρ‘ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ для частиц
        for i in range(NUM_EMBERS):
            speed = (0.2 + random.random()) * 0.7
            size = 0.5 + random.random() * 0.5
            size = max(size ** 4, 0.1)
            floats += [random.random(), random.random(), random.random(), speed, 0, 0, 0, size]

        initial_data = array('f', floats) # Π°Ρ€Ρ€Π°Π΅ΠΌ наши Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹
        buffer = ShaderBuffer('embers', initial_data.tobytes(), GeomEnums.UH_static) # Π²Ρ€ΡƒΠ±Π°Π΅ΠΌ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€

        format = GeomVertexFormat.get_empty()
        vdata = GeomVertexData('embers', format, GeomEnums.UH_static)

        
        tris = GeomTriangles(GeomEnums.UH_static)
        tris.add_next_vertices(NUM_EMBERS * 3)

        
        geom = Geom(vdata)
        geom.add_primitive(tris)
        geom.set_bounds(BoundingBox((0, 0, 0), (1, 1, 1)))

        node = GeomNode("node")
        node.add_geom(geom)

        embertex = loader.load_texture("./shaders/menu/ember.png")
        embertex.wrap_u = SamplerState.WM_clamp
        embertex.wrap_v = SamplerState.WM_clamp

        shader = Shader.load(Shader.SL_GLSL, "./shaders/menu/embers.vert", "./shaders/menu/embers.frag")
        path = base.render.attach_new_node(node)
        path.set_shader(shader)
        path.set_shader_input("EmberBuffer", buffer)
        path.set_texture(embertex)
        path.set_two_sided(True)
        path.set_attrib(ColorBlendAttrib.make(ColorBlendAttrib.M_add, ColorBlendAttrib.O_incoming_alpha, ColorBlendAttrib.O_one))
        path.set_depth_write(False)
        path.node().set_bounds_type(BoundingVolume.BT_box)

        node = ComputeNode("simulate")
        node.add_dispatch(NUM_EMBERS // 16, 1, 1)
        path = base.render.attach_new_node(node)
        path.set_shader(Shader.load_compute(Shader.SL_GLSL, "./shaders/menu/simulate.comp"))
        path.set_shader_input("windmap", loader.load_texture("./shaders/menu/wind.png"))
        path.set_shader_input("EmberBuffer", buffer)

        base.cam.set_x(0.5)
        base.cam.set_y(-2)
        base.cam.set_z(0.5)

class GameApi(DirectObject):
    def __init__(self):
        ShowBase.__init__(self)

    def light(self):
        sun = DirectionalLight("sun")
        sun.set_color_temperature(6000)
        sun.color = sun.color * 4
        sun_path = render.attach_new_node(sun)
        sun_path.set_pos(10, -10, -10)
        sun_path.look_at(0, 0, 0)
        sun_path.hprInterval(self.sun_interval, (sun_path.get_h(), sun_path.get_p() - 360, sun_path.get_r()), bakeInStart=True).loop()
        render.set_light(sun_path)

    def object(self, path, scale, pos):
        self.object = Actor(path)
        self.object.reparentTo(render)
        self.object.setScale(scale)
        self.object.setPos(pos)

        return self.object

    def sound(self, path, volume):
        self.sound = loader.loadMusic(path)
        self.sound.setVolume(volume)

        return self.sound

    def shaders(self, vert, frag):
        render.set_shader(Shader.load(Shader.SL_GLSL, vert, frag))

    def loadParticleConfig(self, filename, pos, object):
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(filename))

        self.p.start(object)
        self.p.setPos(pos)

    def make_shader(self, object, pos):
        '''ΠŸΡ€ΠΎ ΡˆΠ΅ΠΉΠ΄Π΅Ρ€'''
        object.set_shader(self.light_shader())
        object.set_shader_input('pos_light', pos)


Hm… for new version??

No. Just a mistake you made. I fixed it.

EDIT: Actually: ShowBase is a new screen and initiating it will cause errors. So DirectObject is what you have to use.

Ok.