zv
xc
"""
########### LANDER NUMBER ZERO ###########
* A game in the style of "Lunar Lander" and "Pi Lander" by Tim Martin.
* Author Alexander Diorditsa (http://adior.ru)
* Licence: Creative Commons Attribution-ShareAlike 4.0 International
* http://creativecommons.org/licenses/by-sa/4.0/
* Мade in Russian 2026
"""
import warnings
warnings.filterwarnings("ignore", category=RuntimeWarning, message=".*AVX2.*")
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'
import pygame
import pgzrun
from random import *
import math
WIDTH = 960 # Ширина экрана
HEIGHT = 720 # Высота экрана
game_on = False # Игра не запущена
score = 0 # Счёт в игре
prize = 0 # Выигрыш
seg_size = 3 # Ландшафт разбит на сегменты по оси X
count_seg = int(WIDTH/seg_size) # Количество сегментов
mountains = [1] * count_seg # Высота гор в каждом сегменте
n_spots = 4 # Максимальное количество посадочных площадок
landing_spots = [] # Посадочные площадки
len_spot_min = 5 # Наименьшая посадочная площадка
len_spot_max = 20 # Наибольшая посадочная площадка
len_spot_this = 20 # Длина вашей посадочной площадки
landscape_blink = False # Посадочные огни
# Спускаемый аппарат ship и его параметры:
ship = [WIDTH + 50., 100.] # Координаты корабля
leg_length = seg_size * 3 # Длина опор корабля
ship_angle = 0 # Угол поворота корабля
touch_angle = 0 # Угол касания поверхности
rotate_speed = 3 # Скорость поворота корабля в градусах за кадр
power = 0.05 # Мощность двигателей корабля
engine = False # Двигатель выключен
acceleration = [0, 0] # Ускорение корабля по осям X и Y
gravity = [0., 0.01] # Сила гравитации по осям X и Y
altitude = 0 # Высота над поверхностью планеты
max_fuel = 1000 # Топливный бак
fuel = max_fuel # Топливо в начале игры
velocity = [0, 0] # Скорость корабля по осям X и Y
game_time = 0 # Время игры
victory = False # Вы ещё не победили
TEXT1 = "«« LANDER NUMBER ZERO »»\n\nДержите скорость посадки < 1, угол < 20\n" \
+ "Постарайтесь сесть в центр площадки.\n"\
+ "Маленькие площадки расположены ближе к ценным минералам,\n"\
+ "вы на них сможете больше заработать.\n"\
+ "Топливо будете покупать по 0,25 YE за единицу.\n\n"\
+ "Управление стрелками на клавиатуре.\n"\
+ "\nНАЖМИТЕ ПРОБЕЛ ДЛЯ СТАРТА"
TEXT2 = "ВЫ ТОЛЬКО ЧТО УНИЧТОЖИЛИ ЦЕННЫЙ ПОСАДОЧНЫЙ МОДУЛЬ\n\n"\
+ "ВАШИ ПОТЕРИ 250 YE\n\n"\
+ "НАЖМИТЕ ПРОБЕЛ ДЛЯ ПЕРЕЗАПУСКА МИССИИ"
message = TEXT1
def reset(): # Восстановление параметров игры и корабля
global game_on, ship, velocity, ship_angle, fuel, prize, touch_angle,\
game_time, score, victory
game_on = True # Игра запущена
ship = [WIDTH - 50., 100.] # Координаты корабля
velocity = [-random(), random()] # Скорость корабля по осям X и Y
ship_angle = randint(0, 360) # Угол поворота корабля
if fuel == 0: # Если ваш корабль погиб и остатки топлива сгорели
score -= max_fuel // 4 # Покупка топлива
fuel = max_fuel # Топливa полный бак
prize = 0 # Выигрыш
touch_angle = 0 # Угол касания поверхности
game_time = 0 # Время игры
victory = False # Вы ещё не победили
def rotated(x, y, angle):
"""
Вернуть вектор (x, y), повёрнутый на заданный угол (в градусах)
"""
angle = -math.radians(angle)
sina = math.sin(angle)
cosa = math.cos(angle)
return (x * cosa - y * sina, x * sina + y * cosa)
def new_landscape():
"""
Генератор ландшафта
"""
# Создаём посадочные площадки
landing_spots.clear() # Удаляем предыдущие посадочные площадки
region = 0 # Начало площадки, координата х
len_spot = 0 # Длина площадки
for n in range(n_spots):
region += randint(10, count_seg//n_spots)
len_spot = randint(len_spot_min, len_spot_max)
for m in range(len_spot):
landing_spots.append(region)
region += 1
# Создаём горы ущелья и равнины
small = 3 # Перепад высоты
large = 10 # Перепад высоты
landscape_step = 0 # Протяжённость ландшафта
mountains[0] = randint(HEIGHT//3, HEIGHT*2//3)
landscape = "field" # Ландшафт
for step in range(1, count_seg):
if step in landing_spots:
mountains[step] = mountains[step-1]
continue
if landscape_step == 0:
landscape_step = randint(25, 75)
if landscape == "mountain":
landscape = choice(("mountain", "gorges")) # Ландшафты
else:
landscape = choice(("mountain", "gorges", "field")) # Ландшафты
landscape_step -= 1
if landscape == "mountain": # Горы
mountains[step] = (mountains[step-1] + randint(-large, small))
elif landscape == "gorges": # Ущелья
mountains[step] = (mountains[step-1] + randint(-small, large))
else: # Равнины
mountains[step] = (mountains[step-1] + randint(-small, small))
if mountains[step] > HEIGHT - 30: # Ландшафт слишком низкий
landscape = "mountain" # Строим гору
landscape_step = randint(25, 75)
elif mountains[step] < 200: # Ландшафт слишком высокий
landscape = "gorges" # Строим ущелье
landscape_step = randint(25, 75)
def check_game_over(): # Проверки и завершение игры
"""
Проверяет, коснулся ли игрок земли или
вышел за верхнюю или боковые границы
"""
global altitude, game_on, ship_angle, ship, engine, touch_angle, message,\
prize, score, fuel, victory, len_spot_this
n = int(ship[0] / seg_size) # Сегмент ландшафта в котором находится корабль
if n < count_seg:
altitude = int(mountains[n] - ship[1] - leg_length)
if altitude > 0 and 0 < ship[0] < WIDTH and ship[1] > 0 :
return # Игра не окончена
game_on = False # Игра окончена и остановлена
engine = False # Двигатель выключен
victory = True # Предположим вы победили
touch_angle = ship_angle
if 20 < ship_angle < 340:
ship_angle = 135 # Корабль перевернулся
victory = False # Вы проиграли
else:
ship_angle = 0
if ship[1] <= 0 or not 0 < ship[0] < WIDTH :
ship = [WIDTH + 50., 100.] # Корабль потерян
victory = False # Вы проиграли
if abs(velocity[0]) > 0.5 or abs(velocity[1]) > 0.5:
ship[1] += seg_size * 3 # Корабль разбит
victory = False # Вы проиграли
if (ship[0]-seg_size)//seg_size not in landing_spots \
or (ship[0]+seg_size)//seg_size not in landing_spots:
ship_angle = 180 # Корабль не попал на площадку
victory = False # Вы проиграли
if not victory:
message = TEXT2
prize = -250 # Выигрыш
fuel = 0
else:
n = int(ship[0]/seg_size) # Номер сегмента площадки
i = j = landing_spots.index(n) # Индекс этого сегмента
len_spot_this = 1 # Длина посадочной площадки
while i+1 < len(landing_spots):
if landing_spots[i+1] - landing_spots[i] == 1:
len_spot_this += 1
i += 1
else: break
while j-1 >= 0:
if landing_spots[j] - landing_spots[j-1] == 1:
len_spot_this += 1
j -= 1
else: break
prize = int(2000 / len_spot_this) # Выигрыш
message = "ПОЗДРАВЛЯЕМ\n"\
+ "ЭТО БЫЛА ОТЛИЧНАЯ ПОСАДКА!\n\n"\
+ f"ПОЛУЧИТЕ ПРЕМИЮ {prize} YE\n\n"\
+ "НАЖМИТЕ ПРОБЕЛ ДЛЯ СЛЕДУЮЩЕЙ МИССИИ\n"\
+ "\nЗаправить корабль - стрелка вниз на клавиатуре."
score += prize # Счёт в игре
def draw():
"""
Создаёт игровое поле
"""
screen.fill("#000033") # Очистка экрана
pygame.mouse.set_visible(False)
if not game_on: # Вывести сообщение
screen.draw.text(message, center=(WIDTH/2, HEIGHT/5), align="center")
for step in range(0, count_seg - 1): # Нарисовать горы
x1 = seg_size * step
x2 = x1 + seg_size
y1 = mountains[step]
y2 = mountains[step + 1]
screen.draw.line((x1, y1), (x2, y2), "white")
if step in landing_spots: # Посадочные площадки
if ship[0]//seg_size in landing_spots:
screen.draw.circle((x1, mountains[step]+3), 2, 'orange')
elif landscape_blink and step%2 == 0:
screen.draw.circle((x1, mountains[step]+3), 2, 'deepskyblue')
elif not landscape_blink and step%2 != 0:
screen.draw.circle((x1, mountains[step]+4), 2, 'red')
screen.draw.circle(ship, seg_size * 2, "yellow") # Спускаемый аппарат
for alpha in (45, -45):
lx, ly = rotated(0, leg_length, ship_angle + alpha) # Координаты опор относительно центра корабля
screen.draw.line(ship, (ship[0]+lx,ship[1]+ly), "yellow") # Опоры
if engine: # Двигатель включён
fx, fy = rotated(0, seg_size * 3, ship_angle) # Координаты пламени относительно центра корабля
screen.draw.filled_circle((ship[0] + fx, ship[1] + fy), seg_size, "orange")
touch = a if (a := touch_angle) < 180 else -1 * (360 - a)
angle = a if (a := ship_angle) < 180 else -1 * (360 - a)
vx, vy = velocity
screen.draw.text(f"Топливо: {fuel}"
f" Высота: {altitude}"
f" Скорость: ({vx*2:.2f}, {vy*2:.2f})"
f" Угол: ({touch}, {angle})",
(10, HEIGHT-20), color="white",background="black")
screen.draw.text(f"Счёт: {score}",
(10, 20), color="white",background="black")
screen.draw.text(f"Время: {game_time:.1f}",
(WIDTH-100, 20), color="white",background="black")
if victory:
screen.draw.text(f"{len_spot_this} км до шахты",
center=(WIDTH/2, HEIGHT/4*3), align="center")
def update(deltatime):
global game_on, ship, engine, ship_angle, velocity, acceleration, fuel, touch_angle,\
game_time, score, fuel
if not game_on: # Игра не запущена
if keyboard.space: # Пробел
game_on = True
new_landscape() # Новый ландшафт
reset() # Восстановление параметров игры и корабля
elif keyboard.down and fuel < max_fuel: # Стрелка вниз
score -= 1 # Покупка топлива
fuel += 4 # Заправляем корабль
return
if keyboard.up and fuel > 0: # Стрелка вверх
engine = True # Включаем двигатели
fuel -= 2 # Расходуем топливо
acceleration = rotated(0, -power, ship_angle) # Получаем ускорение
else:
engine = False # Выключаем двигатели
acceleration = (0, 0) # Ускорения нет
if keyboard.right: # Стрелка вправо
ship_angle = (ship_angle - rotate_speed) % 360 # Вращаем корабль
elif keyboard.left: # Стрелка влево
ship_angle = (ship_angle + rotate_speed) % 360 # Вращаем корабль
for axis in (0, 1): # Параметры корабля по осям X, Y
velocity[axis] += gravity[axis] + acceleration[axis]
ship[axis] += velocity[axis] # Координаты корабля
touch_angle = ship_angle
game_time += deltatime
check_game_over() # Проверка и завершение игры
def blink():
global landscape_blink
landscape_blink = not landscape_blink
clock.schedule_interval(blink, 0.5)
pgzrun.go()
Лист. 1.