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.6'
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 = 100 # скорость двигателя
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,
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.planet = GameApi.object(self, 'models/player/seeker.egg', 80, (0, -1000, 0))
# вражеский истребитель
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.Intervaldroid = self.droid.posInterval(13,
Point3(0, -500, 0),
startPos=Point3(self.droid.getX(), self.droid.getY(), self.droid.getZ()))
# Врашение планеты
self.planet.hprInterval(50, (360, 360, 0)).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]
# Если игрок захотел поиграть в чёрнобелую игру, проверим это
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() # удалим текстовые очки
for i in range(len(self.objects)):
object = self.objects[i]
object.setY(object.getY() - self.speed)
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) # Напишем сообщение о состоянии корабля
# Вращение корабля
self.environ.hprInterval(50, (360, 360, 0)).loop()
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 check_win(self):
'''Проверка победы'''
if (self.droid.getX(), self.droid.getY()) == (self.planet.getX(), self.planet.getY()):
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='WIN', font=self.font,
pos=(-1.3, -0.5), scale=0.3)
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)
self.check_win() # Проверяем победу
self.check_loss() # Проверяем поражение
if self.droid.getX() > 10 or self.droid.getY() > 10 or self.droid.getZ() > 10:
# вращаем дроида
self.Intervaldroid.loop()
self.droid.hprInterval(1.5, (360, 360, 360)).loop()
# Сделаем специальное условие проверки убрано оружие или нет
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)