V0.5.0 commit
lazy
This commit is contained in:
parent
0b4a4b6145
commit
25299a5efb
@ -9,6 +9,7 @@ QQ: 3695888"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
## TODO 默认位置配置文件+可自定义工作路径
|
||||
|
||||
@ -30,5 +31,9 @@ if __name__ == '__main__':
|
||||
|
||||
os.chdir(sys.path[0]) # TODO 没做完.ing
|
||||
print(hi)
|
||||
game = main.Game()
|
||||
game.start()
|
||||
try:
|
||||
game = main.Game()
|
||||
game.start()
|
||||
except:
|
||||
error = traceback.format_exc()
|
||||
print(error)
|
||||
|
32
README.md
32
README.md
@ -1,32 +1,29 @@
|
||||
# Difficult-Rocket
|
||||
# [Difficult-Rocket(github)](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
# [Difficult-Rocket(gitee)](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
|
||||
|
||||
### Version
|
||||
## Version
|
||||
|
||||
0.4.3 (developing DEMO)
|
||||
- (developing DEMO)(coming s∞n)
|
||||
- 0.4.6 release
|
||||
- 0.5.0 developing
|
||||
|
||||
[Update logs](https://github.com/shenjackyuanjie/Difficult-Rocket/blob/main/docs/update_logs.md)
|
||||
|
||||
[Plan feature list](https://github.com/shenjackyuanjie/Difficult-Rocket/tree/main/docs/plan_features)
|
||||
|
||||
中文README请移步 [这里](https://github.com/shenjackyuanjie/Difficult-Rocket/blob/main/docs/README-cn.md)
|
||||
## 中文README请移步 [这里](./docs/README-cn.md)
|
||||
|
||||
> It's a Simple Rocket liked game build with Python
|
||||
|
||||
## Advantage
|
||||
|
||||
None. Not even one!
|
||||
> Lighter than Vanilla SR
|
||||
|
||||
(Because we are still writing the description, coming s∞n)
|
||||
## [Plan feature list](./docs/plan_features)
|
||||
|
||||
## Planed feature
|
||||
|
||||
- All In [here](https://github.com/shenjackyuanjie/Difficult-Rocket/projects)
|
||||
## [Update logs](./docs/update_logs.md)
|
||||
|
||||
## Environment (been tested / develop on)
|
||||
|
||||
-
|
||||
- `Develop platform 1 - Windows 10`
|
||||
- `Python 3.8.7`
|
||||
- `Python 3.8.10`
|
||||
- `Windows10 x64`
|
||||
- `Pyglet 1.5.16`
|
||||
- `Json5 0.9.5`
|
||||
@ -43,9 +40,10 @@ None. Not even one!
|
||||
|
||||
## Required python modules
|
||||
|
||||
- json5 (pre-installed V0.9.5 path:`./bin/libs/json5`)
|
||||
- pyglet (pre-installed V1.5.16 path:`./bin/libs/pyglet`)
|
||||
- json5 (pre-installed V0.9.6 path:`./bin/libs/json5`)
|
||||
- pyglet (pre-installed V1.5.18 path:`./bin/libs/pyglet`)
|
||||
- pillow
|
||||
- semver
|
||||
|
||||
## thanks to
|
||||
|
||||
@ -54,6 +52,8 @@ None. Not even one!
|
||||
- [@Rayawa](https://github.com/Rayawa) : check mistake in docs
|
||||
- [@Billchyi](https://github.com/Billchyi) : check mistake in docs
|
||||
|
||||
## Other links
|
||||
|
||||
## About License
|
||||
|
||||
#### https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
@ -1,8 +1,23 @@
|
||||
"""
|
||||
writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
github: @shenjackyuanjie
|
||||
"""
|
||||
# import folders
|
||||
#
|
||||
from .new_thread import new_thread
|
||||
from .tools import config
|
||||
|
||||
# import in this folder
|
||||
__all__ = [
|
||||
'new_thread',
|
||||
'config'
|
||||
]
|
||||
|
||||
|
||||
@new_thread('think')
|
||||
def think(some_thing_to_think):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
gotcha = 'think_result'
|
||||
return gotcha
|
||||
|
184
bin/client.py
184
bin/client.py
@ -2,7 +2,8 @@
|
||||
writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
"""
|
||||
|
||||
import configparser
|
||||
import logging
|
||||
import multiprocessing as mp
|
||||
import os
|
||||
import sys
|
||||
@ -22,49 +23,44 @@ except (ModuleNotFoundError, ImportError, ImportWarning):
|
||||
import configs
|
||||
|
||||
|
||||
class client(mp.Process):
|
||||
def __init__(self, logger, dev_dic=None, dev_list=None, language='zh-cn', net_mode='local'):
|
||||
mp.Process.__init__(self)
|
||||
class Client:
|
||||
def __init__(self, dev_dic=None, dev_list=None, net_mode='local'):
|
||||
pass
|
||||
# mp.Process.__init__(self)
|
||||
# logging
|
||||
self.logger = logger
|
||||
self.logger = logging.getLogger('client')
|
||||
# share memory
|
||||
self.dev_list = dev_list
|
||||
self.dev_dic = dev_dic
|
||||
# config
|
||||
self.config = tools.config('configs/main.config')
|
||||
# lang
|
||||
self.lang = tools.config('configs/sys_value/lang/%s.json5' % language, 'client')
|
||||
self.lang = tools.config('configs/lang/%s.json5' % self.config['runtime']['language'], 'client')
|
||||
# value
|
||||
self.process_id = 'Client'
|
||||
self.process_name = 'Client process'
|
||||
self.process_pid = os.getpid()
|
||||
self.view = 'space'
|
||||
self.net_mode = net_mode
|
||||
self.window_config = tools.config('configs/sys_value/window.json5')
|
||||
self.caption = self.window_config['caption']
|
||||
self.caption = tools.name_handler(self.caption, {'version': self.window_config['caption_option']['version']})
|
||||
self.window = window(logger=logger,
|
||||
dev_dic=dev_dic,
|
||||
dev_list=dev_list,
|
||||
language=language,
|
||||
net_mode=net_mode,
|
||||
width=int(self.window_config['width']),
|
||||
height=int(self.window_config['height']),
|
||||
fullscreen=tools.format_bool(self.window_config['full_screen']),
|
||||
caption=self.caption,
|
||||
resizable=tools.format_bool(self.window_config['resizable']),
|
||||
visible=tools.format_bool(self.window_config['visible']))
|
||||
self.log_config()
|
||||
|
||||
def log_config(self):
|
||||
self.logger.info('%s: %s %s' % (self.lang['os.pid_is1'], self.process_pid, self.lang['os.pid_is2']))
|
||||
self.caption = tools.name_handler(self.config['window']['caption'], {'version': self.config['runtime']['version']})
|
||||
self.window = ClientWindow(dev_dic=self.dev_dic,
|
||||
dev_list=self.dev_list,
|
||||
net_mode=self.net_mode,
|
||||
width=int(self.config['window']['width']),
|
||||
height=int(self.config['window']['height']),
|
||||
fullscreen=tools.format_bool(self.config['window']['full_screen']),
|
||||
caption=self.caption,
|
||||
resizable=tools.format_bool(self.config['window']['resizable']),
|
||||
visible=tools.format_bool(self.config['window']['visible']))
|
||||
|
||||
def run(self) -> None:
|
||||
pyglet.app.run()
|
||||
|
||||
|
||||
class window(pyglet.window.Window):
|
||||
class ClientWindow(pyglet.window.Window):
|
||||
|
||||
def __init__(self, logger, dev_dic=None, dev_list=None, language='zh-cn', net_mode='local', *args, **kwargs):
|
||||
super(window, self).__init__(*args, **kwargs)
|
||||
def __init__(self, dev_dic=None, dev_list=None, net_mode='local', *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
"""
|
||||
:param dev_list: 共享内存
|
||||
:param dev_dic: 共享内存
|
||||
@ -72,79 +68,47 @@ class window(pyglet.window.Window):
|
||||
:param net_mode: 网络模式 # local / ip
|
||||
"""
|
||||
# logging
|
||||
self.logger = logger
|
||||
self.logger = logging.getLogger('client')
|
||||
# share memory
|
||||
self.dev_list = dev_list
|
||||
self.dev_dic = dev_dic
|
||||
# value
|
||||
self.FPS = int(tools.config('configs/sys_value/window.json5')['fps'])
|
||||
self.SPF = 1.0 / self.FPS
|
||||
self.view = 'space'
|
||||
self.net_mode = net_mode
|
||||
self.config_file = tools.config('configs/main.config')
|
||||
self.FPS = int(self.config_file['runtime']['fps'])
|
||||
self.SPF = 1.0 / self.FPS
|
||||
# FPS
|
||||
self.max_fps = [self.FPS, time.time()]
|
||||
self.min_fps = [self.FPS, time.time()]
|
||||
self.fps_wait = 5
|
||||
# lang
|
||||
self.lang = tools.config('configs/sys_value/lang/%s.json5' % language, 'client')
|
||||
self.lang = tools.config('configs/lang/%s.json5' % self.config_file['runtime']['language'], 'client')
|
||||
# configs
|
||||
self.view = tools.config('configs/view.json5')
|
||||
self.map_view = [configs.basic_poi(poi_type='chunk')]
|
||||
self.part_list = tools.config('configs/sys_value/parts.json5')
|
||||
pyglet.resource.path = ['textures']
|
||||
pyglet.resource.reindex()
|
||||
# dic
|
||||
self.button_hitbox = {}
|
||||
self.button_toggled = {}
|
||||
self.ships = {} # all ship(part)
|
||||
self.planet_system = tools.config('configs/sys_value/planet.json5') # hole planet system
|
||||
# list
|
||||
# batch
|
||||
self.part_batch = pyglet.graphics.Batch()
|
||||
self.label_batch = pyglet.graphics.Batch()
|
||||
self.runtime_batch = pyglet.graphics.Batch()
|
||||
# window
|
||||
self.logger.info('%s' % self.lang['setup.done'])
|
||||
self.logger.info(self.lang['setup.done'])
|
||||
self.textures = {}
|
||||
# setup
|
||||
self.setup()
|
||||
pyglet.clock.schedule_interval(self.update, self.SPF)
|
||||
|
||||
def setup(self):
|
||||
self.logger.info(self.lang['os.pid_is'].format(os.getpid(), os.getppid()))
|
||||
# values
|
||||
# net_mode
|
||||
if self.net_mode == 'local':
|
||||
pass
|
||||
|
||||
# parts textures
|
||||
self.textures['part'] = {}
|
||||
parts = tools.config('configs/sys_value/parts.json5')
|
||||
for part in parts:
|
||||
path = parts[part][2][0]
|
||||
part_image = pyglet.resource.image(path)
|
||||
self.textures['part'][part] = part_image
|
||||
|
||||
# runtimes textures
|
||||
self.textures['runtime'] = {}
|
||||
runtimes = tools.config('configs/sys_value/runtime.json5')
|
||||
# load textures
|
||||
for runtime in runtimes['textures']:
|
||||
path = runtimes['textures'][runtime]
|
||||
runtime_image = pyglet.resource.image(path)
|
||||
self.textures['runtime'][runtime] = runtime_image
|
||||
# load button's textures
|
||||
for runtime in runtimes['button']:
|
||||
if runtime == 'logic':
|
||||
continue
|
||||
path = runtimes['button'][runtime]
|
||||
runtime_image = pyglet.resource.image(path)
|
||||
runtime_sprite = pyglet.sprite.Sprite(img=runtime_image, batch=self.runtime_batch, x=self.width + 1,
|
||||
y=self.height + 1)
|
||||
# self.textures['runtime'][runtime] = runtime_image
|
||||
self.textures['runtime'][runtime] = runtime_sprite
|
||||
self.button_hitbox[runtime] = [runtime_image.width, runtime_image.height]
|
||||
self.button_toggled[runtime] = -1
|
||||
|
||||
# info_label
|
||||
self.info_label = pyglet.text.Label(text='test %s' % pyglet.clock.get_fps(),
|
||||
x=10, y=self.height - 10,
|
||||
@ -176,11 +140,7 @@ class window(pyglet.window.Window):
|
||||
self.info_label.y = self.height - 10
|
||||
|
||||
def hit_box_update(self):
|
||||
for hit_box in self.button_hitbox:
|
||||
box_ = self.button_hitbox[hit_box]
|
||||
button = self.textures['runtime'][hit_box]
|
||||
box = [button.x, button.y, button.x + button.width, button.y + button.height]
|
||||
self.button_hitbox[hit_box] = box
|
||||
pass
|
||||
|
||||
def on_draw(self):
|
||||
self.clear()
|
||||
@ -193,49 +153,8 @@ class window(pyglet.window.Window):
|
||||
self.label_batch.draw()
|
||||
|
||||
def build_draw(self):
|
||||
self.textures['runtime']['trash_can'].blit(x=self.width - 90, y=self.height - 90)
|
||||
self.textures['runtime']['trash_can'].blit(x=self.width - 90, y=self.height - 90)
|
||||
# button tool bar
|
||||
# start from 20 20
|
||||
# between 30
|
||||
# size 50*50
|
||||
tool_y = 25
|
||||
back = 0
|
||||
while back < self.width:
|
||||
self.textures['runtime']['toolbar_light'].blit(x=back, y=0)
|
||||
back += self.textures['runtime']['toolbar_light'].width - 1
|
||||
self.textures['runtime']['to_menu'].x = 20
|
||||
self.textures['runtime']['to_menu'].y = tool_y
|
||||
self.textures['runtime']['add_part'].x = 100
|
||||
self.textures['runtime']['add_part'].y = tool_y
|
||||
self.textures['runtime']['stage'].x = 180
|
||||
self.textures['runtime']['stage'].y = tool_y
|
||||
self.textures['runtime']['zoom'].x = 260
|
||||
self.textures['runtime']['zoom'].y = tool_y
|
||||
self.textures['runtime']['play'].x = self.width - 50 - 20
|
||||
self.textures['runtime']['play'].y = tool_y
|
||||
if self.button_toggled['zoom'] != -1:
|
||||
self.textures['runtime']['zoom_in'].x = 260 - 40
|
||||
self.textures['runtime']['zoom_in'].y = tool_y + 25 + 50
|
||||
self.textures['runtime']['zoom_out'].x = 260 + 40
|
||||
self.textures['runtime']['zoom_out'].y = tool_y + 25 + 50
|
||||
else:
|
||||
self.button_toggled['zoom_in'] = -1
|
||||
self.button_toggled['zoom_out'] = -1
|
||||
self.textures['runtime']['zoom_in'].x = self.width + 1
|
||||
self.textures['runtime']['zoom_out'].x = self.width + 1
|
||||
|
||||
# //todo 把所有要素都加进来+整个设置图标+布局
|
||||
|
||||
def space_draw(self):
|
||||
# render parts
|
||||
|
||||
for ship in self.ships:
|
||||
# get ship poi
|
||||
ship_poi = ship['brain'][3]
|
||||
distances = tools.distance(ship_poi, self.map_view)
|
||||
for part in ship:
|
||||
pass
|
||||
pass
|
||||
# //todo 重写整个渲染机制
|
||||
|
||||
def draw_label(self):
|
||||
pass
|
||||
@ -244,33 +163,40 @@ class window(pyglet.window.Window):
|
||||
keyboard and mouse input
|
||||
"""
|
||||
|
||||
def on_mouse_motion(self, x, y, dx, dy):
|
||||
def on_mouse_motion(self, x, y, dx, dy) -> None:
|
||||
# self.logger.debug('按键移动 %s %s %s %s' % (x, y, dx, dy))
|
||||
pass
|
||||
|
||||
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
|
||||
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers) -> None:
|
||||
# self.logger.debug('按键拖拽 %s %s %s %s %s %s' %(x, y, dx, dy, buttons, modifiers))
|
||||
pass
|
||||
|
||||
def on_mouse_press(self, x, y, button, modifiers):
|
||||
def on_mouse_press(self, x, y, button, modifiers) -> None:
|
||||
if button == mouse.LEFT:
|
||||
self.logger.debug('左键! 在 x:%s y:%s' % (x, y))
|
||||
for hit_box in self.button_hitbox:
|
||||
box = self.button_hitbox[hit_box]
|
||||
if (box[0] <= x <= box[2]) and (box[1] <= y <= box[3]):
|
||||
self.button_toggled[hit_box] *= -1
|
||||
self.logger.debug('%s %s %s' % (hit_box,
|
||||
self.lang['button.been_press'],
|
||||
self.button_toggled[hit_box]))
|
||||
break
|
||||
self.logger.debug(self.lang['mouse.press_at'].format([x, y], self.lang['mouse.left']))
|
||||
elif button == mouse.RIGHT:
|
||||
self.logger.debug('右键! 在 x:%s y:%s' % (x, y))
|
||||
self.logger.debug(self.lang['mouse.press_at'].format([x, y], self.lang['mouse.right']))
|
||||
|
||||
def on_key_press(self, symbol, modifiers):
|
||||
def on_mouse_release(self, x, y, button, modifiers) -> None:
|
||||
pass
|
||||
|
||||
def on_key_press(self, symbol, modifiers) -> None:
|
||||
if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
|
||||
key.MOD_CAPSLOCK |
|
||||
key.MOD_SCROLLLOCK)):
|
||||
self.dispatch_event('on_close')
|
||||
|
||||
def on_key_release(self, symbol, modifiers):
|
||||
def on_key_release(self, symbol, modifiers) -> None:
|
||||
pass
|
||||
|
||||
def on_close(self) -> None:
|
||||
config_file = configparser.ConfigParser()
|
||||
config_file.read('configs/main.config')
|
||||
config_file['window']['width'] = str(self.width)
|
||||
config_file['window']['height'] = str(self.height)
|
||||
config_file.write(open('configs/main.config', 'w', encoding='utf-8'))
|
||||
# pyglet source code
|
||||
self.has_exit = True
|
||||
from pyglet import app
|
||||
if app.event_loop.is_running:
|
||||
self.close()
|
||||
|
@ -17,6 +17,7 @@
|
||||
from .lib import load, loads, dump, dumps
|
||||
from .version import VERSION
|
||||
|
||||
|
||||
__all__ = [
|
||||
'VERSION',
|
||||
'dump',
|
||||
|
@ -16,5 +16,6 @@ import sys # pragma: no cover
|
||||
|
||||
from .tool import main # pragma: no cover
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
sys.exit(main())
|
||||
|
@ -17,6 +17,7 @@ import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
# pylint: disable=redefined-builtin, invalid-name
|
||||
str = unicode
|
||||
|
@ -19,9 +19,12 @@ import unicodedata
|
||||
|
||||
from .parser import Parser
|
||||
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
str_types = (str, unicode)
|
||||
str = unicode # pylint: disable=redefined-builtin, invalid-name
|
||||
else:
|
||||
str_types = (str,)
|
||||
long = int # pylint: disable=redefined-builtin, invalid-name
|
||||
|
||||
|
||||
@ -86,7 +89,7 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
|
||||
elif object_hook:
|
||||
dictify = lambda pairs: object_hook(dict(pairs))
|
||||
else:
|
||||
dictify = lambda pairs: dict(pairs) # pylint: disable=unnecessary-lambda
|
||||
dictify = lambda pairs: dict(pairs) # pylint: disable=unnecessary-lambda
|
||||
|
||||
if not allow_duplicate_keys:
|
||||
_orig_dictify = dictify
|
||||
@ -107,7 +110,6 @@ def _reject_duplicate_keys(pairs, dictify):
|
||||
keys.add(key)
|
||||
return dictify(pairs)
|
||||
|
||||
|
||||
def _walk_ast(el, dictify, parse_float, parse_int, parse_constant):
|
||||
if el == 'None':
|
||||
return None
|
||||
@ -240,24 +242,23 @@ def _dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, indent,
|
||||
separators, default, sort_keys,
|
||||
quote_keys, trailing_commas, allow_duplicate_keys,
|
||||
seen, level, is_key):
|
||||
s = None
|
||||
if obj is True:
|
||||
s = u'true'
|
||||
if obj is False:
|
||||
elif obj is False:
|
||||
s = u'false'
|
||||
if obj is None:
|
||||
elif obj is None:
|
||||
s = u'null'
|
||||
|
||||
t = type(obj)
|
||||
if t == type('') or t == type(u''):
|
||||
elif isinstance(obj, str_types):
|
||||
if (is_key and _is_ident(obj) and not quote_keys
|
||||
and not _is_reserved_word(obj)):
|
||||
and not _is_reserved_word(obj)):
|
||||
return True, obj
|
||||
return True, _dump_str(obj, ensure_ascii)
|
||||
if t is float:
|
||||
s = _dump_float(obj, allow_nan)
|
||||
if t is int:
|
||||
elif isinstance(obj, float):
|
||||
s = _dump_float(obj,allow_nan)
|
||||
elif isinstance(obj, int):
|
||||
s = str(obj)
|
||||
else:
|
||||
s = None
|
||||
|
||||
if is_key:
|
||||
if s is not None:
|
||||
@ -300,14 +301,14 @@ def _dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, indent,
|
||||
|
||||
# In Python3, we'd check if this was an abc.Mapping or an abc.Sequence.
|
||||
# For now, just check for the attrs we need to iterate over the object.
|
||||
if hasattr(t, 'keys') and hasattr(t, '__getitem__'):
|
||||
if hasattr(obj, 'keys') and hasattr(obj, '__getitem__'):
|
||||
s = _dump_dict(obj, skipkeys, ensure_ascii,
|
||||
check_circular, allow_nan, indent,
|
||||
separators, default, sort_keys,
|
||||
quote_keys, trailing_commas,
|
||||
allow_duplicate_keys, seen, level,
|
||||
item_sep, kv_sep, indent_str, end_str)
|
||||
elif hasattr(t, '__getitem__') and hasattr(t, '__iter__'):
|
||||
elif hasattr(obj, '__getitem__') and hasattr(obj, '__iter__'):
|
||||
s = _dump_array(obj, skipkeys, ensure_ascii,
|
||||
check_circular, allow_nan, indent,
|
||||
separators, default, sort_keys,
|
||||
@ -459,7 +460,6 @@ def _is_id_continue(ch):
|
||||
|
||||
_reserved_word_re = None
|
||||
|
||||
|
||||
def _is_reserved_word(k):
|
||||
global _reserved_word_re
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
# pylint: disable=redefined-builtin,invalid-name
|
||||
chr = unichr
|
||||
@ -474,8 +475,7 @@ class Parser(object):
|
||||
lambda: self._bind(self._hex_, 'b'),
|
||||
lambda: self._bind(self._hex_, 'c'),
|
||||
lambda: self._bind(self._hex_, 'd'),
|
||||
lambda: self._succeed(
|
||||
self._xtou(self._get('a') + self._get('b') + self._get('c') + self._get('d')))])
|
||||
lambda: self._succeed(self._xtou(self._get('a') + self._get('b') + self._get('c') + self._get('d')))])
|
||||
self._pop('unicode_esc')
|
||||
|
||||
def _element_list_(self):
|
||||
|
@ -12,4 +12,4 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
VERSION = '0.9.5'
|
||||
VERSION = '0.9.6'
|
||||
|
@ -53,15 +53,7 @@ _is_pyglet_doc_run = hasattr(sys, "is_pyglet_doc_run") and sys.is_pyglet_doc_run
|
||||
#:
|
||||
#: Valid only if pyglet was installed from a source or binary distribution
|
||||
#: (i.e. not in a checked-out copy from SVN).
|
||||
#:
|
||||
#: Use setuptools if you need to check for a specific release version, e.g.::
|
||||
#:
|
||||
#: >>> import pyglet
|
||||
#: >>> from pkg_resources import parse_version
|
||||
#: >>> parse_version(pyglet.version) >= parse_version('1.1')
|
||||
#: True
|
||||
#:
|
||||
version = '1.5.16'
|
||||
version = '1.5.18'
|
||||
|
||||
|
||||
if sys.version_info < (3, 6):
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
import pyglet
|
||||
import warnings
|
||||
from pyglet import app
|
||||
|
||||
from .base import Display, Screen, ScreenMode, Canvas
|
||||
|
||||
|
||||
@ -56,12 +56,13 @@ class HeadlessDisplay(Display):
|
||||
if num_devices.value > 0:
|
||||
headless_device = pyglet.options['headless_device']
|
||||
if headless_device < 0 or headless_device >= num_devices.value:
|
||||
raise ValueError('Invalid EGL devide id: %d' % headless_device)
|
||||
raise ValueError('Invalid EGL devide id: %d' % headless_device)
|
||||
devices = (eglext.EGLDeviceEXT * num_devices.value)()
|
||||
eglext.eglQueryDevicesEXT(num_devices.value, devices, byref(num_devices))
|
||||
self._display_connection = eglext.eglGetPlatformDisplayEXT(eglext.EGL_PLATFORM_DEVICE_EXT, devices[headless_device], None)
|
||||
self._display_connection = eglext.eglGetPlatformDisplayEXT(
|
||||
eglext.EGL_PLATFORM_DEVICE_EXT, devices[headless_device], None)
|
||||
else:
|
||||
warning.warn('No device available for EGL device platform. Using native display type.')
|
||||
warnings.warn('No device available for EGL device platform. Using native display type.')
|
||||
display = egl.EGLNativeDisplayType()
|
||||
self._display_connection = egl.eglGetDisplay(display)
|
||||
|
||||
@ -76,9 +77,10 @@ class HeadlessDisplay(Display):
|
||||
|
||||
class HeadlessCanvas(Canvas):
|
||||
def __init__(self, display, egl_surface):
|
||||
super(HeadlessCanvas, self).__init__(display)
|
||||
super().__init__(display)
|
||||
self.egl_surface = egl_surface
|
||||
|
||||
|
||||
class HeadlessScreen(Screen):
|
||||
def __init__(self, display, x, y, width, height):
|
||||
super().__init__(display, x, y, width, height)
|
||||
@ -89,7 +91,6 @@ class HeadlessScreen(Screen):
|
||||
# XXX deprecate
|
||||
for config in configs:
|
||||
config.screen = self
|
||||
# print("Canvas", canvas, "configs", configs)
|
||||
return configs
|
||||
|
||||
def get_modes(self):
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -144,7 +144,7 @@ def load(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None
|
||||
font = _font_class(name, size, bold=bold, italic=italic, stretch=stretch, dpi=dpi)
|
||||
|
||||
# Save parameters for new-style layout classes to recover
|
||||
font.name = name
|
||||
# TODO: add properties to the Font classes, so these can be queried:
|
||||
font.size = size
|
||||
font.bold = bold
|
||||
font.italic = italic
|
||||
|
@ -303,6 +303,11 @@ class Font:
|
||||
self.textures = []
|
||||
self.glyphs = {}
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the Family Name of the font as a string."""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def add_font_data(cls, data):
|
||||
"""Add font data to the font loader.
|
||||
@ -394,7 +399,6 @@ class Font:
|
||||
glyphs.append(self.glyphs[c])
|
||||
return glyphs
|
||||
|
||||
|
||||
def get_glyphs_for_width(self, text, width):
|
||||
"""Return a list of glyphs for `text` that fit within the given width.
|
||||
|
||||
|
@ -1821,7 +1821,7 @@ class Win32DirectWriteFont(base.Font):
|
||||
self._font_index, self._collection = self.get_collection(name)
|
||||
assert self._collection is not None, "Font: {} not found in loaded or system font collection.".format(name)
|
||||
|
||||
self.name = name
|
||||
self._name = name
|
||||
self.bold = bold
|
||||
self.size = size
|
||||
self.italic = italic
|
||||
@ -1867,7 +1867,7 @@ class Win32DirectWriteFont(base.Font):
|
||||
# Create the text format this font will use permanently.
|
||||
# Could technically be recreated, but will keep to be inline with other font objects.
|
||||
self._text_format = IDWriteTextFormat()
|
||||
self._write_factory.CreateTextFormat(self.name,
|
||||
self._write_factory.CreateTextFormat(self._name,
|
||||
self._collection,
|
||||
self._weight,
|
||||
self._style,
|
||||
@ -1903,6 +1903,10 @@ class Win32DirectWriteFont(base.Font):
|
||||
self.max_glyph_height = (self._font_metrics.ascent + self._font_metrics.descent) * self.font_scale_ratio
|
||||
self.line_gap = self._font_metrics.lineGap * self.font_scale_ratio
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def render_to_image(self, text, width=10000, height=80):
|
||||
"""This process takes Pyglet out of the equation and uses only DirectWrite to shape and render text.
|
||||
This may allow more accurate fonts (bidi, rtl, etc) in very special circumstances at the cost of
|
||||
|
@ -168,7 +168,7 @@ class FreeTypeFont(base.Font):
|
||||
warnings.warn("The current font render does not support stretching.")
|
||||
|
||||
super().__init__()
|
||||
self.name = name
|
||||
self._name = name
|
||||
self.size = size
|
||||
self.bold = bold
|
||||
self.italic = italic
|
||||
@ -177,6 +177,10 @@ class FreeTypeFont(base.Font):
|
||||
self._load_font_face()
|
||||
self.metrics = self.face.get_font_metrics(self.size, self.dpi)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.face.family_name
|
||||
|
||||
@property
|
||||
def ascent(self):
|
||||
return self.metrics.ascent
|
||||
@ -191,14 +195,14 @@ class FreeTypeFont(base.Font):
|
||||
return self.face.get_glyph_slot(glyph_index)
|
||||
|
||||
def _load_font_face(self):
|
||||
self.face = self._memory_faces.get(self.name, self.bold, self.italic)
|
||||
self.face = self._memory_faces.get(self._name, self.bold, self.italic)
|
||||
if self.face is None:
|
||||
self._load_font_face_from_system()
|
||||
|
||||
def _load_font_face_from_system(self):
|
||||
match = get_fontconfig().find_font(self.name, self.size, self.bold, self.italic)
|
||||
match = get_fontconfig().find_font(self._name, self.size, self.bold, self.italic)
|
||||
if not match:
|
||||
raise base.FontException('Could not match font "%s"' % self.name)
|
||||
raise base.FontException('Could not match font "%s"' % self._name)
|
||||
self.face = FreeTypeFace.from_fontconfig(match)
|
||||
|
||||
@classmethod
|
||||
@ -320,7 +324,7 @@ class FreeTypeFace:
|
||||
descent=-ascent // 4) # arbitrary.
|
||||
|
||||
def _get_best_name(self):
|
||||
self.name = self.family_name
|
||||
self._name = self.family_name
|
||||
self._get_font_family_from_ttf
|
||||
|
||||
def _get_font_family_from_ttf(self):
|
||||
@ -339,7 +343,7 @@ class FreeTypeFace:
|
||||
name.encoding_id == TT_MS_ID_UNICODE_CS):
|
||||
continue
|
||||
# name.string is not 0 terminated! use name.string_len
|
||||
self.name = name.string.decode('utf-16be', 'ignore')
|
||||
self._name = name.string.decode('utf-16be', 'ignore')
|
||||
except:
|
||||
continue
|
||||
|
||||
|
@ -231,9 +231,17 @@ class QuartzFont(base.Font):
|
||||
cf.CFRelease(descriptor)
|
||||
assert self.ctFont, "Couldn't load font: " + name
|
||||
|
||||
string = c_void_p(ct.CTFontCopyFamilyName(self.ctFont))
|
||||
self._family_name = str(cocoapy.cfstring_to_string(string))
|
||||
cf.CFRelease(string)
|
||||
|
||||
self.ascent = int(math.ceil(ct.CTFontGetAscent(self.ctFont)))
|
||||
self.descent = -int(math.ceil(ct.CTFontGetDescent(self.ctFont)))
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._family_name
|
||||
|
||||
def __del__(self):
|
||||
cf.CFRelease(self.ctFont)
|
||||
|
||||
|
@ -492,26 +492,25 @@ class GDIPlusFont(Win32Font):
|
||||
if stretch:
|
||||
warnings.warn("The current font render does not support stretching.")
|
||||
|
||||
super(GDIPlusFont, self).__init__(name, size, bold, italic, stretch, dpi)
|
||||
super().__init__(name, size, bold, italic, stretch, dpi)
|
||||
|
||||
self._name = name
|
||||
|
||||
family = ctypes.c_void_p()
|
||||
name = ctypes.c_wchar_p(name)
|
||||
|
||||
# Look in private collection first:
|
||||
if self._private_fonts:
|
||||
gdiplus.GdipCreateFontFamilyFromName(name,
|
||||
self._private_fonts, ctypes.byref(family))
|
||||
gdiplus.GdipCreateFontFamilyFromName(name, self._private_fonts, ctypes.byref(family))
|
||||
|
||||
# Then in system collection:
|
||||
if not family:
|
||||
gdiplus.GdipCreateFontFamilyFromName(name,
|
||||
None, ctypes.byref(family))
|
||||
gdiplus.GdipCreateFontFamilyFromName(name, None, ctypes.byref(family))
|
||||
|
||||
# Nothing found, use default font.
|
||||
if not family:
|
||||
name = self._default_name
|
||||
gdiplus.GdipCreateFontFamilyFromName(ctypes.c_wchar_p(name),
|
||||
None, ctypes.byref(family))
|
||||
self._name = self._default_name
|
||||
gdiplus.GdipCreateFontFamilyFromName(ctypes.c_wchar_p(self._name), None, ctypes.byref(family))
|
||||
|
||||
if dpi is None:
|
||||
unit = UnitPoint
|
||||
@ -527,13 +526,16 @@ class GDIPlusFont(Win32Font):
|
||||
if italic:
|
||||
style |= FontStyleItalic
|
||||
self._gdipfont = ctypes.c_void_p()
|
||||
gdiplus.GdipCreateFont(family, ctypes.c_float(size),
|
||||
style, unit, ctypes.byref(self._gdipfont))
|
||||
gdiplus.GdipCreateFont(family, ctypes.c_float(size), style, unit, ctypes.byref(self._gdipfont))
|
||||
gdiplus.GdipDeleteFontFamily(family)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def __del__(self):
|
||||
super(GDIPlusFont, self).__del__()
|
||||
result = gdiplus.GdipDeleteFont(self._gdipfont)
|
||||
gdiplus.GdipDeleteFont(self._gdipfont)
|
||||
|
||||
@classmethod
|
||||
def add_font_data(cls, data):
|
||||
|
@ -39,8 +39,8 @@
|
||||
import array
|
||||
import itertools
|
||||
|
||||
from pyglet.image import *
|
||||
from pyglet.image.codecs import *
|
||||
from pyglet.image import ImageData, ImageDecodeException
|
||||
from pyglet.image.codecs import ImageDecoder, ImageEncoder
|
||||
|
||||
import pyglet.extlibs.png as pypng
|
||||
|
||||
@ -54,8 +54,7 @@ class PNGImageDecoder(ImageDecoder):
|
||||
reader = pypng.Reader(file=file)
|
||||
width, height, pixels, metadata = reader.asDirect()
|
||||
except Exception as e:
|
||||
raise ImageDecodeException(
|
||||
'PyPNG cannot read %r: %s' % (filename or file, e))
|
||||
raise ImageDecodeException('PyPNG cannot read %r: %s' % (filename or file, e))
|
||||
|
||||
if metadata['greyscale']:
|
||||
if metadata['alpha']:
|
||||
@ -95,10 +94,10 @@ class PNGImageEncoder(ImageEncoder):
|
||||
|
||||
image.pitch = -(image.width * len(image.format))
|
||||
|
||||
writer = pypng.Writer(image.width, image.height, bytes_per_sample=1, greyscale=greyscale, alpha=has_alpha)
|
||||
writer = pypng.Writer(image.width, image.height, greyscale=greyscale, alpha=has_alpha)
|
||||
|
||||
data = array.array('B')
|
||||
data.fromstring(image.get_data(image.format, image.pitch))
|
||||
data.frombytes(image.get_data(image.format, image.pitch))
|
||||
|
||||
writer.write_array(file, data)
|
||||
|
||||
|
@ -236,7 +236,8 @@ def get_devices(display=None):
|
||||
def _create_joystick(device):
|
||||
if device._type in (dinput.DI8DEVTYPE_JOYSTICK,
|
||||
dinput.DI8DEVTYPE_1STPERSON,
|
||||
dinput.DI8DEVTYPE_GAMEPAD):
|
||||
dinput.DI8DEVTYPE_GAMEPAD,
|
||||
dinput.DI8DEVTYPE_SUPPLEMENTAL):
|
||||
return base.Joystick(device)
|
||||
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
from ctypes import *
|
||||
|
||||
import pyglet.lib
|
||||
from pyglet.gl.lib import missing_function
|
||||
import pyglet
|
||||
import pyglet.util
|
||||
|
||||
from pyglet.util import asbytes
|
||||
|
||||
__all__ = ['link_EGL']
|
||||
|
||||
@ -22,11 +21,11 @@ def link_EGL(name, restype, argtypes, requires=None, suggestions=None):
|
||||
func.argtypes = argtypes
|
||||
return func
|
||||
except AttributeError:
|
||||
bname = cast(pointer(create_string_buffer(asbytes(name))), POINTER(c_ubyte))
|
||||
bname = cast(pointer(create_string_buffer(pyglet.util.asbytes(name))), POINTER(c_ubyte))
|
||||
addr = eglGetProcAddress(bname)
|
||||
if addr:
|
||||
ftype = CFUNCTYPE(*((restype,) + tuple(argtypes)))
|
||||
func = cast(addr, ftype)
|
||||
return func
|
||||
|
||||
return missing_function(name, requires, suggestions)
|
||||
return pyglet.gl.lib.missing_function(name, requires, suggestions)
|
||||
|
@ -410,18 +410,6 @@ class StreamingSource(Source):
|
||||
:class:`~pyglet.media.player.Player`.
|
||||
"""
|
||||
|
||||
@property
|
||||
def is_queued(self):
|
||||
"""
|
||||
bool: Determine if this source is a player current source.
|
||||
|
||||
Check on a :py:class:`~pyglet.media.player.Player` if this source
|
||||
is the current source.
|
||||
|
||||
:deprecated: Use :attr:`is_player_source` instead.
|
||||
"""
|
||||
return self.is_player_source
|
||||
|
||||
def get_queue_source(self):
|
||||
"""Return the ``Source`` to be used as the source for a player.
|
||||
|
||||
|
@ -116,7 +116,7 @@ def ffmpeg_get_audio_buffer_size(audio_format):
|
||||
|
||||
Buffer size can accomodate 1 sec of audio data.
|
||||
"""
|
||||
return audio_format.bytes_per_second
|
||||
return audio_format.bytes_per_second + FF_INPUT_BUFFER_PADDING_SIZE
|
||||
|
||||
|
||||
def ffmpeg_init():
|
||||
@ -558,8 +558,8 @@ class FFmpegSource(StreamingSource):
|
||||
self._max_len_audioq = 50 # Need to figure out a correct amount
|
||||
if self.audio_format:
|
||||
# Buffer 1 sec worth of audio
|
||||
self._audio_buffer = \
|
||||
(c_uint8 * ffmpeg_get_audio_buffer_size(self.audio_format))()
|
||||
nbytes = ffmpeg_get_audio_buffer_size(self.audio_format)
|
||||
self._audio_buffer = (c_uint8 * nbytes)()
|
||||
|
||||
self.videoq = deque()
|
||||
self._max_len_videoq = 50 # Need to figure out a correct amount
|
||||
@ -887,7 +887,9 @@ class FFmpegSource(StreamingSource):
|
||||
width = self.video_format.width
|
||||
height = self.video_format.height
|
||||
pitch = width * 4
|
||||
buffer = (c_uint8 * (pitch * height))()
|
||||
# https://ffmpeg.org/doxygen/3.3/group__lavc__decoding.html#ga8f5b632a03ce83ac8e025894b1fc307a
|
||||
nbytes = (pitch * height + FF_INPUT_BUFFER_PADDING_SIZE)
|
||||
buffer = (c_uint8 * nbytes)()
|
||||
try:
|
||||
result = self._ffmpeg_decode_video(video_packet.packet,
|
||||
buffer)
|
||||
|
@ -67,7 +67,12 @@ class _GLibMainLoopThread(Thread):
|
||||
|
||||
|
||||
class _MessageHandler:
|
||||
"""Message Handler class for GStreamer Sources."""
|
||||
"""Message Handler class for GStreamer Sources.
|
||||
|
||||
This separate class holds a weak reference to the
|
||||
Source, preventing garbage collection issues.
|
||||
|
||||
"""
|
||||
def __init__(self, source):
|
||||
self.source = weakref.proxy(source)
|
||||
|
||||
@ -208,13 +213,13 @@ class GStreamerSource(StreamingSource):
|
||||
self._file.close()
|
||||
|
||||
try:
|
||||
# self._pipeline.bus.remove_signal_watch()
|
||||
while not self.queue.empty():
|
||||
self.queue.get_nowait()
|
||||
sink = self.appsink.get_static_pad("sink")
|
||||
if sink.handler_is_connected(self.caps_handler):
|
||||
sink.disconnect(self.caps_handler)
|
||||
while not self.queue.empty():
|
||||
self.queue.get_nowait()
|
||||
self._pipeline.set_state(Gst.State.NULL)
|
||||
self._pipeline.bus.remove_signal_watch()
|
||||
self.filesrc.set_property("location", None)
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
|
@ -71,11 +71,7 @@ def get_audio_driver():
|
||||
from pyglet.libs.win32.constants import WINDOWS_8_OR_GREATER
|
||||
if WINDOWS_8_OR_GREATER:
|
||||
from . import xaudio2
|
||||
try:
|
||||
_audio_driver = xaudio2.create_audio_driver()
|
||||
except ImportError:
|
||||
# Occurs when default audio device is not found, and cannot bind.
|
||||
pass
|
||||
_audio_driver = xaudio2.create_audio_driver()
|
||||
break
|
||||
elif driver_name == 'directsound':
|
||||
from . import directsound
|
||||
@ -94,6 +90,9 @@ def get_audio_driver():
|
||||
print('Error importing driver %s:' % driver_name)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
from . import silent
|
||||
_audio_driver = silent.create_audio_driver()
|
||||
|
||||
return _audio_driver
|
||||
|
||||
|
@ -56,12 +56,12 @@ def _gain2db(gain):
|
||||
Convert linear gain in range [0.0, 1.0] to 100ths of dB.
|
||||
|
||||
Power gain = P1/P2
|
||||
dB = 10 log(P1/P2)
|
||||
dB = 2 log(P1/P2)
|
||||
dB * 100 = 1000 * log(power gain)
|
||||
"""
|
||||
if gain <= 0:
|
||||
return -10000
|
||||
return max(-10000, min(int(1000 * math.log10(min(gain, 1))), 0))
|
||||
return max(-10000, min(int(1000 * math.log2(min(gain, 1))), 0))
|
||||
|
||||
|
||||
def _db2gain(db):
|
||||
|
@ -76,6 +76,8 @@ class XAudio2Driver:
|
||||
|
||||
self._players = [] # Only used for resetting/restoring xaudio2. Store players to callback.
|
||||
|
||||
self._create_xa2()
|
||||
|
||||
if self.restart_on_error:
|
||||
audio_devices = get_audio_device_manager()
|
||||
if audio_devices:
|
||||
@ -87,8 +89,6 @@ class XAudio2Driver:
|
||||
|
||||
pyglet.clock.schedule_interval_soft(self._check_state, 0.5)
|
||||
|
||||
self._create_xa2()
|
||||
|
||||
def _check_state(self, dt):
|
||||
"""Hack/workaround, you cannot shutdown/create XA2 within a COM callback, set a schedule to check state."""
|
||||
if self._dead is True:
|
||||
@ -115,7 +115,11 @@ class XAudio2Driver:
|
||||
|
||||
def _create_xa2(self, device_id=None):
|
||||
self._xaudio2 = lib.IXAudio2()
|
||||
lib.XAudio2Create(ctypes.byref(self._xaudio2), 0, self.processor)
|
||||
|
||||
try:
|
||||
lib.XAudio2Create(ctypes.byref(self._xaudio2), 0, self.processor)
|
||||
except OSError:
|
||||
raise ImportError("XAudio2 driver could not be initialized.")
|
||||
|
||||
if _debug:
|
||||
# Debug messages are found in Windows Event Viewer, you must enable event logging:
|
||||
|
@ -260,6 +260,8 @@ class Player(pyglet.event.EventDispatcher):
|
||||
|
||||
The internal audio player and the texture will be deleted.
|
||||
"""
|
||||
if self._source:
|
||||
self.source.is_player_source = False
|
||||
if self._audio_player:
|
||||
self._audio_player.delete()
|
||||
self._audio_player = None
|
||||
|
@ -36,12 +36,12 @@
|
||||
"""2D shapes.
|
||||
|
||||
This module provides classes for a variety of simplistic 2D shapes,
|
||||
such as Rectangles, Circles, and Lines. These shapes are are made
|
||||
such as Rectangles, Circles, and Lines. These shapes are made
|
||||
internally from OpenGL primitives, and provide excellent performance
|
||||
when drawn as part of a :py:class:`~pyglet.graphics.Batch`.
|
||||
Convenience methods are provided for positioning, changing color
|
||||
and opacity, and rotation (where applicible). To create more
|
||||
complex shapes than what is provided here, the lower evel
|
||||
complex shapes than what is provided here, the lower level
|
||||
graphics API is more appropriate.
|
||||
See the :ref:`guide_graphics` for more details.
|
||||
|
||||
@ -60,6 +60,7 @@ A simple example of drawing shapes::
|
||||
rectangle.rotation = 33
|
||||
line = shapes.Line(100, 100, 100, 200, width=19, batch=batch)
|
||||
line2 = shapes.Line(150, 150, 444, 111, width=4, color=(200, 20, 20), batch=batch)
|
||||
star = shapes.Star(800, 400, 60, 40, num_spikes=20, color=(255, 255, 0), batch=batch)
|
||||
|
||||
@window.event
|
||||
def on_draw():
|
||||
@ -467,7 +468,7 @@ class Circle(_ShapeBase):
|
||||
points = [(x + (r * math.cos(i * tau_segs)),
|
||||
y + (r * math.sin(i * tau_segs))) for i in range(self._segments)]
|
||||
|
||||
# Create a list of trianges from the points:
|
||||
# Create a list of triangles from the points:
|
||||
vertices = []
|
||||
for i, point in enumerate(points):
|
||||
triangle = x, y, *points[i - 1], *point
|
||||
@ -946,4 +947,125 @@ class Triangle(_ShapeBase):
|
||||
self._update_position()
|
||||
|
||||
|
||||
__all__ = ('Arc', 'Circle', 'Line', 'Rectangle', 'BorderedRectangle', 'Triangle')
|
||||
class Star(_ShapeBase):
|
||||
def __init__(self, x, y, outer_radius, inner_radius, num_spikes, rotation=0,
|
||||
color=(255, 255, 255), batch=None, group=None) -> None:
|
||||
"""Create a star.
|
||||
|
||||
The star's anchor point (x, y) defaults to the center of the star.
|
||||
|
||||
:Parameters:
|
||||
`x` : float
|
||||
The X coordinate of the star.
|
||||
`y` : float
|
||||
The Y coordinate of the star.
|
||||
`outer_radius` : float
|
||||
The desired outer radius of the star.
|
||||
`inner_radius` : float
|
||||
The desired inner radius of the star.
|
||||
`num_spikes` : float
|
||||
The desired number of spikes of the star.
|
||||
`rotation` : float
|
||||
The rotation of the star in degrees. A rotation of 0 degrees
|
||||
will result in one spike lining up with the X axis in
|
||||
positive direction.
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the star, specified as
|
||||
a tuple of three ints in the range of 0-255.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the star to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
Optional parent group of the star.
|
||||
"""
|
||||
self._x = x
|
||||
self._y = y
|
||||
self._outer_radius = outer_radius
|
||||
self._inner_radius = inner_radius
|
||||
self._num_spikes = num_spikes
|
||||
self._rgb = color
|
||||
self._rotation = rotation
|
||||
|
||||
self._batch = batch or Batch()
|
||||
self._group = _ShapeGroup(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, group)
|
||||
|
||||
self._vertex_list = self._batch.add(self._num_spikes*6, GL_TRIANGLES,
|
||||
self._group, 'v2f', 'c4B')
|
||||
self._update_position()
|
||||
self._update_color()
|
||||
|
||||
def _update_position(self):
|
||||
if not self._visible:
|
||||
vertices = (0, 0) * self._num_spikes * 6
|
||||
else:
|
||||
x = self._x + self._anchor_x
|
||||
y = self._y + self._anchor_y
|
||||
r_i = self._inner_radius
|
||||
r_o = self._outer_radius
|
||||
|
||||
# get angle covered by each line (= half a spike)
|
||||
d_theta = math.pi / self._num_spikes
|
||||
|
||||
# phase shift rotation
|
||||
phi = self._rotation / 180 * math.pi
|
||||
|
||||
# calculate alternating points on outer and outer circles
|
||||
points = []
|
||||
for i in range(self._num_spikes):
|
||||
points.append((x + (r_o * math.cos(2*i * d_theta + phi)),
|
||||
y + (r_o * math.sin(2*i * d_theta + phi))))
|
||||
points.append((x + (r_i * math.cos((2*i+1) * d_theta + phi)),
|
||||
y + (r_i * math.sin((2*i+1) * d_theta + phi))))
|
||||
|
||||
# create a list of doubled-up points from the points
|
||||
vertices = []
|
||||
for i, point in enumerate(points):
|
||||
triangle = x, y, *points[i - 1], *point
|
||||
vertices.extend(triangle)
|
||||
|
||||
self._vertex_list.vertices[:] = vertices
|
||||
|
||||
def _update_color(self):
|
||||
self._vertex_list.colors[:] = [*self._rgb, int(self._opacity)] * self._num_spikes * 6
|
||||
|
||||
@property
|
||||
def outer_radius(self):
|
||||
"""The outer radius of the star."""
|
||||
return self._outer_radius
|
||||
|
||||
@outer_radius.setter
|
||||
def outer_radius(self, value):
|
||||
self._outer_radius = value
|
||||
self._update_position()
|
||||
|
||||
@property
|
||||
def inner_radius(self):
|
||||
"""The innter radius of the star."""
|
||||
return self._inner_radius
|
||||
|
||||
@inner_radius.setter
|
||||
def inner_radius(self, value):
|
||||
self._inner_radius = value
|
||||
self._update_position()
|
||||
|
||||
@property
|
||||
def num_spikes(self):
|
||||
"""Number of spikes of the star."""
|
||||
return self._num_spikes
|
||||
|
||||
@num_spikes.setter
|
||||
def num_spikes(self, value):
|
||||
self._num_spikes = value
|
||||
self._update_position()
|
||||
|
||||
@property
|
||||
def rotation(self):
|
||||
"""Rotation of the star, in degrees.
|
||||
"""
|
||||
return self._rotation
|
||||
|
||||
@rotation.setter
|
||||
def rotation(self, rotation):
|
||||
self._rotation = rotation
|
||||
self._update_position()
|
||||
|
||||
__all__ = ('Arc', 'Circle', 'Line', 'Rectangle', 'BorderedRectangle', 'Triangle', 'Star')
|
||||
|
@ -40,7 +40,7 @@ Abstract representation
|
||||
|
||||
Styled text in pyglet is represented by one of the :py:class:`~pyglet.text.document.AbstractDocument` classes,
|
||||
which manage the state representation of text and style independently of how
|
||||
it is loaded or rendered.
|
||||
it is loaded or rendered.
|
||||
|
||||
A document consists of the document text (a Unicode string) and a set of
|
||||
named style ranges. For example, consider the following (artificial)
|
||||
@ -131,7 +131,7 @@ entire paragraph, otherwise results are undefined.
|
||||
``align``
|
||||
``left`` (default), ``center`` or ``right``.
|
||||
``indent``
|
||||
Additional horizontal space to insert before the first
|
||||
Additional horizontal space to insert before the first
|
||||
``leading``
|
||||
Additional space to insert between consecutive lines within a paragraph,
|
||||
in points. Defaults to 0.
|
||||
@ -159,7 +159,7 @@ document; it will be ignored by the built-in text classes.
|
||||
|
||||
All style attributes (including those not present in a document) default to
|
||||
``None`` (including the so-called "boolean" styles listed above). The meaning
|
||||
of a ``None`` style is style- and application-dependent.
|
||||
of a ``None`` style is style- and application-dependent.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
"""
|
||||
@ -181,8 +181,8 @@ class InlineElement:
|
||||
|
||||
Elements behave like a single glyph in the document. They are
|
||||
measured by their horizontal advance, ascent above the baseline, and
|
||||
descent below the baseline.
|
||||
|
||||
descent below the baseline.
|
||||
|
||||
The pyglet layout classes reserve space in the layout for elements and
|
||||
call the element's methods to ensure they are rendered at the
|
||||
appropriate position.
|
||||
@ -225,8 +225,8 @@ class InlineElement:
|
||||
|
||||
It is the responsibility of the element to clip itself against
|
||||
the layout boundaries, and position itself appropriately with respect
|
||||
to the layout's position and viewport offset.
|
||||
|
||||
to the layout's position and viewport offset.
|
||||
|
||||
The `TextLayout.top_state` graphics state implements this transform
|
||||
and clipping into window space.
|
||||
|
||||
@ -263,7 +263,7 @@ class AbstractDocument(event.EventDispatcher):
|
||||
This class can be overridden to interface pyglet with a third-party
|
||||
document format. It may be easier to implement the document format in
|
||||
terms of one of the supplied concrete classes :py:class:`~pyglet.text.document.FormattedDocument` or
|
||||
:py:class:`~pyglet.text.document.UnformattedDocument`.
|
||||
:py:class:`~pyglet.text.document.UnformattedDocument`.
|
||||
"""
|
||||
_previous_paragraph_re = re.compile(u'\n[^\n\u2029]*$')
|
||||
_next_paragraph_re = re.compile(u'[\n\u2029]')
|
||||
@ -717,13 +717,13 @@ class _FontStyleRunsRangeIterator:
|
||||
from pyglet import font
|
||||
for start, end, styles in self.zip_iter.ranges(start, end):
|
||||
font_name, font_size, bold, italic, stretch = styles
|
||||
ft = font.load(font_name, font_size, bold=bold, italic=italic, stretch=stretch, dpi=self.dpi)
|
||||
ft = font.load(font_name, font_size, bold=bool(bold), italic=bool(italic), stretch=stretch, dpi=self.dpi)
|
||||
yield start, end, ft
|
||||
|
||||
def __getitem__(self, index):
|
||||
from pyglet import font
|
||||
font_name, font_size, bold, italic, stretch = self.zip_iter[index]
|
||||
return font.load(font_name, font_size, bold=bold, italic=italic, stretch=stretch, dpi=self.dpi)
|
||||
return font.load(font_name, font_size, bold=bool(bold), italic=bool(italic), stretch=stretch, dpi=self.dpi)
|
||||
|
||||
|
||||
class _NoStyleRangeIterator:
|
||||
|
@ -595,27 +595,18 @@ class IncrementalTextLayoutGroup(graphics.Group):
|
||||
|
||||
def set_state(self):
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT)
|
||||
|
||||
glEnable(GL_BLEND)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
# Disable clipping planes to check culling.
|
||||
glEnable(GL_CLIP_PLANE0)
|
||||
glEnable(GL_CLIP_PLANE1)
|
||||
glEnable(GL_CLIP_PLANE2)
|
||||
glEnable(GL_CLIP_PLANE3)
|
||||
# Left
|
||||
glClipPlane(GL_CLIP_PLANE0, (GLdouble * 4)(1, 0, 0, -(self._clip_x - 1)))
|
||||
# Top
|
||||
glClipPlane(GL_CLIP_PLANE1, (GLdouble * 4)(0, -1, 0, self._clip_y))
|
||||
# Right
|
||||
glClipPlane(GL_CLIP_PLANE2, (GLdouble * 4)(-1, 0, 0, self._clip_x + self._clip_width + 1))
|
||||
# Bottom
|
||||
glClipPlane(GL_CLIP_PLANE3, (GLdouble * 4)(0, 1, 0, -(self._clip_y - self._clip_height)))
|
||||
glEnable(GL_SCISSOR_TEST)
|
||||
glScissor(self._clip_x, self._clip_y - self._clip_height, self._clip_width, self._clip_height)
|
||||
|
||||
glTranslatef(self.translate_x, self.translate_y, 0)
|
||||
|
||||
def unset_state(self):
|
||||
glTranslatef(-self.translate_x, -self.translate_y, 0)
|
||||
glDisable(GL_SCISSOR_TEST)
|
||||
glPopAttrib()
|
||||
|
||||
@property
|
||||
@ -941,7 +932,9 @@ class TextLayout:
|
||||
else:
|
||||
dx = x - self._x
|
||||
for vertex_list in self._vertex_lists:
|
||||
vertex_list.vertices[::2] = [v + dx for v in vertex_list.vertices[::2]]
|
||||
vertices = vertex_list.vertices[:]
|
||||
vertices[::2] = [x + dx for x in vertices[::2]]
|
||||
vertex_list.vertices[:] = vertices
|
||||
self._x = x
|
||||
|
||||
@property
|
||||
@ -965,7 +958,9 @@ class TextLayout:
|
||||
else:
|
||||
dy = y - self._y
|
||||
for vertex_list in self._vertex_lists:
|
||||
vertex_list.vertices[1::2] = [v + dy for v in vertex_list.vertices[1::2]]
|
||||
vertices = vertex_list.vertices[:]
|
||||
vertices[1::2] = [y + dy for y in vertices[1::2]]
|
||||
vertex_list.vertices[:] = vertices
|
||||
self._y = y
|
||||
|
||||
@property
|
||||
|
@ -125,6 +125,7 @@ above, "Working with multiple screens")::
|
||||
|
||||
import sys
|
||||
import math
|
||||
import warnings
|
||||
|
||||
import pyglet
|
||||
import pyglet.window.key
|
||||
@ -647,6 +648,15 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
app.windows.add(self)
|
||||
self._create()
|
||||
|
||||
# Raise a warning if an OpenGL 2.0 context is not available. This is a common case
|
||||
# with virtual machines, or on Windows without fully supported GPU drivers.
|
||||
gl_info = context.get_info()
|
||||
if not gl_info.have_version(2, 0):
|
||||
message = ("\nYour graphics drivers do not support OpenGL 2.0.\n"
|
||||
"You may experience rendering issues or crashes.\n"
|
||||
f"{gl_info.get_vendor()}\n{gl_info.get_renderer()}\n{gl_info.get_version()}")
|
||||
warnings.warn(message)
|
||||
|
||||
self.switch_to()
|
||||
if visible:
|
||||
self.set_visible(True)
|
||||
|
26
bin/main.py
26
bin/main.py
@ -3,10 +3,11 @@ writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
import multiprocessing
|
||||
# share memory
|
||||
from multiprocessing import Manager as share
|
||||
|
||||
@ -38,11 +39,11 @@ class Game:
|
||||
# lang_config
|
||||
self.language = tools.config('configs/sys_value/basic_config.json5')
|
||||
self.language = self.language['language']
|
||||
self.lang = tools.config('configs/sys_value/lang/%s.json5' % self.language, 'main')
|
||||
self.lang = tools.config('configs/lang/%s.json5' % self.language, 'main')
|
||||
# logger
|
||||
self.log_config = tools.config('configs/logging.json5', 'file')
|
||||
self.log_filename = tools.name_handler(self.log_config['filename']['main'],
|
||||
{'date': self.log_config['date_fmt']})
|
||||
{'{date}': self.log_config['date_fmt']})
|
||||
self.root_logger_fmt = logging.Formatter(self.log_config['fmt'], self.log_config['date_fmt'])
|
||||
self.root_logger_stream_handler = logging.StreamHandler()
|
||||
self.root_logger_stream_handler.setFormatter(self.root_logger_fmt)
|
||||
@ -59,19 +60,18 @@ class Game:
|
||||
logging.getLogger().addHandler(self.root_logger_stream_handler)
|
||||
logging.getLogger().addHandler(self.root_logger_file_handler)
|
||||
# create logger
|
||||
self.main_logger = logging.getLogger().getChild('main')
|
||||
self.server_logger = logging.getLogger().getChild('server')
|
||||
self.client_logger = logging.getLogger().getChild('client')
|
||||
self.main_logger = logging.getLogger('main')
|
||||
# output info
|
||||
self.main_logger.info(self.lang['logger.created'])
|
||||
self.main_logger.info(self.lang['logger.main_done'])
|
||||
self.log_configs()
|
||||
# version check
|
||||
self.python_version_check()
|
||||
# client and server
|
||||
self.client = client.client(self.client_logger, self.dicts, self.lists, self.language, net_mode='local')
|
||||
self.server = server.server(self.lists, self.dicts, self.server_logger, language=self.language,
|
||||
net_mode='local')
|
||||
self.setup()
|
||||
|
||||
def setup(self):
|
||||
self.client = client.Client(self.lists, self.dicts, net_mode='local')
|
||||
self.server = server.server(self.lists, self.dicts, net_mode='local')
|
||||
|
||||
def log_configs(self):
|
||||
self.main_logger.info('%s %s' % (self.lang['logger.language'], self.lang['lang.language']))
|
||||
@ -81,15 +81,15 @@ class Game:
|
||||
self.main_logger.debug('%s %s' % (self.lang['logger.logfile_fmt'], self.log_config['fmt']))
|
||||
self.main_logger.debug('%s %s' % (self.lang['logger.logfile_datefmt'], self.log_config['date_fmt']))
|
||||
|
||||
def python_version_check(self): # best 3.8+ and write at 3.8.9
|
||||
def python_version_check(self): # best 3.8+ and write at 3.8.10
|
||||
self.main_logger.info('%s %s' % (self.lang['version.now_on'], self.on_python_v))
|
||||
if self.on_python_v_info[0] == 2:
|
||||
self.main_logger.critical('%s' % self.lang['version.need3+'])
|
||||
raise SystemError('%s' % self.lang['version.need3+'])
|
||||
elif self.on_python_v_info[1] < 9:
|
||||
elif self.on_python_v_info[1] < 8:
|
||||
warning = tools.name_handler(self.lang['version.best3.8+'])
|
||||
self.main_logger.warning(warning)
|
||||
|
||||
def start(self):
|
||||
# start
|
||||
self.server.run()
|
||||
self.client.run()
|
||||
|
@ -27,7 +27,7 @@ def new_thread(thread_name: Optional[str or Callable] = None):
|
||||
|
||||
# bring the signature of the func to the wrap function
|
||||
# so inspect.getfullargspec(func) works correctly
|
||||
# https://stackoverflow.com/questions/39926567find/python-create-decorator-preserving-function-arguments
|
||||
# https://stackoverflow.com/questions/39926567/python-create-decorator-preserving-function-arguments
|
||||
wrap.__signature__ = inspect.signature(func)
|
||||
return wrap
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
"""
|
||||
|
||||
import logging
|
||||
import multiprocessing as mp
|
||||
import os
|
||||
|
||||
@ -12,23 +12,24 @@ except (ModuleNotFoundError, ImportError, ImportWarning):
|
||||
import tools
|
||||
|
||||
|
||||
class server(mp.Process):
|
||||
def __init__(self, dev_list, dev_dic, logger, language='zh-cn', net_mode='local'):
|
||||
class server:
|
||||
def __init__(self, dev_list, dev_dic, net_mode='local'):
|
||||
# father class __init__()
|
||||
mp.Process.__init__(self)
|
||||
# mp.Process.__init__(self)
|
||||
# logging
|
||||
self.logger = logger
|
||||
self.logger = logging.getLogger('server')
|
||||
# value
|
||||
self.process_id = 'Server'
|
||||
self.process_name = 'server process'
|
||||
self.process_pid = os.getpid()
|
||||
# config
|
||||
self.config = tools.config('configs/main.config')
|
||||
# lang
|
||||
self.lang = tools.config('configs/sys_value/lang/%s.json5' % language, 'server')
|
||||
self.lang = tools.config('configs/lang/%s.json5' % self.config['runtime']['language'], 'server')
|
||||
# share memory
|
||||
self.dev_list = dev_list
|
||||
self.dev_dic = dev_dic
|
||||
self.logger.info('%s: %s %s' % (self.lang['os.pid_is1'], self.process_pid, self.lang['os.pid_is2']))
|
||||
self.logger.info('%s' % self.lang['setup.done'])
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
self.logger.info(self.lang['os.pid_is'].format(os.getpid(), os.getppid()))
|
||||
|
||||
|
35
bin/tools.py
35
bin/tools.py
@ -5,12 +5,14 @@ github: @shenjackyuanjie
|
||||
"""
|
||||
|
||||
import configparser
|
||||
import traceback
|
||||
import decimal
|
||||
import logging
|
||||
import semver
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
from xml.dom.minidom import parse
|
||||
|
||||
sys.path.append('./bin/libs/')
|
||||
@ -31,14 +33,14 @@ file configs
|
||||
|
||||
|
||||
def report_file_error(filetype: str, error_type, filename: str, stack: any):
|
||||
if error_type == FileNotFoundError:
|
||||
log = 'no config %s file \n file name: %s \n file type: %s \n stack: %s' % (filetype, filename, filetype, stack)
|
||||
elif error_type == KeyError:
|
||||
error = traceback.format_exc()
|
||||
if isinstance(error_type, FileNotFoundError):
|
||||
log = 'no {} file was found!: \n file name: {} \n file type: {} \n stack: {} \n traceback: {}'.format(filetype, filename, filetype, stack, error)
|
||||
elif isinstance(error_type, KeyError):
|
||||
log = 'no stack in %s file: %s \n file type: %s \n stack: %s' % (filetype, filename, filetype, stack)
|
||||
else:
|
||||
log = 'some error has been found! \n error type: %s \n file name: %s \n file type: %s \n stack: %s' % (error_type, filename, filetype, stack)
|
||||
tools_logger.exception(log)
|
||||
raise error_type(log)
|
||||
|
||||
|
||||
def config(file_name: str, stack=None):
|
||||
@ -73,12 +75,23 @@ def config(file_name: str, stack=None):
|
||||
if stack:
|
||||
rd = rd[stack]
|
||||
return rd
|
||||
except FileNotFoundError:
|
||||
log = 'no {} file was found!: \n file name: {} \n file type: {} \n stack: {}'.format(f_type, file_name, f_type, stack)
|
||||
tools_logger.error(log)
|
||||
raise
|
||||
except KeyError:
|
||||
log = 'no stack in {} file {} was found! \n file type: {} \n file name: {} \n stack: {}'.format(f_type, file_name, f_type, file_name, stack)
|
||||
tools_logger.error(log)
|
||||
raise
|
||||
except Exception as exp:
|
||||
report_file_error(f_type, exp, file_name, stack)
|
||||
log = 'some error has been found!\n error type: {} \n file name: {} \n file type: {} \n stack: {}'.format(type(exp), file_name, f_type, stack)
|
||||
tools_logger.error(log)
|
||||
raise
|
||||
|
||||
|
||||
# main config
|
||||
main_config_file = config('./configs/main.config')
|
||||
Version = semver.VersionInfo.parse(str(main_config_file['runtime']['version']))
|
||||
|
||||
|
||||
def get_At(name, in_xml, need_type=str):
|
||||
@ -117,17 +130,21 @@ def default_name_handler(name_: str) -> str:
|
||||
name = name.replace('{dir}', str(os.getcwd()))
|
||||
name = name.replace('{py_v}', str(sys.version.split(' ')[0]))
|
||||
name = name.replace('{version}', str(main_config_file['runtime']['version']))
|
||||
name = name.replace('{write_v}', str(main_config_file['runtime']['write_py_v']))
|
||||
return name
|
||||
|
||||
|
||||
def name_handler(name: str, formats=None) -> str:
|
||||
def name_handler(name: str, formats: dict = None) -> str:
|
||||
if formats is None:
|
||||
return default_name_handler(name)
|
||||
name = default_name_handler(name)
|
||||
for need_replace in formats:
|
||||
replace = formats[need_replace]
|
||||
if need_replace == '{date}':
|
||||
replace = time.strftime(formats['{date}'], time.gmtime(time.time()))
|
||||
if '{date}' in formats:
|
||||
replace = time.strftime(formats['{date}'], time.gmtime(time.time()))
|
||||
else:
|
||||
replace = time.strftime(main_config_file['runtime']['date_fmt'], time.gmtime(time.time()))
|
||||
name = name.replace(need_replace, replace)
|
||||
return name
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
'main': {
|
||||
'version.now_on': 'Difficult Rocket is running on Python Vision',
|
||||
'version.need3+': 'Difficult Rocket need Python vision 3.0+',
|
||||
'': '',
|
||||
'version.best3.8+': 'Difficult Rocket is writen in Python {write_py_v}, and now is running on Python {py_v} may cause BUG',
|
||||
'lang.language': 'English (EN-US)',
|
||||
'logger.language': 'Logging language is: ',
|
||||
'logger.created': 'Log handler created',
|
||||
@ -15,14 +15,15 @@
|
||||
},
|
||||
'client': {
|
||||
'setup.done': 'Client load complete ',
|
||||
'os.pid_is1': 'Client is using PID',
|
||||
'os.pid_is2': ' To Run',
|
||||
'os.pid_is': 'Client is using PID',
|
||||
'button.been_press': 'The button is pressed, the current state of the button is:',
|
||||
'mouse.press_at': 'mouse was click at {} button is: {}',
|
||||
'mouse.right': 'right button',
|
||||
'mouse.left': 'left button'
|
||||
},
|
||||
'server': {
|
||||
'setup.done': 'server load complete ',
|
||||
'os.pid_is1': 'server is using PID',
|
||||
'os.pid_is2': 'To Run'
|
||||
'os.pid_is': 'Client is using PID: {} PPID: {}'
|
||||
}
|
||||
}
|
||||
/*
|
@ -2,12 +2,12 @@
|
||||
'main': {
|
||||
'version.now_on': '困难火箭的运行Python环境为',
|
||||
'version.need3+': '困难火箭需要Python3.0+的环境',
|
||||
'version.best3.8+': '困难火箭是在Python3.8的环境下编写的,目前正在运行在Python{py_v}的环境下,可能产生BUG',
|
||||
'version.best3.8+': '困难火箭是在Python{write_py_v}的环境下编写的,目前正在运行在Python{py_v}的环境下,可能产生BUG',
|
||||
'lang.language': '简 体 中 文 (zh-cn)',
|
||||
'logger.language': '日志记录语言为:',
|
||||
'logger.created': '日志处理器创建完成',
|
||||
'logger.main_done': '主日志处理器创建完成',
|
||||
'logger.logfile_name': '日志文件文件名::',
|
||||
'logger.logfile_name': '日志文件文件名:',
|
||||
'logger.logfile_level': '日志文件记录级别:',
|
||||
'logger.logfile_fmt': '日志文件记录格式:',
|
||||
'logger.logfile_datefmt': '日志文件日期格式:',
|
||||
@ -15,13 +15,14 @@
|
||||
},
|
||||
'client': {
|
||||
'setup.done': '客户端载入完成',
|
||||
'os.pid_is1': '客户端正在以pid',
|
||||
'os.pid_is2': '运行',
|
||||
'button.been_press': '按钮被按下,目前状态为:'
|
||||
'os.pid_is': '客户端 PID: {} PPID: {}',
|
||||
'button.been_press': '按钮被按下,目前状态为:',
|
||||
'mouse.press_at': '鼠标在 {} 被按下,按键为:{}',
|
||||
'mouse.right': '右键',
|
||||
'mouse.left': '左键'
|
||||
},
|
||||
'server': {
|
||||
'setup.done': '服务端载入完成',
|
||||
'os.pid_is1': '服务端正在以pid',
|
||||
'os.pid_is2': '运行'
|
||||
'os.pid_is': '服务端 PID: {} PPID: {}'
|
||||
}
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
[runtime]
|
||||
version = 0.4.4
|
||||
fps = 60
|
||||
version = 0.4.5
|
||||
language = zh-CN
|
||||
date_fmt = %%Y-%%m-%%d %%H-%%M-%%S
|
||||
write_py_v = 3.8.10
|
||||
|
||||
[window]
|
||||
style = None
|
||||
width = 1024
|
||||
height = 768
|
||||
visible = true
|
||||
caption = Difficult Rocket {version}
|
||||
resizable = true
|
||||
full_screen = false
|
||||
caption = Difficult Rocket {version}
|
||||
|
||||
[window_default]
|
||||
width = 1024
|
||||
height = 768
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
{
|
||||
'textures': {
|
||||
'toolbar_dark': 'Editor/ToolbarDark.png',
|
||||
'toolbar_light': 'Editor/ToolbarLight.png',
|
||||
'trash_can': 'Editor/TrashCan.png'
|
||||
},
|
||||
'button': {
|
||||
'rotate': 'Editor/RotateButton.png',
|
||||
'add_part': 'Editor/ToolbarIconAddPart.png',
|
||||
'to_menu': 'Editor/ToolbarIconMenu.png',
|
||||
// 'part_button': 'Editor/PartButton.png',
|
||||
'stage': 'Editor/ToolbarIconStaging.png',
|
||||
'zoom': 'Editor/ToolbarIconZoom.png',
|
||||
'zoom_in': 'Editor/ToolbarIconZoomIn.png',
|
||||
'zoom_out': 'Editor/ToolbarIconZoomOut.png',
|
||||
'play': 'Editor/ToolbarIconPlay.png',
|
||||
'logic': {
|
||||
'zoom': {
|
||||
'zoom_in': 'child',
|
||||
'zoom_out': 'child'
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
{
|
||||
'width': '1024',
|
||||
'height': '768',
|
||||
'full_screen': 'false',
|
||||
// bool
|
||||
'caption': 'Simple Rocket {version}',
|
||||
// {version} -> version of SR
|
||||
'caption_option': {
|
||||
'version': '0.4.4'
|
||||
},
|
||||
'resizable': 'true',
|
||||
// bool
|
||||
'visible': 'true',
|
||||
// bool
|
||||
'style': 'None',
|
||||
'fps': 60,
|
||||
'views': [
|
||||
'space',
|
||||
'map',
|
||||
'menu'
|
||||
]
|
||||
}
|
23
configs/textures.json5
Normal file
23
configs/textures.json5
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
'Editor': {
|
||||
'runtime': {
|
||||
'toolbar.dark': 'Editor/ToolbarDark.png',
|
||||
'toolbar.light': 'Editor/ToolbarLight.png',
|
||||
'button_side.dark': 'Editor/ButtonDarkSide.png',
|
||||
'button_side.light': 'Editor/ButtonLightSide.png'
|
||||
},
|
||||
'toggle_button': {
|
||||
'stage': 'Editor/ToolbarIconStaging.png',
|
||||
'add_part': 'Editor/ToolbarIconAddPart.png',
|
||||
'menu': 'Editor/ToolbarIconMenu.png'
|
||||
},
|
||||
'push_button': {
|
||||
'zoom': 'Editor/ToolbarIconZoom.png',
|
||||
'zoom.in': 'Editor/ToolbarIconZoomIn.png',
|
||||
'zoom.out': 'Editor/ToolbarIconZoomOut.png',
|
||||
'play': 'Editor/ToolbarIconPlay.png',
|
||||
'rotate': 'Editor/RotateButton.png',
|
||||
'trash_can': 'Editor/TrashCan.png'
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +1,29 @@
|
||||
# Difficult-Rocket
|
||||
# [Difficult-Rocket(github)](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
# [Difficult-Rocket(gitee)](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
|
||||
|
||||
## 版本
|
||||
|
||||
0.4.3 (开发DEMO.ing)
|
||||
- (开发DEMO.ing)(coming s∞n)
|
||||
- 0.4.6 预览版
|
||||
- 0.5.0 开发中.ing
|
||||
|
||||
[更新日志](https://github.com/shenjackyuanjie/Difficult-Rocket/blob/main/docs/update_logs.md)
|
||||
|
||||
[计划特性列表](https://github.com/shenjackyuanjie/Difficult-Rocket/tree/main/docs/plan_features)
|
||||
|
||||
For an English version of readme, please move [here](https://github.com/shenjackyuanjie/Difficult-Rocket).
|
||||
### For an English version of readme, please move [here](https://github.com/shenjackyuanjie/Difficult-Rocket).
|
||||
|
||||
> 这是一个用Python制作的类Simple Rocket游戏
|
||||
|
||||
## 优势
|
||||
|
||||
没有。一个也没有
|
||||
> 相对于原版SR比较“轻量化”
|
||||
|
||||
(因为还没写完呢)
|
||||
## [计划特性列表](./plan_features)
|
||||
|
||||
## 计划特性
|
||||
|
||||
- 都在 [这](https://github.com/shenjackyuanjie/Difficult-Rocket/projects)
|
||||
## [更新日志](./update_logs.md)
|
||||
|
||||
## 环境需求 (测试过的 / 开发平台)
|
||||
|
||||
-
|
||||
- `开发平台1 Windows 10`
|
||||
- `Python 3.8.7`
|
||||
- `Python 3.8.10`
|
||||
- `Windows10 x64`
|
||||
- `Pyglet 1.5.16`
|
||||
- `Json5 0.9.5`
|
||||
@ -43,9 +40,10 @@ For an English version of readme, please move [here](https://github.com/shenjack
|
||||
|
||||
## 需要的Python模块
|
||||
|
||||
- json5 (已经内置V0.9.5 路径:`./bin/libs/json5`)
|
||||
- pyglet (已经内置V1.5.16 路径:`./bin/libs/pyglet`)
|
||||
- json5 (已经内置V0.9.6 路径:`./bin/libs/json5`)
|
||||
- pyglet (已经内置V1.5.18 路径:`./bin/libs/pyglet`)
|
||||
- pillow
|
||||
- semver
|
||||
|
||||
## 感谢
|
||||
|
||||
@ -54,6 +52,8 @@ For an English version of readme, please move [here](https://github.com/shenjack
|
||||
- [@Rayawa](https://github.com/Rayawa) : 文档矫正
|
||||
- [@Billchyi](https://github.com/Billchyi) : 文档矫正
|
||||
|
||||
## 相关链接
|
||||
|
||||
## 关于分享协议
|
||||
|
||||
#### https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
@ -6,6 +6,54 @@
|
||||
- [中文README](README-cn.md)
|
||||
- Using [SemVer 2.0.0](https://semver.org/) to manage version
|
||||
|
||||
## 202108 V 0.5.0
|
||||
|
||||
making
|
||||
|
||||
## 20210811 V 0.4.6
|
||||
|
||||
### DEBUG
|
||||
|
||||
- game window doesn't use input `(*args, **kwargs)` to setup
|
||||
|
||||
### Change
|
||||
|
||||
- language type `zh-cn` -> `zh-CN`
|
||||
- game window config now use `configs/main.config` to config
|
||||
- `on_mouse_click` function's debug message now use `self.lang` to debug message (witch is multi-language)
|
||||
- server client and main now use `logging.getLogger()`
|
||||
|
||||
### Add
|
||||
|
||||
- `[window_default]` in `configs/main.config`
|
||||
- server and client now will output `PID` and `PPID` info as `INFO`
|
||||
- `client` now change to `ClientWindow`
|
||||
|
||||
### Delete
|
||||
|
||||
- all game window render has been deleted
|
||||
- - will be rewritten in 0.5.0
|
||||
- delete some useless code
|
||||
- delete some useless file
|
||||
|
||||
## 20210723 V 0.4.5
|
||||
|
||||
### DEBUG
|
||||
|
||||
- `new_thread.py` link of stackoverflow have an extra 'find' in the middle REMOVED
|
||||
|
||||
### Add
|
||||
|
||||
- `new_thread.py` now can use @new_thread to get a threaded fun
|
||||
|
||||
### Change
|
||||
|
||||
- `README.md` and `README-cn.md` change URL to file path
|
||||
- `README.md` and `README-cn.md` some label style change
|
||||
- Pre-installed `pyglet` upgrade from `1.5.16` -> `1.5.18`
|
||||
- Pre-installed `json5` upgrade from `0.9.5` -> `0.9.6`
|
||||
|
||||
|
||||
## 20210708 V 0.4.4
|
||||
|
||||
### PS
|
||||
|
@ -1,3 +1,5 @@
|
||||
-i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
semver
|
||||
pyglet
|
||||
json5
|
||||
pillow
|
||||
pillow
|
||||
json5
|
39
tests/test_process.py
Normal file
39
tests/test_process.py
Normal file
@ -0,0 +1,39 @@
|
||||
"""
|
||||
writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
github: @shenjackyuanjie
|
||||
"""
|
||||
from multiprocessing import Process
|
||||
import os
|
||||
|
||||
|
||||
def testsss(a):
|
||||
print(os.getpid())
|
||||
print(os.getppid())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(os.getpid())
|
||||
print(os.getppid())
|
||||
pro = Process(target=testsss, args=('a',))
|
||||
pro.start()
|
||||
pro.join()
|
||||
|
||||
|
||||
def info(title):
|
||||
print(title)
|
||||
print('module name:', __name__)
|
||||
print('parent process:', os.getppid())
|
||||
print('process id:', os.getpid())
|
||||
|
||||
|
||||
def f(name):
|
||||
info('function f')
|
||||
print('hello', name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
info('main line')
|
||||
p = Process(target=f, args=('bob',))
|
||||
p.start()
|
||||
p.join()
|
Loading…
Reference in New Issue
Block a user