view package

The View in the Model-View-Controller paradigm.

The view package is responsible for maintaining classes that can be drawn using the PyQt4 interface.

Submodules

view.actors module

The actors.

class view.actors.Actor(scene, cx, cy)[source]

Bases: PyQt4.QtGui.QGraphicsItem

The primary base class for all Actors that are to be added to the scene for game play. If you decide to extend the game and introduce more types of actors, you must inherit from this class.

Parameters:
scene (model.Scene)

The Scene that this actor is bound to.

cx (float)

The starting location \(c_x\) of this Actor, saved so that the game can be reset.

cy (float)

The starting location \(c_y\) of this Actor, saved so that the game can be reset.

Attributes:
scene (model.Scene)

The Scene that this actor is bound to.

moveFlags (int)

An integer that embeds the representation of the direction this Actor is currently moving in. This integer is used in conjunction with bitmasking, and may only contain the values represented by constants.STATIONARY | constants.MOVE_NORTH | constants.MOVE_SOUTH | constants.MOVE_EAST | constants.MOVE_WEST.

cx (float)

The starting location \(c_x\) of this Actor, saved so that the game can be reset.

cy (float)

The starting location \(c_y\) of this Actor, saved so that the game can be reset.

The coordinate \((c_x, c_y)\) represents the center of the Actor’s starting location, and should never change. To acquire the current position of the actor, use the x() and y() methods respectively, these methods are inherited from the PyQt4.QtGui.QGraphicsItem class.

NORTH = PyQt4.QtCore.QPointF(0.0, -1.0)

A PyQt4.QtCore.QPointF representing the direction North.

SOUTH = PyQt4.QtCore.QPointF(0.0, 1.0)

A PyQt4.QtCore.QPointF representing the direction South.

EAST = PyQt4.QtCore.QPointF(1.0, 0.0)

A PyQt4.QtCore.QPointF representing the direction East.

WEST = PyQt4.QtCore.QPointF(-1.0, 0.0)

A PyQt4.QtCore.QPointF representing the direction West.

boundingRect()[source]

Returns the bounding rectangle for this Actor. This is used by the graphics backend to determine things such as collisions, whether or not the Actor should be drawn (e.g. if it is not visible, don’t waste time).

Note

All subclasses must override this method.

Return:
PyQt4.QtCore.QRectF

The bounding rectangle of the actor’s current position.

paint(painter, option, widget)[source]

The method that is responsible for drawing this Actor.

You need not be concerned with the details of this method. Refer to the parent class PyQt4.QtGui.QGraphicsItem documentation on this method for more information.

Note

All subclasses must override this method.

queueMove(direction, press)[source]

Adds or removes the direction to this Actors’ move flags.

Parameters:
direction (int)

The direction to add or remove from self.moveFlags.

press (bool)

Whether the key corresponding to this direction is being pressed. True if coming from a key press event, False if the key is being released.

Preconditions:
Direction Value

direction may only be one of constants.MOVE_NORTH, constants.MOVE_SOUTH, constants.MOVE_EAST, or constants.MOVE_WEST. Any other values will yield varied and unreliable results.

isStationary()[source]

Returns whether or not this Actor is currently moving.

Return:
bool

True if this Actor is not moving, False otherwise.

setStationary()[source]

Stops the actor from moving by settings its moveFlags to be constants.STATIONARY.

isMoveDirection(direction)[source]

Returns whether or not this Actor is currently moving in the specified direction.

Parameters:
direction (int)

The direction to test whether or not the Actor is currently moving in.

Return:
bool

True if the Actor is moving in the specified direction, False otherwise.

Preconditions:
Direction Value

direction may only be one of constants.MOVE_NORTH, constants.MOVE_SOUTH, constants.MOVE_EAST, or constants.MOVE_WEST. Any other values will yield varied and unreliable results.

reset()[source]

Resets the starting position of this Actor and makes it stationary. This implementation can be overriden, but it is important that this code is actually executed. Refer to the implementation of view.actors.Food.reset() for how to do this.

The position is reset to (self.cx, self.cy), and self.moveFlags is reset to be constants.STATIONARY.

advance(phase)[source]

Updates the current position of this Actor depending on the value of its current move flags.

Parameters:
phase (int)

The update phase. For this framework, we only need to worry about when the second phase occurs, which is when phase == 1. Refer to the advance documentation for the parent class PyQt4.QtGui.QGraphicsItem

class view.actors.Food(scene, cx, cy, color, radius)[source]

Bases: view.actors.Actor

Animated food.

Parameters:
scene (model.Scene)

