I am making a windows form application in C# and i'm having some problems with the movement of images with transparency. I have 4 pictureboxes with .png images with transparent background (changing the BackColor and parent properties) and I use the following code to move them:
public class runner {
public PictureBox PictBox = null;
public int Pos = 0;
public int MaxLenght = 800;
...
public bool Run()
{
int distance = Rand.Next(1, 5);
PictBox.Location = new Point(PictBox.Location.X + distance, PictBox.Location.Y);
Pos += distance;
if (Pos >= MaxLenght) return true;
else return false;
}
}
...
public Form1()
{
InitializeComponent();
runners = new Runner[]{new Runner(pictureBox3), new Runner(pictureBox4), new Runner(pictureBox5), new Runner(pictureBox6)};
...
int n = 0;
while (!victory){
foreach(Runner runn in runners)
{
n +=1;
if (runn.Run())
{
victory = true;
break;
}
}
}
The problem is that if the images have transparent backcolor only the first and the last "frames" are showed (the image in the first position and the image in the last position once the while ends). If you know how to solve the problem please help me D:
Thanks in advance.
PD: The problem appears when I change the BackColor property to transparent, the parent property doesn't affect.
Related
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;
}
}
}
}
I'm trying to draw a Rectangle object for my game with a different colour so it looks like it's opened.
Basically when I run the program, it should render the doors as grey rectangles and then switch their colour after 10 seconds. They should then 'close', returning back to their original colour, after 3 seconds of being open. However, they start off as the wrong colour and then don't change at all.
I looked into using a state machine to determine whether or not the door object is open or closed, and then calling a method in Draw() to either draw it as a blue rectangle or a grey rectangle.
My enum for _doorStates:
enum doorState
{
Open,
Closed,
}
doorState[] _doorStates = new doorState[50];
This is my code in Update() that determines whether or not the door needs to be opened. I have an array of door objects and an array of _doorStates. I know this isn't the most efficient way of doing it but it's a bit late to change it!
for (int i = 0; i < doorNumber; i++)
{
if (doors[i].doorState == false)//if the object's bool value says it is closed
{
if (timeElapsed % doors[i].doorOpenRate == 0 && timeElapsed >= doors[i].doorOpenRate)//is it time for the door to open?
{
doors[i].doorState = true;
_doorStates[i] = doorState.Open;
timeOpened = timeElapsed;
}
}
else
{
if (timeElapsed - timeOpened == 3)//has it been open for 3 seconds?
{
doors[i].doorState = false;
_doorStates[i] = doorState.Closed;
}
}
}
This is the code inside the Draw() method:
for (int i = 0; i < doorNumber; i++)
{
switch(_doorStates[i])
{
case doorState.Open:
drawOpenDoor(doors[i], gameTime);
break;
case doorState.Closed:
drawClosedDoor(doors[i], gameTime);
break;
}
}
And these are my separate draw methods:
private void drawOpenDoor(door door, GameTime deltaTime)
{
spriteBatch.Draw(rect, door.doorObject, Color.CornflowerBlue);
}
private void drawClosedDoor(door door, GameTime deltatime)
{
spriteBatch.Draw(rect, door.doorObject, Color.DarkGray);
}
This is my constructor for the door objects:
public door (int xPos, int yPos, int width, int height, int orientation, int openRate, int openDuration)
{
if (orientation == 0)
{
doorObject = new Rectangle(xPos, yPos, width, height);
}
else
{
doorObject = new Rectangle(xPos + 15, yPos, height, width);
}
doorOrientation = orientation;//horizontal = 0, vertical = 1
doorOpenRate = openRate;
doorOpenDuration = openDuration;
doorState = false;
}
This is my first post so let me know if you need any more info like how the classes work. I used this post for creating the state machine.
I am new to programming and new to c#, yet I am trying to make a 2D game. I created a Background class and a Close class, the Close class is for an exit button that I want to implement. What I want to achieve from this is that when I release the close button, the background will gradually lower is tone from white to a darker white. The problem is that I don't know how to really code this.Here is a view to my code.
Close Class
private Texture2D texture;
private Vector2 position;
private Rectangle bounds;
private Color color;
MouseState oldstate;
public Close(Texture2D texture, Vector2 position){
this.texture = texture;
this.position = position;
bounds = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
color = new Color(40, 40, 40);
}
public void Update(GameTime gameTime){
MouseState state = Mouse.GetState();
Point point = new Point(state.X, state.Y);
if(bounds.Contains(point) && !(state.LeftButton == ButtonState.Pressed)){
color = new Color(235, 50, 50);
} else if((!(bounds.Contains(point)) && (state.LeftButton == ButtonState.Pressed)) || (!(bounds.Contains(point)) && (state.LeftButton == ButtonState.Released))){
color = new Color(40, 40, 40);
}
if((state.LeftButton == ButtonState.Pressed) && (oldstate.LeftButton == ButtonState.Released) && (bounds.Contains(point))){
color = new Color(172, 50, 50);
}
if((state.LeftButton == ButtonState.Released) && (oldstate.LeftButton == ButtonState.Pressed) && (bounds.Contains(point))){
}
oldstate = state;
}
public void Draw(SpriteBatch spriteBatch){
spriteBatch.Draw(texture, position, color);
}
Background Class
public Color color;
public Background(Color color){
this.color = color;
}
public void Update(GameTime gameTime){
}
Just to be a little more specific, I want the color to change within the Background class and be able to call this through the Close class. Also, keep in mind that the background color is being specified in the Game1 class, and the Update method is being called from it too.
Anyway, any help will be appreciated.
What I would do is something like this, though I don't have a lot of experience with Forms so it may or may not work as expected.
You'd call SyncFadeOut()/AsycFadeOut() through your Close class as required.
Synchronous (blocking) version:
public void SyncFadeOut()
{
// define how many fade-steps you want
for (int i = 0; i < 1000; i ++)
{
System.Threading.Thread.Sleep(10); // pause thread for 10 ms
// ----
// do the incremental fade step here
// ----
}
}
Async (non-blocking) version:
System.Timers.Timer timer = null;
public void FadeOut(object sender, EventArgs e)
{
// ----
// do the incremental fade step here
// ----
// end conditions
if ([current_color] <= [end_color])
{
timer.Stop();
// trigger any additional things you want, like close window
}
}
public void AsyncFadeOut()
{
System.Timers.Timer timer = new System.Timers.Timer(10); // triggers every 10ms, change this if you want a faster/slower fade
timer.Elapsed += new System.Timers.ElapsedEventHandler(FadeOut);
timer.AutoReset = true;
timer.Start();
}
i am creating a classic snake game where i need to shrink the board from the original size to smaller one as the level increases, what i got currently was that i managed to resize the board but the unused PictureBox are still there and unable to delete them. i am having trouble on how to delete and recall the method to recreate the PictureBox with new variable.
Really appreciate if there is someone who can help me solve my issue regarding PictureBox deletion/removal in C#. Here are some parts of the source code for my project. For Viewing the whole source code, can request from me directly.
Here where placed my code for the board to recreate/refresh.
private void gotoNextLevel(int nextLevel)
{
mode = "REST";
mySnake = new Snake(mainBoard); //Brand new snake with length 1
apples = new Rewards(nextLevel, mainBoard); //<--- Generate 5 apples
}
Here is how i create my board for the game.
int maxRow = 10, maxCol = 20; //Max 10 rows, and 20 columns in the board
int squareSize = 30; //Each square is 30px by 30px
PictureBox[,] squares;
public Board(Form mainForm)
{
squares = new PictureBox[maxRow, maxCol];
for (int row = 0; row < maxRow; row++)
{
for (int col = 0; col < maxCol; col++)
{
squares[row, col] = new PictureBox();
squares[row, col].Location = new Point(col * squareSize, row * squareSize);
squares[row, col].Height = squareSize;
squares[row, col].Width = squareSize;
squares[row, col].SizeMode = PictureBoxSizeMode.StretchImage;
squares[row, col].BackColor = Color.DarkGray;
squares[row, col].BorderStyle = BorderStyle.FixedSingle;
mainForm.Controls["boardPanel"].Controls.Add(squares[row, col]);
}
}
mainForm.Controls["controlPanel"].Location = new Point(mainForm.Controls["boardPanel"].Location.X, mainForm.Controls["boardPanel"].Location.Y + mainForm.Controls["boardPanel"].Height + 20);
}
Here is the refresh method.
private void refresh(Object myObject, EventArgs myEventArgs)
{
mySnake.move(mode); //Move the snake based on mode
modeLBL.Text = mode;
mainBoard.draw();
apples.draw(); //<----- draw apples
mySnake.draw();
//increment the duration by amount of time that has passed
//this method is called every speed millisecond
duration += speed;
timerLBL.Text = Convert.ToString(duration / 1000); //Show time passed
//Check if snke is biting itself. If so, call GameOver.
if (mySnake.checkEatItself() == true)
{
GameOver();
}
else if (apples.checkIFSnakeHeadEatApple( mySnake.getHeadPosition()) == true)
{
score += apples.eatAppleAtPostion(mySnake.getHeadPosition());
scoreLBL.Text = Convert.ToString(score);
if (apples.noMoreApples() == true)
{
clock.Stop();
level++;
levelLBL.Text = Convert.ToString(level);
gotoNextLevel(level);
MessageBox.Show("Press the start button to go to Level " + level, "Congrats");
}
else
{
//Length the snake and continue with the Game
mySnake.extendBody();
}
}
}
First of all: is the signature of refresh() generated by Visual Studio itself? If so, why don't you copy the body and put it in a new method without parameters because apparently you don't even use the ones in your current refresh() method.
Secondly: if you create that new method, you can create a method where you first clear the controls and then you call the redraw. I think it doesn't get redrawn because it was an event from a control which never gets called again because you just cleared all the controls.
And last but not least: if you have other controls than PictureBox but you only want to remove PictureBox you could use this:
foreach (Control control in this.Controls)
{
if (control is PictureBox)
{
this.Controls.Remove(control);
}
}
I have tried to create an animated bitmap on windows forms application. A timer object is set to an interval of 100ms, and the code works like this:
I have a 2560x2560 bitmap that is my map, a picture box called 'pb' contains this map and the size of the picture box is 800x800 with image stretch parameter on to give better resolution. I have a bitmap array of 7 elements containing the frames for a torch. The idea is that i draw the current torch bitmap onto the map, set the image of 'pb' to the map and call invalidate procedure to redraw it. Then the bitmap with torch drawn onto it is reverted to the original map bitmap 'org_btm'.
The code is below:
private void animationtick_Tick(object sender, EventArgs e)
{
using (Graphics g = Graphics.FromImage(btm))
{ g.DrawImage(torch_anim[torch_anim_c], new Point(20*64, 20*64)); }
pb.Image = btm;
pb.Invalidate();
btm = org_btm;
if (torch_anim_c < 6)
{
torch_anim_c++;
}
else
{
torch_anim_c = 0;
}
pb.Invalidate();
}
'torch_anim_c' is the index counter of the bitmap array.
So the problem that occurs is that the torch works for the first few frames and stops working there after, being stuck on 1 frame, when i run the code in debugger with a break point, it shows that the code runs through even when the image is stuck, and the program is responsive with other functions still working.
Do you have any ideas how to fix this?
Thank you in advance.
I have a snippet of the map with the stuck torch animation:
Torch Stuck Snippet
edit: the 'Point()' is 20*64 because the torch size is 64x64 and it's at position 20 and the map is 40*40 tiles.
convert it to gif format using photoshop and then use this class
public class GifImage
{
private Image gifImage;
private FrameDimension dimension;
private int frameCount;
private int currentFrame = -1;
private bool reverse;
private int step = 1;
public GifImage(string path)
{
gifImage = Image.FromFile(path);
dimension = new FrameDimension(gifImage.FrameDimensionsList[0]);
frameCount = gifImage.GetFrameCount(dimension);
}
public bool ReverseAtEnd {
get { return reverse; }
set { reverse = value; }
}
public Image GetNextFrame()
{
currentFrame += step;
if (currentFrame >= frameCount || currentFrame < 1) {
if (reverse) {
step *= -1;
currentFrame += step;
}
else {
currentFrame = 0;
}
}
return GetFrame(currentFrame);
}
public Image GetFrame(int index)
{
gifImage.SelectActiveFrame(dimension, index);
return (Image)gifImage.Clone();
}
}
Initialize it at formload ot whenever
GifImage gifImage = new GifImage(filePath);
set the Reverse variable to true if youn want to reverse it at the end
at timer tick use that code
pb.Image = gifImage.GetNextFrame();
change pb.Invalidate(); with pb.Update();