diff bGrease/entity.py @ 86:a9cc5559ec2a

Move the identifier field from the FifeAgent component to the new General component. Added General Entity.
author KarstenBock@gmx.net
date Sat, 24 Sep 2011 15:48:24 +0200
parents ff3e395abf91
children
line wrap: on
line diff
--- a/bGrease/entity.py	Fri Sep 23 15:09:02 2011 +0200
+++ b/bGrease/entity.py	Sat Sep 24 15:48:24 2011 +0200
@@ -1,212 +1,212 @@
-#############################################################################
-#
-# Copyright (c) 2010 by Casey Duncan and contributors
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the MIT License
-# A copy of the license should accompany this distribution.
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#
-#############################################################################
-"""Grease entities are useful as actionable, interactive
-game elements that are often visible to the player.
-
-You might use entities to represent:
-
-- Characters
-- Bullets
-- Particles
-- Pick-ups
-- Space Ships
-- Weapons
-- Trees
-- Planets
-- Explosions
-
-See :ref:`an example entity class in the tutorial <tut-entity-example>`.
-"""
-
-__version__ = '$Id$'
-
-__all__ = ('Entity', 'EntityComponentAccessor', 'ComponentEntitySet')
-
-
-class EntityMeta(type):
-	"""The entity metaclass enforces fixed slots of `entity_id` and `world`
-	for all subclasses. This prevents accidental use of other entity instance 
-	attributes, which may not be saved. 
-	
-	Class attributes are not affected by this restriction, but subclasses
-	should be careful not to cause name collisions with world components,
-	which are exposed as entity attributes. Using a naming convention for
-	class attributes, such as UPPER_CASE_WITH_UNDERSCORES is recommended to
-	avoid name clashes.
-
-	Note as a result of this, entity subclasses are not allowed to define
-	`__slots__`, and doing so will cause a `TypeError` to be raised.
-	"""
-
-	def __new__(cls, name, bases, clsdict):
-		if '__slots__' in clsdict:
-			raise TypeError('__slots__ may not be defined in Entity subclasses')
-		clsdict['__slots__'] = ('world', 'entity_id')
-		return type.__new__(cls, name, bases, clsdict)
-
-
-class Entity(object):
-	"""Base class for grease entities.
-	
-	Entity objects themselves are merely identifiers within a :class:`grease.world.World`.
-	They also provide a facade for convenient entity-wise access of component
-	data. However, they do not contain any data themselves other than an
-	entity id.
-
-	Entities must be instantiated in the context of a world. To instantiate an
-	entity, you must pass the world as the first argument to the constructor.
-	Subclasses that implement the :meth:`__init__()` method, must accept the world
-	as their first argument (after ``self``). Other constructor arguments can be
-	specified arbitarily by the subclass.
-	"""
-	__metaclass__ = EntityMeta
-
-	def __new__(cls, world, *args, **kw):
-		"""Create a new entity and add it to the world"""
-		entity = object.__new__(cls)
-		entity.world = world
-		entity.entity_id = world.new_entity_id()
-		world.entities.add(entity)
-		return entity
-	
-	def __getattr__(self, name):
-		"""Return an :class:`EntityComponentAccessor` for this entity
-		for the component named.
-
-		Example::
-
-			my_entity.movement
-		"""
-		component = getattr(self.world.components, name)
-		return EntityComponentAccessor(component, self)
-	
-	def __setattr__(self, name, value):
-		"""Set the entity data in the named component for this entity.
-		This sets the values of the component fields to the values of
-		the matching attributes of the value provided. This value must
-		have attributes for each of the component fields.
-
-		This allows you to easily copy component data from one entity
-		to another.
-
-		Example::
-
-			my_entity.position = other_entity.position
-		"""
-		if name in self.__class__.__slots__:
-			super(Entity, self).__setattr__(name, value)
-		else:
-			component = getattr(self.world.components, name)
-			component.set(self, value)
-	
-	def __delattr__(self, name):
-		"""Remove this entity and its data from the component.
-		
-		Example::
-		
-			del my_entity.renderable
-		"""
-		component = getattr(self.world.components, name)
-		del component[self]
-	
-	def __hash__(self):
-		return self.entity_id
-	
-	def __eq__(self, other):
-		return self.world is other.world and self.entity_id == other.entity_id
-
-	def __repr__(self):
-		return "<%s id: %s of %s %x>" % (
-			self.__class__.__name__, self.entity_id,
-			self.world.__class__.__name__, id(self.world))
-
-	def delete(self):
-		"""Delete the entity from its world. This removes all of its
-		component data. If then entity has already been deleted, 
-		this call does nothing.
-		"""
-		self.world.entities.discard(self)
-
-	@property
-	def exists(self):
-		"""True if the entity still exists in the world"""
-		return self in self.world.entities
-
-
-class EntityComponentAccessor(object):
-	"""A facade for accessing specific component data for a single entity.
-	The implementation is lazy and does not actually access the component
-	data until needed. If an attribute is set for a component that the 
-	entity is not yet a member of, it is automatically added to the
-	component first.
-
-	:param component: The :class:`grease.Component` being accessed
-	:param entity: The :class:`Entity` being accessed
-	"""
-	
-	# beware, name mangling ahead. We want to avoid clashing with any
-	# user-configured component field names
-	__data = None
-
-	def __init__(self, component, entity):
-		clsname = self.__class__.__name__
-		self.__dict__['_%s__component' % clsname] = component
-		self.__dict__['_%s__entity' % clsname] = entity
-	
-	def __nonzero__(self):
-		"""The accessor is True if the entity is in the component,
-		False if not, for convenient membership tests
-		"""
-		return self.__entity in self.__component
-	
-	def __getattr__(self, name):
-		"""Return the data for the specified field of the entity's component"""
-		if self.__data is None:
-			try:
-				data = self.__component[self.__entity]
-			except KeyError:
-				raise AttributeError(name)
-			clsname = self.__class__.__name__
-			self.__dict__['_%s__data' % clsname] = data
-		return getattr(self.__data, name)
-	
-	def __setattr__(self, name, value):
-		"""Set the data for the specified field of the entity's component"""
-		if self.__data is None:
-			clsname = self.__class__.__name__
-			if self.__entity in self.__component:
-				self.__dict__['_%s__data' % clsname] = self.__component[self.__entity]
-			else:
-				self.__dict__['_%s__data' % clsname] = self.__component.set(self.__entity)
-		setattr(self.__data, name, value)
-
-
-class ComponentEntitySet(set):
-	"""Set of entities in a component, can be queried by component fields"""
-
-	_component = None
-
-	def __init__(self, component, entities=()):
-		self.__dict__['_component'] = component
-		super(ComponentEntitySet, self).__init__(entities)
-	
-	def __getattr__(self, name):
-		if self._component is not None and name in self._component.fields:
-			return self._component.fields[name].accessor(self)
-		raise AttributeError(name)
-	
-	def __setattr__(self, name, value):
-		if self._component is not None and name in self._component.fields:
-			self._component.fields[name].accessor(self).__set__(value)
-		raise AttributeError(name)
-
+#############################################################################
+#
+# Copyright (c) 2010 by Casey Duncan and contributors
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the MIT License
+# A copy of the license should accompany this distribution.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#
+#############################################################################
+"""Grease entities are useful as actionable, interactive
+game elements that are often visible to the player.
+
+You might use entities to represent:
+
+- Characters
+- Bullets
+- Particles
+- Pick-ups
+- Space Ships
+- Weapons
+- Trees
+- Planets
+- Explosions
+
+See :ref:`an example entity class in the tutorial <tut-entity-example>`.
+"""
+
+__version__ = '$Id$'
+
+__all__ = ('Entity', 'EntityComponentAccessor', 'ComponentEntitySet')
+
+
+class EntityMeta(type):
+	"""The entity metaclass enforces fixed slots of `entity_id` and `world`
+	for all subclasses. This prevents accidental use of other entity instance 
+	attributes, which may not be saved. 
+	
+	Class attributes are not affected by this restriction, but subclasses
+	should be careful not to cause name collisions with world components,
+	which are exposed as entity attributes. Using a naming convention for
+	class attributes, such as UPPER_CASE_WITH_UNDERSCORES is recommended to
+	avoid name clashes.
+
+	Note as a result of this, entity subclasses are not allowed to define
+	`__slots__`, and doing so will cause a `TypeError` to be raised.
+	"""
+
+	def __new__(cls, name, bases, clsdict):
+		if '__slots__' in clsdict:
+			raise TypeError('__slots__ may not be defined in Entity subclasses')
+		clsdict['__slots__'] = ('world', 'entity_id')
+		return type.__new__(cls, name, bases, clsdict)
+
+
+class Entity(object):
+	"""Base class for grease entities.
+	
+	Entity objects themselves are merely identifiers within a :class:`grease.world.World`.
+	They also provide a facade for convenient entity-wise access of component
+	data. However, they do not contain any data themselves other than an
+	entity id.
+
+	Entities must be instantiated in the context of a world. To instantiate an
+	entity, you must pass the world as the first argument to the constructor.
+	Subclasses that implement the :meth:`__init__()` method, must accept the world
+	as their first argument (after ``self``). Other constructor arguments can be
+	specified arbitarily by the subclass.
+	"""
+	__metaclass__ = EntityMeta
+
+	def __new__(cls, world, *args, **kw):
+		"""Create a new entity and add it to the world"""
+		entity = object.__new__(cls)
+		entity.world = world
+		entity.entity_id = world.new_entity_id()
+		world.entities.add(entity)
+		return entity
+	
+	def __getattr__(self, name):
+		"""Return an :class:`EntityComponentAccessor` for this entity
+		for the component named.
+
+		Example::
+
+			my_entity.movement
+		"""
+		component = getattr(self.world.components, name)
+		return EntityComponentAccessor(component, self)
+	
+	def __setattr__(self, name, value):
+		"""Set the entity data in the named component for this entity.
+		This sets the values of the component fields to the values of
+		the matching attributes of the value provided. This value must
+		have attributes for each of the component fields.
+
+		This allows you to easily copy component data from one entity
+		to another.
+
+		Example::
+
+			my_entity.position = other_entity.position
+		"""
+		if name in self.__class__.__slots__:
+			super(Entity, self).__setattr__(name, value)
+		else:
+			component = getattr(self.world.components, name)
+			component.set(self, value)
+	
+	def __delattr__(self, name):
+		"""Remove this entity and its data from the component.
+		
+		Example::
+		
+			del my_entity.renderable
+		"""
+		component = getattr(self.world.components, name)
+		del component[self]
+	
+	def __hash__(self):
+		return self.entity_id
+	
+	def __eq__(self, other):
+		return self.world is other.world and self.entity_id == other.entity_id
+
+	def __repr__(self):
+		return "<%s id: %s of %s %x>" % (
+			self.__class__.__name__, self.entity_id,
+			self.world.__class__.__name__, id(self.world))
+
+	def delete(self):
+		"""Delete the entity from its world. This removes all of its
+		component data. If then entity has already been deleted, 
+		this call does nothing.
+		"""
+		self.world.entities.discard(self)
+
+	@property
+	def exists(self):
+		"""True if the entity still exists in the world"""
+		return self in self.world.entities
+
+
+class EntityComponentAccessor(object):
+	"""A facade for accessing specific component data for a single entity.
+	The implementation is lazy and does not actually access the component
+	data until needed. If an attribute is set for a component that the 
+	entity is not yet a member of, it is automatically added to the
+	component first.
+
+	:param component: The :class:`grease.Component` being accessed
+	:param entity: The :class:`Entity` being accessed
+	"""
+	
+	# beware, name mangling ahead. We want to avoid clashing with any
+	# user-configured component field names
+	__data = None
+
+	def __init__(self, component, entity):
+		clsname = self.__class__.__name__
+		self.__dict__['_%s__component' % clsname] = component
+		self.__dict__['_%s__entity' % clsname] = entity
+	
+	def __nonzero__(self):
+		"""The accessor is True if the entity is in the component,
+		False if not, for convenient membership tests
+		"""
+		return self.__entity in self.__component
+	
+	def __getattr__(self, name):
+		"""Return the data for the specified field of the entity's component"""
+		if self.__data is None:
+			try:
+				data = self.__component[self.__entity]
+			except KeyError:
+				raise AttributeError(name)
+			clsname = self.__class__.__name__
+			self.__dict__['_%s__data' % clsname] = data
+		return getattr(self.__data, name)
+	
+	def __setattr__(self, name, value):
+		"""Set the data for the specified field of the entity's component"""
+		if self.__data is None:
+			clsname = self.__class__.__name__
+			if self.__entity in self.__component:
+				self.__dict__['_%s__data' % clsname] = self.__component[self.__entity]
+			else:
+				self.__dict__['_%s__data' % clsname] = self.__component.set(self.__entity)
+		setattr(self.__data, name, value)
+
+
+class ComponentEntitySet(set):
+	"""Set of entities in a component, can be queried by component fields"""
+
+	_component = None
+
+	def __init__(self, component, entities=()):
+		self.__dict__['_component'] = component
+		super(ComponentEntitySet, self).__init__(entities)
+	
+	def __getattr__(self, name):
+		if self._component is not None and name in self._component.fields:
+			return self._component.fields[name].accessor(self)
+		raise AttributeError(name)
+	
+	def __setattr__(self, name, value):
+		if self._component is not None and name in self._component.fields:
+			self._component.fields[name].accessor(self).__set__(value)
+		raise AttributeError(name)
+