日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Python3.7版---双人联机雷霆战机(2D特效+音效+道具+Linux系统)

發布時間:2023/12/29 linux 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python3.7版---双人联机雷霆战机(2D特效+音效+道具+Linux系统) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作品原名稱:MultiplayerGameEngine-master

作者:Tomcat(好像是這個名字沒注意…)

改良者:CSDN阿坤

Hello everyone!
Today ,I will to be give everyone show a game!(英語-2級水平)
今天為大家帶來的是一款雙人游戲并且是2D喲,并且還附帶音效道具等等,游戲環境只需要Python3以及pygame&&numpy即可完美運行,是小編從pygame上挑的一款比較不錯的游戲,初始解包后直接運行雖然各種報錯但是經過小編不辭辛苦的努力終于將其在Linux系統下完美運行!

因為是一款雙人游戲,所以游戲的主文件分為兩個 分別是Player1、Player2

由于兩者內容差不多所以呢在這里只展示Player1完整代碼:

#!/usr/bin/env python3 # -*- coding:utf-8 -*-import osfrom pygame import freetype__author__ = "Yoann Berenguer" __credits__ = ["Yoann Berenguer"] __version__ = "1.0.0" __maintainer__ = "Yoann Berenguer" __email__ = "yoyoberenguer@hotmail.com"import random import socket import _pickle as cpickle import threading import time import copyregtry:import pygame except ImportError:print("\n<Pygame> library is missing on your system.""\nTry: \n C:/pip install pygame on a window command prompt.")raise SystemExittry:import lz4.frame except ImportError:print("\n<lz4> library is missing on your system.""\nTry: \n C:/pip install lz4 on a window command prompt.")raise SystemExittry:from CreateHalo import PlayerHalofrom SoundServer import SoundControlfrom TextureTools import *from NetworkBroadcast import Broadcast, EventAttr, StaticSprite, AnimatedSprite, SoundAttr, BlendSpritefrom Explosions import Explosionfrom LayerModifiedClass import LayeredUpdatesModifiedimport GLOBALfrom GLOBAL import GLfrom ShootingStars import ShootingStarfrom AfterBurners import AfterBurnerfrom End import PlayerLostfrom PlayerScore import DisplayScorefrom CosmicDust import COSMIC_DUST_ARRAY, create_dust, display_dustfrom Gems import MakeGemsfrom LifeBar import HorizontalBarexcept ImportError:print("\nOne or more game libraries is missing on your system.""\nDownload the source code from:\n""https://blog.csdn.net/qq_43417559")raise SystemExit# socket.setdefaulttimeout(0)def unserialize_event(is_set: threading.Event) -> threading.Event:"""Set the internal flag to true. All threads waiting for it to become true are awakened.Return a threading event set to True:param is_set: threading event:return: return a threading event set to true.>>> event_ = threading.Event()>>> u_event = unserialize_event(event_)>>> assert isinstance(u_event, threading.Event)>>> event_.set()>>> event_.isSet()True>>> u_event = unserialize_event(event_)>>> u_event.isSet()True>>> event_.clear()>>> u_event = unserialize_event(event_)>>> u_event.isSet()True"""assert isinstance(is_set, threading.Event), \print("Positional argument <is_set> is type %s , expecting threading.Event." % type(is_set))event_ = threading.Event()if is_set:event_.set()return event_def serialize_event(e: threading.Event) -> tuple:""":param e: threading event:return: <function unserialize_event>, True or False>>> event_ = threading.Event()>>> s = serialize_event(event_)>>> assert isinstance(s, tuple)>>> u, v = list(s)>>> assert isinstance(u, type(unserialize_event))>>> assert v[0] == False>>> event_ = threading.Event()>>> event_.set()>>> s = serialize_event(event_)>>> assert isinstance(s, tuple)>>> u, v = list(s)>>> assert isinstance(u, type(unserialize_event))>>> assert v[0] == True"""assert isinstance(e, threading.Event), \print("Positional argument <e> is type %s , expecting threading.Event." % type(e))return unserialize_event, (e.isSet(),)copyreg.pickle(threading.Event, serialize_event)class LaserImpact(pygame.sprite.Sprite):containers = Noneimages = Nonedef __init__(self, gl_, pos_, parent_, timing_=16, blend_=None, layer_=0):"""Create an impact sprite effect (absorption effect) where the laser is colliding.:param gl_: class GL (contains all the game global variables):param pos_: tuple of the impact position (x:int, y:int):param parent_: parent object (MirroredPlayer1Class class instance):param timing_: integer; refreshing time in milliseconds (default 16ms is 60FPS):param blend_: integer; blend effect to apply to the sprite, default pygame.BLEND_RGB_ADD = 0:param layer_: integer < 0; represent the sprite layer. default = 0"""assert isinstance(pos_, tuple), \"Positional argument <pos_> is type %s , expecting tuple." % type(pos_)assert isinstance(parent_, Asteroid), \"Positional argument <parent_> is type %s , expecting class MirroredPlayer1Class instance." % type(parent_)assert isinstance(timing_, int), \"Positional argument <timing_> is type %s , expecting integer." % type(timing_)if blend_ is None:raise ValueError('Blend should not be unset!')else:assert isinstance(blend_, int), \"Positional argument <blend_> is type %s , expecting integer." % type(blend_)assert isinstance(layer_, int), \"Positional argument <layer_> is type %s , expecting integer." % type(layer_)if self.containers is None:raise ValueError('LaserImpact.containers is not initialised.\nMake sure to assign the containers to'' a pygame group prior instantiation.\ne.g: LaserImpact.containers = ''pygame.sprite.Group()')if self.images is None:raise ValueError("LaserImpact.images is not initialised.\nMake sure to assign a texture to ""prior instantiation.\ne.g: LaserImpact.images = 'P1_SURFACE'")if timing_ < 0:raise ValueError('Positional argument timing_ cannot be < 0')pygame.sprite.Sprite.__init__(self, self.containers)if isinstance(self.containers, pygame.sprite.LayeredUpdates):if layer_:self.containers.change_layer(self, layer_)assert isinstance(self.images, (list, pygame.Surface))self.image = self.images[0] if isinstance(self.images, list) else self.imagesself.rect = self.image.get_rect(center=pos_)self.timing = timing_self.dt = 0self.index = 0self.gl = gl_self.blend = blend_self.layer = layer_self.length = len(self.images) - 1self.parent_ = parent_self.surface_name = 'IMPACT_LASER'self.id_ = id(self)self.impact_object = Broadcast(self.make_object())def make_object(self) -> AnimatedSprite:"""Create an AnimatedSprite message object (see NetworkBroadcast library):return: AnimatedSprite instance"""# Only attributes self.gl.FRAME change, self.rect and self.index are changing over the time.return AnimatedSprite(frame_=self.gl.FRAME, id_=self.id_, surface_=self.surface_name,layer_=self.layer, blend_=self.blend, rect_=self.rect,index_=self.index)def update(self):if self.dt > self.timing:if self.rect.colliderect(self.gl.SCREENRECT):if isinstance(self.images, list):self.image = self.images[self.index % self.length]# follow the parent object with half of its speedself.rect.move_ip(self.parent_.speed // 2)self.index += 1if self.index > self.length:self.kill()self.dt = 0else:self.kill()if self.rect.colliderect(self.gl.SCREENRECT):self.impact_object.update({'frame': self.gl.FRAME, 'rect': self.rect, 'index': self.index})self.impact_object.queue()self.dt += self.gl.TIME_PASSED_SECONDSclass Shot(pygame.sprite.Sprite):images = Nonecontainers = Nonelast_shot = 0shooting = Falsedef __init__(self, parent_, pos_, gl_, timing_=0, layer_=-1, surface_name_=''):"""Create a sprite shoot:param parent_: parent object class Player:param pos_: tuple (x:int, y:int); sprite shoot position (start position):param gl_: Constants (class GL):param timing_: integer; sprite refreshing time FPS, e.g 16ms is 60FPS:param layer_: integer; sprite layer (default 0 top layer):param surface_name_: string; surface name e.g 'BLUE_LASER'; surface = eval(BLUE_LASER')"""assert isinstance(parent_, Player1), \"Positional argument <parent_> is type %s , expecting class MirroredPlayer1Class instance." % type(parent_)assert isinstance(pos_, tuple), \"Positional argument <pos_> is type %s , expecting tuple." % type(pos_)assert isinstance(timing_, int), \"Positional argument <timing_> is type %s , expecting integer." % type(timing_)assert isinstance(layer_, int), \"Positional argument <layer_> is type %s , expecting integer." % type(layer_)assert isinstance(surface_name_, str), \"Positional argument <surface_name_> is type %s , " \"expecting python string." % type(surface_name_)if self.containers is None:raise ValueError('Shot.containers is not initialised.\nMake sure to assign the containers to'' a pygame group prior instantiation.\ne.g: Shot.containers = pygame.sprite.Group()')if self.images is None:raise ValueError("Shot.images is not initialised.\nMake sure to assign a texture to ""prior instantiation.\ne.g: Shot.images = 'P1_SURFACE'")if timing_ < 0:raise ValueError('Positional argument timing_ cannot be < 0')self.layer = layer_pygame.sprite.Sprite.__init__(self, self.containers)if isinstance(gl_.All, pygame.sprite.LayeredUpdates):if layer_:gl_.All.change_layer(self, layer_)self.images = Shot.imagesself.image = self.images[0] if isinstance(self.images, list) else self.imagesself.speed = pygame.math.Vector2(0, -35)self.timing = timing_self.pos = pos_self.gl = gl_self.position = pygame.math.Vector2(*self.pos)self.rect = self.image.get_rect(center=self.pos)self.dt = 0self.blend = pygame.BLEND_RGBA_ADD# todo test if convert_alpha otherwise this is uselessself.mask = pygame.mask.from_surface(self.image) # Image have to be convert_alpha compatibleself.index = 0self.parent = parent_self.surface_name = surface_name_self.id_ = id(self)if Shot.shooting and self.is_reloading(self.gl.FRAME):self.kill()else:self.gl.MIXER.stop_object(id(BLUE_LASER_SOUND))self.gl.MIXER.play(sound_=BLUE_LASER_SOUND, loop_=False, priority_=0, volume_=1.0,fade_out_ms=0, panning_=True, name_='BLUE_LASER_SOUND', x_=self.rect.centerx,object_id_=id(BLUE_LASER_SOUND), screenrect_=self.gl.SCREENRECT)self.sound_object = Broadcast(self.make_sound_object('BLUE_LASER_SOUND'))self.sound_object.play()Shot.last_shot = FRAMEShot.shooting = True# Create a network object self.shot_object = Broadcast(self.make_object())self.shot_object.queue()def make_sound_object(self, sound_name_: str) -> SoundAttr:"""Create a sound object for network broadcasting.:param sound_name_: string; representing the texture to use e.g 'BLUE_LASER_SOUND":return: Sound object, SoundAttr instance."""assert isinstance(sound_name_, str), \"Positional argument <sound_name_> is type %s , expecting python string." % type(sound_name_)if sound_name_ not in globals():raise NameError('Sound %s is not define.' % sound_name_)return SoundAttr(frame_=self.gl.FRAME, id_=self.id_, sound_name_=sound_name_, rect_=self.rect)def make_object(self) -> StaticSprite:"""Create a StaticSprite message object (see NetworkBroadcast library):return: StaticSprite object"""# Only attributes self.gl.FRAME change and self.rect are changing over the time.return StaticSprite(frame_=self.gl.FRAME, id_=self.id_, surface_=self.surface_name,layer_=self.layer, blend_=self.blend, rect_=self.rect)@staticmethoddef is_reloading(frame_: int) -> bool:"""Check if the player is shooting or reloading.Compare the actual FRAME number to the latest Shot frame number.Shot.last_shot default value is set to 0 during instantiation.Reloading time is hard encoded to 10 frames interval.When the player is ready to shoot, the shooting flag is set to false, otherwise stays True:frame_: integer; must be > 0 (Actual frame number):return: True or False. True player is reloading, False player is ready to shoot>>> Shot.shooting = True>>> Shot.last_shot = 0>>> Shot.is_reloading(9)True>>> assert Shot.shooting is True>>> Shot.is_reloading(10)False>>> Shot.is_reloading(-1)Traceback (most recent call last):...ValueError: frame_ must be >= 0"""assert isinstance(frame_, int), \"argument frame_ should be integer got %s" % type(frame_)if not frame_ >= 0:raise ValueError("frame_ must be >= 0")assert hasattr(Shot, 'last_shot'), 'Class Shot is missing attribute <last_shot>.'assert hasattr(Shot, 'shooting'), 'Class Shot is missing attribute <shooting>.'assert isinstance(Shot.last_shot, int), \"last_shot variable should be integer got %s" % type(Shot.last_shot)assert frame_ >= Shot.last_shot, \"Game constant frame_ value:%s should be > or equal to %s " % (frame_, Shot.last_shot)if frame_ - Shot.last_shot < 10:# still reloadingreturn Trueelse:# ready to shootShot.shooting = Falsereturn Falsedef collide(self, rect_: pygame.Rect, object_) -> None:"""Create a laser impact sprite:param rect_: pygqme.Rect object:param object_: object colliding with the rectangle:return: None"""assert isinstance(rect_, pygame.Rect), \'Positional argument rect_ should be a <pygame.Rect> type got %s ' % type(rect_)assert object_ is not None, 'Positional argument object_ cannot be None'# if sprite belongs to any group(s)if self.alive():LaserImpact.containers = self.gl.AllLaserImpact.images = IMPACT_LASERLaserImpact(gl_=self.gl, pos_=rect_.topleft, parent_=object_,timing_=self.timing, blend_=pygame.BLEND_RGBA_ADD, layer_=0)self.kill()def update(self) -> None:"""Update shot sprites whereabouts.sprite position is given by its rectangle.The position changed by incrementing the position with its speed vector (self.speed)if the sprite belongs to the screen dimensions, a message is broadcast to the client:return: None"""if self.dt > self.timing:if self.gl.SCREENRECT.colliderect(self.rect):# Move the laser spriteif self.images != IMPACT_LASER:self.position += self.speedself.rect.center = (self.position.x, self.position.y)self.dt = 0 else:self.kill()# broadcast network messageif self.rect.colliderect(self.gl.SCREENRECT):self.shot_object.update({'frame': self.gl.FRAME, 'rect': self.rect})self.shot_object.queue()self.dt += self.gl.TIME_PASSED_SECONDSclass Player1(pygame.sprite.Sprite):containers = Noneimage = Nonedef __init__(self, gl_, timing_=15, pos_: tuple = (0, 0), layer_=0):""":param gl_: Game constants (GL class) see GLOBAL library for more details:param timing_: integer; default 15ms (60 FPS):param pos_: tuple; (x:int, y:int) representing player 1 position (default x=0, y=0):param layer_: Sprite layer used by player 1"""assert isinstance(timing_, int), \"Positional argument <timing_> is type %s , expecting integer." % type(timing_)assert isinstance(pos_, tuple), \"Positional argument <pos_> is type %s , expecting tuple." % type(pos_)assert isinstance(layer_, int), \"Positional argument <layer_> is type %s , expecting integer." % type(layer_)if self.containers is None:raise ValueError('MirroredPlayer1Class.containers is not initialised.\nMake sure to assign the containers to'' a pygame group prior instantiation.\ne.g: MirroredPlayer1Class.containers = pygame.sprite.Group()')if self.image is None:raise ValueError("MirroredPlayer1Class.image is not initialised.\nMake sure to assign a texture to ""prior instantiation.\ne.g: MirroredPlayer1Class.image = 'P1_SURFACE'")pygame.sprite.Sprite.__init__(self, self.containers)assert isinstance(Player1.image, (pygame.Surface, list)), \"image is not a pygame.Surface or a list, got %s instead" % type(Player1.image)if timing_ < 0:raise ValueError('Positional argument timing_ cannot be < 0')self.image = Player1.imageself.image_copy = self.image.copy()self.rect = self.image.get_rect(center=pos_)self.timing = timing_self.surface_name = 'P1_SURFACE'self.gl = gl_self.dt = 0self.speed = 300self.layer = layer_self.blend = 0self.shooting = Falseself.previous_pos = pygame.math.Vector2() # previous positionself.life = 200 # player's lifeself.max_life = 200 # maximum lifeself.eng_right = self.right_engine() # instance for right engineself.eng_left = self.left_engine() # isntance for left engine# todo test if convert_alpha otherwise this is uselessself.mask = pygame.mask.from_surface(self.image) # Image have to be convert_alpha compatibleself.damage = 800 # -> gives 800 hit point of damage after collisionself.id_ = id(self)self.player_object = Broadcast(self.make_object())self.impact_sound_object = Broadcast(self.make_sound_object('IMPACT'))self.update_score = self.gl.P1_SCORE.score_updatedef make_sound_object(self, sound_name_: str) -> SoundAttr:"""Create a sound object for network broadcasting.:param sound_name_: string; representing the texture to use e.g 'BLUE_LASER_SOUND":return: Sound object, SoundAttr instance."""assert isinstance(sound_name_, str), \'Positional argument sound_name_ is not a string type, got %s ' % type(sound_name_)if sound_name_ not in globals():raise NameError('Sound %s is not define.' % sound_name_)return SoundAttr(frame_=self.gl.FRAME, id_=self.id_, sound_name_=sound_name_, rect_=self.rect)def make_object(self) -> StaticSprite:"""Create a sprite object for network broadcast similar to MirroredPlayer1Class:return: StaticSprite object (see NetworkBroadcast library for more details)"""# Only attributes self.gl.FRAME, self.rect are changing over the time.return StaticSprite(frame_=self.gl.FRAME, id_=self.id_, surface_=self.surface_name,layer_=self.layer, blend_=self.blend, rect_=self.rect, life=self.life, damage=self.damage)def player_lost(self):PlayerLost.containers = self.gl.AllPlayerLost.DIALOGBOX_READOUT_RED = DIALOGBOX_READOUT_REDPlayerLost.SKULL = SKULLfont = freetype.Font('/home/student/桌面/MultiplayerGameEngine-master/Assets/Fonts/Gtek Technology.ttf', size=14)PlayerLost(gl_=self.gl, font_=font, image_=FINAL_MISSION, layer_=0)def explode(self) -> None:"""Player explosion sprites and halo:return: None"""if self.alive():Explosion.images = EXPLOSION2Explosion(self, self.rect.center,self.gl, self.timing, self.layer, texture_name_='EXPLOSION2')PlayerHalo.images = HALO_SPRITE13PlayerHalo.containers = self.gl.AllPlayerHalo(texture_name_='HALO_SPRITE13', object_=self, timing_=10)self.player_lost()self.kill()def collide(self, damage_: int) -> None:"""MirroredPlayer1Class collide with object, transfer the damage and play the collision sound locallyif life < 1, trigger player1 explosion.:param damage_: integer; must be > 0 (total damage transferred to the player after collision.):return: None"""assert isinstance(damage_, int), \'Positional argument damage_ is not an int, got %s instead.' % type(damage_)assert damage_ > 0, 'damage_ argument should be > 0 'print(self.life, damage_, self.life - damage_)if self.alive():self.life -= damage_self.gl.MIXER.play(sound_=IMPACT, loop_=False, priority_=0,volume_=1.0, fade_out_ms=0, panning_=True,name_='IMPACT', x_=self.rect.centerx,object_id_=id(IMPACT),screenrect_=self.gl.SCREENRECT) self.impact_sound_object.play()"""def hit(self, damage_: int) -> None:#Transfer damage to the player after being hit.#:param damage_: integer > 0, damage transfer to the player#:return: Noneassert isinstance(damage_, int), \'Positional argument damage_ is not an int, got %s instead.' % type(damage_)assert damage_ > 0, 'damage_ argument should be > 0 'if self.alive():self.life -= damage_"""def left_engine(self) -> AfterBurner:"""Create a sprite for the left engine:return: AfterBurner instance"""if EXHAUST:AfterBurner.images = EXHAUSTelse:raise NameError('EXHAUST is not defined.')return AfterBurner(self, self.gl, (-22, 38),self.timing, pygame.BLEND_RGB_ADD, self.layer - 1, texture_name_='EXHAUST')def right_engine(self) -> AfterBurner:"""Create a sprite for the right engine:return: AfterBurner instance"""if EXHAUST:AfterBurner.images = EXHAUSTelse:raise NameError('EXHAUST is not defined.')return AfterBurner(self, self.gl, (22, 38),self.timing, pygame.BLEND_RGB_ADD, self.layer - 1, texture_name_='EXHAUST')def get_centre(self) -> tuple:"""Get MirroredPlayer1Class position.:return: tuple representing MirroredPlayer1Class rect centre"""return self.rect.centerdef disruption(self) -> None:"""Create an electric effect on MirroredPlayer1Class hull.:return: None"""if 'DISRUPTION' in globals():if isinstance(DISRUPTION, list):index = (FRAME >> 1) % len(DISRUPTION) - 1else:raise ValueError('DISRUPTION is not a list, got %s instead.' % type(DISRUPTION))else:raise NameError('DISRUPTION is not defined.')self.image.blit(DISRUPTION[index], (-20, -20), special_flags=pygame.BLEND_RGB_ADD)# self.disruption_object.update({'frame': self.gl.FRAME, 'surface': 'DISRUPTION',# 'rect': self.rect, 'index': index})# self.disruption_object.show(self.disruption_object)# self.disruption_object.queue()def shooting_effect(self) -> pygame.Surface:"""Apply a special effect on the aircraft hull when firing.:return: pygame.Surface"""if 'GRID' in globals():self.image.blit(GRID, (0, 0), special_flags=pygame.BLEND_RGB_ADD)else:raise NameError('GRID is not defined.')return self.imagedef update(self) -> None:"""Update MirroredPlayer1Class sprite:return: None"""self.rect.clamp_ip(self.gl.SCREENRECT)if self.dt > self.timing:self.image = self.image_copy.copy()if self.life < 1:self.explode()if self.gl.KEYS[pygame.K_UP]:self.rect.move_ip(0, -self.speed * self.gl.SPEED_FACTOR)if self.gl.KEYS[pygame.K_DOWN]:self.rect.move_ip(0, +self.speed * self.gl.SPEED_FACTOR)if self.gl.KEYS[pygame.K_LEFT]:self.rect.move_ip(-self.speed * self.gl.SPEED_FACTOR, 0)if self.gl.KEYS[pygame.K_RIGHT]:self.rect.move_ip(+self.speed * self.gl.SPEED_FACTOR, 0)# if self.gl.JOYSTICK is not None and self.gl.JOYSTICK.PRESENT:# x, y = self.gl.JOYSTICK.axes_status[0]if self.gl.KEYS[pygame.K_SPACE]:self.shooting_effect()Shot(self, self.rect.center, self.gl, 0, self.layer - 1, surface_name_='BLUE_LASER')if joystick is not None:self.rect.move_ip(JL3.x * self.gl.SPEED_FACTOR * self.speed,JL3.y * self.gl.SPEED_FACTOR * self.speed)if self.alive():# Broadcast the spaceship position every framesself.player_object.update({'frame': self.gl.FRAME,'rect': self.rect,'life': self.life})self.player_object.queue()if self.previous_pos == self.rect.center:self.rect.centerx += random.randint(-1, 1)self.rect.centery += random.randint(-1, 1)self.previous_pos = self.rect.center# !UPDATE the <follower> sprites with the new player position.self.eng_left.update()self.eng_right.update()else:self.dt += self.gl.TIME_PASSED_SECONDSself.disruption()class MirroredPlayer2Class(pygame.sprite.Sprite):def __init__(self, sprite_):"""Create an instance of Player2 on the server:param sprite_: object containing all attributes>>> import pygame>>> pygame.init()(8, 0)>>> SCREENRECT = pygame.Rect(0, 0, 800, 1024)>>> screen = pygame.display.set_mode(SCREENRECT.size, pygame.HWSURFACE, 32)>>> from Textures import P1_SURFACE, DISRUPTION>>> attributes = {'rect': pygame.Rect(0, 0, 0, 0),... 'image':eval('P1_SURFACE'), 'blend':0, 'layer':-1, 'id_':35555,... 'frame':0, 'damage': 800, 'life': 200, 'surface':'P1_SURFACE'}>>> sprite_ = pygame.sprite.Sprite()>>> for attr, value in attributes.items():... setattr(sprite_, attr, value)>>> spr = MirroredPlayer2Class(sprite_)>>> print(spr.surface)P1_SURFACE"""assert sprite_ is not None, 'Positional argument sprite_ is None.'attributes = ['rect', 'image', 'blend', 'layer', 'id_', 'frame', 'damage', 'life', 'surface']for attr in attributes:assert hasattr(sprite_, attr),\'Positional argument sprite_ is missing attribute %s ' % attrpygame.sprite.Sprite.__init__(self)self.rect = sprite_.rectself.image = sprite_.imageself.image_copy = sprite_.image.copy()self.blend = sprite_.blendself.layer = sprite_.layerself.id_ = sprite_.id_self.frame = sprite_.frameself.surface = sprite_.surfaceself.damage = sprite_.damageself.gl = GLdef disruption(self) -> None:if globals().__contains__('FRAME') and globals().__contains__('DISRUPTION'):index = (FRAME >> 1) % len(DISRUPTION) - 1self.image.blit(DISRUPTION[index], (-20, -20), special_flags=pygame.BLEND_RGB_ADD)def update(self) -> None:if self.image is None:raise ValueError('Cannot copy() NoneType.')self.image = self.image_copy.copy()self.disruption()class P2Shot(pygame.sprite.Sprite):def __init__(self, gl_, sprite_, timing_=0):""":param gl_: class GL (Constants):param sprite_: object containing all the original sprite attributes:param timing_: integer > 0 representing the refreshing time."""assert isinstance(gl_, type(GL)), \"Positional argument <gl_> is type %s , expecting class GL instance." % type(gl_)assert sprite_ is not None, 'Positional argument sprite_ is None.'attributes = ['rect', 'image', 'blend', 'layer', 'id_', 'surface']for attr in attributes:assert hasattr(sprite_, attr), \'Positional argument sprite_ is missing attribute %s ' % attrif timing_ < 0:raise ValueError('argument timing_ must be > 0')pygame.sprite.Sprite.__init__(self)self.rect = sprite_.rectself.image = sprite_.imageself.blend = sprite_.blendself.layer = sprite_.layerself.id_ = sprite_.id_self.surface = sprite_.surfaceself.gl = gl_self.timing = timing_def collide(self, rect_, object_) -> None:""":param rect_: pygame.Rect type:param object_::return:"""if hasattr(GL, 'All'):LaserImpact.containers = GL.Allelse:raise AttributeError('Class GL missing attribute All.')if IMPACT_LASER:LaserImpact.images = IMPACT_LASERelse:raise NameError('IMPACT_LASER is not define.')LaserImpact(gl_=self.gl, pos_=rect_.topleft, parent_=object_,timing_=self.timing, blend_=pygame.BLEND_RGBA_ADD, layer_=0)def update(self) -> None:...class SpriteServer(threading.Thread):def __init__(self,gl_, # Global variables classhost_: str, # host address (string)port_: int, # port value (integer)):""":param gl_: class GL:param host_: string; ip address:param port_: integer; port to use"""assert isinstance(host_, str), \"Positional argument <host_> is type %s , expecting string." % type(host_)assert isinstance(port_, int), \"Positional argument <port_> is type %s , expecting integer" % type(port_)threading.Thread.__init__(self)self.gl = gl_self.gl.SPRITE_SERVER_STOP = Falsetry:self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)except socket.error as error:print('\n[-]SpriteServer - ERROR : %s %s' % (error, time.ctime()))gl_.P1CS_STOP = Trueself.gl.SPRITE_SERVER_STOP = Truetry:self.sock.bind((host_, port_))self.sock.listen(1)except socket.error as error:print('\n[-]SpriteServer - ERROR : %s %s' % (error, time.ctime()))gl_.P1CS_STOP = Trueself.gl.SPRITE_SERVER_STOP = Trueself.buf = self.gl.BUFFERself.total_bytes = 0self.view = memoryview(bytearray(self.buf))def run(self):# Accept a connection. The socket must be bound to# an address and listening for connections.# The return value is a pair (conn, address) where# conn is a new socket object usable to send and receive# data on the connection, and address is the address# bound to the socket on the other end of the connection.connection = Nonetry:# The thread will be stopped here until first connectionconnection, client_address = self.sock.accept()except socket.error as error:print("\n[-]SpriteServer - Lost connection with Player 2 ...")print("\n[-]SpriteServer - ERROR %s %s" % (error, time.ctime()))self.gl.P1CS_STOP = Truewhile not self.gl.P1CS_STOP and not self.gl.SPRITE_SERVER_STOP:# try:while not self.gl.P1CS_STOP and not self.gl.SPRITE_SERVER_STOP:# Receive data from the socket, writing it into buffer instead# of creating a new string. The return value is a pair (nbytes, address)# where nbytes is the number of bytes received and address is the address# of the socket sending the data.try:nbytes, sender = connection.recvfrom_into(self.view, self.buf)except socket.error as error:print("\n[-]SpriteServer - Lost connection with Player 2 ...")print("\n[-]SpriteServer - ERROR %s %s" % (error, time.ctime()))# signal to kill both threads SpriteServer and SpriteClient# todo : Player 2 is now deconnected from the server and should not be# display on the server display, create a method to kill the sprite of Player 2self.gl.SPRITE_SERVER_STOP = Truenbytes = 0buffer = self.view.tobytes()[:nbytes]try:connection.sendall(self.view.tobytes()[:nbytes])except ConnectionResetError as error:print("\n[-]SpriteServer - Lost connection with Player 2 ...")print("\n[-]SpriteServer - ERROR %s %s" % (error, time.ctime()))# todo : Player 2 is now deconnected from the server and should not be# display on the server display, create a method to kill the sprite of Player 2# signal to kill both threads SpriteServer and SpriteClientself.gl.SPRITE_SERVER_STOP = Truetry:# Decompress the data framedecompress_data = lz4.frame.decompress(buffer)data = cpickle.loads(decompress_data)except Exception:# The decompression error can also happen when# the bytes stream sent is larger than the buffer size.# todo : Player 2 is now deconnected from the server and should not be# display on the server display, create a method to kill the sprite of Player 2# signal to kill both threads SpriteServer and SpriteClientself.gl.SPRITE_SERVER_STOP = Trueself.gl.SPRITE_CLIENT_STOP = Truedata = None# todo check if self.gl.NetGroupAll.empty() is faster# self.gl.NetGroupAll = LayeredUpdatesModified()data_set = set()if isinstance(data, list):for sprite_ in data:# print(GL.FRAME, sprite_.id_, sprite_.surface if hasattr(sprite_, "surface") else None)if hasattr(sprite_, 'event'):continueelif hasattr(sprite_, 'sound_name'):try:sound = eval(sprite_.sound_name)except NameError:raise NameError("\n[-]SpriteServer - Sound effect ""'%s' does not exist " % sprite_.sound_name)# self.gl.MIXER.stop_object(id(sound))# play the sound locallyself.gl.MIXER.play(sound_=sound, loop_=False, priority_=0,volume_=1.0, fade_out_ms=0, panning_=True,name_=sprite_.sound_name, x_=sprite_.rect.centerx,object_id_=id(sound),screenrect_=self.gl.SCREENRECT)# data.remove(sprite_)else:assert hasattr(sprite_, 'surface'), "\nBroadcast message is missing <surface> attribute."try:sprite_.image = eval(sprite_.surface) # load surfaceexcept (NameError, AttributeError):raise RuntimeError("\n[-]SpriteServer - Surface ""'%s' does not exist " % sprite_.surface)if isinstance(sprite_.image, list):sprite_.image = sprite_.image[sprite_.index % len(sprite_.image) - 1]# --- Apply transformation ---# Apply transformation to texture rotation/scale and# store the transformation inside a buffer# Check if the texture has been already transformed and use# the buffer transformation instead (for best performance).if hasattr(sprite_, 'rotation'):if sprite_.rotation is not None and sprite_.rotation != 0:if sprite_.id_ in self.gl.XTRANS_ROTATION.keys():sprite_.image = self.gl.XTRANS_ROTATION[sprite_.id_]else:sprite_.image = pygame.transform.rotate(sprite_.image, sprite_.rotation)self.gl.XTRANS_ROTATION.update({sprite_.id_: sprite_.image})if hasattr(sprite_, 'scale'):if sprite_.scale != 1:if sprite_.id_ in self.gl.XTRANS_SCALE.keys():sprite_.image = self.gl.XTRANS_SCALE[sprite_.id_]else:sprite_.image = pygame.transform.scale(sprite_.image, (int(sprite_.image.get_size()[0] * sprite_.scale),int(sprite_.image.get_size()[1] * sprite_.scale)))self.gl.XTRANS_SCALE.update({sprite_.id_: sprite_.image})s = None# find Player 2if sprite_.surface == 'P2_SURFACE':s = MirroredPlayer2Class(sprite_)# find player 2 shotselif sprite_.surface == "RED_LASER":s = P2Shot(self.gl, sprite_, 16)# generic sprite that doesn't have# to be instantiated with specific methodselse:# Generic sprite (without methods)s = pygame.sprite.Sprite()s.frame = sprite_.frames.rect = sprite_.rects.surface = sprite_.surfaces.image = sprite_.images.blend = sprite_.blends.layer = sprite_.layers.id_ = sprite_.id_if hasattr(sprite_, 'life'):s.life = sprite_.lifeif hasattr(sprite_, 'damage'):s.damage = sprite_.damage# Add broadcast sprites to DATA_SET (reset every time a message from client is received).# DATA_SET contains all sprites sent by the client for a specific frame number.# The DATA_SET cannot contains duplicates. The id attribute (memory location)# is used as unique identification number to store sprites in the DATA_SET.# The element in data set represent all active (alive) sprites display on the# client side (before client collision detection).data_set.add(sprite_.id_)# Add the sprite in self.gl.NetGroupAll (if not already in the group) or# update position and texture.# NetGroupAll, will be used in the main loop (locally) to display# all the sprites broadcast from a specific frame number.# If a sprite is not added to that group, it will be ignored# and not display on the client side.if s is not None and len(self.gl.NetGroupAll) > 0:has_ = Falsefor sprites in self.gl.NetGroupAll:if sprites.id_ == s.id_:has_ = Truesprites.rect = s.rectsprites.image = sprite_.imagesprites.frame = sprite_.framebreakif not has_:self.gl.NetGroupAll.add(s)else:self.gl.NetGroupAll.add(s)# Compare NetGroupAll group to DATA_SET and delete sprite(s)# accordingly. Sprites in NetGroupAll and not in DATA_SET will# be killed and remove from every groups they are belonging to.# When a sprite is deleted, the transformation/scale buffer associated# to it will be deleted (using its id).for spr_ in self.gl.NetGroupAll:if spr_.id_ not in data_set:spr_.kill()if spr_.id_ in self.gl.XTRANS_SCALE.keys():self.gl.XTRANS_SCALE.pop(spr_.id_)if spr_.id_ in self.gl.XTRANS_ROTATION.keys():self.gl.XTRANS_ROTATION.pop(spr_.id_)# Reload original texture# for pair in modified_surface.items():# globals()[pair[0]] = pair[1]buffer = b''# data fully received breaking the loop, clear the bufferbreak# pygame.time.wait(1)"""except Exception as error:print('\n[-]SpriteServer - ERROR @ frame: %s : %s %s' % (FRAME, error, time.ctime()))finally:# Clean up the connectionif 'connection' in globals() and connection is not None:connection.close()"""print('\n[-]SpriteServer is now terminated...')def force_quit(host_: str, port_: int) -> None:"""function used for terminating SERVER/ CLIENT threads listening (blocking socket):param host_: string; ip address:param port_: integer; port to use:return: None"""assert isinstance(host_, str), \"Positional argument <host_> is type %s , expecting string." % type(host_)assert isinstance(port_, int), \"Positional argument <port_> is type %s , expecting integer." % type(port_)# todo create assert ( port should be > 1024)sock = Nonetry:sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect((host_, port_))data = cpickle.dumps(b"QUIT")sock.sendall(data)print("\n[+]Termination signal sent to SpriteServer...")except Exception as error:print("\n[-]Cannot send termination signal to SpriteServer...")print("\n[-]ERROR %s " % error)finally:if 'sock' in globals() and isinstance(sock, socket.socket):sock.close()def collision_detection():p2_shots = pygame.sprite.Group()p2 = Nonefor sprite_ in GL.NetGroupAll:# detect player spriteif hasattr(sprite_, 'surface'):if sprite_.surface == "P2_SURFACE":p2 = sprite_continue# detect player 2 shots and add them to a specific# group p2_shots. p2_shots has to be destroyed before# leaving the function.elif sprite_.surface == "RED_LASER":p2_shots.add(sprite_)if P1 is not None and P1.alive():# Player 1 collision with asteroid# Use collision mask for collision detection# It is compulsory to have sprite textures with alpha transparency information# in order to check for collision otherwise the collision will be ignored.collision = pygame.sprite.spritecollideany(P1, GL.ASTEROID, collided=pygame.sprite.collide_mask)if collision is not None:P1.collide(collision.damage)if hasattr(collision, 'collide'):collision.collide(P1, P1.damage)else:print(type(collision))raise AttributeError# Player 1 shots collision with asteroids# same than abovefor shots, asteroids in pygame.sprite.groupcollide(GL.PLAYER_SHOTS, GL.ASTEROID, 0, 0, collided=pygame.sprite.collide_mask).items():if asteroids is not None:for aster in asteroids:if hasattr(aster, 'hit'):aster.hit(P1, 100)new_rect = shots.rect.clamp(aster.rect) # todo need to make sure shots is not a listshots.collide(rect_=new_rect, object_=aster)else:print(type(aster))raise AttributeError# Player 2 shots colliding with asteroidif p2 is not None and p2.alive():for shots, asteroids in pygame.sprite.groupcollide(p2_shots, GL.ASTEROID, 0, 0).items(): # ,collided=pygame.sprite.collide_mask).items():if asteroids is not None:for aster in asteroids:if hasattr(aster, 'hit'):aster.hit(None, 100)new_rect = shots.rect.clamp(aster.rect) # todo need to make sure shots is not a listshots.collide(rect_=new_rect, object_=aster)else:print(type(aster))raise AttributeErrorfor spr in GL.NetGroupAll:if spr.id_ == shots.id_:spr.kill()# Use collision mask for collision detection# Check collision between Player 2 and asteroidsif p2 is not None and p2.alive():collision = pygame.sprite.spritecollideany(p2, GL.ASTEROID, collided=pygame.sprite.collide_mask)if collision is not None:# Cannot send damage to player 2, this# is done on the remote host in the collision detection section# Pass only damage to the asteroidcollision.collide(p2.damage)# MirroredTransportClass collision with asteroidif T1 is not None and T1.alive():# todo check collision maskscollision = pygame.sprite.spritecollideany(T1, GL.ASTEROID, collided=pygame.sprite.collide_mask)if collision is not None:T1.collide(collision.damage)if hasattr(collision, 'collide'):collision.collide(T1, T1.damage)else:print(type(collision))raise AttributeErrorp2_shots.remove()p2_shots.empty()del p2_shotsdef window():scrw_half = SCREENRECT.w >> 1scrh_half = SCREENRECT.h >> 1w, h = FRAMEBORDER.get_size()screen.blit(BACKGROUND, (0, 0))screen.blit(FRAMEBORDER, (scrw_half - (w >> 1), scrh_half - (h >> 1)))font = freetype.Font(os.path.join('Assets/Fonts/', 'ARCADE_R.TTF'), size=15)frame_ = FRAME.copy()rect = font.get_rect("Waiting for connection...")font.render_to(frame_, ((frame_.get_width() - rect.w) // 2,(frame_.get_height() - rect.h) // 2),"Waiting for connection...",fgcolor=pygame.Color(255, 255, 255), size=15)screen.blit(frame_, (scrw_half - (w >> 1) + 20, scrh_half - (h >> 1) + 40))clock = pygame.time.Clock()frame = 0while GL.CONNECTION is False:screen.blit(BACKGROUND, (0, 0))pygame.event.pump()Square()GL.All.update()GL.All.draw(screen)screen.blit(frame_, (scrw_half - (w >> 1) + 20, scrh_half - (h >> 1) + 40))GL.TIME_PASSED_SECONDS = clock.tick(70)frame += 1pygame.display.flip()"""frame = 0frame_ = FRAME.copy()for s, t in GL.CLIENTS.items():font.render_to(frame_, ((frame_.get_width() - rect.w) // 2,(frame_.get_height() - rect.h) // 2),'Client connected : ' + str(s) + ':' + str(t),fgcolor=pygame.Color(255, 255, 255), size=15)while 1:pygame.event.pump()screen.blit(BACKGROUND, (0, 0))screen.blit(frame_, (scrw_half - (w >> 1) + 20, scrh_half - (h >> 1) + 40))GL.TIME_PASSED_SECONDS = clock.tick(70)frame += 1pygame.display.flip()..."""class Square(pygame.sprite.Sprite):def __init__(self):self.layer = -1pygame.sprite.Sprite.__init__(self, GL.All)if isinstance(GL.All, pygame.sprite.LayeredUpdates):if self.layer:GL.All.change_layer(self, self.layer)self.image = pygame.Surface((randint(200, 500), randint(200, 500)))self.image.fill((10, 15, 25, 15))self.image.convert(32, pygame.RLEACCEL)self.rect = self.image.get_rect(center=(randint(0, SCREENRECT.w),randint(0, SCREENRECT.h)))self.dt = 0self.blend = pygame.BLEND_RGBA_ADDself.i = 128def update(self):self.image.set_alpha(self.i)self.i -= 10if self.i < 0:self.kill()if __name__ == '__main__':RECT = pygame.sprite.Group()import doctestdoctest.testmod()SERVER = '127.0.0.1'CLIENT = '127.0.0.1'# SERVER = '192.168.0.1'# CLIENT = '192.168.0.4'SCREENRECT = pygame.Rect(0, 0, 800, 1024)GL.SCREENRECT = SCREENRECTscreen = pygame.display.set_mode(SCREENRECT.size, pygame.HWSURFACE, 32)GL.SCREEN = screenpygame.display.set_caption('PLAYER 1')# *********************************************************************# JOYSTICK joystick_count = pygame.joystick.get_count()if joystick_count > 0:joystick = pygame.joystick.Joystick(0)joystick.init()else:joystick = NoneGL.JOYSTICK = joystickfrom Textures import *from Sounds import BLUE_LASER_SOUND, RED_LASER_SOUND, EXPLOSION_SOUND, IMPACT, IMPACT1from Backgrounds import Backgroundfrom Asteroids import Asteroidfrom MessageSender import SpriteClientfrom Transports import Transport# background vectorvector1 = pygame.math.Vector2(x=0, y=0)vector2 = pygame.math.Vector2(x=0, y=-1024)# ********************************************************************# NETWORK SERVER / CLIENT# SpriteServer -> receive client(s) positions# 1) Start the Server to receive client(s) position(s)# If no connection is made, the thread will remains listening/running# in the background, except if an error is raised.server = SpriteServer(GL, SERVER, 1025)server.start()# SpriteClient -> forward all sprites positions# 2) Start the Client to send all sprites positions to client(s)client = SpriteClient(gl_=GL, host_=CLIENT, port_=1024)client.start()# Killing threads if no client connectedif not client.is_alive() or GL.CONNECTION is False:print('No player detected')GL.SPRITE_CLIENT_STOP = TrueGL.SPRITE_SERVER_STOP = Trueforce_quit(SERVER, 1025)window()# *********************************************************************GL.All = LayeredUpdatesModified()GL.ASTEROID = pygame.sprite.Group()GL.PLAYER_SHOTS = pygame.sprite.Group()GL.TRANSPORT = pygame.sprite.GroupSingle()Player1.image = P1_SURFACEPlayer1.containers = GL.AllShot.images = BLUE_LASERShot.containers = GL.All, GL.PLAYER_SHOTSExplosion.containers = GL.AllBackground.containers = GL.AllAfterBurner.containers = GL.AllAsteroid.containers = GL.All, GL.ASTEROIDAsteroid.image = DEIMOSTransport.image = TRANSPORTTransport.containers = GL.All, GL.TRANSPORTBackground.image = BACK1_SBackground(vector_=pygame.math.Vector2(0, 1), position_=vector2, gl_=GL, layer_=-2, event_name_='BACK1_S')Background.image = BACK2_SBackground(vector_=pygame.math.Vector2(0, 1), position_=vector1, gl_=GL, layer_=-2, event_name_='BACK2_S')Background.image = CL1Background(vector_=pygame.math.Vector2(0, 2.5),position_=pygame.math.Vector2(x=0, y=-480),gl_=GL, layer_=-2, blend_=pygame.BLEND_RGB_ADD, event_name_='CL1')Background.image = CL2Background(vector_=pygame.math.Vector2(0, 2.5),position_=pygame.math.Vector2(x=randint(0, 800), y=200),gl_=GL, layer_=-2, blend_=pygame.BLEND_RGB_ADD, event_name_='CL2')ShootingStar.containers = GL.AllShootingStar.image = SHOOTING_STARDisplayScore.containers = GL.AllDisplayScore.images = pygame.Surface((10, 10))GL.P1_SCORE = DisplayScore(gl_=GL, timing_=15)MakeGems.containers = GL.AllP1 = Player1(GL, 15, (screen.get_size()[0] // 2, screen.get_size()[1] // 2))# P1 = NoneT1 = Transport(gl_=GL, timing_=15,pos_=(SCREENRECT.w >> 1,(SCREENRECT.h >> 1) - 100), surface_name_='TRANSPORT', layer_=0)life_bar = HorizontalBar(start_color=pygame.Color(0, 7, 255, 0),end_color=pygame.Color(120, 255, 255, 0),max_=P1.max_life, min_=0,value_=P1.life,start_color_vector=(0, 1, 0), end_color_vector=(0, 0, 0), alpha=False, height=32, xx=200,scan=True)transport_life_bar = HorizontalBar(start_color=pygame.Color(255, 7, 15, 0),end_color=pygame.Color(12, 12, 255, 0),max_=T1.max_life, min_=0,value_=T1.life,start_color_vector=(0, 1, 0), end_color_vector=(0, 0, 0), alpha=False, height=32,xx=200,scan=True)GL.TIME_PASSED_SECONDS = 0clock = pygame.time.Clock()GL.STOP_GAME = FalseFRAME = 0GL.FRAME = 0GL.MIXER = SoundControl(30)f = open('P1_log.txt', 'w')while not GL.STOP_GAME:pygame.event.pump()# print('Server frame # %s vector1 %s vector2 %s' % (FRAME, vector1, vector2))# Send an event to the client triggering the next frameGL.NEXT_FRAME.set() # set the eventevent_obj = EventAttr(event_=GL.NEXT_FRAME, frame_=GL.FRAME)Broadcast(event_obj).next_frame()# Create cosmic dustif GL.FRAME % 10 == 0:if len(COSMIC_DUST_ARRAY) < 15:create_dust(GL)if len(GL.ASTEROID) < 15:asteroid = random.choices(['DEIMOS', 'EPIMET'])[0]scale = random.uniform(0.1, 0.5)rotation = random.randint(0, 360)Asteroid.image = pygame.transform.rotozoom(eval(asteroid).copy(), rotation, scale)GL.ASTEROID.add(Asteroid(asteroid_name_=asteroid,gl_=GL, blend_=0, rotation_=rotation,scale_=scale, timing_=16, layer_=-2))if joystick is not None:JL3 = pygame.math.Vector2(joystick.get_axis(0), joystick.get_axis(1))for event in pygame.event.get():keys = pygame.key.get_pressed()GL.KEYS = keysif event.type == pygame.QUIT:print('Quitting')GL.STOP_GAME = Trueif keys[pygame.K_ESCAPE]:GL.STOP_GAME = Trueif keys[pygame.K_F8]:pygame.image.save(screen, 'dump0.png')if event.type == pygame.MOUSEMOTION:GL.MOUSE_POS = pygame.math.Vector2(event.pos)if random.randint(0, 1000) > 985:shoot = ShootingStar(gl_=GL, layer_=0, timing_=16, surface_name_='SHOOTING_STAR')# update sprites positions and add sprites transformation# At this stage no sprites are display onto the screen. Therefore,# sprite's methods blit directly surface or image onto the screen# will takes the risk to see their surfaces overlay by another sprites surface while calling# any group's draw methods (see below)GL.All.update()# Authorize Player 1 to send data to the client.# Allowing to send only one set of data every frame.# The clear method is used in the class SpriteClient# right after receiving the EventGL.SIGNAL.set()# Always display the group GL.All first has it contains the background surfaces# Any sprite attached to the group GL.All and blit directly to the screen surface# will be override by the network sprite if sprites occupy the same location..# Ideally all sprites should be on the same group in order to draw them ordered by# their layer number.# Todo :# create single group type pygame.sprite.layerUpdatesModified() group by adding network sprites directly# into the GL.All group (also pygame.sprite.layerUpdatesModified())# Note, all network sprites added to the GL.All group have to be killed after being blit onto# the display to avoid filling up the group of new instances (Broadcast class calls will add a# new sprite instances to the group GL.All each frames without killing the previous one, with the# effect of slowing down the game loop and displaying un-necessary sprites.GL.All.draw(screen)# Draw the network sprite above the backgroundif GL.CONNECTION:GL.NetGroupAll.update() # -> run all the update methodGL.NetGroupAll.draw(screen)# *************************************************************# Draw here all the other sprites that does not belongs to# common groups (GL.All & GL.NetGroupAll).# Sprite blit last onto the display are at the top layer.# Be aware that any surface(s) blit with blend attribute will# also blend with the entire sprite scene (blending with# sprites from all layers)# e.g Drawing GUI and life/energy sprite bars, screen bullet impacts# special effects, final score, ending screen and text inputs etc.# Update the sound ControllerGL.MIXER.update()collision_detection()GL.TIME_PASSED_SECONDS = clock.tick(70)GL.SPEED_FACTOR = GL.TIME_PASSED_SECONDS / 1000GL.FPS.append(clock.get_fps())# half = SCREENRECT.w >> 1# safe_zone = pygame.Rect(half - 200, half, 400, SCREENRECT.bottom - half)# pygame.draw.rect(screen, pygame.Color(255, 0, 0, 0), safe_zone, 1)# dust particles (show on the top of all other sprites)if len(COSMIC_DUST_ARRAY) > 0:display_dust(GL)if P1.life > 1:life_bar.VALUE = int(P1.life)life = life_bar.display_gradient()screen.blit(life, (10, 10), special_flags=0)screen.blit(life_bar.display_value(), (50, 10))if T1.life > 1:transport_life_bar.VALUE = int(T1.life)life = transport_life_bar.display_gradient()screen.blit(life, (SCREENRECT.w // 2 + 100, 10), special_flags=0)screen.blit(transport_life_bar.display_value(), (SCREENRECT.w // 2 + 150, 10))pygame.display.flip()FRAME += 1GL.FRAME = FRAMEBroadcast.empty()# for r in GL.All:# print(r)"""print(GL.FRAME)for r in GL.NetGroupAll:f.write('\n NETGROUPALL ' + str(GL.FRAME) + " ")f.write(' Surface: ' + str(r.surface) if hasattr(r, 'surface') else str(r))f.write(' Rect: ' + str(r.rect) if hasattr(r, 'rect') else '')f.write(' id: ' + str(r.id_))for r in GL.All:f.write('\n GL.All ' + str(GL.FRAME) + ' ')f.write(' Surface: ' + str(r.surface) if hasattr(r, 'surface') else str(r))f.write(' Rect: ' + str(r.rect) if hasattr(r, 'rect') else '')f.write(' id: ' + str(r.id_) if hasattr(r, 'id_') else '')"""f.close()GL.SPRITE_CLIENT_STOP = TrueGL.SPRITE_SERVER_STOP = Trueforce_quit(SERVER, 1025)import matplotlib.pyplot as pltplt.title("FPS ")# plt.plot(GL.BYTES_SENT)plt.plot(GL.FPS)plt.draw()plt.show()plt.title("BYTES RECEIVED")plt.plot(GL.BYTES_RECEIVED)plt.draw()plt.show()pygame.quit()

