Hello everyone ı have a problem with flyweight patter ;
I try to implement flyweight patter to my sprite class. There are tons of smilarty as attributes each Sprite object only diffirences are Position and frame;
Im my code ı have a problem, whenever ı set(Position or frame) of one sprite , every other objects attribute also change, ı dont want that ı want most of attributes are same but frame and position is diffrent for each object.
Here is the code:
public enum Type
{
sprite,
None,
};
public class FactorySprite
{
private LinkList SpriteList = new LinkList();
private Hashtable Sprites = new Hashtable();
public FactorySprite()
{
// SpriteList.AddtoBegining(new Sprite());
Sprites.Add(Type.sprite, new Sprite());
}
public GameSprite getSprite(Type type)
{
// return (Sprite)SpriteList.Search(O);
GameSprite gamesprite = null;
if(Sprites.ContainsKey(type))
{
gamesprite =( GameSprite)Sprites[type];
}
return gamesprite;
}
}
public abstract class GameSprite
{
protected Texture2D texture;
// protected Vector2 position;
protected Texture loadTexture;
// protected int frame;
protected Vector2 Speed;
protected Rectangle SourceRectangle;
protected Color color;
public Type type;
protected SpriteBatch spriteBatch;
public abstract void Draw();
public abstract void Update();
public abstract void setframe(int frame_number);
public abstract void setPosition(int x,int y);
}
public class Sprite : GameSprite
{
private int frame;
private Vector2 position;
public Sprite()
{
frame =0;
type = Type.sprite;
spriteBatch = Game1.GameInstance.spriteBatch;
texture = Texture.Instance().GetTexture();
Speed = new Vector2(0, 1);
color = Color.White;
}
public override void Draw()
{
spriteBatch.Draw(texture,position,Image.Instance().drawframe(this.frame), color);
}
public override void setframe(int frame_number) {this.frame = frame_number; }
public override void setPosition(int x, int y) {this.position = new Vector2(x, y); }
public Type getType()
{
return type;
}
public override void Update(){}
}
Here is manin that ı create factory flayweight and each object that ı create
SpriteManager sm = SpriteManager.Instance();
FactorySprite factory = new FactorySprite();
Sprite s1 = (Sprite)factory.getSprite(Type.sprite);
s1.setframe(6);
s1.setPosition(200, 300);
sm.AddSprite(s1);
Sprite s2 = (Sprite)factory.getSprite(Type.sprite);
s2.setframe(5);
s2.setPosition(100, 100);
sm.AddSprite(s2);
Problem here to be more clear s1 and s2 has same frame and position(whic one is last updated all other object become same)
This thing about the FlyWeight pattern is that every time you ask for one, you get the same instance. Thus every time you call GetSprite you are returning the same one, not a copy but the same one.
So if you call it twice, you now have two references to the same object. If you change it in one place it will change in the other because the two ARE THE SAME THING! That's actually the point of the FlyWeight pattern.
I would suggest that you don't use this pattern where you need different objects as you do.
One way around trhis is to extract all this bits of a Sprite which do not ever change into a new class, which you can then use the FlyWeight pattern on. The changeable bits would stay in the Sprite class, with the addition of a reference to your new 'ImutableSprite' instance.
The Flyweight pattern doesn't apply here.
Flyweight means that you use the same object with a specific in all cases where you want this specific value. Obviously, if you change the value in one place, the change will appear everywhere.
If you want to reduce the number of sprites, you could use immutable semantics: Use a single Sprite instance for a specific set of Position,Frame and create a copy when you want a Sprite with a different set.
Related
I'm creating a 2d Turret Defense game in C# and I have a question about the management of the updates of the turrets.
I want to create the menu over the turret sprite with several options for the upgrade.
My idea is to load the menu from the resources as sprite, assign it as child to the turret gameObject and then manage the comunication between the button to the turret to start the upgrade process.
There is a way to assign a method/function to a resource freshly loaded?
For example (in turret class):
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
myMenuButton.OnMouseDown(){
// do something with the current turret's class
};
Or I have to save the gameObject sprite in resource folder with inside a script that will manage the OnMouseDown method searching the parent script of the turret and use the correct method?
For example (in menu sprite class):
void OnMouseDown(){
GameObject parent = gameObject.transform.parent.gameObject;
turretScript parentScript = (turretScript) go.GetComponent(typeof(turretScript));
parentScript.doUpgrade();
}
Thanks for any help!
I don't know about Sprite itself (documentation may have information about it, did you already research there?)
But I don't see why you cant use Buttons instead of Sprite to handle this "menu behaviour" you wants to do. Button class have an onClick event handler that you can use to assign listners at runtime like
myMenuButton.onClick.AddListener(() => {
//handle click here
});
you can also set methods by lambda expression, just google about it and you'll find a lot of resources to learn how to use it ;)
first create a class which already implements the OnMouseDown and a list of function pointers and attach this class to every single item you are going to use it on beforehand.
public class MouseDownScript : MonoBehaviour
{
public List<Action> Actions = new List<Action>();
void OnMouseDown(){
foreach(Action action in Actions)
action();
}
}
Then you have the ability to:
{
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
// Cache the script
MouseDownScript mouseScript = myMenuButton.GetComponent<MouseDownScript>();
// Add anonymous actions with a lambda as such:
mouseScript.Actions.Add(() => /*Any action here*/);
// Add existing functions as such:
mouseScript.Actions.Add(MouseDownAction));
}
public void MouseDownAction() {}
I don't know Unity but you might be able to inherit from Sprite, add a property to it of type Action and assign that after you create it with Resources.Load
class Program
{
static void Main(string[] args)
{
var s = new Sprite();
s.Action = dostuff;
// outputs Hello
s.Action.Invoke();
Console.ReadLine();
}
public static void dostuff() { Console.WriteLine("Hello"); }
public class Sprite
{
public Action Action { get; set; }
}
}
You can add new class to Sprite when create Sprite
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
myMenuButton.AddComponent<ClassForSprite>();
In ClassForSprite
public class MouseDownScript : MonoBehaviour
{
void onAction1(){
//Code process for action 1
}
void onAction2(){
//Code process for action 2
}
}
I think you'll want to use delegates.
Basically you define a method signature e.g.
public delegate void ClickHandler();
then you define an instance of that signature:
public ClickHandler OnClick;
you can assign a method to OnClick on runtime and execute.
in turret:
public void ExecuteOnTurrent()
{
// do stuff in turret
}
public void LoadSprite()
{
Sprite myMenuButton = Resources.Load <Sprite> ("sprite_menu_to_load");
myMenuButton.OnClick= ExecuteOnTurrent;
}
in sprite
public delegate void ClickHandler();
public ClickHandler OnClick;
public void Update()
{
//- detect click or other action
if(click and OnClick!= null)
{
OnClick();
}
}
I've created a rectangle, that has its own class. In the class I have a delegate created, that closes the game.
Creating the delegate:
public event EventHandler ExitRequested = delegate { };
In the update method I tell when to execute it:
if (mouseState.LeftButton == ButtonState.Pressed)
{
ExitRequested(this, EventArgs.Empty);
}
In my main class I execute the delegate like this (the exitGame is a rectangle):
exitGame.ExitRequested += exitGame_ExitRequested;
What I'm wondering about is there a way how to remove all items from the screen? Lets say it's for a "new game" functionality. I tried to create this functionality the same way I created the exit functionality but I can't figure out how to remove the items...
As far as I understand, you are trying to remove all game entities / objects in order to start a new game. Usually this is achieved by storing entities in a collection, and then simply removing all collection entries when a 'new game' is needed. As for entities which are not generic, such as the player, usually you just reset every member that needs to be reset; position, points etc.
Say you have a class to hold information about entities, such as enemies:
public class Entity
{
public Texture2D Sprite;
public Rectangle Bounds;
public Entity(Texture2D Sprite, Rectangle Bounds)
{
this.Sprite = Sprite;
this.Bounds = Bounds;
}
public void Update(GameTime gameTime)
{
//Movement code here
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Sprite,Bounds,Color.White);
}
}
And you then store all entities in a collection:
public List<Entity> Entities = new List<Entity>();
You update and draw each entity by looping through the collection:
//In main game class
public void Update(GameTime gameTime)
{
foreach (Entity e in Entities)
e.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
foreach (Entity e in Entities)
e.Draw(spriteBatch);
}
Then when you want to start a new game, and effectively remove all entities, you can simply remove all entries in the Entities list. (For example using List.Clear(), there are many ways)
Keep in mind this is an example which has not been tested, so to say. This is can be optimized, and is more to give you an idea of why collections are useful for organizing game objects / entities.
I have a basic core interface called IComponent.
public interface IComponent
{
void Initialize();
void Update();
void Draw(Color tint);
BoundingBox BoundingBox { get; }
bool Initialized { get; }
}
It is used by any class that will drawable (button, text, texture, ...)
I want to develop a set of effects that can be applied to any IComponent, such as:
Shake(IComponent component, TimeSpan duration)
-> Causes the Component to vibrate for a given duration. It works by initially storing the center position of the passed component and offsetting it at each Update till duration ends.
Translate(IComponent component, Vector2 destination, TimeSpan timeToReach)
-> Causes the Component to move to the given destination after a certain time. It works by incrementally offsetting the component at each Update.
You can imagine more...
So assume I want a certain class (Texture : IComponent) to shake while also moving to a certain point. I thought of possibly using the decorator pattern like so:
Create a Texture => Wrap it in a Shake (5 sec duration) => Wrap it in a Translate (10 sec duration)
but there are some problems with that.
Primarily, The Shake wrapper would work fine alone with a static stationary texture, but combined with a Translate it would fail since it would keep returning the texture to its original position and it wont translate properly.
Secondly, while the translation will take 10 seconds to finish, the vibrating will take only 5 seconds, so afterwards I don't know how to automatically remove the Shake wrapper from within the chain, and also finally remove the Translate when its done, leaving behind the original texture.
Thirdly, the decorator pattern hides any specific functions of the wrapped object, so after wrapping a Texture with a Shake, I wont be able to invoke the setPixelColor() of Texture, unless I also create a second direct reference to Texture before wrapping it.
Any suggestions of how to tackle such a challenge elegantly are welcome. Thanks.
Note: In practice I am likely to apply those effects to probably 2% of all created objects that are IComponent.
Maybe another approach along the following lines.
In your example both shake and translate are Animation effects. All animations need some form of duration and are applied to a component. Which could lead to the following first take:
public interface IAnimationEffect
{
IComponent targetComponent;
int Duration { get; set; }
}
Duration of an animation may seem like a good initial approach, however, when you need to combine animations, each animation needs to manipulate the BoundingRect of its encapsulated IComponent over the same period of time as other animations. In order to be able to stack animations like this, the draw methods for the animation effects need to be instructed to draw a specific frame of the animation.
An improved version of the IAnimationEffect interface would be:
public interface IAnimationEffect
{
IComponent targetComponent;
int StartFrame { get; set; }
int EndFrame { get; set; }
void CalculateFrame(int frame);
}
Whichever class is responsible for drawing your IComponents (Lets call it DrawingEngine for now), is now also responsible for holding an internal List of all applicable animation effects. It also needs to have some sort of timeline and rendering logic in frames per second, so that calculations for a specific animation frame can be performed.
public class ShakeAnimationEffect : IAnimationEffect
{
public IComponent TargetComponent { get; set; }
public int StartFrame { get; set; }
public int EndFrame { get; set; }
// Some shake specific properties can be added, to control the type of vibration etc
// (could be a rotating vibration an updown shake), but these really should have dedicated classes of their own.
public void CalculateFrame(int frame)
{
// your maths manipulations for calculating the bounds of the IComponent go here
}
}
public class TranslateAnimation : IAnimationEffect
{
public IComponent targetComponent { get; set; }
public int StartFrame { get; set; }
public int EndFrame { get; set; }
public int TranslateX { get; set; }
public int TranslateY { get; set; }
public void CalculateFrame(int frame)
{
// your maths manipulations for calculating the bounds of the IComponent go here
}
}
As proposed above then your AnimationEffects classes do not have any responsibility for drawing IComponents, that remains the responsibility of the DrawingEngine.
What you would need to introduce directly before your DrawingLoop, is a loop for running all animation effects, all this would do is update the bounds of the objects that happen to have an animation effect associated with them. Then you carry on drawing the object as usual.
Suppose that you have something like this:
// suppose your drawing engine has the following:
List<IComponent> components = new List<IComponent>();
//now just add the following
List<IAnimationEffect> animationEffects = new List<IAnimationEffect>();
// create some animation effects and register them to your list
animationEffects.Add(new ShakeAnimationEffect
{
TargetComponent = Lorry,
StartFrame = 0,
EndFrame = 150, //At 30 frames per second, this would be a 5sec animation
}
);
//sample pseudecode
RunAnimationCalculations();
RunDrawingLoop();
All that RunAnimationCalculations would do is loop through through your animationEffects collection and run Calculate passing in the current frame so that the bounds of the IComponent are updated, before the frame is subsequently drawn.
Good luck!
You can about something like this:
public Shake : ITransformation
{
}
public Translate : ITransformation
{
}
IComponent interface defines also a collection of transformations applied to it:
public interface IComponent
{
public IEnumerable<ITransformation> GetTransformation();
}
in some concrete implementation of the Component
public MyCompo : IComponennt
{
public Draw(Color tint) {
//apply here transformations available in list of GetTransformation()
....
// draw
}
}
Just an idea.
Hope this helps.
I know people have asked this before, but it would appear that their solution doesn't work for me or I'm doing something wrong.
public class Sprite
{
private Game m_game;
private SpriteBatch m_spriteBatch;
private string m_filename;
private Texture2D m_texture;
public Sprite(Game game, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice)
{
m_game = game;
m_spriteBatch = spriteBatch;
m_texture = new Texture2D(graphicsDevice, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height);
}
public void LoadSprite(string filename)
{
m_texture = m_game.Content.Load<Texture2D>(filename);
}
}
The error is generated at LoadSprite when I pass "tree" as the filename.
m_texture isn't null because (tried to) initialise it in the constructor.
The same call to Content.Load is used in the main loop fine but I want to move that into the Sprite class.
treeTexture = Content.Load<Texture2D>("tree");
This works fine in the main loop so it shows that the "tree" file exists.
Can anyone see what I'm doing wrong?
m_game or m_game.Content is probably null.
I have an interface (ICamera) which is implemented by 2 classes (FreeCamera, StaticCamera). The classes are inheriting from GameComponent.
Example definiton:
public class FreeCamera : GameComponent, ICamera
{
...
}
Now I'm adding the classes to the Game Components and register one of the components to a game service
private FreeCamera freeCam;
private StaticCamera staticCam;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
freeCam = new FreeCamera(this) { Enabled = true };
staticCam = new StaticCamera(this) { Enabled = false };
Services.AddService(typeof(ICamera, freeCam);
Components.Add(freeCam);
Components.Add(staticCam);
...
}
Then I want to change the provider for the service during the application flow with help of a toggle function
namespace Game1
{
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
if(keyboard.IsKeyDown(Keys.C))
{
if(freeCam.Enabled)
{
Services.RemoveService(typeof(ICamera));
Services.AddService(typeof(ICamera, staticCam);
freeCam.Enabled = !freeCam.Enabled;
staticCam.Enabled = !staticCam.Enabled;
}
else
{
Services.RemoveService(typeof(ICamera));
Services.AddService(typeof(ICamera, freeCam);
freeCam.Enabled = !freeCam.Enabled;
staticCam.Enabled = !staticCam.Enabled;
}
}
base.Update(gameTime);
}
}
The StaticCamera takes only input by mouse (you can rotate the camera), the FreeCamera can also moved by keyboard input. When I call the method above (by pressing C on the keyboard) the FreeCamera class gets deactivated but the viewport seems frozen and does not react to any input. When I call the method again after a short time the FreeCamera gets activated again and everything works as expected.
Now I have 2 questions regarding this:
Is it possible to change the service
provider of a game service in the
game loop?
Is there a better approach
to handle different camera types in a
game and switch between them easily?
Thanks in advance for any help.
Like you answered, use a camera manager. It acts as both a factory and a container for the current camera. The manager you can register as a service. Manager would look something like this:
public class CameraManager
{
private Dictionary<Type, ICamera> _cameras;
private ICamera _current;
public ICamera Current
{
get
{
return _current;
}
}
// Sets the current cammera to the internal instance of the camera type
public void SetCurrent<T>() where T : ICamera
{
if (!_cameras.ContainsKey(typeof(T)))
{
// TODO: Instantiate a new camera class here...
}
_current = _cameras[typeof(T)];
}
}
This is just rough code - would need to be filled in more. One limitation is you can only have one camera per type. Giving cameras a string name, or an enum flag would let you toggle between an arbitrary number of cameras.
Thanks for the tip. I just wrote the code down from my head without my IDE at hand, so please do not look too much into syntax errors etc.
In my game I'm using wrapper classes for the input. The code is just a brief example of the problem - how to substitute a game service if both classes are using the same interface.
My new idea: I could use a "manager" class (like CameraManager in this case) which has the following methods
public void SetCameraType(CameraType type) //CameraType could be an enum
public ICamera GetCamera()
and then put the manager class into the service (with its own interface like ICameraManager).
Edit: this was considered as an answer to the comment above ... but it seems I clicked the wrong button - sorry
I think if you left off the code about adding and removing the service in the Update you'd be good and added lines changing the Visible property. The Enable property effects calls to Update, but the Visible property effects calls to Draw.
So I'd suggest the Update look like this:
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
if(keyboard.IsKeyDown(Keys.C))
{
if(freeCam.Enabled)
{
freeCam.Enabled = false;
freeCam.Visible = false;
staticCam.Enabled = true;
staticCam.Visible= true;
}
else
{
freeCam.Enabled = true;
freeCam.Visible = true;
staticCam.Enabled = false;
staticCam.Visible= false;
}
}
base.Update(gameTime);
}