From 50a839826da2a4b620cb9f9f09aa386cba4cd4b6 Mon Sep 17 00:00:00 2001 From: Nguyễn Gia Phong Date: Thu, 8 Feb 2018 20:41:08 +0700 Subject: Add control configuration --- brutalmaze/main.py | 105 +++++++++++++++++++++++++++++++++++++----------- brutalmaze/maze.py | 6 +-- brutalmaze/misc.py | 9 +---- brutalmaze/settings.ini | 7 ---- settings.ini | 22 ++++++++++ 5 files changed, 108 insertions(+), 41 deletions(-) delete mode 100644 brutalmaze/settings.ini create mode 100644 settings.ini diff --git a/brutalmaze/main.py b/brutalmaze/main.py index c77cde6..9dc7a4c 100644 --- a/brutalmaze/main.py +++ b/brutalmaze/main.py @@ -17,35 +17,88 @@ # # Copyright (C) 2017 Nguyễn Gia Phong +import re from collections import deque -try: - from configparser import ConfigParser # Python 3 -except ImportError: - from ConfigParser import ConfigParser # Python 2 +try: # Python 3 + from configparser import ConfigParser, NoOptionError, NoSectionError +except ImportError: # Python 2 + from ConfigParser import ConfigParser, NoOptionError, NoSectionError from os.path import join -from appdirs import AppDirs +from appdirs import user_config_dir, site_config_dir from pkg_resources import resource_filename import pygame -from pygame.locals import * +from pygame import DOUBLEBUF, KEYDOWN, OPENGL, QUIT, RESIZABLE, VIDEORESIZE from .constants import * from .maze import Maze -from .misc import some + + +USER_CONFIG = join(user_config_dir('brutalmaze'), 'settings.ini') +SITE_CONFIG = join(site_config_dir('brutalmaze'), 'settings.ini') +DEFAULT_BINDINGS = {'New game': 'F2', 'Pause': 'p', + 'Move left': 'Left', 'Move right': 'Right', + 'Move up': 'Up', 'Move down': 'Down', + 'Long-range attack': 'Mouse1', + 'Close-range attack': 'Mouse3'} + + +def getconf(config, section, option, valtype=str, fallback=None): + """Return an option value for a given section from a ConfigParser + object. + + If the key is not found, return the fallback value. + """ + if fallback is None: fallback = valtype() + try: + if valtype == str: + return config.get(section, option) + elif valtype == bool: + return config.getboolean(section, option) + elif valtype == float: + return config.getfloat(section, option) + elif valtype == int: + return config.getint(section, option) + except NoSectionError, NoOptionError: + return fallback def main(): """Start game and main loop.""" # Read configuration file - dirs = AppDirs(appname='brutalmaze') config = ConfigParser() - if not config.read(join(dirs.user_config_dir, 'settings.ini')): - if not config.read(join(dirs.site_config_dir, 'settings.ini')): - config.read(resource_filename('brutalmaze', 'settings.ini')) + conf = config.read(USER_CONFIG) + if not conf: conf = config.read(SITE_CONFIG) + conf = conf[0] if conf else '' + + # Read graphics configurations + width = getconf(config, 'Graphics', 'Screen width', int, 640) + height = getconf(config, 'Graphics', 'Screen height', int, 480) scrtype = RESIZABLE - if config.getboolean('Graphics', 'OpenGL'): - surftype |= OPENGL | DOUBLEBUF - fps = config.getfloat('Graphics', 'Maximum FPS') + if getconf(config, 'Graphics', 'OpenGL', bool): + scrtype |= OPENGL | DOUBLEBUF + fps = getconf(config, 'Graphics', 'Maximum FPS', float, 60.0) + + # Read control configurations + key, mouse = {}, {} + for cmd, bind in DEFAULT_BINDINGS.items(): + i = getconf(config, 'Control', cmd, fallback=bind).lower() + if re.match('mouse[1-3]$', i): + if cmd not in ('Long-range attack', 'Close-range attack'): + print('File "{}", section Control'.format(conf)) + print('\tOne does not simply {} using a mouse'.format(cmd)) + quit() + mouse[cmd] = int(i[-1]) - 1 + continue + if len(i) == 1: + key[cmd] = ord(i) + continue + try: + key[cmd] = getattr(pygame, 'K_{}'.format(i.upper())) + except AttributeError: + print('File "{}", section Control, option {}'.format(conf, cmd)) + print('\t"{}" is not recognized as a valid input'.format(i)) + quit() # Initialization pygame.mixer.pre_init(frequency=44100) @@ -54,8 +107,7 @@ def main(): pygame.mixer.music.play(-1) pygame.display.set_icon(ICON) pygame.fastevent.init() - maze = Maze((config.getint('Graphics', 'Screen width'), - config.getint('Graphics', 'Screen height')), scrtype, fps) + maze = Maze((width, height), scrtype, fps) clock, flash_time, going = pygame.time.Clock(), deque(), True # Main loop @@ -67,19 +119,26 @@ def main(): elif event.type == VIDEORESIZE: maze.resize((event.w, event.h), scrtype) elif event.type == KEYDOWN: - if event.key == K_F2: # new game - maze.__init__((maze.w, maze.h), fps) - elif event.key in (K_ESCAPE, K_p) and not maze.hero.dead: + if event.key == key['New game']: + maze.__init__((maze.w, maze.h), scrtype, fps) + elif event.key == key['Pause'] and not maze.hero.dead: maze.paused ^= True if not maze.hero.dead: keys = pygame.key.get_pressed() + maze.move(keys[key['Move left']] - keys[key['Move right']], + keys[key['Move up']] - keys[key['Move down']], fps) buttons = pygame.mouse.get_pressed() - maze.move(some(keys, LEFT) - some(keys, RIGHT), - some(keys, UP) - some(keys, DOWN), fps) - maze.hero.slashing = keys[K_RETURN] or buttons[2] - maze.hero.firing = buttons[0] + try: + maze.hero.firing = keys[key['Long-range attack']] + except KeyError: + maze.hero.firing = buttons[mouse['Long-range attack']] + try: + maze.hero.slashing = keys[key['Close-range attack']] + except KeyError: + maze.hero.slashing = buttons[mouse['Close-range attack']] + # Compare current FPS with the average of the last 5 seconds if len(flash_time) > 5: new_fps = 5000.0 / (flash_time[-1] - flash_time[0]) flash_time.popleft() diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py index f8c8169..197fb5e 100644 --- a/brutalmaze/maze.py +++ b/brutalmaze/maze.py @@ -347,11 +347,11 @@ class Maze: offsetx = (self.centerx-self.x) / self.distance offsety = (self.centery-self.y) / self.distance - self.distance = (w * h / 416) ** 0.5 - self.x, self.y = w // 2, h // 2 + self.distance = (self.w * self.h / 416) ** 0.5 + self.x, self.y = self.w // 2, self.h // 2 self.centerx = self.x + offsetx*self.distance self.centery = self.y + offsety*self.distance - w, h = int(w/self.distance/2 + 2), int(h/self.distance/2 + 2) + w, h = int(self.w/self.distance/2 + 2), int(self.h/self.distance/2 + 2) self.rangex = range(MIDDLE - w, MIDDLE + w + 1) self.rangey = range(MIDDLE - h, MIDDLE + h + 1) self.slashd = self.hero.R + self.distance/SQRT2 diff --git a/brutalmaze/misc.py b/brutalmaze/misc.py index 6593c48..d58a2ca 100644 --- a/brutalmaze/misc.py +++ b/brutalmaze/misc.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# characters.py - module for shared functions and macros +# misc.py - module for miscellaneous functions # This file is part of brutalmaze # # brutalmaze is free software: you can redistribute it and/or modify @@ -19,9 +19,7 @@ __doc__ = 'brutalmaze module for hero and enemy classes' -from functools import reduce from math import cos, sin, pi -from operator import or_ from random import uniform import pygame @@ -30,11 +28,6 @@ from pygame.gfxdraw import filled_polygon, aapolygon from .constants import MIDDLE -def some(a, keys): - """Return True if there is a key k in keys that bool(a[k]) is True.""" - return bool(reduce(or_, (a[k] for k in keys))) - - def round2(number): """Round a number to an int.""" return int(round(number)) diff --git a/brutalmaze/settings.ini b/brutalmaze/settings.ini deleted file mode 100644 index ee5aefa..0000000 --- a/brutalmaze/settings.ini +++ /dev/null @@ -1,7 +0,0 @@ -[Graphics] -Screen width: 640 -Screen height: 480 -# OpenGL should be supported on all machines with hardware acceleration -OpenGL: no -# FPS should not be greater than refresh rate -Maximum FPS: 60 diff --git a/settings.ini b/settings.ini new file mode 100644 index 0000000..00a071f --- /dev/null +++ b/settings.ini @@ -0,0 +1,22 @@ +[Graphics] +Screen width: 640 +Screen height: 480 +# OpenGL should be supported on all machines with hardware acceleration. +OpenGL: no +# FPS should not be greater than refresh rate. +Maximum FPS: 60 + +[Control] +# Input values should be either from Mouse1 to Mouse3 or a keyboard key +# and they are case-insensitively read. +# Aliases for special keys are listed here (without the K_ part): +# http://www.pygame.org/docs/ref/key.html +# Key combinations are not supported. +New game: F2 +Pause: p +Move left: Left +Move right: Right +Move up: Up +Move down: Down +Long-range attack: Mouse1 +Close-range attack: Mouse3 -- cgit 1.4.1