mirror of
https://github.com/n0remac/game-jam-2020.git
synced 2025-12-09 14:05:20 -06:00
31
triple-dungeon/.github/workflows/ci.yml
vendored
Normal file
31
triple-dungeon/.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Continuous Integration (PEP8 Lint + pytest)
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: Install pipenv & sync
|
||||
run: |
|
||||
# cd triple-dungeon
|
||||
python -m pip install --upgrade pip
|
||||
pip install pipenv
|
||||
pipenv lock
|
||||
pipenv sync
|
||||
- name: Linting
|
||||
run: |
|
||||
pip install pycodestyle
|
||||
# PyCharm sets line length at 120 chars
|
||||
pycodestyle . --count --statistics --max-line-length=120
|
||||
- name: Test with pytest
|
||||
run: |
|
||||
pip install pytest
|
||||
pytest tests.py
|
||||
3
triple-dungeon/.gitignore
vendored
3
triple-dungeon/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.idea/**
|
||||
.idea/**
|
||||
.pytest_cache
|
||||
@@ -9,6 +9,7 @@ verify_ssl = true
|
||||
arcade = "*"
|
||||
networkx = "*"
|
||||
pathfinding = "*"
|
||||
pytest = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
|
||||
90
triple-dungeon/Pipfile.lock
generated
90
triple-dungeon/Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "072e8938371eb0a39830868ce97961536e15f31d82fcdf3019e870522684c661"
|
||||
"sha256": "a4938aef96c9adc916384dca2f6b171095dc8fcbd90da0e757dfc73f1da98907"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -23,6 +23,14 @@
|
||||
"index": "pypi",
|
||||
"version": "==2.3.15"
|
||||
},
|
||||
"atomicwrites": {
|
||||
"hashes": [
|
||||
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
|
||||
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
|
||||
],
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
|
||||
@@ -30,6 +38,14 @@
|
||||
],
|
||||
"version": "==19.3.0"
|
||||
},
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
|
||||
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
|
||||
],
|
||||
"markers": "sys_platform == 'win32'",
|
||||
"version": "==0.4.3"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
"sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760",
|
||||
@@ -37,6 +53,21 @@
|
||||
],
|
||||
"version": "==4.4.2"
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f",
|
||||
"sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"
|
||||
],
|
||||
"markers": "python_version < '3.8'",
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"more-itertools": {
|
||||
"hashes": [
|
||||
"sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c",
|
||||
"sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"
|
||||
],
|
||||
"version": "==8.2.0"
|
||||
},
|
||||
"networkx": {
|
||||
"hashes": [
|
||||
"sha256:cdfbf698749a5014bf2ed9db4a07a5295df1d3a53bf80bf3cbd61edf9df05fa1",
|
||||
@@ -71,6 +102,13 @@
|
||||
],
|
||||
"version": "==1.18.3"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3",
|
||||
"sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"
|
||||
],
|
||||
"version": "==20.3"
|
||||
},
|
||||
"pathfinding": {
|
||||
"hashes": [
|
||||
"sha256:3e3809abada1fdb292ced85cd7f63700c4f28a20f10eae68168a760be52ca746",
|
||||
@@ -106,6 +144,20 @@
|
||||
],
|
||||
"version": "==7.1.1"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
|
||||
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
|
||||
],
|
||||
"version": "==0.13.1"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa",
|
||||
"sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"
|
||||
],
|
||||
"version": "==1.8.1"
|
||||
},
|
||||
"pyglet": {
|
||||
"hashes": [
|
||||
"sha256:bd96b9c374a7192e4787f989e8f911719476c71476466a02312839e8cb6a0d4e",
|
||||
@@ -113,11 +165,47 @@
|
||||
],
|
||||
"version": "==1.5.3"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
|
||||
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
|
||||
],
|
||||
"version": "==2.4.7"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:0e5b30f5cb04e887b91b1ee519fa3d89049595f428c1db76e73bd7f17b09b172",
|
||||
"sha256:84dde37075b8805f3d1f392cc47e38a0e59518fb46a431cfdaf7cf1ce805f970"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.4.1"
|
||||
},
|
||||
"pytiled-parser": {
|
||||
"hashes": [
|
||||
"sha256:7664f5ed291fa51bad131c0f844f80c81ee604c768eb05ebe29530ddff4a0000"
|
||||
],
|
||||
"version": "==0.9.3"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
|
||||
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
|
||||
],
|
||||
"version": "==1.14.0"
|
||||
},
|
||||
"wcwidth": {
|
||||
"hashes": [
|
||||
"sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1",
|
||||
"sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"
|
||||
],
|
||||
"version": "==0.1.9"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b",
|
||||
"sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"
|
||||
],
|
||||
"version": "==3.1.0"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
|
||||
@@ -3,17 +3,17 @@ main.py
|
||||
The main class used to load the game.
|
||||
Holds the main game window, as well as manages basic functions for organizing the game.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import math
|
||||
import random
|
||||
import time
|
||||
|
||||
import arcade
|
||||
import math
|
||||
|
||||
from config import Config
|
||||
from map import Dungeon
|
||||
from mobs import Player, Enemy
|
||||
from config import Config
|
||||
from mobs import Player
|
||||
from projectiles import Temp
|
||||
|
||||
|
||||
@@ -45,23 +45,16 @@ class Game(arcade.Window):
|
||||
# Call the parent class and set up the window
|
||||
super().__init__(Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT, Config.SCREEN_TITLE)
|
||||
|
||||
# These are 'lists' that keep track of our sprites. Each sprite should
|
||||
# go into a list.
|
||||
# Sprite Lists
|
||||
self.enemy_list = None
|
||||
self.bullet_list = None
|
||||
self.player = None
|
||||
|
||||
# Game Objects
|
||||
self.dungeon = None
|
||||
|
||||
# list to keep track of keypresses
|
||||
self.prev_keypress = []
|
||||
|
||||
# Our physics engine
|
||||
self.physics_engine = None
|
||||
|
||||
self.prev_keypress = [] # A list that assists with tracking keypress events
|
||||
self.physics_engine = None # Our physics engine
|
||||
# Used to keep track of our scrolling
|
||||
self.view_bottom = 0
|
||||
self.view_left = 0
|
||||
self.view_bottom = self.view_left = 0
|
||||
|
||||
arcade.set_background_color(arcade.color.BLACK)
|
||||
|
||||
@@ -74,7 +67,7 @@ class Game(arcade.Window):
|
||||
self.bullet_list = arcade.SpriteList()
|
||||
|
||||
# Create the dungeon
|
||||
self.dungeon = Dungeon(0, 8)
|
||||
self.dungeon = Dungeon(0, 3)
|
||||
|
||||
# Set up the player, specifically placing it at these coordinates.
|
||||
self.player = Player()
|
||||
@@ -110,12 +103,16 @@ class Game(arcade.Window):
|
||||
self.enemy_list.draw()
|
||||
self.bullet_list.draw()
|
||||
|
||||
self.player.draw_hit_box()
|
||||
x, y = self.player.center_x, self.player.center_y
|
||||
arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial')
|
||||
arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30,
|
||||
arcade.color.WHITE, 16, font_name='Arial')
|
||||
self.fps.tick()
|
||||
if Config.DEBUG:
|
||||
x, y = self.player.position
|
||||
tile = Config.TILE_WIDTH * Config.TILE_SCALING
|
||||
arcade.draw_rectangle_outline(round(x / tile) * tile, round(y / tile) * tile, tile, tile,
|
||||
arcade.color.RED)
|
||||
self.player.draw_hit_box()
|
||||
arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial')
|
||||
arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30,
|
||||
arcade.color.WHITE, 16, font_name='Arial')
|
||||
self.fps.tick()
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
@@ -169,8 +166,8 @@ class Game(arcade.Window):
|
||||
bullet.center_y = start_y
|
||||
|
||||
# Get from the mouse the destination location for the bullet
|
||||
dest_x = x+self.view_left
|
||||
dest_y = y+self.view_bottom
|
||||
dest_x = x + self.view_left
|
||||
dest_y = y + self.view_bottom
|
||||
|
||||
# Do math to calculate how to get the bullet to the destination.
|
||||
# Calculation the angle in radians between the start points
|
||||
@@ -245,10 +242,10 @@ class Game(arcade.Window):
|
||||
|
||||
# If the bullet flies off-screen, remove it. TEMP change to range calc
|
||||
if (
|
||||
bullet.bottom < self.view_bottom or
|
||||
bullet.top > self.view_bottom+Config.SCREEN_HEIGHT or
|
||||
bullet.right > self.view_left+Config.SCREEN_WIDTH or
|
||||
bullet.left < self.view_left
|
||||
bullet.bottom < self.view_bottom or
|
||||
bullet.top > self.view_bottom + Config.SCREEN_HEIGHT or
|
||||
bullet.right > self.view_left + Config.SCREEN_WIDTH or
|
||||
bullet.left < self.view_left
|
||||
):
|
||||
bullet.remove_from_sprite_lists()
|
||||
|
||||
|
||||
@@ -7,12 +7,10 @@ Pathfinding will also depend on objects here, and is thus integral to it's funct
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import arcade
|
||||
import numpy as np
|
||||
|
||||
from itertools import chain
|
||||
|
||||
from config import Config
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 311 B |
@@ -2,13 +2,13 @@
|
||||
sprites.py
|
||||
A file dedicated to managing sprites and animations for characters.
|
||||
"""
|
||||
from itertools import cycle
|
||||
|
||||
import arcade
|
||||
import os
|
||||
import re
|
||||
|
||||
from typing import Pattern
|
||||
from typing import Pattern, Iterable
|
||||
from itertools import cycle
|
||||
|
||||
|
||||
class AnimationSet(object):
|
||||
@@ -16,7 +16,7 @@ class AnimationSet(object):
|
||||
A class that helps assist with grabbing new animations from a set.
|
||||
"""
|
||||
|
||||
def __init__(self, directory: str):
|
||||
def __init__(self, directory: str) -> None:
|
||||
"""
|
||||
Initializes the AnimationSet class by loading files and
|
||||
|
||||
@@ -26,7 +26,7 @@ class AnimationSet(object):
|
||||
self.directory = directory
|
||||
self.animations = os.listdir(directory)
|
||||
|
||||
def getAnimations(self, pattern: Pattern) -> iter:
|
||||
def getAnimations(self, pattern: Pattern) -> Iterable[arcade.Texture]:
|
||||
"""
|
||||
Loads all animations from the AnimationSet's directory that match the pattern.
|
||||
The pattern must have 1 group that specifies the animation's index.
|
||||
@@ -56,7 +56,7 @@ class PlayerAnimations(AnimationSet):
|
||||
index: [0,) - The index of the animation. Index should be enumerated in ascending order.
|
||||
"""
|
||||
|
||||
def __init__(self, directory: str):
|
||||
def __init__(self, directory: str) -> None:
|
||||
"""
|
||||
Initializes the PlayerAnimations class.
|
||||
"""
|
||||
|
||||
134
triple-dungeon/tests.py
Normal file
134
triple-dungeon/tests.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
tests.py
|
||||
A file dedicated to testing our game and ensuring it can run.
|
||||
Integrate this into your IDE's workflow to ensure the game runs from top to bottom.
|
||||
The tests used here should test all of our game's features as best they can.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from typing import Pattern, List
|
||||
|
||||
|
||||
class TestGame:
|
||||
"""
|
||||
Tests that the Arcade framework runs the game correctly.
|
||||
Only tests that it launches and runs for a little bit, not that it is functioning properly.
|
||||
"""
|
||||
|
||||
def test_game_runs(self) -> None:
|
||||
"""
|
||||
Simply test that the Game runs.
|
||||
"""
|
||||
|
||||
# imports
|
||||
from main import Game
|
||||
|
||||
# instantiate and setup
|
||||
game = Game()
|
||||
game.setup()
|
||||
game.minimize() # Minimizes window, should reduce annoyance a little bit.
|
||||
# test for 100 frames
|
||||
game.test(20)
|
||||
|
||||
|
||||
class TestSprites:
|
||||
"""
|
||||
Tests the Sprite classes as well as the available sprites.
|
||||
"""
|
||||
|
||||
@pytest.fixture
|
||||
def sprites(self) -> List[str]:
|
||||
"""
|
||||
:return: List of absolute paths to Sprite images
|
||||
"""
|
||||
|
||||
import os
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
IMAGE_DIR = os.path.join(BASE_DIR, 'resources', 'images')
|
||||
|
||||
_sprites = []
|
||||
for primary in os.listdir(IMAGE_DIR):
|
||||
for secondary in os.listdir(os.path.join(IMAGE_DIR, primary)):
|
||||
secondary = os.path.join(IMAGE_DIR, primary, secondary)
|
||||
if os.path.isfile(secondary):
|
||||
_sprites.append(secondary)
|
||||
else:
|
||||
_sprites.extend(
|
||||
os.path.join(secondary, file) for file in
|
||||
os.listdir(os.path.join(IMAGE_DIR, primary, secondary)))
|
||||
return _sprites
|
||||
|
||||
@pytest.fixture
|
||||
def patterns(self) -> List[Pattern]:
|
||||
"""
|
||||
:return: A list of Pattern objects to test.
|
||||
"""
|
||||
import re
|
||||
_patterns = [
|
||||
r'\w+_(?:\w+_)?\d+\.(?:jp(?:eg|e|g)|png)',
|
||||
r'\w+\d+\.(?:jp(?:eg|e|g)|png)',
|
||||
r'\w+_tile\.(?:jp(?:eg|e|g)|png)'
|
||||
]
|
||||
return list(map(re.compile, _patterns))
|
||||
|
||||
def test_sprite_schema(self, sprites: List[str], patterns: List[Pattern]) -> None:
|
||||
"""
|
||||
Tests that all sprites follow the naming conventions.
|
||||
"""
|
||||
import os
|
||||
|
||||
for sprite in sprites:
|
||||
head, tail = os.path.split(sprite)
|
||||
if any(pattern.match(tail) is not None for pattern in patterns):
|
||||
continue
|
||||
pytest.fail(f"Sprite '{tail}' in '{head}' did not match the schema.")
|
||||
|
||||
def test_sprite_loads(self, sprites) -> None:
|
||||
"""
|
||||
Tests that all sprites can be loaded by the arcade framework.
|
||||
"""
|
||||
import arcade
|
||||
|
||||
for sprite in sprites:
|
||||
_sprite = arcade.Sprite(sprite)
|
||||
|
||||
|
||||
class TestLevels:
|
||||
"""
|
||||
Tests the Level class.
|
||||
"""
|
||||
|
||||
@pytest.fixture
|
||||
def levels(self) -> List[str]:
|
||||
"""
|
||||
:return: List of paths to Level files
|
||||
"""
|
||||
import os
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
LEVEL_DIR = os.path.join(BASE_DIR, 'resources', 'levels')
|
||||
levels = [os.path.join(LEVEL_DIR, file) for file in os.listdir(LEVEL_DIR)]
|
||||
|
||||
return levels
|
||||
|
||||
def test_levels_are_loadable(self, levels) -> None:
|
||||
"""
|
||||
Tests whether or not a level can be loaded.
|
||||
"""
|
||||
from map import Level
|
||||
|
||||
for level in levels:
|
||||
Level.load_file(2, 3, level)
|
||||
|
||||
|
||||
class TestDungeon:
|
||||
"""
|
||||
Tests the Dungeon class.
|
||||
"""
|
||||
|
||||
|
||||
class TestMisc:
|
||||
"""
|
||||
Tests things that don't fit anywhere else.
|
||||
"""
|
||||
Reference in New Issue
Block a user