Add control configuration
This commit is contained in:
parent
dbe0ae4c01
commit
50a839826d
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue