Comments (2)
I agree on the class hierarchy.
For creating the Entities, what about a simple factory function for each type?
def create_orc(x: int, y: int):
return Entity(x=x, y=y, char="o", color=(63, 127, 63), name="Orc", blocks_movement=True)
def create_player(x: int, y: int):
return Entity(x=x, y=y, char="@", color=(255, 255, 255), name="Player", blocks_movement=True)
def create_troll(x: int, y: int):
return Entity(x=x, y=y, char="T", color=(0, 127, 0), name="Troll", blocks_movement=True)
from tcod_tutorial_v2.
I was hoping to also reduce the complexity of defining them, so that the end result would be more tabulated.
I'd recommend using a factory function for procedurally generated monsters, but not for predefined ones.
functools.partial doesn't look that great either.
create_orc: Callable[[int, int], Entity] = functools.partial(
Entity, char="o", color=(63, 127, 63), name="Orc", blocks_movement=True
)
It might be a little awkward to pass Callable[[int, int], Entity]
around, but that's totally doable compared to some worse examples. It's also more convenient when GameMap is included in the spawning function.
I didn't give an example of how the spawn method would be implemented, but now I'll gave several examples to compare.
Based on your given example, behold the factory function factory:
def new_monster(
char: str,
color: Tuple[int, int, int],
name: str,
blocks_movement: bool = True,
) -> Callable[[GameMap, int, int], Entity]:
"""Define a new monster type"""
def spawn(gamemap: GameMap, x: int, y: int) -> Entity:
"""Spawn a monster at the given location."""
new_obj = Entity(
x=x,
y=y,
char=char,
color=color,
name=name,
blocks_movement=blocks_movement,
)
gamemap.entities.add(new_obj)
return new_obj
return spawn
spawn_orc = new_monster(
char="o", color=(63, 127, 63), name="Orc",
)
spawn_orc(gamemap, x, y)
It's a little better but I don't think it will keep up with the subclassing of Entity. You'd need more factories for different kinds of entities. This could also work as a classmethod but it'll always need to be overridden by subclasses.
Tabulated data as a plain dictionary:
monsters = {
"orc": {
"char": "o",
"color": (63, 127, 63),
"name": "Orc",
"blocks_movement": True,
},
"troll": dict(
char="T",
color=(0, 127, 0),
name="Troll",
blocks_movement=True,
),
}
new_orc = Entity(x=0, y=0, **monsters["orc"])
gamemap.entities.add(new_orc)
The idea is that you'd use dictionaries in Python the same way you'd use JSON in JavaScript. I'm not sure how well these are typed but any specific item should be checked where they're used. Any dictionaries generated from code or loaded from a file will break type hinting.
It probably only looks clean to me because I've used Python for so long. Using dict
with keywords helps a little but I don't know how well that preserves types. There isn't a good system for tracking the types of dictionary items in general.
There's also no information on that types these dictionary items are bound to, so subclassing Entity will cause confusion.
Data class factory class:
import dataclasses
@dataclasses.dataclass
class MonsterType:
char: str
color: Tuple[int, int, int]
name: str
blocks_movement: bool = True
def spawn(self, gamemap: GameMap, x: int, y: int) -> Entity:
"""Spawn this monster at the given location."""
new_obj = Entity(
x=x,
y=y,
char=self.char,
color=self.color,
name=self.name,
blocks_movement=self.blocks_movement,
)
gamemap.entities.add(new_obj)
return new_obj
orc_type = MonsterType(
char="o",
color=(63, 127, 63),
name="Orc",
)
orc = orc_type.spawn(dungeon, x, y)
The whole point of dataclasses is to avoid boilerplate and yet it always seems to turn into a huge mess anyway especially when type hinting is involved. dataclasses.asdict
could be used but I doubt that type hinting will work correctly there. If you ignore the class itself then the data definitions look as good as the factory function factory, but I'd hate to update this class as things are extended.
I thought of using NamedTuple's but I know that passing parameters positionally would cause trouble later when somebody inevitably messes it up and doesn't think to check MyPy.
Prototype deepcopy method:
import copy
from typing import TypeVar
T = TypeVar('T')
class Entity:
... # Change 'x, y' defaults to 0.
def spawn(self: T, gamemap: GameMap, x: int, y: int) -> T:
"""Spawn a copy of this instance at the given location."""
clone = copy.deepcopy(self)
clone.x = x
clone.y = y
gamemap.entities.add(clone)
return clone
orc = Entity(
name="Orc",
char="o",
color=(63, 127, 63),
blocks_movement=True, # Actor class should imply 'blocks_movement=True' later.
)
new_orc = orc.spawn(gamemap, x, y)
I changed my mind on deepcopy, it will work fine and this will also work with subclasses without any extra code.
The best part is that this is DRY and nothing else needs to be updated separately when the Entity class or subclasses are changed. Most of the other examples were making copies of its type hints and attributes.
from tcod_tutorial_v2.
Related Issues (17)
- Notes on Part 4: Field of View. HOT 3
- Part 5: Context sensitive actions. HOT 4
- Part 5: Entity contianer issues. HOT 2
- Part 5: Enemy turn. HOT 2
- Part 9, consumable.py, LightningDamageConsumable HOT 1
- Question regarding best practices HOT 2
- Question: Difference between going to engine vs entity for game_map? HOT 2
- Part 6: Clarification on Player AI HOT 1
- render_functions.py : get_names_at_location Capitalization HOT 1
- AskUserEventHandler for Inventory
- Feedback on part 12 HOT 3
- Dropping multiple identical items on a tile only creates one instance of the item. HOT 6
- Planned refactors for 2021. HOT 1
- Notes on tcod event handling. HOT 3
- Part 6: AttributeError: 'Actor' object has no attribute 'render_order' HOT 2
- Entities is initialized as a list, but code treats it as a set. HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tcod_tutorial_v2.