The Scene that this food is bound to.

cx (float)

The starting location \(c_x\) of this Food, saved so that the game can be reset.

cy (float)

The starting location \(c_y\) of this Food, saved so that the game can be reset.

color (PyQt4.QtGui.QColor)

The color for the outer circle of this Food.

radius (float)

The radius of the Food (should be constants.FOOD_RADIUS).

Attributes:
outerRadius (float)

The input radius.

innerRadius (float)

Exactly half the outerRadius.

outerColor (PyQt4.QtGui.QColor)

The input color.

innerColor (PyQt4.QtGui.QColor)

The inverse of outerColor.

outerSweep (float)

The value between [0,360] representing how far the outer food circle should be swept.

innerSweep (float)

The value between [0,360] representing how far the inner food circle should be swept.

decreasing (bool)

Whether or not at each time step the radii should be increased or decreased. When True, the outerSweep is decreased by 1 and the innerSweep is increased by one. When False, the outerSweep is increased by 1 and the innerSweep is decreased by 1.

outerBoundingRect (PyQt4.QtCore.QRectF)

The bounding rectangle for the circle described by outerRadius.

innerBoundingRect (PyQt4.QtCore.QRectF)

The bounding rectangle for the circle described by innerRadius.

startAngle (float)

A random number in the range [0, 360.0] representing where the sweep should begin from.

computeBoundingRect(radius)[source]

Computes the bounding rectangle for the specified radius, based off the food’s current position.

Parameters:
radius (float)

The radius of the circle.

Return:
PyQt4.QtCore.QRectF

The bounding rectangle defined by the circle of the specified radius.

Preconditions:
Radius Size

The radius must be strictly greater than 0.

boundingRect()[source]

The current bounding rectangle for this food. Currently, it just returns self.outerBoundingRect, but if the animation slowed down significantly it would be feasible to change it to return self.innerBoundingRect when the animation has reached a state where only the inner circle is drawn.

paint(painter, option, widget)[source]

Displays the food at its current sweep state.

advance(phase)[source]

Increases / decreases both radii depending on self.decreasing. When the outerSweep reaches 0.0, decreasing is set to False. When outerSweep reaches 360.0, decreasing is set to True.

Parameters:
phase (int)

The update phase, either 0 or 1. Updates to the radii are applied at phase 1.

reset()[source]

This method resets the self.innerSweep and self.outerSweep to the initial starting positions, and sets self.decreasing to False, thus “restarting” the animation of the Food.

After, it calls the super class reset method (view.actors.Actor.reset()) so that the position will be reset as well. This is necessary, for example, if you wanted to incorporate moving Food into the game as well.

class view.actors.SplineDrawer(scene, cx, cy, dataResource, sx, sy)[source]

Bases: view.actors.Actor

Do not edit this class.

Parameters:
scene (model.Scene)

The Scene that this ghost is bound to.

cx (float)

The starting location \(c_x\) of this Ghost, saved so that the game can be reset.

cy (float)

The starting location \(c_y\) of this Ghost, saved so that the game can be reset.

dataResource (str)

The Qt Resource string that points to the json formatted file to load.

sx (float)

The \(x\) scaling factor \(s_x\) of this Ghost, should be the value of constants.SPLINE_COORD_SCALE.

sy (float)

The \(y\) scaling factor \(s_y\) of this Ghost, should be the value of -1.0 * constants.SPLINE_COORD_SCALE.

Attributes:
path (PyQt4.QtGui.QPainterPath)

The painter path as parsed by view.actors.SplineDrawer.parseResourceJson().

pathRect (PyQt4.QtCore.QRectF)

The bounding rectangle for the painter path.

poly (PyQt4.QtCore.QPolygonF)

The minimal polygon that describes the path.

polyRect (PyQt4.QtCore.QRectF)

The bounding rectangle for the polygon.

This class exists to take Bezier data points from Blender’s representation and use Qt’s representation instead. A valid input data json looks like this:

{
  "0": {
    "handle_left": [
      2.777250289916992,
      0.6249623894691467,
      0.0
    ],
    "co": [
      2.992664337158203,
      -0.2417435348033905,
      0.0
    ],
    "handle_right": [
      1.0,
      -0.10000000149011612,
      0.0
    ]
  },
  "1": {
    "handle_left": [
      0.4000000059604645,
      -1.0,
      0.0
    ],
    "co": [
      0.0,
      -2.1055381298065186,
      0.0
    ],
    "handle_right": [
      -0.4000000059604645,
      -1.0,
      0.0
    ]
  },
  "closed": true
}

