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.