First time doing this. I am currently building a bot using C# and want my bot to be able to move the mouse to a given point in a way that looks human. By this I am referring to the dragging of the mouse when a human moves the cursor to a point they are trying to click on. Currently my C# bot moves the mouse instantly to the location which doesn't look human.
private static Point[] FindColor(Color color)
{
int searchValue = color.ToArgb();
List<Point> result = new List<Point>();
using (Bitmap bmp = GetScreenShot())
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
if (searchValue.Equals(bmp.GetPixel(x, y).ToArgb()))
result.Add(new Point(x, y));
}
}
}
return result.ToArray();
}
// FUNCTIONS OCCUR BELOW
// Error message if program could not find bitmap within screenshot show error message
Color myRgbColor = new Color(); // Creates new colour called myRgbColor
myRgbColor = Color.FromArgb(51, 90, 9); // This colour equals the RGB value
Point[] points = FindColor(myRgbColor); // Create an array called points which list all the points found in the screen where the RgB value matches.
if (points.Length > 0)
{
Cursor.Position = points[2]; // Move mouse cursor to first point (Point 0)
Thread.Sleep(0200);
MouseClick();
}
if (points.Length == 0)
{
MessageBox.Show("No matches!"); // Return error
goto checkore;
}
You're going to want to use some kind of Timer with a callback, to move the mouse incrementally, step by step. As for the movement itself, you have a world of possibilities, but it's all maths.
So, let's decompose the problem.
What is a natural mouse movement?
Position change rate
It doesn't necessarilly looks like it, but when you move your mouse, you're simply setting its position multiple times per seconds.
The amount of times the position changes per second is equivalent to the polling rate of your mouse. The default polling rate for USB mice is 125Hz (or 125 position changes per second, if you will). This is the value we'll use for our Timer: its callback will be called 125 times per second.
var timer = new Timer(1000 / 125d);
timer.Elapsed += MoveMouse;
void MoveMouse(object sender, ElpasedEventArgs e) { }
Speed and acceleration
When you move your mouse, the distance between two cursor positions is not constant, because you're fast when you start moving your mouse, but you slow down when you get close to the item you want your cursor to be on.
There are also two ways I personally usually move my mouse depending on the context/mood:
One fast uniform movement to get close to the destination, then one slow to correct and get on it (I'll usually go past the destination during the first move)
One medium-slow movement with a small deceleration, follow by a stronger deceleration at the end
The overall speed of the movement also depends on three factors:
The distance between your cursor and the destination
The size of the destination area
Your personal speed
I have absolutely NO IDEA how to work out the formula based on these factors, that's gonna be a work of trial and error for yourself.
This one is purely math and observation based, and will be tricky to get perfectly right, if ever; every person moves their mouse a different way.
The solution I can offer you is to simply forget about deceleration, correction and so on, and just divide your movement into equal steps. That has the merit of being simple.
using System;
using System.Timers;
using System.Drawing;
public class Program
{
static int stepCount = 0;
static int numberOfSteps = 0;
static float stepDistanceX = 0;
static float stepDistanceY = 0;
static PointF destinationPoint;
static Timer timer;
public static void Main()
{
int timerStepDurationMs = 1000 / 125;
PointF currentPoint = Cursor.Position;
destinationPoint = new PointF(2000, 1800); // or however you select your point
int movementDurationMs = new Random().Next(900, 1100); // roughly 1 second
int numberOfSteps = movementDurationMs / timerStepDurationMs;
stepDistanceX = (destinationPoint.X - currentPoint.X) / (float)numberOfSteps;
stepDistanceY = (destinationPoint.Y - currentPoint.Y) / (float)numberOfSteps;
timer = new Timer(timerStepDurationMs);
timer.Elapsed += MoveMouse;
timer.Start();
while (stepCount != numberOfSteps) { }
}
static void MoveMouse(object sender, ElapsedEventArgs e)
{
stepCount++;
if (stepCount == numberOfSteps)
{
Cursor.Position = destinationPoint;
timer.Stop();
}
Cursor.Position.X += stepDistanceX;
Cursor.Position.Y += stepDistanceY;
}
}
Note that I haven't tested with "Cursor", but with some PointF variable instead. It seems to work fine here: dotnetfiddle.
Related
I'm trying to plot the function y = x ^ 2 at a certain interval using the Graphics, but I can't. When I write start + = 1/10 (to increase the number of points) knocks out the error that the index went beyond the array, and in this case what it is now, the graph does not look as it should. Maybe someone can help me build this chart using Graphics.
P.S: yes I know I can use Chart, but the task is to do it through Graphics.
using System.Drawing;
using System.Windows.Forms;
namespace FormsForProgrammin
{
public partial class Form15 : Form
{
PointF[] p = new PointF[10];
int count = 0;
public Form15()
{
InitializeComponent();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form15_Paint);
Calc();
}
private void Calc()
{
float start = float.Parse(textBox1.Text);
while(start<= float.Parse(textBox2.Text))
{
float res = start * start;
p[count] = new PointF(start, res);
count += 1;
start += 1;
}
}
private void Form15_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.TranslateTransform(150, 150);
e.Graphics.ScaleTransform(1, 0.25F);
e.Graphics.DrawLines(Pens.Blue, p);
}
}
}
you have an array of 10 points, and you are indexing them with the count variable. you have a couple of problems in that code:
you never reset count
you set start to the textBox1 value, and increment it by 1 untill it is over the textBox2 value. but this gap may be bigger than the number of points you have in the array
to solve for 1 you can either reset count once the loop is done, or simply define count in the Calc method itself (the latter would be the better option, since count is only relevant to the Calc method)
to solve for 2 you would need to calculate a step amount: the difference between values divided by the number of points,
use this step amount to make sure that the loop doesn't run more times than the numbers of points you have
I am doing a project about a chess-like game, so players own their pawns on the map. Every time player decides to move a pawn, he needs to get a number from a dice, then that pawn would move according to the rolled number. Move function of pawns is finished, but I didn't show the moving process for them.
I have one panel for map and four panels for starting base(holding the pawns at the beginning of the game).
GUI for gameboard
In paint event, I ask the system to draw everything.
private void P_Map_Paint(object sender, PaintEventArgs e)
{
manager.VisualizeCollection(map, gr_map);
manager.VisualizeStartingBase(bases, grs);
manager.VisualizePawns(manager.Players, grs, gr_map);
manager.DisplayAvailablePawn(gr_map, grs);
manager.DisplaySelectedPawn(gr_map, grs);
}
For every move of a pawn, I am trying to use a timer to make the image moving on the screen.
public void DoMovement(Pawn pawn)
{
if (TargetSpot != null)
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
EventHandler t_tick = null;
Point targetP = TargetSpot.Location;
Point currentP = pawn.ImageLocation;
int XMove = (targetP.X - currentP.X) / 10;
int YMove = (targetP.Y - currentP.Y) / 10;
Rectangle drawRange = new Rectangle(pawn.ImageLocation.X - (int)(0.5 * pawn.Image.Width),
pawn.ImageLocation.Y - (int)(0.5 * pawn.Image.Height), pawn.Image.Width, pawn.Image.Height);
t_tick = (senders, args) =>
{
if (currentP.X > targetP.X - XMove || currentP.X < targetP.X + XMove)
{// if the image of the pawn doesn't reach the destination
//we keep moving it and ask the pawn to redraw the old place
pawn.ImageLocation = new Point(currentP.X + XMove, currentP.Y + YMove);
pawn.CurrentPanel.Invalidate(drawRange);
}
else
{
pawn.CurrentLocation.LeaveAPawn(pawn);
pawn.CurrentLocation = TargetSpot;
TargetSpot.AddAPawn(pawn);
pawn.CurrentPanel.Invalidate(drawRange);
}
};
t.Tick += t_tick;
t.Interval = 300;
t.Start();
}
}
This is not working fine, everything on the panel is still redrawing. Why?
Excepting the project, I do have a question about the invalidating a region. Like I told the rules of drawing to paint event, then the panel invalidates itself. When we are going to invalidate a region, how the system knows the rule about drawing?
I am having problems getting this function to work properly. I have to create a winform app that acts as a taxi mapper. On load the taxis are placed in the same location based on a text file. When a user clicks on the form the nearest taxi is supposed to move to the "user" or location, then stop.
Everything is working fine except that the closest taxi does not always go to the location. A taxi further away will go to the location instead. It seems to work some of the time, but not all the time. I am not sure if my logic is correct in the Form1_MouseDown function
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (pickUp) //Are we picking up a passenger?
{
//Convert mouse pointer location to local window locations
int mLocalX = this.PointToClient(Cursor.Position).X;
int mLocalY = this.PointToClient(Cursor.Position).Y;
//set the minimum value (for range finding)
int min = int.MaxValue;
//Temporary object to get the handle for the taxi object we want to manipulate
taxiCabTmp = new TaxiClass();
//Iterate through each object to determine who is the closest
foreach (TaxiClass taxiCab in taxi)
{
if (Math.Abs(Math.Abs(taxiCab.CabLocationX - mLocalX) + Math.Abs(taxiCab.CabLocationY - mLocalY)) <= min)
{
min = Math.Abs(Math.Abs(taxiCab.CabLocationX - mLocalX) + Math.Abs(taxiCab.CabLocationY - mLocalY));
//We found a minimum, grab a handle to the object's instance
taxiCab.GetReference(ref taxiCabTmp);
}
}
//Call the propogate method so it can spin off a thread to slowly change it's location for the timer to also change
taxiCabTmp.Propogate(mLocalX - 20, mLocalY - 20);
taxiCabTmp.occupied = true; //This taxi object is occupied
pickUp = false; //We are not picking up a passenger at the moment
}
else //We are dropping off a passenger
{
taxiCabTmp.Propogate(this.PointToClient(Cursor.Position).X, this.PointToClient(Cursor.Position).Y);
taxiCabTmp.occupied = false;
pickUp = true; //We can pick up a passenger again!
}
}
You are correct that the calculation you use for determining distance will not always be correct. Objects at an angle will calculate to be further away than they really are.
Have a look at this link for more information: http://www.purplemath.com/modules/distform.htm
Here's an example:
int mLocalX = 1;
int mLocalY = 1;
int taxiCab.CabLocationX = 2;
int taxiCab.CabLocationY = 2;
double distance = Math.Sqrt(Math.Pow((taxiCab.CabLocationX - mLocalX), 2) + Math.Pow((taxiCab.CabLocationY - mLocalY), 2));
Just as a side note, you shouldn't append your classes with Class, i.e TaxiClass, it should simply be called Taxi.
Use this formula to calculate distance between two coordinates.
var distance = Math.Sqrt(Math.Pow(taxiCab.CabLocationX - mLocalX, 2) + Math.Pow(taxiCab.CabLocationY - mLocalY, 2));
if (distance <= min) {
min = distance;
//We found a minimum, grab a handle to the object's instance
taxiCab.GetReference(ref taxiCabTmp);
}
I'm building my very first game with XNA and i'm trying to get my sprite to run.
Everything is working fine for the first sprite.
E.g : if I go right(D) my sprite is looking right , if I go left(A) my sprite is looking left and if I don't touch anything my sprite is the default one.
Now what I want to do is if the sprite goes Right, i want to alternatively change sprites (left leg, right leg, left leg etc..) xCurrent is the current sprite drawn xRunRight is the first running Sprite and xRunRight1 is the one that have to exchange with xRunRight while running right.
This is what I have now :
protected override void Update(GameTime gameTime)
{
float timer = 0f;
float interval = 50f;
bool frame1 = false ;
bool frame2 = false;
bool running = false;
KeyboardState FaKeyboard = Keyboard.GetState();
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if ((FaKeyboard.IsKeyUp(Keys.A)) || (FaKeyboard.IsKeyUp(Keys.D)))
{
xCurrent = xDefault;
}
if (FaKeyboard.IsKeyDown(Keys.D))
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
if (timer > interval)
{
if (frame1)
{
xCurrent = xRunRight;
frame1 = false;
}
else
{
xCurrent = xRunRight1;
frame1 = true;
}
}
xPosition += xDeplacement;
}
Any ideas...? I've been stuck on this for a while..
Thanks in advance and let me know if you need any other part from the code.
You forgot to reset the timer, you could do this when you hit the timer interval condition. Also, 50ms seems a bit too small for an interval, maybe you could do like 400ms?
Other than that, looks good, it will do what you want.
Alternatively, you could look into making animated sprites for walking. What you do is make an image with the walking animation sprites one next to the other, of the same size. You draw only a portion of this image (one sprite) and move through them based on time.
Here is a quick code for what could be an animated texture:
class AnimatedTexture2D : Texture2D
{
int _numberOfImages;
int _currentImage = 0;
int _timeInterval;
int _spriteWidth;
public Rectangle DrawFromRectangle
{
get
{
return new Rectangle(_currentImage * _spriteWidth, 0, _spriteWidth, this.Height);
}
}
public AnimatedTexture2D(Texture2D entireImage, int spriteWidth, int numberOfImages, int timeInterval)
: base(entireImage.GraphicsDevice, entireImage.Width, entireImage.Height)
{
_numberOfImages = numberOfImages;
_timeInterval = timeInterval;
_spriteWidth = spriteWidth;
Color[] data = new Color[entireImage.Width * entireImage.Height];
entireImage.GetData<Color>(0, new Rectangle(0, 0, entireImage.Width, entireImage.Height), data, 0, entireImage.Width * entireImage.Height);
this.SetData<Color>(data);
}
public void Animate(GameTime gameTime)
{
int totalImageTime = _timeInterval * _numberOfImages;
int currentPoint = (int)gameTime.TotalGameTime.TotalMilliseconds % totalImageTime;
_currentImage = currentPoint / _timeInterval;
}
}
Usage is fairly simple:
1) declare it somewhere:
AnimatedTexture2D animatedTexture;
2) initiate it with your texture (i had a 2560x64 sequence of 40 64*64 images), where individual images are placed next to each other horizontally:
animatedTexture = new AnimatedTexture2D(Content.Load<Texture2D>(#"Textures\Loading"), 64, 40, 20);
3) in your Update() method, call:
animatedTexture.Animate(gameTime);
4) in your Draw() method, call:
SpriteBatch.Draw(animatedTexture, new Rectangle(20, 20, 64, 64), animatedTexture.DrawFromRectangle, Color.White);
Don't forget the DrawFromRectangle in part 4! (notice that the destination rectangle uses the declared individual part width, not the entire texture width which is in my test 2560 pixels)
Now, in your code you could forget the interval part, and the gametime part, and you could just use this instead of the default one!
Also, if you don't like my timing code (its ultra simple but lacks a way to reset the animation) change it so you have an elapsed time variable, and add to it like you do in your own code, and use that to change _currentImage. You could even make that variable public so you can use it to reset the animation (or set it to a specified point).
Of course, you could also make the default one an animated texture with only one frame so you can use the same code everywhere. Hope this helps!
You need to keep the last time Update(..) was called, and the interval should be... well.. an interval, that is, the difference between ElapsedGameTime and last call to update ElapsedGameTime.
Do it with a new member of your class (LastElapsedGameTimeUpdateCalled) or a static member of your sub.
If you know that every animation is going to have the same number of frames you could keep 3 variables per sprite (encapsulate in class for best results).
BaseFrame is an integer to hold a global animation number.
SubFrame is an offset in to the animation that holds which frame you are currently on.
FrameAccumulator to hold timing information.
Each time update is called, add the number of ms since the last update to the accumulator. Once the accumulator goes above your animation timing, increment SubFrame, and reset the accumulator. Check to see if subFrame is greater than the number of frames for each animation, and if it is, set it back to 0. You can get the real frame index from this by adding BaseFrame + Subframe. When you need to display a different animation just change the BaseFrame.
Lets say that each animation has 3 frames, and you have 2 total animations. You would have 6 total frames. RunLeft would be BaseFrame 0, and RunRight would be BaseFrame 3. That should easily give you the frame number to draw.
I'm sorry if question title was unclear, but with my cheap english, I cant find a way to ask it clearly.
But I can explain it in long way.
So I have realized if I design my world(and with world, I mean ENTIRE game, it will be one level) 10.000x10.000... it will be very enough, other than few another sprite(and I mean like 4 or 5 with maximum of 50x50, nothing big.)
So I thought, why dont I make my entire map as 10.000x10.000(or lets say tons of 512x512) picture ?
But I have one question, there is few things you can "interact". they will(with they, I mean the stuff that is in my "world.jpg") be always stay at same place, but player(which is actually a sprite as you know) will move, therefore my 10.000x10.000 will "move".
So look at picture below, there is black dot which is "player" and red dot, which is lets say, a door.
and world is always centered to black dot unless he goes to end of the world. as you can see, (look at picture part 1 and part 2) when he moves a little bit to east, red dot looks moved. but I just moved my 10.000x10.000 image. Thats what I meant with the stuff on 10kx10k pic will move.
Anyway, but as you can see in last part of pic, when he goes near red dot, I want to my "action"
How to do it ?
-part below is not really related to main question
Is it useful to use 10kx10 pic instead of another sprites appearing on world when he moves ? but If I want to do that, not just I will check if he is nearby, but I will also check his point to realize if I should or shouldnt show him sprite.
Will it be more useful if I show my stuff when he comes to coordinates I want, or is using one big picture is OK ?
Thanks.
I would suggest a structure of the map somewhat like this..
public class Map
{
public MapPoint[,] mapPoints; //the map
public Player player; //the player/user object
public Vector2 DrawHeroPosition;
//where at the screen the player is going to be drawn
public Vector2 RangeStart;
//what part of the map who is going to be drawn
public int SizeX; //number of mapPoints the screen can contain at one time
public int SizeY; //number of mapPoints the screen can contain at one time
//MapPoint represents a specific 512x512 point (mapPoint) its position at
//the map but also includes the sprite that is going to be drawn and objects
//that the player can interact with at that place (like the door)
//the player object includes reference to where in the world it is place
public Map(ContentManager theContentManager, int x, int y)
{
MapSizeX = x;
MapSizeY = y;
int ScreenSizeX = 9;
int ScreenSizeY = 9;
mapPoints = new MapPoint[MapSizeX , MapSizeY];
//ad code for generating/creating map...
//important that you store the MapPoints position inside each mapPoint
player = new Player(mapPoints[0,0]); //crate a player who knows where he is
}
public void Update()
{
//in the update method you do a lot of things like movement and so
//set what part of the map the game should draw if the game for example
//can show 9x9 512points at a single time
//give range value from the players position
RangeStart.X = player.PositionX;
//test if the maps position is in the left corner of the map
//if it is draw the map from the start..(RangeStart.X = 0)
if (player.PositionX - (ScreenSizeX / 2) < 0) { RangeStart.X = 0; }
//if not draw the hero in the mitle of the screen
else
{
RangeStart.X = player.PositionX - (ScreenSizeX / 2);
}
//if the hero is in the right corer, fix his position
while (RangeStart.X + ScreenSizeX > MapSizeX)
{
RangeStart.X--;
}
//the same thing for the Y axle
RangeStart.Y = player.PositionY;
if (player.PositionY - (ScreenSizeY / 2) < 0) { RangeStart.Y = 0; }
else
{
RangeStart.Y = player.PositionY - (ScreenSizeY / 2);
}
while (RangeStart.Y + ScreenSizeY > MapSizeY)
{
RangeStart.Y--;
}
//time to set the position of the hero...
//he works like the opposite of the range, if you move what part of the map
//you draw you dont change the heros draw position, if you dont move the range
//you have to move the hero to create the illusion of "moment"
//if you are in the left part you have to move the heros draw position..
if (player.PositionX - (ScreenSizeX / 2) < 0)
{ DrawHeroPosition.X = player.PositionX; }
//if you are in the right part
else if (player.PositionX+1 > MapSizeX - (ScreenSizeX / 2))
{
DrawHeroPosition.X = player.PositionX - (MapSizeX - ScreenSizeX);
}
//if you aint in a corner, just place the hero in the middle of the map
else
{
DrawHeroPosition.X = (ScreenSizeX / 2);
}
//the same thing for Y
if (player.PositionY - (ScreenSizeY / 2) < 0)
{ DrawHeroPosition.Y = player.PositionY; }
else if (player.PositionY+1 > MapSizeY - (ScreenSizeY / 2))
{
DrawHeroPosition.Y = player.PositionY - (MapSizeY - ScreenSizeY);
}
else
{
DrawHeroPosition.Y = (ScreenSizeY / 2);
}
}
public void Draw()
{
int x = (int)RangeStart.X;
int y = (int)RangeStart.Y;
for(int counterX = 0; x < ((MapSizeX)); x++, counterX++)
{
for (int counterY = 0; y < (MapSizeY); y++, counterY++)
{
if (mapPoints[x, y] != null)
{
mapPoints[x, y].Draw(spriteBatch, mapPoints[counterX,counterY].positonInMatrix);
//mapPoints[counterX,counterY] = where to draw
//mapPoints[x, y] = what to draw
}
}
y = (int)RangeStart.Y;
}
}
}
how i draw inside the MapPoint Class...
public void Draw(SpriteBatch theSpriteBatch, Vector2 positonOnScreen)
{
positonOnScreen = new Vector2(positonOnScreen.X * base.Scale * 16,
positonOnScreen.Y * base.Scale * 16);
//base.Scale is just a variable for have the ability to zoom in/out
//16 represents the original size of the picture (16x16 pixels)
theSpriteBatch.Draw(mSpriteTexture, new Rectangle((int)positonOnScreen.X,
(int)(positonOnScreen.Y), 64, 64),new Rectangle(0, 0, 16, 16), Color.White);
}
If you are asking for collision detection within a radius of your red dot. You can simply use the following test (pseudocode, I don't write C# :-)
if( (player.GetPosition() - point.GetPosition()).length() < radius )
{ /* Do code here */ }
This will detect if your player is within a certain radius of your dot, you can then perform whatever action you wish.
Hope this helps! :)
Ok, from what I understand of your question, you have a large image which contains different objects you want your player to interact with, yes? By which I mean, the image file itself has doors or hills or other things which the player would interact with.
This is a bad idea, honestly, so I hope I misunderstood. It is far better to have your background image just be something generic and make all interactive objects classes within your game. If you do this, then you can have your object classes contain behavior to intersect with each other either based on their distance (circle collision) or based on a bounding box you define for them.
Circle Collision:
if (Math.Abs(Vector2.Distance(player.Position - obj.Position)) < player.Radius + obj.Radius)
//do the action
Rectangle Collision:
if (player.Bounds.Intersects(obj.Bounds))
//do the action
Also, if you are planning on making a 10,000 x 10,000 pixel image, understand that the XNA Content Pipeline will not import an image greater than 4,000 pixels to a side.
If you are set on having the player interact with pixels in the background of the image, you can either make an array of interactive object locations manually or you can use the Texture2D.GetData() method to load in the colors of every single pixel in the image for processing-- but be aware that this will take a long time, especially for large or numerous textures.