Every key must be an integer, except for the last key, which must be exactly closed. Each integer key represents a control point, which must have nested keys of

handle_left
The left handle of the blender control point.
co
The blender control point.
handle_right
The right handle of the blender control point.

Note

Observe that all points have a z value of 0. Nothing will break if you have non-zero z values, but they will be ignored. AKA the resultant spline will be a projection into the XY plane, which may look nothing like the spline you intended to have drawn.

Using Blender’s Interactive Console, you can acquire the properly formatted json of your own model using this adaptation of an excellent blog post modified to suit the needs of this program.

import bpy
import sys
import json

# Make sure you have your Bezier Curve selected
obj = bpy.context.active_object

# Store all points in the same dictionary
all_points = {}

# Go through the curve
if obj.type == 'CURVE':
    for subcurve in obj.data.splines:
        # Only support bezier curves
        curvetype = subcurve.type
        if curvetype == 'BEZIER':
            idx = 0
            for bp in subcurve.bezier_points:
                co_x, co_y, co_z = bp.co
                hL_x, hL_y, hL_z = bp.handle_left
                hR_x, hR_y, hR_z = bp.handle_right
                as_dict = {
                  "co": [co_x, co_y, co_z],
                  "handle_left": [hL_x, hL_y, hL_z],
                  "handle_right": [hR_x, hR_y, hR_z]
                }
                all_points[idx] = as_dict
                idx += 1

# I only support closed curves, make sure yours is
all_points["closed"] = True

# Save everything, or print if testing
save_file = True
all_data = json.dumps(all_points, indent=2)
save_filebase = "/home/sven/Downloads"  # set this to where you want it saved
save_filetail = "ghost_body.json"       # use absolute paths!
save_filename = "{}/{}".format(save_filebase, save_filetail)

if save_file:
    with open(save_filename, "w") as file:
        file.write("{}\n".format(all_data))
else:
    print(all_data)

We gratefully acknowledge Ian Scott for his excellent tutorials on Blender, and as tribute used his using curves Bat unadulterated for CitizenPac.

The Ghost and CitizenPac in Blender form are available here: citizen_pac_curves.blend.

Once you have the interactive console open (it should open by default for this file) you can run in the console:

exec(bpy.data.texts[0].as_string())

Tip

If you want to add some more characters to your game, this would be a good file to work in so that they all stay in the same coordinate system / can have the same scaling factor (constants.SPLINE_COORD_SCALE) applied :)

classmethod parseResourceJson(dataResource, sx, sy)[source]

Responsible for parsing the properly formatted (see class documentation) and scaling the points, returning a painter path representing the same spline created using Qt’s cubic methods.

Parameters:
dataResource (str)

The Qt Resource descriptor that contains the json data to parse.

sx (float)

The \(x\) scaling factor \(s_x\) of this Ghost, should be the value of constants.SPLINE_COORD_SCALE.

sy (float)

The \(y\) scaling factor \(s_y\) of this Ghost, should be the value of -1.0 * constants.SPLINE_COORD_SCALE.

Return:
PyQt4.QtGui.QPainterPath

The cubic painter path representing the same spline as modeled by Blender.

paint(painter, option, widget)[source]

Paints this spline. Currently, since the actors in the game are small, the polygon path is used instead of the cubic path. If you desire to draw any of the actors at a higher resolution, you should draw with self.path instead.

boundingRect()[source]

Returns the bounding rectangle of this spline.

Return:
PyQt4.QtCore.QRectF

The bounding rectangle, currently it returns self.polyRect but if you need to draw the spline (see view.actors.SplineDrawer.paint()) then you should return self.pathRect instead.

class view.actors.GhostActor(scene, cx, cy, sx, sy)[source]

Bases: view.actors.SplineDrawer

The ghosts.

Parameters:
scene (model.Scene)

The Scene that this ghost is bound to.

cx (float)

The starting location \(c_x\) of this Ghost, saved so that the game can be reset.

cy (float)

The starting location \(c_y\) of this Ghost, saved so that the game can be reset.

sx (float)

The \(x\) scaling factor \(s_x\) of this Ghost, should be the value of constants.SPLINE_COORD_SCALE.

sy (float)

The \(y\) scaling factor \(s_y\) of this Ghost, should be the value of -1.0 * constants.SPLINE_COORD_SCALE.

Attributes:
moveTimer (PyQt4.QtCore.QTimer)

The timer to control when a ghost will randomly change its move pattern, connected directly to view.actors.GhostActor.timerEvent() and refreshes at the interval defined by view.actors.GhostActor.GHOST_MOVE_TIME.

