im trying to make character move in VS without picture boxes, i seem to be getting close but when i tried to put in the key presses there is a red line under the key of key.keycodes and a red line under my public enum direction and i dont know why. here is my code, it isnt fully complete but you will probably get the idea. so what im asking in a nutshell is why cant i put in keycodes and why is my enum directional code underlined.
public enum Direction { Up, Right, Down, Left }
public class Cat
{
public Direction currentDirection = Direction.Up;
public PictureBox CatImage = new PictureBox();
public int mouseSize = 25;
public int maxScreenX;
public int maxScreenY;
private ImageList CatImages = new ImageList();
public Cat(Form formInstance)
{
maxScreenX = formInstance.Width - 50;
maxScreenY = formInstance.Height - 80;
// start with mouse in the centre of the screen
CatImage.Location = new System.Drawing.Point(maxScreenX / 2, maxScreenY / 2);
// we'll add the mouse images
CatImages.Images.Add(Properties.Resources.catUp);
CatImages.Images.Add(Properties.Resources.catRight);
CatImages.Images.Add(Properties.Resources.catDown);
CatImages.Images.Add(Properties.Resources.catLeft);
formInstance.Controls.Add(CatImage);
CatImage.BringToFront();
}
public void MoveMouse()
{
if (!canMove)
{
}
// Change the mouse image to match the new direction
CatImage.Image = CatImages.Images[(int)currentDirection];
if (canMove)
{
if (key.KeyCode == Keys.W)
{
CatImage.Top -= 5;
}
if (key.KeyCode == Keys.S)
{
CatImage.Top += 5;
}
if (key.KeyCode == Keys.A)
{
CatImage.Left -= 5;
}
if (key.KeyCode == Keys.D)
{
CatImage.Left += 5;
}
}
}
}
Related
I'm working on a tile game, but I ran into a big problem.
The idea is that if a tile is selected it turns red and a few tiles surounded turn blue. if you click one of the blue ones the unit of the slected one is transported to that one , but every time a do this my selected tile has a NullException . I can use the Tile itself, but non of the values or voids it contains which always return null. I'd be very thankfull if someone could pinpoint the problem
Code in order of likelyhood of problem
Part of Update():
while (j < baseLayer.MapDimensions.Y)
{
while (i < baseLayer.MapDimensions.X)
{
if (moveToMap[i, j] && standardCheck.Click(new Rectangle(i * 100, j * 100, 100, 100), mouseState, prevMouseState))
{
tileArray[i, j].changeColor = Color.Gold;
tileArray[i, j].MoveTo(tileArray[(int)selectedTile.X, (int)selectedTile.Y].Position,
tileArray[(int)selectedTile.X, (int)selectedTile.Y].getUnit);// problem occors here
//problem occurres here
}
else
{
tileArray[i, j].Checkclick(mouseState, prevMouseState, relativeMousePosition);
if (tileArray[i, j].ReturnIfSelected)
{
selectedTile = new Vector2(i, j);
}
else if (selectedTile == new Vector2(i, j))
selectedTile = new Vector2(200, 200);
}
i++;
}
i = 0;
j++;
}
j = 0;
Tile class
public Unit unit = new Unit();
public Unit Building = new Unit();
public Unit getUnit
{
get { return unit; }
}
public Color tileColor = Color.White;
public Vector2 position;
public Vector2 drawPosition;
public int[] map { set; get; } = new int[4];
public bool selected = false;
public void LoadContent(Vector2 _position ,int[,,] _map)
{
}
public void Checkclick(MouseState mS, MouseState prevMS,Vector2 matrixPosition)
{
}
}
public bool checkifselectable()
{
}
public void Update(int[,,] _map)
{
unit.Reset();
}
public void MoveTo(Vector2 oldTile,Unit _unit)
{
int change = 0;
if (oldTile.X - position.X != 0)
change = (int)(oldTile.X - position.X);
if (oldTile.Y - position.Y !=0)
change = (int)(oldTile.Y - position.Y);
unit = _unit;
map[2] = _unit.ID;
if (change>= 0)
unit.RemainingMoveSpeed = change;
if (change < 0)
unit.RemainingMoveSpeed = -change;
}
Thanks already for your time
The Young Programmer
Maybe you have NullReferenceException. In this case, this exception is thrown when there is an attempt to dereference a null object reference. This might help you https://msdn.microsoft.com/en-us/library/system.nullreferenceexception%28v=vs.110%29.aspx.
For a school project I need to make a small game where multiple Ellipses move.
The last one that gets made with my method to make multiple at the same time moves with the timer I make.
How do you make one timer for all the Ellipses.
class EnemyTeam
{
private Ellipse enemy;
private Canvas canvas;
private double xChange = 50, yChange = 50;
public DispatcherTimer enemyTimer;
private char direction = '0';
private Thickness enemyThickness;
public EnemyTeam(Canvas canvas, double startPosition, SolidColorBrush playerBrush)
{
this.canvas = canvas;
DrawTeam(canvas, 40, playerBrush);
enemyTimer.Interval = TimeSpan.FromMilliseconds(100);
enemyTimer.Start();
}
private void DrawBall(SolidColorBrush brush, Canvas canvas,double x,double y)
{
enemy = new Ellipse();
enemy.Stroke = brush;
enemy.Fill = brush;
enemy.Height = 30;
enemy.Width = 30;
enemy.Margin = new Thickness(x,y, 0, 0);
enemyTimer = new DispatcherTimer();
enemyThickness = enemy.Margin;
canvas.Children.Add(enemy);
enemyTimer.Tick += enemyTimer_Tick;
}
void enemyTimer_Tick(object sender, EventArgs e)
{
if (enemyThickness.Left >= canvas.Width - 100)
{
GoDown();
direction = '1';
}
if (enemyThickness.Left <= 0 + 20)
{
GoDown();
direction = '0';
}
MoveTeam(enemy);
}
private void MoveTeam(Ellipse enemy)
{
enemyThickness = enemy.Margin;
if (direction == '1')
{
enemyThickness.Left -= xChange;
}
if (direction == '0')
{
enemyThickness.Left += xChange;
}
enemy.Margin = enemyThickness;
}
private void GoDown()
{
enemyThickness.Top += yChange;
enemy.Margin = enemyThickness;
}
}
Instead of initializing and assigning event handler in DrawBall method, do that in constructor of EnemyTeam class. This is will give you on timer per EnemyTeam object.
Declare enemyTimer as a static field:
class EnemyTeam
{
private static enemyTimer = new DispatcherTimer();
...
The keyword static will make the field shared for the class.
You're making multiple timers and throwing them away. See this line:
enemyTimer = new DispatcherTimer();
Every time you call that, you're making a new timer and throwing away the previous copy that enemyTimer held a reference to. Because enemyTimer.Start() is called after DrawTeam, it's called only on the last-created timer. None of the other timers get started.
But even if the other timers got started, you'd still only see one Ellipse move, because in enemyTimer_Tick you only ever make changes to enemy, which is a class member variable that points to the last Ellipse created.
I would suggest that you only use one timer, that you save all the Ellipses you create in a list for later use, and that in enemyTimer_Tick you update all of those Ellipses by iterating through the list.
EDIT: Here is a copy of your code, reworked a bit to show you what I mean. I don't really understand what you're trying to do with MoveTeam and the enemyThickness variable, so I didn't mess with that stuff. That is to say, this isn't a complete working solution, just an example of the changes I'm suggesting.
using System.Collections.Generic;
class EnemyTeam
{
private List<Ellipse> enemies = new List<Ellipse>();
private Canvas canvas;
private double xChange = 50, yChange = 50;
public DispatcherTimer enemyTimer;
private char direction = '0';
private Thickness enemyThickness;
public EnemyTeam(Canvas canvas, double startPosition, SolidColorBrush playerBrush)
{
this.canvas = canvas;
DrawTeam(canvas, 40, playerBrush);
enemyTimer = new DispatcherTimer();
enemyTimer.Interval = TimeSpan.FromMilliseconds(100);
enemyTimer.Tick += enemyTimer_Tick;
enemyTimer.Start();
}
private void DrawBall(SolidColorBrush brush, Canvas canvas,double x,double y)
{
enemy = new Ellipse();
enemy.Stroke = brush;
enemy.Fill = brush;
enemy.Height = 30;
enemy.Width = 30;
enemy.Margin = new Thickness(x,y, 0, 0);
enemyThickness = enemy.Margin; // what is this supposed to do?
canvas.Children.Add(enemy);
enemies.Add(enemy);
}
void enemyTimer_Tick(object sender, EventArgs e)
{
foreach (Ellipse enemy in enemies)
{
if (enemyThickness.Left >= canvas.Width - 100)
{
GoDown();
direction = '1';
}
if (enemyThickness.Left <= 0 + 20)
{
GoDown();
direction = '0';
}
MoveTeam(enemy);
}
}
private void MoveTeam(Ellipse enemy)
{
enemyThickness = enemy.Margin;
if (direction == '1')
{
enemyThickness.Left -= xChange;
}
if (direction == '0')
{
enemyThickness.Left += xChange;
}
enemy.Margin = enemyThickness;
}
private void GoDown()
{
enemyThickness.Top += yChange;
enemy.Margin = enemyThickness;
}
}
So, I have a simple task (so I thought) - I have a panel control which contains a label control.
I have directional control buttons, and movement buttons. The movement buttons should move the location of the label control in either x or y direction depending on which movement button is selected. The selected direction is stored as a property of the Class.
All of these functions are working, except this: when I instantiate the Robot class, the pointer should be on the center of the screen. This needs to be the origin. However, by clicking the Move 10 button, the pointer moves to 0,10 (x,y) starting from the top left corner position.
Since I need the center to be the origin, I tried moving the control's 0,0 point to where I want it, but that makes any negative values (from the controls top left) invisible, which can not work.
I am hoping someone can explain to me how to fix this. Oh, while I am at it, why isnt the panel's border showing?
A Robot object is created from the class when the form loads. The directional and movement code is like this:
private void btnGoTen_Click(object sender, EventArgs e)
{
if (isValidDirection())
if (robot.Direction == "N")
robot.Y -= 10;
if (robot.Direction == "E")
robot.X -= 10;
if (robot.Direction == "S")
robot.Y += 10;
if (robot.Direction == "W")
robot.X += 10;
lblPosition.Text = robot.GetFormattedLocation();
lblRobotLoc.Location = new Point(robot.X, robot.Y);
}
private void btnNorth_Click(object sender, EventArgs e)
{
robot.Direction = "N";
}
private void btnEast_Click(object sender, EventArgs e)
{
robot.Direction = "E";
}
private void btnSouth_Click(object sender, EventArgs e)
{
robot.Direction = "S";
}
private void btnWest_Click(object sender, EventArgs e)
{
robot.Direction = "W";
}
And the class itself is simple enough, as follows:
public class Robot
{
//fields
private int x;
private int y;
private string direction;
public Robot()
{
x = 0;
y = 0;
direction = "N";
}
public int X
{
get { return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
public string Direction
{
get { return direction; }
set { direction = value; }
}
public string GetFormattedLocation()
{
string locationString = "{X=" + Convert.ToString(x) + ",Y=" + Convert.ToString(y) + "}";
return locationString;
}
I am back with another question. I am still new to SFML so this one seemed a bit tough. I have tried using while loops and such but to no avail.
The game I am doing at the moment is a car going back and forth on the X axis and then I guess will be able to pick up points and stuff or simply just avoid objects coming towards the car until it eventually dies.
How do I make the movement smoother? Currently the car will move 8 units first, before moving 8 units in the desired direction until I let go of the button. It's the same when I do it the other way. I would like it to just instantly move and keep moving when I press either key.
static void OnKeyPressed(object sender, EventArgs e)
{
Vector2f newPos = new Vector2f(0, car.Position.Y);
KeyEventArgs ke = (KeyEventArgs)e;
if (ke.Code.Equals(Keyboard.Key.A))
{
if (car.Position.X != 0)
{
newPos.X = car.Position.X - 8;
car.Position = newPos;
}
else if (car.Position.X < 0)
{
newPos.X = 0;
car.Position = newPos;
}
else if(car.Position.X == 0)
{
// Do nothing
}
}
else if (ke.Code.Equals(Keyboard.Key.D))
{
if (car.Position.X != window.Size.X - 32)
{
newPos.X = car.Position.X + 8;
car.Position = newPos;
}
else if (car.Position.X > window.Size.X)
{
newPos.X = window.Size.X;
car.Position = newPos;
}
else if (car.Position.X == window.Size.X)
{
// Do nothing
}
}
}
And the entire thing for reference:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SFML.Audio;
using SFML.Graphics;
using SFML.Window;
namespace SFMLCarGame
{
class Program
{
private static RenderWindow window;
private static Sprite car;
static void Main(string[] args)
{
window = new RenderWindow(new VideoMode(256,512), "Car Game");
window.Closed += new EventHandler(OnClose);
window.KeyPressed += new EventHandler<KeyEventArgs>(OnKeyPressed);
Sprite bg = new Sprite(new Texture("road.png"));
car = new Sprite(new Texture("car.png"));
car.Position = new Vector2f(window.Size.X / 2, window.Size.Y - 96);
while (window.IsOpen())
{
window.DispatchEvents();
window.Clear();
window.Draw(bg);
window.Draw(car);
window.Display();
}
}
static void OnClose(object sender, EventArgs e)
{
RenderWindow window = (RenderWindow)sender;
window.Close();
}
static void OnKeyPressed(object sender, EventArgs e)
{
Vector2f newPos = new Vector2f(0, car.Position.Y);
KeyEventArgs ke = (KeyEventArgs)e;
if (ke.Code.Equals(Keyboard.Key.A))
{
if (car.Position.X != 0)
{
newPos.X = car.Position.X - 8;
car.Position = newPos;
}
else if (car.Position.X < 0)
{
newPos.X = 0;
car.Position = newPos;
}
else if(car.Position.X == 0)
{
// Do nothing
}
}
else if (ke.Code.Equals(Keyboard.Key.D))
{
if (car.Position.X != window.Size.X - 32)
{
newPos.X = car.Position.X + 8;
car.Position = newPos;
}
else if (car.Position.X > window.Size.X)
{
newPos.X = window.Size.X;
car.Position = newPos;
}
else if (car.Position.X == window.Size.X)
{
// Do nothing
}
}
}
}
}
You may want to read this short tutorial from the SFML's website.
The events are fired by the operating system, and are good for certain purposes (quit event, a key is pressed, the left mouse button is clicked) but aren't for things that need to be updated really often. Imagine that you are writing some text, and keep the 'A' key pressed. Your text will progressively grow like aaaaaaaaaaa but there is a little delay between the a spawns, imposed by the OS. You would get, say, 6 letters by second. This is the same with events. With a game running and displaying at 60 fps it is clear that your movement will not be smooth and barely manageable.
Hopefully SFML provides a way to check the instant state of the keyboard (and mouse and joystick). With the C# binding (I am assuming you are using the binding for 2.0 version, and if you don't then you should) you only have to check Keyboard.isKeyPressed(yourKey).
Doing this in the main loop will check at each frame that the key is pressed, and not wait for an OS event that is way slower.
On a side note, if your previous questions were answered correctly please mark them so by accepting an answer.
Edit : I haven't SFML for .NET installed on my computer but here is what it could look like
static void Main(string[] args)
{
window = new RenderWindow(new VideoMode(256,512), "Car Game");
window.Closed += new EventHandler(OnClose);
// Note this
// window.KeyPressed += new EventHandler<KeyEventArgs>(OnKeyPressed);
Sprite bg = new Sprite(new Texture("road.png"));
car = new Sprite(new Texture("car.png"));
car.Position = new Vector2f(window.Size.X / 2, window.Size.Y - 96);
while (window.IsOpen())
{
window.DispatchEvents();
CheckInputs(); // and this !
window.Clear();
window.Draw(bg);
window.Draw(car);
window.Display();
}
}
void CheckInputs()
{
if(Keyboard.isKeyPressed(Keyboard.key.A))
{
if(car.Position.X < 0)
car.Position.X = 0
else if(car.Position.X > 0)
car.Position.X -= 8; // shortcut for 'car.Position.X = car.Position.X - 8'
}
else if(Keyboard.isKeyPressed(Keyboard.key.D))
{
// etc
}
}
This way your transition should be much smoother, but beware, 8 pixels might be very fast !
I really recommend you to read the tutorial I have linked, because it explains the functionning of inputs in an language-agnostic way (even if the examples are in C++).
Also, you don't need your event handler anymore so I commented it. But if you are checking for other keys (like escape for pause or whatever) don't delete it, just remove the part you wrote about moving the car.
I have a delightful rectangle named ship, which I control with the right and left arrow keys. When I initially press a key ship moves in the opposite direction it should for the first movement, then goes back the right way. What would be an elegant solution to this particular conundrum?
public double p = 0;
private void Window_KeyDown_1(object sender, KeyEventArgs e)
{
if (e.Key == Key.Right)
{
ship.Margin = new Thickness(p, 259, 0, 12);
p = p + 10;
}
if (e.Key == Key.Left)
{
ship.Margin = new Thickness(p, 259, 0, 12);
p = p - 10;
}
You're changing the value of p after you set the margin. That means you're effectively always one key-press behind. I would expect you to want to set it before you make the change. (I'm not sure that setting the margin is really the ideal way of moving something around, mind you...)
Consier removing field for current left margin. You can get current ship margin before you change it. Also split handling user input and ship movement operations:
// Handle user input
private void Window_KeyDown_1(object sender, KeyEventArgs e)
{
switch(e.Key)
{
case (Key.Right):
MoveShip(Direction.Right); return;
case (Key.Left):
MoveShip(Direction.Left); return;
default:
return;
}
}
// Here you implement ship movement (Margin, Canvas.SetLeft, etc)
private void MoveShip(Direction direction)
{
var margin = ship.Margin; // or create copy here
const int distance = 10;
switch(direction)
{
case(Direction.Left):
margin.Left -= distance;
break;
case(Direction.Right):
margin.Left += distance;
break;
default:
return;
}
ship.Margin = margin;
}
private enum Direction
{
Left,
Right
}