運行效果如下圖:


游戲中的玩家1和玩家2


GameOver!


player1服務端+玩家1
player2玩家2(玩家2在大母艦的下面!)

看了是不是很激動呢!由于代碼量過多,后續我回逐個發出(點擊關注+點贊不迷路哦!)

總結

以上是生活随笔為你收集整理的Python3.7版---双人联机雷霆战机(2D特效+音效+道具+Linux系统)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲国产丝袜 | 97成人精品 | 国产精品免费在线 | 18岁成年人网站 | 午夜中文字幕 | 欧美性猛交xxx乱大交3蜜桃 | youjizz.com中国 | 国产精品色悠悠 | 午夜精品久久久久久毛片 | 中文精品久久久久人妻不卡 | 四虎三级| 99精品网 | 2023国产精品 | 天天鲁| 91亚色 | 色播综合 | 色爱AV综合网国产精品 | 中文高清av | 久久99久久99精品免观看软件 | 最新国产拍偷乱偷精品 | 国产精品视频一 | 麻豆com | 乱色熟女综合一区二区三区 | 国产乱淫a∨片免费视频 | 精品无码国产一区二区三区51安 | 青青视频免费看 | 蜜桃视频导航 | 久久少妇av | 免费观看在线观看 | 日韩 欧美 国产 综合 | 国产黄片一区二区三区 | 九色在线播放 | 中文字幕一区二区在线观看 | 日韩精品欧美在线 | 色欧美日韩| 色综合久久久久久久 | 天天操中文字幕 | 欧美精品大片 | 亚洲色图av在线 | 日本国产中文字幕 | 好吊色在线视频 | 久久传媒 | 99re7| 青青青青青青青青草 | 狠狠做| 欧美乱日| 青青自拍视频 | 欧美久久久久久久久久久久 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 奇米四色网| 99福利在线| 蜜桃久久久久久 | 黄色录象片 | 黄色小视频在线 | 久久久久亚洲 | 日批网站在线观看 | 国产精品欧美激情在线 | 丁香八月婷婷 | 国产男男gay网站 | 亚洲成熟毛多妇女av毛片 | 国产农村老头老太视频 | 久久久久欧美 | 欧美一区二区视频 | 国产理论片在线观看 | 久久综合激情 | 中国老太婆性视频 | 黄色免费小视频 | av毛片网| 毛片在线视频 | 女优在线观看 | 精品综合久久 | 国产熟女精品视频 | 谁有av网址 | 成人精品亚洲 | 求免费黄色网址 | 国内91视频| 在线播放亚洲 | 国产一区久久久 | 最新黄色av | 欧美高清在线视频 | 欧美激情性做爰免费视频 | 蜜桃视频污在线观看 | 在线观看视频毛片 | 国产精品白浆一区二小说 | 日韩中文字幕亚洲精品欧美 | 就操网| 久久99久久99精品中文字幕 | 91黄色免费网站 | 91欧美激情一区二区三区 | 亚洲一级中文字幕 | 国产夫妇交换聚会群4p | 日韩另类| 男女高潮网站 | 小柔好湿好紧太爽了国产网址 | 成都电影免费大全 | 九九香蕉视频 | 丁香视频在线观看 | 亚洲最大视频网站 | 国产小视频在线 |