What I have currently is two objects that can be played though nav keys and the other one with wasd. The point is to get the 3rd object and score a point, and it randoms a new pos after catching it, which works.
Now... I want the npc2 to not longer be controlled by human, and create a method for it to move on its own TOWARDS the scoring object. How would I possibly do to achieve this? Im new to c# :)
FORM.cs below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SPEL
{
public partial class Form1 : Form
{
npc npc1 = new npc();
npc npc2 = new npc();
sten ste1 = new sten();
int poang1 = 0;
int poang2 = 0;
private _keyControl cc = new _keyControl();
public Form1()
{
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
InitializeComponent();
// Hantera tangentbordet
#region captute evenents
this.KeyDown += new System.Windows.Forms.KeyEventHandler(cc.addKey);
this.KeyUp += new System.Windows.Forms.KeyEventHandler(cc.delKey);
#endregion
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
npc1.Rita(e.Graphics);
npc2.Rita(e.Graphics);
ste1.Draw(e.Graphics);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//MessageBox.Show(e.KeyData.ToString());
}
private void timer1_Tick(object sender, EventArgs e)
{
//spelare 1
this.Text = cc.keyStr;
if (cc.getKey("Right"))
{
npc1.Flytta("Right");
this.Invalidate();
}
if (cc.getKey("Left"))
{
npc1.Flytta("Left");
this.Invalidate();
}
if (cc.getKey("Up"))
{
npc1.Flytta("Up");
this.Invalidate();
}
if (cc.getKey("Down"))
{
npc1.Flytta("Down");
this.Invalidate();
}
//Spelare 2
if (cc.getKey("D"))
{
npc2.Flytta("Right");
this.Invalidate();
}
if (cc.getKey("A"))
{
npc2.Flytta("Left");
this.Invalidate();
}
if (cc.getKey("W"))
{
npc2.Flytta("Up");
this.Invalidate();
}
if (cc.getKey("S"))
{
npc2.Flytta("Down");
this.Invalidate();
}
if (npc1.checkkoll().IntersectsWith(ste1.checkkoll()))
{
poang1++;
ste1.randomxy(this.Width -30, this.Height -30);
}
if (npc2.checkkoll().IntersectsWith(ste1.checkkoll()))
{
poang2++;
ste1.randomxy(this.Width -30, this.Height -30);
}
}
private void timer2_Tick(object sender, EventArgs e)
{
if (this.BackColor == Color.Red)
this.BackColor = Color.Blue;
else
this.BackColor = Color.Red;
}
private void flytta_Tick(object sender, EventArgs e)
{
}
}
}
}
And here's my movement class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace SPEL
{
class npc
{
private Bitmap strid;
private Point pt;
public npc()
{
strid = new Bitmap("hej.gif");
pt.X = 20;
pt.Y = 20;
}
public void Rita(Graphics f)
{
Rectangle re = new Rectangle(pt.X, pt.Y, strid.Width, strid.Height);
f.DrawImage(strid, re);
}
public Rectangle checkkoll()
{
Rectangle re = new Rectangle(pt.X, pt.Y, strid.Width, strid.Height);
return re;
}
public void Flytta(string dir)
{
if (dir == "Left")
{
pt.X = pt.X - 2;
}
if (dir == "Right")
{
pt.X = pt.X + 2;
}
if (dir == "Up")
{
pt.Y = pt.Y - 2;
}
if (dir == "Down")
{
pt.Y = pt.Y + 2;
}
}
}
}
I do understand that it's much to ask for, but i'd be more than thankful if you could help me!
Try something like this
public void FlyttaMot(int x, int y, float speed)
{
float tx = x - pt.X;
float ty = y - pt.Y;
float length = Math.Sqrt(tx*tx + ty*ty);
if (length > speed)
{
// move towards the goal
pt.X = (int)(pt.X + speed* tx/length);
pt.Y = (int)(pt.Y + speed* ty/length);
}
else
{
// already there
pt.X = x;
pt.Y = y;
}
}
Call it from your timer tick code in Form.cs like this for example.
npc2.FlyttaMot(200, 200, 0.5f);
I based this on linear algebra. Take a look at this video for example. The (tx,ty) is the vector in which direction the npc should go. Dividing with the length of the vector gives us a vector of length 1. I multiply this with a speed parameter so you can adjust the speed of the npc.
The easiest and most accurate way, is to rely on vector geometry.
Define class
public class Vector2 {
public float x {get;set;};
public float y {get;set;};
public Vector2(float a_x, float a_y, float b_x, float b_y)
{
x = b_x - a_x;
y = b_y - a_y;
}
//calculate vector length
public float Length {
get {
return Math.Sqrt((x * x) + (y * y));
}
}
public void SetVectorLength(float desiredLength){
double r = desiredLength/ this.Length;
this.x *= r;
this.y *= r;
}
}
this is just a set of functions for this case, but you can add others, plenty of them need for various parts of your calculations.
After what you have to do is just, calculate next position of your vertex toward the directional vector.
//hypothetical X coordinate
float x_coord = 1.34f;
//move towards the vector
var vector = new Vector2(10, 10, 20, 20);
//set vector move step
vector.SetLength(0.1f);
var movedX = x_coord + vector.x;
Repeat: this is just hypothetical example, you need to work on this. It's hard to put in small answer all related vector geometry stuff.
Related
I am doing an exercise from my book on WinForms, inheritance, interfaces and abstract classes. The exercise is to create couple of balls moving in random directions and having obstacles of shapes like a box interact with the balls.
The thought process in the book was that there is a Ball class and another class that is called Engine to handle the creations of the ellipses. My job is to create the obstacles and have them interact with the balls.
This are the requirements
All obstacles should be treated the same w.r.t. the engine; perhaps by using an interface. Do not use fully abstract classes
All obstacles should share as much code as possible, but only code that makes sense to share; use abstract classes if necessary to avoid inheriting methods that do not make sense or empty methods.
The Ball and Engine, class where given.
Position :
public class Position
{
public float X, Y;
public Position(float x, float y)
{
X = x; Y = y;
}
}
Vector :
public class Vector
{
public float X, Y;
public Vector(float x, float y)
{
X = x; Y = y;
}
}
Ball :
public class Ball
{
static Pen Pen = new Pen(Color.Black);
Position Position;
Vector Speed;
float Radius;
static Random Random = new Random();
public Ball(float x, float y, float radius)
{
Position = new Position(x,y);
var xd = Random.Next(1, 6);
var yd = Random.Next(1, 6);
if (Random.Next(0, 2) == 0) xd = -xd;
if (Random.Next(0, 2) == 0) yd = -yd;
Speed = new Vector(xd,yd);
Radius = radius;
}
public void Draw(Graphics g)
{
g.DrawEllipse(Pen,Position.X - Radius, Position.Y - Radius, 2 * Radius, 2 * Radius);
}
public void Move()
{
Position.X += Speed.X;
Position.Y += Speed.Y;
}
}
Engine :
public class Engine
{
MainForm Form = new MainForm();
Timer Timer = new Timer();
List<Ball> Balls = new List<Ball>();
Redbox RBox = new Redbox(); //My added code
Random Random = new Random();
public void Run()
{
Form.Paint += Draw;
Timer.Tick += TimerEventHandler;
Timer.Interval = 1000/25;
Timer.Start();
Application.Run(Form);
}
private void Form_Paint(object sender, PaintEventArgs e)
{
throw new NotImplementedException();
}
void TimerEventHandler(Object obj, EventArgs args)
{
if (Random.Next(100) < 25)
{
var ball = new Ball(400, 300, 10);
Balls.Add(ball);
}
foreach (var ball in Balls)
{
ball.Move();
}
Form.Refresh();
}
void Draw(Object obj, PaintEventArgs args)
{
foreach (var ball in Balls)
{
ball.Draw(args.Graphics);
}
RBox.Draw(args.Graphics); //Testing
}
}
And this is the interface I created :
interface IObstacles
{
void Draw(Graphics g);
}
class Redbox : IObstacles
{
public void Draw(Graphics g)
{
Pen Pen = new Pen(Color.Red);
Random Random = new Random();
Position Position = new Position(Random.Next(100, 700), Random.Next(100, 700));
var width = Random.Next(30, 100);
var height = Random.Next(30, 100);
g.DrawRectangle(Pen, Position.X , Position.Y, width, height);
}
}
I am stuck figuring out how would my one (for now) rectangle would be drawn without it being refreshed every time. I might sound like an idiot, but I am fairly new. The result that I get is same rectangle appearing and disappearing with the same tick. I have also noticed that the Ball class creates and stores new "balls" in the list, but I cant do the same I think because of my interface implementation. I am creating interface for all the Obstacles as they are the same but with different shape. I might be wrong in my implementation but it sound logical to me at least.
Any help would be appreciated, as I am newbie in C#.
Using Jimi's Suggestios :
It turns out that he was right the randomness declared in Draw wasn't the right solution and it caused like he said for the obstacles to be redrawn every time with random position. This is all fixed by moving them outside I also modified the class so that it was possible to chose where the position of the box would be drawn.
I am posting the answer so that others that stumble on this can have a look on how I solved my problem thanks to Jimi's solution.
Interface :
interface IObstacles
{
void Draw(Graphics g);
}
class Redbox : IObstacles
{
Pen Pen = new Pen(Color.Red);
Random Random = new Random();
Position Position;
float width;
float height;
public Redbox(float x, float y)
{
Position = new Position(x, y);
width = Random.Next(30, 100);
height = Random.Next(30, 100);
}
public void Draw(Graphics g)
{
g.DrawRectangle(Pen, Position.X , Position.Y, width, height);
}
}
Engine :
public class Engine
{
MainForm Form = new MainForm();
Timer Timer = new Timer();
List<Ball> Balls = new List<Ball>();
List<IObstacles> RBox = new List<IObstacles>();
Random Random = new Random();
public void Run()
{
Form.Paint += Draw;
Timer.Tick += TimerEventHandler;
Timer.Interval = 1000/25;
Timer.Start();
Application.Run(Form);
}
private void Form_Paint(object sender, PaintEventArgs e)
{
throw new NotImplementedException();
}
void TimerEventHandler(Object obj, EventArgs args)
{
if (Random.Next(100) < 25)
{
var ball = new Ball(400, 300, 10);
Balls.Add(ball);
}
if (RBox.Count() < 2)
{
RBox.Add(new Redbox(100 * Random.Next(1, 8), 100 * Random.Next(0, 6)));
}
foreach (var ball in Balls)
{
ball.Move();
}
Form.Refresh();
}
void Draw(Object obj, PaintEventArgs args)
{
foreach (var ball in Balls)
{
ball.Draw(args.Graphics);
}
foreach (var rbox in RBox)
{
rbox.Draw(args.Graphics);
}
}
}
If there are still issues or some suggestion that anyone would like to add feel free to comment.
I created a slider bar user control but at run time when I move the slider to the left or right why it's not getting to the end or swallow?
In the user control designer I added a pictureBox control :
Then in the code I did :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Extract
{
public partial class Slider : UserControl
{
public float Height;
public float Min = 0.0f;
public float Max = 1.0f;
private float defaultValue = 0.1f;
public Slider()
{
InitializeComponent();
}
private void sliderControl_Paint(object sender, PaintEventArgs e)
{
float bar_size = 0.45f;
float x = Bar(defaultValue);
int y = (int)(sliderControl.Height * bar_size);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.FillRectangle(Brushes.DimGray, 0, y, sliderControl.Width, y / 2);
e.Graphics.FillRectangle(Brushes.Red, 0, y, x, sliderControl.Height - 2 * y);
using (Pen pen = new Pen(Color.Black, 8))
{
e.Graphics.FillRectangle(Brushes.Red, 0, y, x, y / 2);
FillCircle(e.Graphics, Brushes.Red, x, y + y / 4, y / 2);
}
using (Pen pen = new Pen(Color.White, 5))
{
DrawCircle(e.Graphics, pen, x, y + y / 4, y/ 2);
}
}
public static void DrawCircle(Graphics g, Pen pen,
float centerX, float centerY, float radius)
{
g.DrawEllipse(pen, centerX - radius, centerY - radius,
radius + radius, radius + radius);
}
public static void FillCircle(Graphics g, Brush brush,
float centerX, float centerY, float radius)
{
g.FillEllipse(brush, centerX - radius, centerY - radius,
radius + radius, radius + radius);
}
private float Bar(float value)
{
return (sliderControl.Width - 24) * (value - Min) / (float)(Max - Min);
}
private void Thumb(float value)
{
if (value < Min) value = Min;
if (value > Max) value = Max;
defaultValue = value;
sliderControl.Refresh();
}
private float SliderWidth(int x)
{
return Min + (Max - Min) * x / (float)(sliderControl.Width);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
MaintainPictureBoxSize();
}
private void MaintainPictureBoxSize()
{
sliderControl.SizeMode = PictureBoxSizeMode.Normal;
sliderControl.Location = new Point();
sliderControl.Size = new Size();
var clientSize = this.ClientSize;
if (sliderControl.Image == null)
sliderControl.Size = clientSize;
else
{
Size s = sliderControl.Image.Size;
sliderControl.Size = new Size(
clientSize.Width > s.Width ? clientSize.Width : s.Width,
clientSize.Height > s.Height ? clientSize.Height : s.Height);
}
}
bool mouse = false;
private void sliderControl_MouseDown(object sender, MouseEventArgs e)
{
mouse = true;
Thumb(SliderWidth(e.X));
}
private void sliderControl_MouseMove(object sender, MouseEventArgs e)
{
if (!mouse) return;
Thumb(SliderWidth(e.X));
}
private void sliderControl_MouseUp(object sender, MouseEventArgs e)
{
mouse = false;
}
}
}
When I drag the control to the form1 designer and then running the application then when I drag the slider for example to the left or to the right the circle of the slider is partly swallow.
and if I resize the control in form1 designer to be smaller and then running the application to left it swallow as before but to the right it's not getting to the end at all.
The easiest way to explain it is to show an image:
Now, inside the picture box, imagine the thumb circle to be in the left most and right most positions. This means that the bar must start at x = radius and that the width of the bar must be the width of the picture box minus twice the radius.
Everything must be drawn inside the picture box (dotted line). But this needs not to be in a PictureBox placed on a UserControl. Let's derive the slider from Control instead.
public class Slider : Control
{
...
}
Now, after having compiled this code for the first time, this Slider automatically appears in the Toolbox window and is ready to be placed on a form in the forms designer.
Since we want to be able to set its properties in the properties window and we want to be able to read the current value after sliding, let's add an event and some properties.
public event EventHandler ValueChanged;
private float _min = 0.0f;
public float Min
{
get => _min;
set {
_min = value;
RecalculateParameters();
}
}
private float _max = 1.0f;
public float Max
{
get => _max;
set {
_max = value;
RecalculateParameters();
}
}
private float _value = 0.3f;
public float Value
{
get => _value;
set {
_value = value;
ValueChanged?.Invoke(this, EventArgs.Empty);
RecalculateParameters();
}
}
This requires some fields and the RecalculateParameters method.
private float _radius;
private PointF _thumbPos;
private SizeF _barSize;
private PointF _barPos;
private void RecalculateParameters()
{
_radius = 0.5f * ClientSize.Height;
_barSize = new SizeF(ClientSize.Width - 2f * _radius, 0.5f * ClientSize.Height);
_barPos = new PointF(_radius, (ClientSize.Height - _barSize.Height) / 2);
_thumbPos = new PointF(
_barSize.Width / (Max - Min) * Value + _barPos.X,
_barPos.Y + 0.5f * _barSize.Height);
Invalidate();
}
Inside this derived control we override the event handlers (On... methods) instead of subscribing to the events:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillRectangle(Brushes.DimGray,
_barPos.X, _barPos.Y, _barSize.Width, _barSize.Height);
e.Graphics.FillRectangle(Brushes.Red,
_barPos.X, _barPos.Y, _thumbPos.X - _barPos.X, _barSize.Height);
e.Graphics.FillCircle(Brushes.White, _thumbPos.X, _thumbPos.Y, _radius);
e.Graphics.FillCircle(Brushes.Red, _thumbPos.X, _thumbPos.Y, 0.7f * _radius);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
RecalculateParameters();
}
Now let's compile this code and let's add a slider to a form. See how we can resize it in the designer.
Note also, that in the properties window we see the new Slider properties Max, Min and Value in the "Misc" section. We can change them here and the thumb position is automatically updated.
We still need the code to enable moving the slider. When we click on the thumb, we might have clicked a bit off its center. It feels natural to keep this offset while moving the mouse. Therefore, we store this difference in a variable _delta.
bool _moving = false;
SizeF _delta;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// Difference between tumb and mouse position.
_delta = new SizeF(e.Location.X - _thumbPos.X, e.Location.Y - _thumbPos.Y);
if (_delta.Width * _delta.Width + _delta.Height * _delta.Height <= _radius * _radius) {
// Clicking inside thumb.
_moving = true;
}
}
We also calculate the distance of the mouse position to the thumb position in OnMouseDown by using the Pythagorean theorem. Only if the mouse is inside the thumb, we initiate moving the thumb by setting _moving = true;
In OnMouseMove we calculate and set the new Value. This automatically triggers recalculating the parameters and redraws the slider.
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (_moving) {
float thumbX = e.Location.X - _delta.Width;
if (thumbX < _barPos.X) {
thumbX = _barPos.X;
} else if (thumbX > _barPos.X + _barSize.Width) {
thumbX = _barPos.X + _barSize.Width;
}
Value = (thumbX - _barPos.X) * (Max - Min) / _barSize.Width;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
_moving = false;
}
We can test the slider by adding a TextBox to the form and responding to the ValueChanged event. We can add an event handler by switching the properties window to "Events" by clicking on the flash symbol and then double click on ValueChanged in the "Misc" section.
private void Slider1_ValueChanged(object sender, EventArgs e)
{
textBox1.Text = slider1.Value.ToString();
}
Now, when we move the thumb, the text box displays the values.
Here again the whole code of the slider (using C# 10.0 file scoped namespaces):
using System.Drawing.Drawing2D;
namespace WinFormsSliderBar;
public class Slider : Control
{
private float _radius;
private PointF _thumbPos;
private SizeF _barSize;
private PointF _barPos;
public event EventHandler ValueChanged;
public Slider()
{
// This reduces flicker
DoubleBuffered = true;
}
private float _min = 0.0f;
public float Min
{
get => _min;
set {
_min = value;
RecalculateParameters();
}
}
private float _max = 1.0f;
public float Max
{
get => _max;
set {
_max = value;
RecalculateParameters();
}
}
private float _value = 0.3f;
public float Value
{
get => _value;
set {
_value = value;
ValueChanged?.Invoke(this, EventArgs.Empty);
RecalculateParameters();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillRectangle(Brushes.DimGray,
_barPos.X, _barPos.Y, _barSize.Width, _barSize.Height);
e.Graphics.FillRectangle(Brushes.Red,
_barPos.X, _barPos.Y, _thumbPos.X - _barPos.X, _barSize.Height);
e.Graphics.FillCircle(Brushes.White, _thumbPos.X, _thumbPos.Y, _radius);
e.Graphics.FillCircle(Brushes.Red, _thumbPos.X, _thumbPos.Y, 0.7f * _radius);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
RecalculateParameters();
}
private void RecalculateParameters()
{
_radius = 0.5f * ClientSize.Height;
_barSize = new SizeF(ClientSize.Width - 2f * _radius, 0.5f * ClientSize.Height);
_barPos = new PointF(_radius, (ClientSize.Height - _barSize.Height) / 2);
_thumbPos = new PointF(
_barSize.Width / (Max - Min) * Value + _barPos.X,
_barPos.Y + 0.5f * _barSize.Height);
Invalidate();
}
bool _moving = false;
SizeF _delta;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
// Difference between tumb and mouse position.
_delta = new SizeF(e.Location.X - _thumbPos.X, e.Location.Y - _thumbPos.Y);
if (_delta.Width * _delta.Width + _delta.Height * _delta.Height <= _radius * _radius) {
// Clicking inside thumb.
_moving = true;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (_moving) {
float thumbX = e.Location.X - _delta.Width;
if (thumbX < _barPos.X) {
thumbX = _barPos.X;
} else if (thumbX > _barPos.X + _barSize.Width) {
thumbX = _barPos.X + _barSize.Width;
}
Value = (thumbX - _barPos.X) * (Max - Min) / _barSize.Width;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
_moving = false;
}
}
and the graphic extensions for drawing circles:
namespace WinFormsSliderBar;
public static class GraphicsExtensions
{
public static void DrawCircle(this Graphics g, Pen pen,
float centerX, float centerY, float radius)
{
g.DrawEllipse(pen, centerX - radius, centerY - radius,
radius + radius, radius + radius);
}
public static void FillCircle(this Graphics g, Brush brush,
float centerX, float centerY, float radius)
{
g.FillEllipse(brush, centerX - radius, centerY - radius,
radius + radius, radius + radius);
}
}
using System.Drawing;
using System.Windows.Forms;
public partial class Form1 : Form
{
int vx = 5;
int vy = 5;
int bx = 0;
int by = 50;
int px = 93;
public Form1()
{
InitializeComponent();
timer1.Interval = 100;
timer1.Start();
}
public class Ball
{
public int X;
public int Y;
public int W;
public int H;
public Ball(int x, int y, int w, int h)
{
X = x;
Y = y;
W = w;
H = h;
}
}
public class Paddle
{
public int X;
public int Y;
public int W;
public int H;
public Paddle(int x, int y, int w, int h)
{
X = x;
Y = y;
W = w;
H = h;
}
}
public class Brick
{
public int X;
public int Y;
public int W;
public int H;
public Brick(int x, int y, int w, int h)
{
X = x;
Y = y;
W = w;
H = h;
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
int[] brickxs = { 0, 51, 102, 153, 204, 255, 306, 357, 408, 459, 510, 561, 612, 663, 714, 765 };
int bc = 0;
SolidBrush blueBrush = new SolidBrush(Color.Blue);
Ball b = new Ball(55, 55, 25, 25);
Paddle p = new Paddle(93, 377, 130, 30);
Brick br = new Brick(20, 20, 51, 20);
br.X = 0;
while (bc < 16)
{
br.X = brickxs[bc];
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(br.X, 0, 49, 20));
myBrush.Dispose();
formGraphics.Dispose();
bc = bc + 1;
}
Rectangle ball = new Rectangle(bx, by, b.W, b.H);
Rectangle paddle = new Rectangle(px, p.Y, p.W, p.H);
//Rectangle brick = new Rectangle(br.X, br.Y, br.W, br.H);
e.Graphics.FillEllipse(blueBrush, ball);
e.Graphics.FillRectangle(blueBrush, paddle);
//e.Graphics.FillRectangle(blueBrush, brick);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Right)
{
px += 5;
}
}
private void MoveTimer_Tick(object sender, EventArgs e)
{
Invalidate();
}
private void timer1_Tick(object sender, EventArgs e)
{
bx = bx + vx;
by = by + vy;
if (px <= 0)
{
px = 0;
}
if (px >= 771)
{
px = 771;
}
WallCollision();
floorandCeilingCollision();
Invalidate();
}
public void WallCollision()
{
if (bx >= 771)
{
vx = -5;
}
if (bx <= 0)
{
vx += 5;
}
}
public void floorandCeilingCollision()
{
if (by >= 420)
{
vy = -5;
}
if (by <= 0)
{
vy = 5;
}
}
}
I am creating a game and I need some help.
In my code have classes for each of the parts of the game: the ball, paddle and bricks. The array positions the bricks.
I want to move the paddle (which just a rectangle) left and right with the arrow keys. I tried to use the key down method but it did not work.
Could you suggest any solutions or point out anything that I left out?
Personally, I use e.KeyCode instead of e.KeyData, try this first.
Make sure your Form is focused, and not a picturebox or something else you might have in the game. Because you try to call the KeyDown event for your Form, not for a control inside your Form.
I never used a Paint event, are you sure it is called? It might be the case that your game registeres the movement but never shows the changes to you. I usually have a separate method for drawing and I call it every time there is a change, you should try this too.
If nothing works, try debugging. Set a break point in your KeyDown method to see if it is called. If it does, set it in the Paint method. This one will surely be called once, at runtime, but if you click "Continue" on that time and try to move your object. If it is not called any other time, then here is your answer :)
Please update me with what you find after trying this things, and ask me what to do next if you get stuck or simply don't know what else there is to do :)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm receiving no errors but when I'm running it I'm also unable to see the Mandelbrot it just displays the grey box, I'm currently stuck at this one point thanks for any help, if you see any other parts of my code which contains grammar or coding errors it would be much appreciated if you told me.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace SE_Fractal_Assignment
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public struct HSBColor
{
float h;
float s;
float b;
int a;
public HSBColor(float h, float s, float b)
{
this.a = 0xff;
this.h = Math.Min(Math.Max(h, 0), 255);
this.s = Math.Min(Math.Max(h, 0), 255);
this.b = Math.Min(Math.Max(h, 0), 255);
}
public float H
{
get { return h; }
}
public float S
{
get { return s; }
}
public float B
{
get { return b; }
}
public int A
{
get { return a; }
}
public Color Color
{
get
{
return FromHSB(this);
}
}
public static Color FromHSB(HSBColor hsbColor)
{
float r = hsbColor.b;
float g = hsbColor.b;
float b = hsbColor.b;
if (hsbColor.s != 0)
{
float max = hsbColor.b;
float dif = hsbColor.b * hsbColor.s / 255f;
float min = hsbColor.b - dif;
float h = hsbColor.h * 360f / 255f;
if (h < 60f)
{
r = max;
g = h * dif / 60f + min;
b = min;
}
else if (h < 120f)
{
r = -(h - 120f) * dif / 60f + min;
g = max;
b = min;
}
else if (h < 180f)
{
r = min;
g = max;
b = -(h - 120f) * dif / 60f + min;
}
else if (h < 240f)
{
r = min;
g = -(h - 240f) * dif / 60f + min;
b = max;
}
else if (h < 300f)
{
r = -(h - 240f) * dif / 60f + min;
g = min;
b = max;
}
else if (h <= 360f)
{
r = max;
g = min;
b = -(h - 360f) * dif / 60f + min;
}
else
{
r = 0;
g = 0;
b = 0;
}
}
return Color.FromArgb
(
hsbColor.a,
(int)Math.Round(Math.Min(Math.Max(r, 0), 255)),
(int)Math.Round(Math.Min(Math.Max(g, 0), 255)),
(int)Math.Round(Math.Min(Math.Max(b, 0), 255))
);
}
}
private const int MAX = 256; // max iterations
private const double SX = -2.025; // start value goal
private const double SY = -1.125; // start value imaginary
private const double EX = 0.6; // end value real
private const double EY = 1.125; // end value imaginary
private static int x1, y1, xs, ys, xe, ye;
private static double xstart, ystart, xende, yende, xzoom, yzoom;
private static bool action, rectangle, finished;
private static float xy;
//private Image picture1;
private System.Drawing.Bitmap bitmap;
private Graphics g1;
private Cursor c1, c2;
private HSBColor HSBcol = new HSBColor();
// private HSB HSBcol = new HSB();
private void Form1_Paint(object sender, PaintEventArgs e)
{
g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
g1.Dispose();
}
private void Form1_Load(object sender, EventArgs e)
{
init();
start();
}
public void init()
{
//HSBcol = new HSB();
finished = false;
c1 = Cursors.WaitCursor;
c2 = Cursors.Cross;
x1 = 640;
y1 = 480;
xy = (float)x1 / (float)y1;
bitmap.SetPixel(x1, y1, Color.Blue);
g1 = Graphics.FromImage(bitmap);
finished = true;
// xy = (float)x1 / (float)y1;
//picture = createImage(x1, y1);
//g1 = picture.getGraphics();
}
public void destroy() // delete all instances
{
if (finished)
{
//removeMouseListener(this);
//removeMouseMotionListener(this);
//bitmap = null;
g1 = null;
c1 = null;
c2 = null;
//System.gc(); // garbage collection
GC.Collect();
}
}
public void start()
{
action = false;
rectangle = false;
initvalues();
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
mandelbrot();
}
public void stop()
{
}
public void paint(Graphics g)
{
update(g);
}
public void update(Graphics g)
{
/* Pen myPen = new Pen(Color.White);
g.DrawImage(bitmap, 0, 0);
if (rectangle)
{
if (xs < xe)
{
if (ys < ye)
{
g.DrawRectangle(myPen, xs, ys, (xe - xs), (ye - ys));
}
}
else
{
g.DrawRectangle(myPen, xs, ys, (xe - xs), (ye - ys));
}
myPen.Dispose();
}*/
}
private void mandelbrot() // calculate all points
{
int x, y;
float h, b, alt = 0.0f;
action = false;
for (x = 0; x < x1; x += 2)
for (y = 0; y < y1; y++)
{
h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y);
// color value
if (h != alt)
{
b = 1.0f - h * h; // brightnes
///djm added
///HSBcol.fromHSB(h,0.8f,b);
///
//convert hsb to rgb then make a Java Color
Color color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255));
///g1.setColor(col);
//djm end
//djm added to convert to RGB from HSB
//g1.setColor(Color.getHSBColor(h, 0.8f, b));
//djm test
// Color col = Color.FromArgb(0, 0, 0, 0);
//red = Color.Red;
// green = Color.Green;
// blue = Color.Blue;
//djm
alt = h;
}
Pen pen = new Pen(Color.Aqua);
g1.DrawLine(pen, x, y, x + 1, y);
}
//showStatus("Mandelbrot-Set ready - please select zoom area with pressed mouse.");
//setCursor(c2);
action = true;
}
private float pointcolour(double xwert, double ywert)
// color value from 0.0 to 1.0 by iterations
{
double r = 0.0, i = 0.0, m = 0.0;
int j = 0;
while ((j < MAX) && (m < 4.0))
{
j++;
m = r * r - i * i;
i = 2.0 * r * i + ywert;
r = m + xwert;
}
return (float)j / (float)MAX;
}
private void initvalues() // reset start values
{
xstart = SX;
ystart = SY;
xende = EX;
yende = EY;
if ((float)((xende - xstart) / (yende - ystart)) != xy)
xstart = xende - (yende - ystart) * (double)xy;
}
private void Form1_paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g1 = g;
action = false;
rectangle = false;
initvalues();
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
//picture = g.DrawImage;
//g.DrawImage(picture,0,0);
update(g);
mandelbrot();
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (action)
{
xs = e.X;
ys = e.Y;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
// e.consume();
if (action)
{
xe = e.X;
ye = e.Y;
rectangle = true;
//repaint();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
rectangle = false;
}
private void Form1_Click(object sender, MouseEventArgs e)
{
}
public String getAppletInfo()
{
return "fractal.class - Mandelbrot Set a Java Applet by Eckhard Roessel 2000-2001";
}
}
}
Honestly, the code is so cluttered and disorganized, it's hard to know all of what might be wrong with it. Sorry to be so blunt.
That said, a couple of obvious problems I see involving your "g1" Graphics instance member.
First, you are using the same field for two purposes: when computing the original image, you expect this to be a Graphics instance you can use to draw into your bitmap. But in the Paint event, you set it to the Graphics instance for the window, into which the painting should be done.
Second, in that Paint event, you dispose the Graphics instance before you return. But the instance you're disposing isn't yours. It belongs to the Forms system, and the only thing you should be doing with it is drawing into it.
There actually appear to be two different Paint event handlers and it's not clear which one you're using. You only dispose the Graphics instance in one of those places, so that may or may not be the real problem.
Personally, I would break the problem down into different elements. For a relative novice, it can be hard enough just to correctly draw a bitmap. It can also be difficult to really grasp how Paint event handling should be done. And of course, there's the Mandelbrot computations themselves. Trying to implement all three things (and more) at the same time can be overwhelming, and will take a lot longer assuming you can figure it out at all.
I would start by writing a simple program that just has a single PictureBox, which when you click a button, your program creates a new Bitmap object, into which you draw something simple (say, a rectangle, circle, or maybe just some text) and then assigns that Bitmap object to the PictureBox.Image property.
Once you have that working, then you can change the drawing part of the code to draw a Mandelbrot image instead.
Finally, once you have that working, then you can work on using the Paint event to draw the bitmap into your window directly instead of using the PictureBox control (the main reason for wanting to do this would presumably be that you eventually want to update the image as it's being drawn...if you only want to show it at the very end, then IMHO the PictureBox is a better approach).
I need to implement a simple animation of a ball moving in uniform circular motion. I've tried several formulas and the following version seems the best so far.However, there are still 2 issues and I really can't figure out what's wrong.
First, a couple of seconds right after the program starts, the ball moves erratically. I think that the values for theta (the angle in radians) are not computed correctly, but I don't know why.
Secondly, the movement becomes more uniform after a while, but it seems to decrease over time.
The value for 'speed' indicates the number of seconds it takes to do a full revolution.
What I want is an uniform, correct circular movement (according to the value of speed) and without the jerkiness in the beginning.
My code so far:
public partial class ServerForm : Form
{
Stopwatch watch;
//Angular velocity
float angularVelocity;
//Angle
float theta = 20;
//Speed - time to complete a full revolution, in seconds
private float speed = 3;
//Circle center
private int centerX = 250;
private int centerY = 200;
//Circle radius
private float R = 120;
//Current position
private LocationData currentLocation;
public ServerForm()
{
InitializeComponent();
}
public void UpdateUI()
{
currentLocation.CoordX = (float)(centerX + Math.Cos(theta) * R);
currentLocation.CoordY = (float)(centerY + Math.Sin(theta) * R);
currentLocation.Speed = speed;
try
{
this.Invoke(new Action(() => { this.Invalidate(); }));
}
catch (Exception ex)
{
watch.Stop();
Application.Exit();
}
theta += (float)((angularVelocity * 1000 / watch.ElapsedMilliseconds));
//Console.Out.WriteLine("elapsed miliseconds: " + watch.ElapsedMilliseconds + " theta = " + theta);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Brush color = new SolidBrush(Color.BlueViolet);
g.FillEllipse(color, currentLocation.CoordX, currentLocation.CoordY, 30, 30);
//Draw circle & center
g.DrawEllipse(new Pen(color), centerX, centerY, 5, 5);
float x = centerX - R;
float y = centerY - R;
float width = 2 * R;
float height = 2 * R;
g.DrawEllipse(new Pen(color), x, y, width, height);
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(textSpeed.Text))
{
ResetValues(float.Parse(textSpeed.Text));
}
}
private void ResetValues(float newSpeed)
{
speed = newSpeed;
angularVelocity = (float)(2 * Math.PI / speed); // radians / sec
//Start at the top
currentLocation.CoordX = centerX;
currentLocation.CoordY = centerY - R;
theta = 90;
watch.Restart();
}
private void ServerForm_Load(object sender, EventArgs e)
{
watch = new Stopwatch();
timer1.Enabled = true;
timer1.Interval = 100;
timer1.Tick += timer1_Tick;
currentLocation = new LocationData();
ResetValues(speed);
}
void timer1_Tick(object sender, EventArgs e)
{
UpdateUI();
}
}
LocationData is just a class holding the coordinates & current speed.
Are the units for time & angular velocity (and the transformations to use miliseconds) correct?
I changed BackgroundWorker to Timer, but I still get that erratic motion and the movement slows down after a while.
Try using a System.Windows.Forms.Timer instead of a BackgroundWorker. I believe you'll get more consistent results. This is definitely not a good case for using a BackgroundWorker.
Here's a more-or-less complete solution. Note that I'm scaling the swing radius and the ball radius by the size of the Form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
}
private void Form1_Load(object sender, System.EventArgs e)
{
_stopwatch.Start();
}
private void Timer1_Tick(object sender, System.EventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(BackColor);
const float rotationTime = 2000f;
var elapsedTime = (float) _stopwatch.ElapsedMilliseconds;
var swingRadius = Math.Min(ClientSize.Width, ClientSize.Height) / 4f;
var theta = Math.PI * 2f * elapsedTime / rotationTime;
var ballRadius = Math.Min(ClientSize.Width, ClientSize.Height) / 10f;
var ballCenterX = (float) ((ClientSize.Width / 2f) + (swingRadius * Math.Cos(theta)));
var ballCenterY = (float) ((ClientSize.Height / 2f) + (swingRadius * Math.Sin(theta)));
var ballLeft = ballCenterX - ballRadius;
var ballTop = ballCenterY - ballRadius;
var ballWidth = ballRadius * 2f;
var ballHeight = ballRadius * 2f;
e.Graphics.FillEllipse(Brushes.Red, ballLeft, ballTop, ballWidth, ballHeight);
e.Graphics.DrawEllipse(Pens.Black, ballLeft, ballTop, ballWidth, ballHeight);
}
private readonly Stopwatch _stopwatch = new Stopwatch();
}