I want to override a method while it's object initialization, something like this:
Button = new Button(parameter1, parameter2){
public override onClicked(){
//implementation
}
};
This it's what a got:
public class Button:Entity
{
protected Texture2D texture2D;
public Vector2 vector2;
public Button(Texture2D image, Vector2 position
{
this.image = image;
this.position = position;
this.action = action;
}
public abstract void onClicked();
}
abstract class Entity
{
public Vector2 position;
public int radius = 20;
protected Texture2D image;
public virtual void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(image,position,Color.White);
}
}
I just try to make an implementation like the one I speak before but it does not compile. How one can get this to compile or implement such "per-instance" overrides?
public class Button:Entity
{
//Vector, Radius and texture are already part of Button, since it extend Entity
public EventHandler onClicked;
public Button(Texture2D image, Vector2 position)
{
this.image = image;
this.position = position;
this.action = action;
}
}
abstract class Entity
{
public Vector2 position;
public int radius = 20;
protected Texture2D image;
public virtual void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(image,position,Color.White);
}
}
And use it this way:
Button = new Button(parameter1, parameter2){
onClicked = new EventHandler(NameOfYourMethod);
};
Related
When i try to print the variable from another class, it prints the undeclared variable, so only 0.
Here is an example:
public class Player
{
Enemy enemy;
public void Initialize(){
enemy = new Enemy();
}
public void Update()
{
Console.WriteLine(enemy.Rectangle);
}
}
public class Enemy()
{
public Rectangle Rectangle;
public void Update()
{
Rectangle = new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height);
}
}
I think the following code can help you
public class Player
{
Enemy enemy;
public void Initialize()
{
enemy = new Enemy();
}
public void Update()
{
enemy.Update();
Console.WriteLine(enemy.Rectangle);
}
}
public class Enemy
{
public System.Drawing.Rectangle Rectangle;
public void Update()
{
Rectangle = new System.Drawing.Rectangle(5, 10, 10, 10);
}
}
Main:
Player p = new Player();
p.Initialize();
p.Update();
Result:
I'm looking to make an abstract class Entity which then has few classes that derive from it like Enemy, Friendly and Player. The reason I do this is because the classes have a lot of properties/fields that are alike. I also have 2 methods: updateEntity and drawEntity. The reason I have the update and draw entity is that drawEntity & updateEntity is the same for most of the classes that inherit from it. This is the code of my entity class:
public abstract class Entity
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private Texture2D texture;
public Texture2D Texture
{
get { return texture; }
set { texture = value; }
}
private Vector2 position;
public Vector2 Position
{
get { return position; }
set { position = value; }
}
private int health;
public int Health
{
get { return health; }
set { health = value; }
}
private Color entColor;
public Color EntColor
{
get { return entColor; }
set { entColor = value; }
}
public Entity(string name, Texture2D texture, Vector2 position, int health, Color entColor)
{
this.name = name;
this.texture = texture;
this.position = position;
this.health = health;
this.entColor = entColor;
}
public virtual void updateEntity(GameTime gameTime)
{
//update stuff here
}
public virtual void drawEntity(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height), entColor);
}
}
And this is how I envision my Enemy class :
public Enemy(string name, Texture2D texture, Vector2 position, int health, Color entColor)
{
Name = name;
Texture = texture;
Position = position;
Health = health;
EntColor = entColor;
}
Can anybody tell me if this is a good use of abstract class or if I'm doing something completely wrong in game design/architecture way?
You usually use an abstract class when its implementation is not complete to work with but it contains properties and/or methods that are common for other types that are derived from it or it provides an interface that should be shared by derived types but cannot be implemented at this lever of abstraction and thus it is not possible to instantiate it.
Such an example could be an abstract class Fruit that has a Color property that is common to all fruits and doesn't have to be implemented by each one of them. It can also have a method Grow() without implementation. This class alone makes no sense yet. You need to implement a concrete fruit like an Apple type and implement the Grow() method for this particular fruit.
In your case the Entity would be such a fruit and the apple could be a rectangle or a circle that implement their own drawing logic.
Base entity:
public abstract class Entity
{
public abstract void Draw(); // no implementation here
public virtual void UpdateEntity(GameTime gameTime)
{
// default update
}
}
Rectangle:
public class Rectangle : Entity
{
public override void Draw()
{
// draw a rectangle here
}
}
Circle which uses a different logic for UpdateEntity:
public class Circle : Entity
{
public override void Draw()
{
// draw a circle here
}
public override void UpdateEntity(GameTime gameTime)
{
// custom update for circles
}
}
I'm using XNA to create a Space Invaders copy. So I'm animating many sprites with the same logic placed in their own class, but using different values for most vars. Here is my way of animating from spritesheets:
Texture2D playerTex;
Vector2 playerPos = new Vector2(x, y), playerOrigin;
Rectangle playerHitBox;
float animationTimer = 0f, animationInterval = 100f;
int currentFrame = 1, frameWidth = example number, frameHeight = example number 2;
public void LoadContent(ContentManager Content)
{
playerTex = Content.Load<Texture2D>("ship");
}
public void Update(GameTime gameTime)
{
playerHitBox = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
playerOrigin = new Vector2(playerHitBox.X / 2, playerHitBox.Y / 2);
animationTimer += (float)gameTime.ElapsedGameTime.Milliseconds;
if (animationTimer > animationInterval)
{
currentFrame++;
animationTimer = 0f;
}
if (currentFrame == 2)
{
currentFrame = 0;
}
playerHitBox = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
playerOrigin = new Vector2(playerHitBox.Width / 2, playerHitBox.Height / 2);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(playerTex, playerPos, playerHitBox, Color.White, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
}
Instead of using this logic for every animating object within its own class I'm looking for a way to create a sprite class anduse inheritance to Update()/Draw() the sprite. Could something like this be a good approach for the Draw() method?
public void Draw(Texture2D spriteTex, Vector2 spritePos, Nullable<Rectangle> spriteSourceRect, Color spriteColor, Single spriteRotation, Vector2 spriteOrigin, Vector2 spriteScale, SpriteEffects spriteEffects, Single spriteLayerDepth, SpriteBatch spriteBatch)
{
if (spriteTex != null)
{
spriteBatch.Draw(spriteTex, spritePos, spriteSourceRect, spriteColor, spriteRotation, spriteOrigin, spriteScale, spriteEffects, spriteLayerDepth);
}
}
You can:
Create Sprite class to keep common animation properties like texture, duration and current index.
Create Invider class for custom data like position, health and other.
Create a collection to store custom data for each object in game class.
For example:
class Sprite
{
public Texture2D texture;
public Rectangle Frame;
private frameIndex;
private frameCount;
private frameDuration;
private frameInterval;
public Sprite(Texture pTexture, ...)
{
// init sprite data
}
public Update(GameTime pGameTime)
{
// update sprite data
}
}
class Invider
{
private Sprite Sprite;
public Vector2 Porision;
public int Health;
public Invider(Sprite pSprite, Vector2 pPosition)
{
this.Sprite = pSprite;
this.Position = pPosition;
}
public void Update(GameTime pGameTime)
{
// update invider data
}
public void Draw(SpriteBatch pSpriteBatch)
{
pSpriteBatch.Draw(this.Sprite.Texture, this.Sprite.Frame, this.Position, Color.White);
}
}
public class Game1 : Game
{
private SpriteBatch spriteBatch;
private Dictionary<int, Invider> invidersByID;
private Sprite inviderSprite;
public override Initialize()
{
// fill inviderByID collection
}
public override LoadData()
{
// create inviderSprite
}
public static UpdateStatic(GameTime pGameTime)
{
// update static data like frame index
}
public override void Update(GameTime pGameTime)
{
this.inviderSprite.Update(pGameTime);
foreach(Invider invider in invidersByID.Values){
{
invider.Update(pGameTime);
}
}
public override Draw(SpriteBatch pSpriteBatch)
{
this.spriteBatch.Begin();
foreach(Invider invider in invidersByID.Values){
{
invider.Update(pGameTime);
}
this.spriteBatch.End();
}
}
I have 3 classes:
- Game1 (main class)
- Entity (base entity class)
- Player (player class, extends Entity class)
I draw the player class, but after that I can't seem to change the position of the player object.
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Create a list with all the entities
List<Entity> entityList = new List<Entity>();
//Player
Player player;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//Create player
Texture2D playertexture = Content.Load<Texture2D>("player/player");
Rectangle playerrectangle = new Rectangle(10, 10, playertexture.Width, playertexture.Height);
player = new Player(playertexture, playerrectangle);
entityList.Add(player);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();
//Update players and entities
player.Update(graphics.GraphicsDevice);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
//Draw player
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
class Entity
{
//Standard variables
int health;
int armor;
float speed;
float friction;
//Get graphic and bounding box
Texture2D texture;
Rectangle rectangle;
public Entity(Texture2D newTexture, Rectangle newRectangle){
texture = newTexture;
rectangle = newRectangle;
}
public void Update(GraphicsDevice graphics) {
}
public void Draw(SpriteBatch spriteBatch) {
}
/*
* Modifiers for the variables
*/
public void modifyHealth(int amount) { health = health + amount; }
public void modifyArmor(int amount){ armor = armor + amount; }
public void modifySpeed(float amount) { speed = speed + amount; }
/*
* Getters for variables
*/
public int getHealth() { return health; }
public int getArmor() { return armor; }
public float getSpeed() { return speed; }
public float getFriction() { return friction; }
/*
* Setters for variables
*/
public void setHealth(int amount) { health = amount; }
public void setArmor(int amount) { armor = amount; }
public void setSpeed(float amount) { speed = amount; }
public void setFriction(float amount) { friction = amount; }
/*
* Functions
*/
public void damage(int damage) {
/*
* Calculate health
*
* Armor takes half the damage, if possible
*/
if (damage / 2 >= armor) {
damage = damage / 2;
armor -= damage;
} else if (armor > 0) {
damage -= armor;
armor = 0;
}
health -= damage;
if(health <= 0){
health = 0;
//TODO Death
}
}
}
class Player : Entity
{
//Create player
Entity player;
//Position and velocity
Vector2 position;
Vector2 velocity;
//Texture and rectangle
Texture2D texture;
Rectangle rectangle;
public Player(Texture2D newtexture, Rectangle newrectangle) : base(newtexture, newrectangle) {
texture = newtexture;
rectangle = newrectangle;
//Set basic variables
this.setHealth(100);
this.setArmor(0);
this.setSpeed(10);
this.setFriction(1);
}
public void Update() {
//Movement
if(Keyboard.GetState().IsKeyDown(Keys.Right)){
rectangle.X += 1;
}
rectangle.Y += 4;
}
public void Draw(SpriteBatch spriteBatch) {
spriteBatch.Draw(texture, rectangle, Color.White);
}
}
If there are also general mistakes I make, do point them out, I want to make everything as good as I can now that I'm still learning. Thanks in advance!
Your calling public void Update(GraphicsDevice graphics)
but the movement code is in public void Update()
What I suggest you do is this, use the virtual and override keywords.
In your entity class it should look like this:
public virtual void Update(GraphicsDevice graphics) {
}
And in your player class
public override void Update(GraphicsDevice graphics) {
//ADD MOVEMENT CODE HERE
}
I'm trying to encapsulate my game objects by having them extend Mircosoft.Xna.Framework.GameCompenent, then merely constructing them and managing them in the Update() method of Game1. I have my Game1 class, a Player class, and an Animation class. Animations are supposed manage the Texture2D changes of an object, in this instance Player.
My problem is that even though I have successfully extended everything, have no syntax errors, no exceptions thrown, and have checked and re-checked what little code I have written, the override functions are not called and I end up with a black screen.
Game1.cs: (note that the only two lines changed are for the Player declaration)
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Player player;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
player = new Player(this);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
base.Draw(gameTime);
}
}
Player.cs:
class Player : Microsoft.Xna.Framework.DrawableGameComponent
{
Rectangle bounds;
Texture2D t;
Animation[] animations = new Animation[4];
String path = #"..\..\..\Content\player.png";
#region Animation Constants
private const int WALK_RIGHT = 0;
#endregion
SpriteBatch spriteBatch;
public Player(Game game) : base(game)
{
//should only ever be one player, all value defaults set in Initialize()
}
public Texture2D T
{
get { return t; }
}
public Rectangle Bounds
{
get { return bounds; }
}
public override void Initialize()
{
base.Initialize();
bounds = new Rectangle(0, 0,
System.Drawing.Image.FromFile(path).Width,
System.Drawing.Image.FromFile(path).Height
);
t = Game.Content.Load<Texture2D>("player");
animations[0] = new Animation(this.Game, "player", "walking", 3);
}
protected override void LoadContent()
{
base.LoadContent();
spriteBatch = new SpriteBatch(this.Game.GraphicsDevice);
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
KeyboardState k = Keyboard.GetState();
if (k.IsKeyDown(Keys.Right)) //walk right
{
bounds.X += 3;
if (animations[WALK_RIGHT].Playing)
{
t = animations[WALK_RIGHT].getTexture();
}
else
{
animations[WALK_RIGHT].Play();
}
}
else if (animations[WALK_RIGHT].Playing)
animations[WALK_RIGHT].Stop();
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
spriteBatch.Begin();
spriteBatch.Draw(t, bounds, Color.White);
spriteBatch.End();
}
}
Animation.cs:
class Animation : Microsoft.Xna.Framework.GameComponent
{
Game game;
String name; //name of default sprite; standing, unmoving, neutral, etc. The rest of the animation sprite names should derive from this
String keyword;
int frameCount;
int delay; //frames between texture change
String[] paths; //texture pathnames generated by the MakePaths() function
int currentFrame = 0;
int delayCount = 0;
bool playing = false;
public Animation(Game associatedGame, String nameVal, String keywordVal, int frameCountVal)
: base(associatedGame)
{
name = nameVal;
keyword = keywordVal;
frameCount = frameCountVal;
paths = MakePaths();
delay = 10;
}
public Animation(Game associatedGame, String nameVal, String keywordVal, int frameCountVal, int delayVal)
: base(associatedGame)
{
name = nameVal;
keyword = keywordVal;
frameCount = frameCountVal;
paths = MakePaths();
delay = delayVal;
}
private String[] MakePaths()
{
//format: name_keyword_anim[i]
//format example: player_walking_anim1
String[] temp = new String[frameCount];
for (int i = 0; i < frameCount; i++)
{
temp[i] = name + "_" + keyword + "_" + "anim" + i.ToString();
}
return temp;
}
public Texture2D getTexture()
{
return Game.Content.Load<Texture2D>(paths[currentFrame]);
}
public void Play()
{
playing = true;
}
public void Stop()
{
currentFrame = 0;
delayCount = 0;
playing = false;
}
public bool Playing
{
get { return playing; }
}
public override void Update(GameTime gameTime)
{
if (playing)
{
if (delayCount == delay)
{
delayCount = 0;
if ((currentFrame + 1) == frameCount) currentFrame = 0;
else currentFrame++;
}
else delayCount++;
}
base.Update(gameTime);
}
public override string ToString()
{
return "params: " + name + "," + keyword + "," + frameCount.ToString() + "\nUsing paths: " + paths;
}
}
The only LoadContent, Initialize, Update, and Draw methods that are called are the ones in Game1. What really baffles me is that I was able to use this technique before without issue. These functions would be called naturally by the Xna update process.
So... why is this?
You need to add game Components to the Components collection to have them called automatically
protected override void Initialize()
{
player = new Player(this);
Components.Add(player);
base.Initialize();
}
See http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.game.components.aspx