Advertisement
DaytonaJohn

Game

Sep 18th, 2020
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.92 KB | None | 0 0
  1. from __future__ import division
  2. from collections import namedtuple
  3. import json
  4. import math
  5. from random import randint, random
  6.  
  7. from kivy import platform
  8. from kivy.app import App
  9. from kivy.base import EventLoop
  10. from kivy.clock import Clock
  11. from kivy.config import Config
  12.  
  13. Config.set('input', 'mouse', 'mouse,disable_multitouch')
  14.  
  15. from kivy.core.audio import SoundLoader
  16. from kivy.core.image import Image
  17. from kivy.core.window import Window
  18. from kivy.graphics import Mesh
  19. from kivy.graphics.instructions import RenderContext
  20. from kivy.uix.widget import Widget
  21. from kivy.utils import get_color_from_hex
  22. from kivy.core.text import LabelBase
  23. from kivy.uix.label import Label
  24.  
  25. from kivy.properties import ListProperty
  26.  
  27. from kivy.lang import Builder
  28. import kivy.uix.screenmanager
  29. from kivy.uix.screenmanager import ScreenManager, Screen
  30.  
  31. Builder.load_string("""
  32. <MenuScreen>:
  33.    BoxLayout:
  34.        Button:
  35.            text: 'Go to main screen'
  36.            on_press: root.manager.current = 'main'
  37. <MainScreen>:
  38.    # add Game widget
  39.    Game:
  40.        power: powerbar
  41.        lifes: lifesbar
  42.        id: game
  43.    BoxLayout:
  44.        Button:
  45.            text: 'Go to the second screen'
  46.            on_press: root.manager.current = 'second'
  47.            size_hint: None, None
  48.            size: self.texture_size
  49.    FloatLayout:
  50.        ShootProgressBar:
  51.            id: powerbar
  52.            pos_hint: {'x': 0.035, 'y': 0.9}
  53.            size_hint: (0.25, 0.1)
  54.            max:10
  55.        LifesProgressBar:
  56.            canvas:
  57.                Color:
  58.                    rgba: 1, 0, 0, 1
  59.            id: lifesbar
  60.            pos_hint: {'x': 0.7, 'y': 0.92}
  61.            size_hint: (0.25, 0.1)
  62.            max:3
  63.            value:3
  64.        Image:
  65.            id: ethereum
  66.            size_hint: (0.04, 0.04)
  67.            pos_hint: {'x': 0.002, 'y': 0.93}
  68.            allow_stretch: True
  69.            source: "ethereum.png"
  70.        Image:
  71.            id: lifes_img
  72.            size_hint: (0.04, 0.04)
  73.            pos_hint: {'x': 0.952, 'y': 0.93}
  74.            allow_stretch: True
  75.            source: "lifes.png"
  76.  
  77. <SecondScreen>:
  78.    BoxLayout:
  79.        Button:
  80.            text: 'Back to menu'
  81.            on_press: root.manager.current = 'menu'
  82. <ShootProgressBar@ProgressBar>:
  83.    # canvas:
  84.    #     Color:
  85.    #         rgb: 1, 1, 1
  86.    #     BorderImage:
  87.    #         border: (12, 12, 12, 12)
  88.    #         pos: self.x, self.center_y - 3
  89.    #         size: self.width, 24
  90.    #         source : 'black_bg.png'
  91.    #     BorderImage:
  92.    #         border: [int(min(self.width * (self.value / float(self.max)) if self.max else 0, 12))] * 4
  93.    #         pos: self.x, self.center_y - 12
  94.    #         size: self.width * (self.value / float(self.max)) if self.max else 0, 24
  95.    #         source : 'blue_fg.png'
  96.  
  97. <LifesProgressBar@ProgressBar>:
  98.    # canvas:
  99.    #     Color:
  100.    #         rgb: 1, 1, 1
  101.    #     BorderImage:
  102.    #         border: (12, 12, 12, 12)
  103.    #         pos: self.x, self.center_y - 14
  104.    #         size: self.width, 24
  105.    #         source: 'black_bg.png'
  106.    #     BorderImage:
  107.    #         border: [int(min(self.width * (self.value / float(self.max)) if self.max else 0, 12))] * 4
  108.    #         pos: self.x, self.center_y - 12
  109.    #         size: self.width * (self.value / float(self.max)) if self.max else 0, 24
  110.    #         source: 'green2_fg.png'
  111.  
  112. <ColourScreen>:
  113.    BoxLayout:
  114.        orientation: 'vertical'
  115.        Label:
  116.            text: 'colour {:.2},{:.2},{:.2} screen'.format(*root.colour[:3])
  117.            font_size: 30
  118.        Widget:
  119.            canvas:
  120.                Color:
  121.                    rgba: root.colour
  122.                Ellipse:
  123.                    pos: self.pos
  124.                    size: self.size
  125.        BoxLayout:
  126.            Button:
  127.                text: 'goto first screen'
  128.                font_size: 30
  129.                on_release: app.root.current = 'first'
  130.            Button:
  131.                text: 'get random colour screen'
  132.                font_size: 30
  133.                on_release: app.root.new_colour_screen()
  134. """)
  135.  
  136.  
  137. # Declare both screens
  138.  
  139. class MenuScreen(Screen):
  140.     pass
  141.  
  142.  
  143. class MainScreen(Screen):
  144.     def on_enter(self, *args):
  145.         self.ids.game.initialize()
  146.         Clock.schedule_interval(self.ids.game.update_glsl, 1.0/60.0)
  147.  
  148. UVMapping = namedtuple('UVMapping', 'u0 v0 u1 v1 su sv')
  149.  
  150. def load_atlas(atlas_name):
  151.     with open(atlas_name, 'rb') as f:
  152.         atlas = json.loads(f.read().decode('utf-8'))
  153.  
  154.     tex_name, mapping = atlas.popitem()
  155.     tex = Image(tex_name).texture
  156.     tex_width, tex_height = tex.size
  157.  
  158.     uvmap = {}
  159.     for name, val in mapping.items():
  160.         x0, y0, w, h = val
  161.         x1, y1 = x0 + w, y0 + h
  162.         uvmap[name] = UVMapping(
  163.             x0 / tex_width, 1 - y1 / tex_height,
  164.             x1 / tex_width, 1 - y0 / tex_height,
  165.             0.5 * w, 0.5 * h)
  166.  
  167.     return tex, uvmap
  168.  
  169. class PSWidget(Widget):
  170.     indices = []
  171.     vertices = []
  172.     particles = []
  173.     killall = False
  174.  
  175.     def __init__(self, **kwargs):
  176.         Widget.__init__(self, **kwargs)
  177.         self.canvas = RenderContext(use_parent_projection=True)
  178.         self.canvas.shader.source = self.glsl
  179.  
  180.         self.vfmt = (
  181.             (b'vCenter', 2, 'float'),
  182.             (b'vScale', 1, 'float'),
  183.             (b'vPosition', 2, 'float'),
  184.             (b'vTexCoords0', 2, 'float'),
  185.         )
  186.  
  187.         self.vsize = sum(attr[1] for attr in self.vfmt)
  188.  
  189.         self.texture, self.uvmap = load_atlas(self.atlas)
  190.  
  191.     def make_particles(self, Cls, num):
  192.         count = len(self.particles)
  193.         uv = self.uvmap[Cls.tex_name]
  194.  
  195.         for i in range(count, count + num):
  196.             j = 4 * i
  197.             self.indices.extend((
  198.                 j, j + 1, j + 2, j + 2, j + 3, j))
  199.  
  200.             self.vertices.extend((
  201.                 0, 0, 1, -uv.su, -uv.sv, uv.u0, uv.v1,
  202.                 0, 0, 1, uv.su, -uv.sv, uv.u1, uv.v1,
  203.                 0, 0, 1, uv.su, uv.sv, uv.u1, uv.v0,
  204.                 0, 0, 1, -uv.su, uv.sv, uv.u0, uv.v0,
  205.             ))
  206.  
  207.             p = Cls(self, i)
  208.             self.particles.append(p)
  209.  
  210.     def update_glsl(self, nap):
  211.         for p in self.particles:
  212.             if isinstance(p, Enemy) and p.active:
  213.                 if self.killall:
  214.                     p.reset()  # kill this enemy
  215.             p.advance(nap)
  216.             p.update()
  217.  
  218.         self.canvas.clear()
  219.  
  220.         with self.canvas:
  221.             Mesh(fmt=self.vfmt, mode='triangles',
  222.                  indices=self.indices, vertices=self.vertices,
  223.                  texture=self.texture)
  224.  
  225.     def ennemy_touch(self):
  226.         if math.hypot(self.parent.player_x - self.x,
  227.                       self.parent.player_y - self.y) < 60:
  228.             return True
  229.  
  230.     def ennemy_shoot(self):
  231.         for b in self.parent.bullets:
  232.             if b.active:
  233.                 if math.hypot(b.x - self.x, b.y - self.y) < 30:
  234.                     return True
  235.  
  236. # class MultiAudio:
  237. #     _next = 0
  238. #
  239. #     def __init__(self, filename, count):
  240. #         self.buf = [SoundLoader.load(filename)
  241. #                     for i in range(count)]
  242. #
  243. #     def play(self):
  244. #         self.buf[self._next].play()
  245. #         self._next = (self._next + 1) % len(self.buf)
  246. #
  247. # snd_hit = MultiAudio('hit.wav', 5)
  248. # snd_laser = MultiAudio('laser.wav', 10)
  249.  
  250. class SecondScreen(Screen):
  251.     UVMapping = namedtuple('UVMapping', 'u0 v0 u1 v1 su sv')
  252.  
  253.     def load_atlas(atlas_name):
  254.         with open(atlas_name, 'rb') as f:
  255.             atlas = json.loads(f.read().decode('utf-8'))
  256.  
  257.         tex_name, mapping = atlas.popitem()
  258.         tex = Image(tex_name).texture
  259.         tex_width, tex_height = tex.size
  260.  
  261.         uvmap = {}
  262.         for name, val in mapping.items():
  263.             x0, y0, w, h = val
  264.             x1, y1 = x0 + w, y0 + h
  265.             uvmap[name] = UVMapping(
  266.                 x0 / tex_width, 1 - y1 / tex_height,
  267.                 x1 / tex_width, 1 - y0 / tex_height,
  268.                 0.5 * w, 0.5 * h)
  269.  
  270.         return tex, uvmap
  271.  
  272. class Particle:
  273.     x = 0
  274.     y = 0
  275.     size = 1
  276.  
  277.     def __init__(self, parent, i):
  278.         self.parent = parent
  279.         self.vsize = parent.vsize
  280.         self.base_i = 4 * i * self.vsize
  281.         self.reset(created=True)
  282.  
  283.     def update(self):
  284.         for i in range(self.base_i,
  285.                        self.base_i + 4 * self.vsize,
  286.                        self.vsize):
  287.             self.parent.vertices[i:i + 3] = (
  288.                 self.x, self.y, self.size)
  289.  
  290.     def reset(self, created=False):
  291.         raise NotImplementedError()
  292.  
  293.     def advance(self, nap):
  294.         raise NotImplementedError()
  295.  
  296. class Star(Particle):
  297.     plane = 1
  298.     tex_name = 'star'
  299.  
  300.     def reset(self, created=False):
  301.         self.plane = randint(1, 3)
  302.  
  303.         if created:
  304.             self.x = random() * self.parent.width
  305.         else:
  306.             self.x = self.parent.width
  307.  
  308.         self.y = random() * self.parent.height
  309.         self.size = 0.1 * self.plane
  310.  
  311.     def advance(self, nap):
  312.         self.x -= 20 * self.plane * nap
  313.         if self.x < 0:
  314.             self.reset()
  315.  
  316. class Player(Particle):
  317.     tex_name = 'player'
  318.  
  319.     def reset(self, created=False):
  320.         self.x = self.parent.player_x
  321.         self.y = self.parent.player_y
  322.  
  323.     advance = reset
  324.  
  325. class Trail(Particle):
  326.     tex_name = 'trail'
  327.  
  328.     def reset(self, created=False):
  329.         self.x = self.parent.player_x + randint(-30, -20)
  330.         self.y = self.parent.player_y + randint(-10, 10)
  331.  
  332.         if created:
  333.             self.size = 0
  334.         else:
  335.             self.size = random() + 0.6
  336.  
  337.     def advance(self, nap):
  338.         self.size -= nap
  339.         if self.size <= 0.1:
  340.             self.reset()
  341.         else:
  342.             self.x -= 120 * nap
  343.  
  344. class Bullet(Particle):
  345.     active = False
  346.     tex_name = 'bullet'
  347.  
  348.     def reset(self, created=False):
  349.         self.active = False
  350.         self.x = -100
  351.         self.y = -100
  352.  
  353.     def advance(self, nap):
  354.         if self.active:
  355.             self.x += 250 * nap
  356.             if self.x > self.parent.width:
  357.                 self.reset()
  358.  
  359.         elif (self.parent.firing and
  360.               self.parent.fire_delay <= 0):
  361.             # snd_laser.play()
  362.  
  363.             self.active = True
  364.             self.x = self.parent.player_x + 40
  365.             self.y = self.parent.player_y
  366.             self.parent.fire_delay += 0.3333
  367.  
  368. class Enemy(Particle):
  369.     active = False
  370.     tex_name = 'ufo'
  371.     v = 0
  372.     shoot = False
  373.  
  374.     def reset(self, created=False):
  375.         self.active = False
  376.         self.x = -100
  377.         self.y = -100
  378.         self.v = 0
  379.  
  380.     def advance(self, nap):
  381.         if self.active:
  382.             if self.ennemy_touch():
  383.                 self.parent.lifes.value -= 1
  384.  
  385.             if self.ennemy_shoot():
  386.                 self.parent.power.value += 1
  387.  
  388.             if self.check_hit():
  389.                 # snd_hit.play()
  390.                 self.x = -100
  391.                 self.y = -100
  392.                 return
  393.  
  394.             self.x -= 200 * nap
  395.  
  396.             if self.x < -50:
  397.                 if self.parent.power.value == 10:
  398.                     return
  399.                 else:
  400.                     self.reset()
  401.  
  402.             self.y += self.v * nap
  403.             if self.y <= 0:
  404.                 self.v = abs(self.v)
  405.             elif self.y >= self.parent.height:
  406.                 self.v = -abs(self.v)
  407.  
  408.         elif self.parent.spawn_delay <= 0:
  409.             self.active = True
  410.             self.x = self.parent.width + 50
  411.             self.y = self.parent.height * random()
  412.             self.v = randint(-100, 100)
  413.             self.parent.spawn_delay += 1
  414.  
  415.     def check_hit(self):
  416.         if math.hypot(self.parent.player_x - self.x,
  417.                       self.parent.player_y - self.y) < 60:
  418.             return True
  419.  
  420.         for b in self.parent.bullets:
  421.             if not b.active:
  422.                 continue
  423.  
  424.             if math.hypot(b.x - self.x, b.y - self.y) < 30:
  425.                 b.reset()
  426.                 return True
  427.  
  428.     def ennemy_touch(self):
  429.         if math.hypot(self.parent.player_x - self.x,
  430.                       self.parent.player_y - self.y) < 60:
  431.             return True
  432.  
  433.     def ennemy_shoot(self):
  434.         for b in self.parent.bullets:
  435.             if b.active:
  436.                 if math.hypot(b.x - self.x, b.y - self.y) < 30:
  437.                     return True
  438.  
  439. class Game(PSWidget):
  440.     glsl = 'game.glsl'
  441.     atlas = 'game.atlas'
  442.  
  443.     firing = False
  444.     fire_delay = 0
  445.     spawn_delay = 1
  446.  
  447.     use_mouse = platform not in ('ios', 'android')
  448.  
  449.     def initialize(self):
  450.         self.player_x, self.player_y = self.center
  451.  
  452.         self.make_particles(Star, 200)
  453.         self.make_particles(Trail, 200)
  454.         self.make_particles(Player, 1)
  455.         self.make_particles(Enemy, 5)
  456.         self.make_particles(Bullet, 25)
  457.  
  458.         self.bullets = self.particles[-25:]
  459.  
  460.     def update_glsl(self, nap):
  461.         if self.use_mouse:
  462.             self.player_x, self.player_y = Window.mouse_pos
  463.  
  464.         if self.firing:
  465.             self.fire_delay -= nap
  466.  
  467.         self.spawn_delay -= nap
  468.  
  469.         PSWidget.update_glsl(self, nap)
  470.  
  471.     def on_touch_down(self, touch):
  472.         self.player_x, self.player_y = touch.pos
  473.         self.firing = True
  474.         self.fire_delay = 0
  475.  
  476.     def on_touch_move(self, touch):
  477.         self.player_x, self.player_y = touch.pos
  478.  
  479.     def on_touch_up(self, touch):
  480.         self.firing = False
  481.  
  482.  
  483. # Create the screen manager
  484. sm = ScreenManager()
  485. sm.add_widget(MenuScreen(name='menu'))
  486. sm.add_widget(MainScreen(name='main'))
  487. sm.add_widget(SecondScreen(name='second'))
  488.  
  489.  
  490. class Game1App(App):
  491.     def build(self):
  492.         EventLoop.ensure_window()
  493.         return sm
  494.  
  495.     Window.clearcolor = get_color_from_hex('111110')  # (1, 1, 1, 1)
  496.     LabelBase.register(name='Roboto',
  497.                        fn_regular='Roboto-Thin.ttf',
  498.                        fn_bold='Roboto-Medium.ttf')
  499.  
  500.  
  501. if __name__ == '__main__':
  502.     Game1App().run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement