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);
}
}
Related
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));
}
}
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.
First I added many properties, but that's not the proper way to pass variables. How should I handle it?
Second, this control will be used like a pictureBox1 in form1 designer (or any other form designer). And in form1, I used some events of the pictureBox1. Now I need to use the events of the picturebox1 in the control, so do I need to create and use all the events in the Control code and not form1?
This is the user control code:
namespace Find_Distance
{
public partial class pictureBox1Control : UserControl
{
public static PictureBox pb1;
// blinking colors: yellow, red, yellow, transparent, repeat...
public static Brush[] cloudColors = new[] { Brushes.Yellow, Brushes.Transparent };
// current color index
public static int cloudColorIndex = 0;
public pictureBox1Control()
{
InitializeComponent();
pb1 = new PictureBox();
this.pictureBox1 = pb1;
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
}
private void pictureBox1Control_Load(object sender, EventArgs e)
{
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.Clear(Color.White);
e.Graphics.DrawImage(pictureBox1Control.pb1.Image, movingPoint);
CloudEnteringAlert.Paint(e.Graphics, currentfactor, _distance);
float distance = _kilometers / (float)1.09;//289617486; // One pixel distance is 1.09 kilometer.
Pen p;
p = new Pen(Brushes.Green);
if (_points == null)
{
return;
}
foreach (Point pt in _pointsint)
{
e.Graphics.FillEllipse(Brushes.Red, pt.X * (float)currentfactor, pt.Y * (float)currentfactor, 2f, 2f);
}
foreach (PointF pt in _movingpoints)
{
if (_Cloud == null)
{
e.Graphics.FillEllipse(Brushes.Red, (pt.X - distance) * (float)currentfactor, pt.Y * (float)currentfactor, 2f, 2f);
}
}
foreach (PointF pt in _pointtocolor)
{
e.Graphics.FillEllipse(Brushes.Yellow, pt.X * (float)currentfactor, pt.Y * (float)currentfactor, 2f, 2f);
}
if (_Cloud != null)
{
foreach (PointF pt in _Cloud)
{
e.Graphics.FillEllipse(cloudColors[cloudColorIndex], pt.X * (float)currentfactor, pt.Y * (float)currentfactor, 2f, 2f);
}
}
else
{
return;
}
foreach (var cloud in _clouds)
{
e.Graphics.FillEllipse(
cloud.Brush, cloud.Center.X, cloud.Center.Y,
cloud.Diameter, cloud.Diameter);
}
}
public static List<Ellipse> _clouds = new List<Ellipse>();
public List<Ellipse> Clouds
{
get { return _clouds; }
}
public static List<PointF> _points = new List<PointF>();
public List<PointF> Points
{
get { return _points; }
}
public static List<Point> _pointsint = new List<Point>();
public List<Point> PointsInt
{
get { return _pointsint; }
}
public static List<PointF> _movingpoints = new List<PointF>();
public List<PointF> MovingPoints
{
get { return _movingpoints; }
}
public static List<PointF> _pointtocolor = new List<PointF>();
public List<PointF> PointtoColor
{
get { return _pointtocolor; }
}
public static List<PointF> _Cloud = new List<PointF>();
public List<PointF> Cloud
{
get { return _Cloud; }
}
public static float _kilometers;
public float Kilometers
{
get { return _kilometers; }
}
public static float _distance;
public float Distance
{
get { return _distance; }
}
public static Point movingPoint;
public static double currentfactor;
public static float distance;
}
}
On this user control designer, I added a pictureBox1.
And this is for example how I'm using it in Form1:
pictureBox1Control.pb1.Image = test.jpg;
But it dosen't show the image on the pictureBox1 in the control.
Instead of using:
pictureBox1Control.pb1.Image = test.jpg;
try using
pictureBox1Control.pb1.Load(#"c:\test.jpg");
Of course, make sure the file exists. Also, you should remove "static" from this line:
public static PictureBox pb1;
If you have 10 windows opened, you might not want to display all the same image. I see that your PictureBox object is not added to the control. In the first method, after you create the PictureBox, use
this.Controls.Add(pb1)
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
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.