That is, Ghosts change their direction independent of the game loop.

DATA_FILE = ':/view/qt_configs/data/ghost_body.json'

The data file needed to instantiate a Ghost.

GHOST_MOVE_TIME = 1000

How frequently a GhostActor should randomly change its direction. This time is specified in milliseconds, i.e. 1000 means 1 second.

timerEvent()[source]

When called the ghost will randomly choose with probability \(p = \frac{1}{2}\) to either add or remove a direction from its moveFlags.

class view.actors.CitizenPacActor(scene, cx, cy, sx, sy)[source]

Bases: view.actors.SplineDrawer

Citizen Pac.

Parameters:
scene (model.Scene)

The Scene that this ghost is bound to.

cx (float)

The starting location \(c_x\) of this Ghost, saved so that the game can be reset.

cy (float)

The starting location \(c_y\) of this Ghost, saved so that the game can be reset.

sx (float)

The \(x\) scaling factor \(s_x\) of this Ghost, should be the value of constants.SPLINE_COORD_SCALE.

sy (float)

The \(y\) scaling factor \(s_y\) of this Ghost, should be the value of -1.0 * constants.SPLINE_COORD_SCALE.

DATA_FILE = ':/view/qt_configs/data/bat_points.json'

The data file needed to instantiate a CitizenPac.

advance(phase)[source]

See parent class documentation in view.actors.Actor.advance().

printMoveFlags()[source]

Prints the current move direction, and what the previously computed move direction was. Only intended to be called after view.actors.CitizenPacActor.advance().

view.display module

The primary display interfaces.

view.display.randomColor()[source]

Returns a random color.

Return:
PyQt4.QtGui.QColor

A random color generated by choosing a random integer in [0, 255] for the red, green, and blue channels.

class view.display.CitizenPacMainWindow(parent=None, f=<PyQt4.QtCore.WindowFlags object>)[source]

Bases: PyQt4.QtGui.QMainWindow, view.qt_configs.qt_generated_ui.Ui_CitizenPacMainWindow

Ui interface. This class is identical to that which would be generated by the Qt UI Toolit using the -w flag, only we also include a resize event handler to allow the game to scale up / down with resizing.

Danger

Do not ever forget to call self.setupUi(self) in the constructor! See the generated Ui file in the qt_configs directory for why.

Attributes:
scene (model.Scene)

The scene everything is being drawn in.

attachScene(scene)[source]

We need the scene in order to determine what size we are trying to display in.

Parameters:
scene (model.Scene)

The scene we are going to store a reference to internally.

resizeEvent(e)[source]

When a resize event occurs, resize the scene viewport to show the game at the maximum resolution possible without distorting the aspect ratio. Makes use of the PyQt4.QtGui.QGraphicsView‘s fitInView method.

Parameters:
e (PyQt4.QtGui.QResizeEvent)

The resize event being dispatched by the Qt backend.

class view.display.GameStats(gameRunning, speedBoost, numLives, scoreBoard)[source]

Bases: object

Wrapper class for displaying the game statistics in the top.

Parameters:
gameRunning (PyQt4.QtGui.QCheckBox)

The checkbox in the top-left of the UI representing whether or not the game is currently running or not.

speedBoost (PyQt4.QtGui.QProgressBar)

The progress bar just to the right of the checkbox indicating by how much the speed of the game has been boosted.

numLives (PyQt4.QtGui.QLCDNumber)

The LCD panel to display the number of lives left on.

scoreBoard (PyQt4.QtGui.QLCDNumber)

The LCD panel to display the game score on.

Attributes:
gameRunning (PyQt4.QtGui.QCheckBox)

The checkbox in the top-left of the UI representing whether or not the game is currently running or not.

speedBoost (PyQt4.QtGui.QProgressBar)

The progress bar just to the right of the checkbox indicating by how much the speed of the game has been boosted.

numLives (PyQt4.QtGui.QLCDNumber)

The LCD panel to display the number of lives left on.

scoreBoard (PyQt4.QtGui.QLCDNumber)

The LCD panel to display the game score on.

setRunning(running)[source]

Checks the gameRunning checkbox.

Parameters:
running (bool)

The value to set checked to, True for checked, False otherwise.

displayGameScore(score)[source]

Sets the game score display.

Parameters:
score (float)

The value to display on the game scoreBoard.

displayGameSpeed(speed)[source]

Sets the game speed boost progress bar.

Parameters:
speed (float)

The value to display on the speedBoost progress bar.

setLives(val)[source]

Sets the lives left display.

Parameters:
val (int)

The value to display on the game scoreBoard.