OK, so I'm creating a pacman game in c# and I've got the pacman down. Now I'm trying to get my monsters in to the game.
I've created a class with moving methods and everything. Now the problem is that I'm drawing the monster and the pacman on a different graphics object. They are both the size of my panel and when I run the code only the pacman shows up, the monster is working but it's underneath the graphics object that the pacman is moving on.
This the code of drawing both the monster and pacman:
private void timMove_Tick(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(panBox.Width, panBox.Height);
Graphics g = Graphics.FromImage(bitmap);
foreach (Monster mon in monsters)
{
mon.move(g);
}
foreach (Pacman pac in characters)
{
pac.move(g);
}
Graphics g2 = panBox.CreateGraphics();
g2.DrawImage(bitmap, 0, 0);
}
My question is: how to either make them drawing on the same graphics object, or that they both just show instead of right now only the pacman?
I think you should think about your class structure in general.
I would recommend using something like this as a starting point:
abstract class GameObject
{
public abstract void Move();
public abstract void Draw(Graphics g);
}
class Pacman : GameObject
{
public override void Move()
{
//Update the Position of Pacman, check for collisions, ...
}
public override void Draw(Graphics g)
{
//Draw Pacman at his x and y coordinates
}
}
class Monster : GameObject
{
public override void Move()
{
//Update the Position of the Monster, ...
}
public override void Draw(Graphics g)
{
//Draw the Monster at his current position
}
}
class GameClass
{
private Pacman _pacman;
private Monster _monster;
private List<GameObject> _gameobjects = new List<GameObject>();
public GameClass()
{
_pacman = new Pacman();
_monster = new Monster();
_gameobjects.Add(_pacman);
_gameobjects.Add(_monster);
}
private void TimerTick()
{
//update all GameObjects
foreach (var gameobject in _gameobjects)
{
gameobject.Move();
}
//Draw every single GameObject to the Bitmap
Bitmap bitmap = new Bitmap(panBox.Width, panBox.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
foreach (var gameobject in _gameobjects)
{
gameobject.Draw(g);
}
}
//Draw the Bitmap to the screen
using (Graphics g = panBox.CreateGraphics())
{
g.DrawImage(bitmap, 0, 0);
}
}
You should take a look at Inheritance/Polimorphism and Classes in general.
Polimorphism:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism
Classes:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes
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:
Im working on a level editor in monogame for my engine.
I want to make a class where i can call a simple function and it will draw a sprite.
This is the function i want to call - and as you may know you have to be able to load and unload content and use the draw method.
Question: How would I make this be able to use those so that all I have to do is call this function and it works?
Here is the function:
public static void DrawSprite(Texture2D Texture, string Path, Vector2 Position, Color Color)
{
}
If you are going to leave the drawing to a single static method then you would be restricting what you are able to draw. I suggest creating an interface and do some abstraction.
Interface
public interface IGameObject
{
void Update(GameTime gameTime);
void Draw();
}
Utility Class
public sealed class GameUtility
{
private static GameUtility instance = null;
private static readonly object _lock = new object();
public ContentManager ContentManager { get; private set; }
public SpriteBatch SpriteBatch { get; private set; }
public static GameUtility Instance
{
get
{
lock (_lock)
{
if (instance == null)
{
instance = new GameUtility();
}
return instance;
}
}
}
public void SetContentManager(ContentManager contentManager)
{
this.ContentManager = contentManager;
}
public void SetSpriteBatch(SpriteBatch spriteBatch)
{
this.SpriteBatch = spriteBatch;
}
public GameUtility(ContentManager contentManager, SpriteBatch spriteBatch)
{
this.contentManager = contentManager;
this.spriteBatch = spriteBatch;
}
}
Game Objects
public class Hero : IGameObject
{
private Texture2D texture;
private Vector2 position;
private Color color;
public Hero(string path)
{
texture = GameUtility.Instance.ContentManager.Load<Texture2D>(path);
}
public void Update(GameTime gameTime)
{
// Do game update logic
}
public void Draw()
{
GameUtility.Instance.SpriteBatch.Begin();
GameUtility.Instance.SpriteBatch.Draw(texture, position, color);
GameUtility.Instance.SpriteBatch.End();
}
}
Game Class
Initialize the GameUtility
GameUtility.Instance.SetContentManager(contentManager);
GameUtility.Instance.SetSpriteBatch(spriteBatch);
Create the game objects
gameObects = new List<IGameObject>();
gameObjects.Add(new Hero("some path"));
Utilize the interface
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
foreach (IGameObject gameObject in gameObjects)
{
gameObject.Draw();
}
base.Draw(gameTime);
}
The beauty of this approach is you can perform different drawings based on your needs. For example, you could use a Rectangle instead of Vector2 based on different scenarios. You can also draw a sprite font or something else.
For unloading content, there is only one option which is
GameUtility.Instance.ContentManager.Unload();
You better unload content during your transition to the next level as calling ContentManager.Unload() will dispose all resources. As to why it disposes everything in one go, I don't really understand but that is the design.
Hope this answer give you some insight. I would not suggest creating this public static void DrawSprite.
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();
}
}
In my game, I have an Ai class which is basically just a linked list of every ai in my game. this same class holds the default textures for every ai, and all of my ai's seperate classes inherit from this class, that way they all can inherit the default textures that were already loaded by the ai class. However, I seem to be having problems with this. My game never loads up the gui when ran, and through debugging, it seems like the game has problems with the textures I am passing. Are you not able to load a single texture and pass that same texture for another object to use?
AI class:
class AIs
{
private GraphicsDevice graphics;
private ContentManager content;
private SpriteBatch spriteBatch;
private LinkedList<object> ais;
private LinkNode<object> current;
//Default Textures
private Texture2D robotTexture
// Default Color Datas
private Color[] robotColorData;
public AIs()
{
}
public void Load(ContentManager content, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
this.spriteBatch = spriteBatch;
this.graphics = graphics;
this.content = content;
// Loading Default Textures
robotTexture = content.Load<Texture2D>("robot");
// Loading Default Color Data
robotColorData = new Color[robotTexture.Width * robotTexture.Height];
robotTexture.GetData(robotColorData);
}
public void Update()
{
current = ais.getHead();
while (current.getNext() != null)
{
if (current.getData() is Robot)
{
((Robot)current.getData()).Update();
}
}
}
public void Draw()
{
current = ais.getHead();
while (current.getNext() != null)
{
if (current.getData() is Robot)
{
((Robot)current.getData()).Draw();
}
}
}
public addRobot(float spawnX, float spawnY)
{
Robot temp = new Robot(spawnX, spawnY);
temp.Load(content, graphics, spriteBatch);
ais.add(temp);
}
public Texture2D getRobotTexture()
{
return robotTexture;
}
public Color[] getRobotColorData()
{
return robotColorData;
}
}
Robot Class:
class Robot : AIs
{
private GraphicsDevice graphics;
private ContentManager content;
private SpriteBatch spriteBatch;
private Texture2D robotTexture;
private Color[] robotColorData;
private Rectangle robotRectangle;
private Vector2 robotPosition = Vector2.Zero;
public Robot(float spawnX, float spawnY)
{
robotPosition = new Vector2(spawnX, spawnY);
}
new public void Load(ContentManager content, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
this.spriteBatch = spriteBatch;
this.graphics = graphics;
this.content = content;
robotTexture = getRobotTexture();
robotColorData = getRobotColorData();
}
new public void Update()
{
robotRectangle = new Rectangle((int)robotPosition.X, (int)robotPosition.Y, robotTexture.Width, robotTexture.Height);
}
new public void Draw()
{
spriteBatch.Draw(robotTexture, robotPosition, Color.White);
}
}
Turns out, all you have to do is add the keyword "static" next to the texture and color data.
If you don't put static, then when the class is created, it will inherit the methods and variables, but the variables will be new, null, because it is a new instance of the class. So putting static next to it makes the value stay the same for all instances.
In the AI class:
//Default Textures
private static Texture2D robotTexture
// Default Color Datas
private static Color[] robotColorData;
It seems the problem here is in your use of inheritance.
What happens is that you run your robots Load-method, which fetches robotTexture from itself through AIs getRobotTexture-method. That method just returns robotTexture, so you might as well write robotTexture = robotTexture.
But since this instance has not ran AIs.Load, robotTexture is null.
To be brutally honest; Read up on inheritance!
To be more helpful;
It seems that what you are really after is having a robotmanager that simplifies the spawning of robots. For this, inheritance is not the answer. Try something like this instead:
public class RobotManager
{
private SpriteBatch spriteBatch;
private Texture2D robotTexture;
private List<Robot> robots;
public RobotManager(SpriteBatch spriteBatch, Texture2D texture)
{
this.spriteBatch = spriteBatch;
this.robotTexture = texture;
robots = new List<Robot>();
}
public void Update()
{
foreach (var robot in robots)
robot.Update();
}
public void Draw()
{
foreach (var robot in robots)
robot.Draw();
}
public void AddRobot(Vector2 position, Texture2D customTexture = null)
{
//Creates a new robot with position set and custom texture if specified
var newRobot = new Robot(spriteBatch, position, (customTexture == null) ? robotTexture : customTexture);
robots.Add(newRobot);
}
}
I am trying to make Pong in XNA/C# using a class for the Paddle and Ball
Game1.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Pong
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Paddle Paddle1 = new Paddle();
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);
}
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);
Paddle1.Draw();
base.Draw(gameTime);
}
}
}
Paddle.cs:
namespace Pong
{
class Paddle
{
SpriteBatch spriteBatch;
ContentManager Content;
Texture2D paddle1;
Texture2D paddle2;
Vector2 Paddle1;
Vector2 Paddle2;
public void LoadContent()
{
paddle1 = Content.Load<Texture2D>("pongpaddle1");
Paddle1 = new Vector2();
Paddle1.X = 50;
Paddle1.Y = 50;
}
public void Draw()
{
spriteBatch.Begin(); //Causes NullReferenceException was unhandled, Object reference not set to an instance of an object.
spriteBatch.Draw(paddle1, Paddle1, Color.White);
spriteBatch.End();
}
}
}
I don't have anything in the Ball class yet, but it will use similar methods to Paddle.cs
Every time I've ran the code, I keep getting a System.StackOverFlow exception whenever it hits this line of code in Game1.cs:
Paddle Paddle1 = new Paddle();
How do I fix this? I don't see how it's run out of memory already.
EDIT: Updated code.
What's happening here is that Paddle inherits Game1. Game1 creates new Paddles:
Paddle Paddle1 = new Paddle();
Paddle Paddle2 = new Paddle();
Those Paddles are Games that need to initialize their own set of Paddles. Infinite recursion! I'm not sure how XNA works, but if that's how the inheritance should be, just move your initializations to Initialize():
// TODO: Add your initialization logic here
base.Initialize();
this.Paddle1 = new Paddle();
this.Paddle2 = new Paddle();
I kind of doubt that a game object should inherit from the game itself, though. That would seem like a rather poor design decision.
public class Game1 : Microsoft.Xna.Framework.Game
{
Paddle Paddle1 = new Paddle();
Paddle Paddle2 = new Paddle();
...
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Paddle1.LoadContent();
}
...
}
class Paddle : Game1
{
...
protected override void LoadContent()
{
Paddle1 = new Vector2();
Paddle1.X = 50;
Paddle1.Y = 50;
base.LoadContent();
}
...
}
Two big problems here, there is a recursive LoadContent call. Not to mention your paddles have paddles which have paddles... Why is your paddle inheriting from Game1? It almost definitely shouldn't be.
Also your paddle instances instantiate other paddle instances, so you're in a loop of instantiating other paddle classes.
It seems like you might want to take a step back and just get used to some basic code first? For what it's worth, I wrote pong in xna for fun a few years back, it's a bit messy, but it might give you some starting help.
Here is an example of a paddle class based off the DrawableGameComponent class (drawn in primatives so it's a bit verbose):
public class Paddle : DrawableGameComponent
{
private readonly VertexPositionColor[] _vertices = new VertexPositionColor[6];
private readonly float _width;
private readonly float _height;
private IndexBuffer _indexbuffer;
private VertexBuffer _vertexbuffer;
public Vector3 Position { get; set; }
public Vector3 Direction { get; set; }
public float Speed { get; set; }
public Paddle(Game game, float width, float height)
: base(game)
{
_width = width;
_height = height;
}
protected override void LoadContent()
{
base.LoadContent();
_vertices[0].Position = new Vector3(0, 0, 0);
_vertices[0].Color = Color.Red;
_vertices[1].Position = new Vector3(_width, _height, 0);
_vertices[1].Color = Color.Green;
_vertices[2].Position = new Vector3(0, _height, 0);
_vertices[2].Color = Color.Blue;
_vertices[3].Position = new Vector3(_width, 0, 0);
_vertices[3].Color = Color.Green;
_vertexbuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), _vertices.Length, BufferUsage.WriteOnly);
_vertexbuffer.SetData(_vertices);
var indices = new short[6];
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 0;
indices[4] = 3;
indices[5] = 1;
_indexbuffer = new IndexBuffer(GraphicsDevice, typeof(short), 6, BufferUsage.WriteOnly);
_indexbuffer.SetData(indices);
}
public BoundingBox GetBoundingBox()
{
return new BoundingBox(Position, Position + new Vector3(_width, _height, 0));
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
GraphicsDevice.SetVertexBuffer(_vertexbuffer);
GraphicsDevice.Indices = _indexbuffer;
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2);
}
}