Why can't I link an resource to a Bitmap? - c#

i'm trying to get a player sprite to be drawn on my form, but when i try it comes up with StackOverflowException. I don't know how to fix this. Any ideas?
Player.cs:
private Bitmap p_SpriteIdle1 = new Bitmap(Properties.Resources.PlayerIdle1);
private Bitmap p_SpriteIdle2 = new Bitmap(Properties.Resources.PlayerIdle2);
private Bitmap p_SpriteWalking1 = new Bitmap(Properties.Resources.PlayerWalking1);
private Bitmap p_SpriteWalking2 = new Bitmap(Properties.Resources.PlayerWalking2);
public void SpawnInRoom()
{
SetSprite(p_SpriteIdle1, p_X, p_Y);
}
private void SetSprite(Bitmap sprite, int X, int Y)
{
Game game = new Game();
game.paint_Sprite = sprite;
game.paint_X = X;
game.paint_Y = Y;
game.Invalidate();
}
Game.cs:
private void RePaint(object sender, PaintEventArgs e)
{
if (paint_Sprite != null)
{
e.Graphics.DrawImage(paint_Sprite, new PointF(paint_X, paint_Y));
}
}

Related

Disappearing Objects

so for my first project with MonoGame I decided to make a tetris clone but I have an issue which I don't know how to solve.
Currently my code is generating a block and moves it downwards until it reach a specific y position. The block need to stay at this position and a new block spawns. I'm doing this with a List which contains object of the block class and then just draw all the blocks in this list.
I took out parts which I believe are not involved in the problem:
public class PlayField : DrawableGameComponent
{
private Game1 gameRef;
private Texture2D fieldTexture;
private BlockGenerator blockGenerator;
private Texture2D[] allBlocks;
private Block currentBlock;
public bool[,] fieldFilled;
private int down_Blocks = 22;
private int side_Blocks = 10;
public List<Block> placedBlocks;
public PlayField(Game game) : base(game)
{
placedBlocks = new List<Block>();
allBlocks = new Texture2D[4];
blockGenerator = new BlockGenerator(allBlocks,gameRef);
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
try
{
if (currentBlock.isMoving == false)
{
placedBlocks.Add(currentBlock);
currentBlock = null;
currentBlock = blockGenerator.GenerateBlock();
}
else
{
currentBlock.UpdatePosition(gameTime);
if (InputManager.CheckForKeyBoardRelease(Keys.A))
{
currentBlock.MoveLeft();
}
if (InputManager.CheckForKeyBoardRelease(Keys.D))
{
currentBlock.MoveRight();
}
}
}
catch(NullReferenceException e)
{
currentBlock = blockGenerator.GenerateBlock();
}
}
public override void Draw(GameTime gameTime)
{
gameRef.SpriteBatch.Begin();
if(currentBlock != null)
{
currentBlock.DrawBlocks();
}
foreach(Block b in placedBlocks)
{
b.DrawBlocks();
}
gameRef.SpriteBatch.End();
base.Draw(gameTime);
}
The method "GenerateBlock" returns a object of type "Block"
public class Block : DrawableGameComponent
{
Game1 gameRef;
public Texture2D blockTexture;
public Vector2[] blockPositions;
TimeSpan lastMove;
TimeSpan blockMove = TimeSpan.FromMilliseconds(500);
public bool isMoving;
public Block(Game game, Texture2D _blockTexture, Vector2[] _blockPositions) : base(game)
{
gameRef = (Game1)game;
blockTexture = _blockTexture;
blockPositions = _blockPositions;
isMoving = true;
}
public void UpdatePosition(GameTime gameTime)
{
Vector2 bottomBlockPositon = FindBottomBlock();
if(bottomBlockPositon.Y < 550)
{
if (WaitTillMove(gameTime))
{
for (int i = 0; i < blockPositions.Length; i++)
{
blockPositions[i] = new Vector2(blockPositions[i].X, blockPositions[i].Y + 25);
}
}
}
else
{
isMoving = false;
Console.WriteLine("X: " +blockPositions[0].X + " Y:" + blockPositions[0].Y);
}
}
public Vector2 FindBottomBlock()
{
Vector2 result = new Vector2(0, 0);
for(int i = 0; i < blockPositions.Length; i++)
{
if(blockPositions[i].Y > result.Y)
{
result = blockPositions[i];
}
}
return result;
}
public bool WaitTillMove(GameTime gameTime)
{
if (lastMove + blockMove < gameTime.TotalGameTime)
{
lastMove = gameTime.TotalGameTime;
return true;
}
return false;
}
public void DrawBlocks()
{
gameRef.SpriteBatch.Draw(blockTexture, blockPositions[0], Color.White);
gameRef.SpriteBatch.Draw(blockTexture, blockPositions[1], Color.White);
gameRef.SpriteBatch.Draw(blockTexture, blockPositions[2], Color.White);
gameRef.SpriteBatch.Draw(blockTexture, blockPositions[3], Color.White);
}
}
Debugging says that my List contains an Element even though it has the wrong positions. But this shouldn't matter because I still only "see" one Block at the same time.
Hopefully someone can toss me into the right direction.
Edit:
public class BlockGenerator
{
Random random;
Texture2D[] allBlocks;
Vector2[] blockPositions;
Texture2D currentBlock;
BlockEnums currentBlockEnum;
Game1 gameRef;
public BlockGenerator(Texture2D[] blocks, Game1 game)
{
gameRef = (Game1)game;
allBlocks = blocks;
currentBlock = allBlocks[1];
blockPositions = new Vector2[4];
random = new Random();
}
public Block GenerateBlock()
{
int colorValue = random.Next(0, 4); //0 = blue, 1 = green, 2 = red, 3 = yellow
currentBlock = allBlocks[colorValue];
currentBlockEnum = BlockEnums.Line;
blockPositions[0] = new Vector2(100, 0);
blockPositions[1] = new Vector2(125, 0);
blockPositions[2] = new Vector2(150, 0);
blockPositions[3] = new Vector2(175, 0);
Block generatedBlock = new Block(gameRef,currentBlock, blockPositions);
return generatedBlock;
}
public class BlockGenerator
{
Random random;
Texture2D[] allBlocks;
Vector2[] blockPositions; // delete this
Then move the initialization code from the constructor into GenerateBlock (add var).
var blockPositions = new Vector2[4];
Then it should work. You were creating new vectors each time you created a block but re-using the same instance of blockPositions each time, so both blocks do exist but will always have the exact same positions.
I haven't had time to test but I think it's right...let me know :)
edit: I'd also suggest moving blockPositions entirely into the Block class. I see no value (in the code you have posted, maybe you have plans for later) in having that logic outside of the class that really owns it...and if it was contained within the class to begin with you would have avoided this problem. Just a suggestion :)

GDI+ Game Engine (What can I do to make my engine run faster?) [duplicate]

This question already exists:
How to make my game engine faster (GDI+, C#)
Closed 6 years ago.
I'm currently working on a 2D Game Engine using GDI+. Everything is running quite smoothly, however I know there must be a few more things I can do to make my engine render graphics faster.
At the moment if I rendered an empty bitmap that's 800x600 pixels to the screen, I get about 130fps. But once I draw an image that's 800x600 pixels on the bitmap, I get about 70fps. That's not an issue at all, I'm actually proud of the results, I just know it can be better.
I was just wondering if anyone had any suggestions as to what might make the engine run even faster?
Here's the code to my window class:
using System;
using System.Windows.Forms;
using GameEngine.Graphics;
using System.Threading;
using System.Drawing;
namespace GameEngine.Core
{
public class Game : Form
{
// Just a class that checks the fps and such
private GameTime gameTime;
private GraphicsEngine graphicsEngine;
private bool isLoaded = false;
private bool isRunning = false;
public Game(int width, int height, string title)
{
this.Width = width;
this.Height = height;
this.Text = title;
this.MaximizeBox = false;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.Paint += Game_Paint;
this.FormClosing += Game_FormClosing;
gameTime = new GameTime();
graphicsEngine = new GraphicsEngine(this);
Show();
}
public void Run()
{
Initialize();
Load();
isRunning = true;
while (isRunning && isLoaded)
{
// Yes I know, this is frowned upon
Application.DoEvents();
gameTime.Update();
// Only update if the form is focused and if the GameTime class says we're allowed
if (this.Focused && gameTime.Cycled)
{
BeginUpdate();
UpdateGame();
LateUpdate();
Render();
}
else
{
Thread.Sleep(1);
}
}
Exit();
}
public void Exit()
{
Unload();
this.Close();
// Using console application, so lets exit the console
Environment.Exit(0);
}
private void Initialize()
{
gameTime.Initialize();
}
private new void Load()
{
isLoaded = true;
}
private void Unload()
{
}
private void BeginUpdate()
{
}
private void UpdateGame()
{
this.Title = "FPS: " + gameTime.FPS;
}
private void LateUpdate()
{
}
Bitmap bmp = new Bitmap("Test.jpg");
private void Render()
{
// Draw the nice tree to the window
graphicsEngine.DrawBitmap(bmp, 0, 0);
// Cause the window to redraw it's self
this.Invalidate();
}
private void Game_Paint(object sender, PaintEventArgs e)
{
// Lets just make sure once again that we're allowed to draw
if (gameTime.Cycled)
{
// Render the graphics to the screen
graphicsEngine.Render(e.Graphics);
}
}
private void Game_FormClosing(object sender, FormClosingEventArgs e)
{
isLoaded = false;
}
public string Title
{
get { return Text; }
set { Text = value; }
}
}
}
and here's the graphics engine class:
using System.Drawing;
using GameEngine.Core;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace GameEngine.Graphics
{
public class GraphicsEngine
{
private Game game;
private System.Drawing.Graphics backBuffer;
private System.Drawing.Bitmap backBufferBitmap;
public GraphicsEngine(Game game)
{
this.game = game;
backBufferBitmap = new Bitmap(800, 600);
backBuffer = System.Drawing.Graphics.FromImage(backBufferBitmap);
backBuffer.CompositingMode = CompositingMode.SourceOver;
backBuffer.CompositingQuality = CompositingQuality.HighSpeed;
backBuffer.SmoothingMode = SmoothingMode.None;
backBuffer.InterpolationMode = InterpolationMode.Low;
backBuffer.TextRenderingHint = TextRenderingHint.SystemDefault;
backBuffer.PixelOffsetMode = PixelOffsetMode.Half;
}
public void Render(System.Drawing.Graphics g)
{
g.CompositingMode = CompositingMode.SourceCopy;
g.CompositingQuality = CompositingQuality.AssumeLinear;
g.SmoothingMode = SmoothingMode.None;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.TextRenderingHint = TextRenderingHint.SystemDefault;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.DrawImage(backBufferBitmap, new Rectangle(0, 0, game.Width, game.Height), new Rectangle(0, 0, game.Width, game.Height), GraphicsUnit.Pixel);
backBuffer.Clear(Color.Black);
}
public void DrawString(string text, int x, int y)
{
backBuffer.DrawString(text, SystemFonts.DefaultFont, Brushes.White, x, y);
}
public void DrawBitmap(Bitmap bitmap, int x, int y)
{
backBuffer.DrawImage(bitmap, x, y);
}
public void DrawBitmap(Bitmap bitmap, int x, int y, int width, int height)
{
backBuffer.DrawImageUnscaled(bitmap, x, y, width, height);
}
}
}
You should try to operate a kind of Logical thread separated from your drawing thread. Maybe replace the thread sleeping in your logical by a (tick management).
As asked in comments below, the fact to separate UI & logic in different thread could help you to have a better flow in both tasks. The hard part is to keep UI and logic Synced, but you're less exposed to slow methods/function which would slow down UI.

Visual C# - Calling a function from a class does nothing

I have a problem trying to draw a rectangle on a panel. I created a class that has a function that does this but when I call it nothing happens. When I use the code from the function instead of the actual function it works. Any ideas? This is the code
class Snake : Form1
{
public static int x = 20;
public static int y = 20;
public static int r = 20;
public void Draw()
{
SolidBrush brush = new SolidBrush(Color.Green);
Graphics G = panel1.CreateGraphics();
G.FillRectangle(brush, x, y, r, r);
}
}
//...
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
Snake s = new Snake();
s.Draw();
}
Snake object is drawing within its own graphics context, which is not the same as the context of the panel you're clicking. To solve the problem, panel would have to provide graphics for the Draw function:
class Snake
{
public static int x = 20;
public static int y = 20;
public static int r = 20;
public void Draw(Graphics G)
{
SolidBrush brush = new SolidBrush(Color.Green);
G.FillRectangle(brush, x, y, r, r);
}
}
//...
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
using (Graphics G = panel1.CreateGraphics())
{
Snake s = new Snake();
s.Draw(G);
}
}
On a related note, make sure to always dispose of the Graphics object.
Implement the Panel Paint event:
class Snake : Form1
{
public static int x = 20;
public static int y = 20;
public static int r = 20;
public void Draw()
{
panel1.Refresh() ;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
SolidBrush brush = new SolidBrush(Color.Green);
Graphics G = panel1.CreateGraphics();
G.FillRectangle(brush, x, y, r, r);
}
}

How to draw an image in c# with path stored in a variable

private string path;
public string Path
{
get { return path; }
set { path = value; }
}
public override void Draw(Graphics.IGraphicsSurface g)
{
//some code here
}
I need to get the image stored at the location path on my file system and draw it on the surface, g, using the DrawImage() function.
EDIT:
The first parameter being passed to DrawImage() must be a string
public void DrawImage(string image, float x, float y)
OR file Stream
public void DrawImage(Stream imageStream, float x, float y)
public void DrawImage(string image, float x, float y)
{
try
{
if (File.Exists(image))
{
Stream stream = new FileStream(image, FileMode.Open);
DrawImage(stream, new Graphics.Point(x, y));
}
}
catch(Exception)
{
}
}
In general, you can use Image.FromFile(string).
var image = Image.FromFile(path);
g.DrawImage(image, 0, 0);
This will draw the image at the point (0, 0).
However, OP is required to use a different DrawImage method which takes in a string. For this, we can simply say:
g.DrawImage(path, 0, 0);
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog()==DialogResult.OK)
{
pictureBox1.Image = Image.FromFile(dlg.FileName);
}
}

Collision between circle and a radius

I need to implement collision detection here. The objects i have here are a ball/circle and a rectangle. The balls are moving vertically, while the rectangle is moving horizontally. The condition is that if the ball and rectangle touch each other then an event should be raised. I have been trying to do that for a while with my colleague but without success. This is my first program in C# so please bear with me.
here is my code:
public partial class Form1 : Form
{
bool collided = false;
Player player;
List<Ball> balls;
const int fps = 60;
public Form1()
{
InitializeComponent();
balls = new List<Ball>();
Random r = new Random();
for(int i =0; i<1;i ++)
{
balls.Add(new Ball(Width, Height,r));
}
var task = new Task(Run);
task.Start();
player = new Player()
{
x = this.Width/2,
y = (Height*9/10),
xvel = 10,
brush = Brushes.Black,
};
}
protected void Run()
{
while (true)
{
for(int i = 0; i < balls.Count; i++)
{
balls[i].Move(this.Width);
}
this.Invalidate();
Thread.Sleep(1000 / fps);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.White);
for(int i = 0; i < balls.Count; i++)
{
balls[i].Draw(g);
}
player.DrawPlayer(g);
}
//This is the part where i was trying to check collision between the circle and a ball
private void CheckCollision(PaintEventArgs e)
{
if (player.IntersectsWith(balls))
{
player.Intersect(balls);
if (!player.IsEmpty)
{
collided = true;
MessageBox.Show("collision detected");
}
}
}
}
public class Player
{
public float x, y, xvel;
public Brush brush;
public Player()
{
}
public void DrawPlayer(Graphics g)
{
g.FillRectangle(brush, new RectangleF(x, y, 30,30));
}
public void MovePlayerLeft(int gameWidth)
{
if (x > 0)
{
x -= xvel;
}
}
public void MovePlayerRight(int gameWidth)
{
if (x < gameWidth-47)
{
x += xvel;
}
}
}
public class Ball
{
public float x, y, yvel, radius;
public Brush brush;
public Ball(int gamewidth,int gameHeight,Random r)
{
x = r.Next(gamewidth);
y = r.Next(gameHeight);
yvel = r.Next(2) + 5;
radius = r.Next(10) + 5;
brush = new SolidBrush(Color.Blue);
}
public void Move(int gameHeight)
{
if (y + radius >= gameHeight)
{
y = 0;
}
y += yvel;
}
public void Draw(Graphics g)
{
g.FillEllipse(brush, new RectangleF(x-radius,y - radius, radius * 2, radius * 2));
}
}
If you're trying to figure out if a rectangle and a circle is intersecting, try this algorithm for each of the four sides:
Circle line-segment collision detection algorithm?
You can probably speed this up by checking if corners are inside the circle.
Also, remember that a circle completely inside a rectangle and vice versa should probably count as a collision.

Categories

Resources