How can I access member of main form - c#

I am only learning C# and I am trying to make a 2D game. I am at the stage where I have my Form1 set up with a 'PictureBox' for the player and the start of a player class:
class Player
{
private string _name;
private int _health;
internal Player(string name, int health = 100)
{
_name = name;
_health = health;
}
int X = 0;
internal void Draw()
{
updateInput();
Draw();
}
internal void updateInput()
{
if(Keyboard.IsKeyDown(Key.Right))
X = 1;
else if (Keyboard.IsKeyDown(Key.Left))
X = -1;
else
X = 0;
}
}
There is a PictureBox "pb_play" which contains the character's sprite on the main form. I tried setting its access modifier to public but that did not help. I want to change the position of the character by whatever the X value becomes. So I was trying to essentially access that member of the form the class.
I was attempting to do this inside the draw method, so it would update the input, then after that it would set the position, and then repeat the Draw method, looping constantly.
If there is a better way though, feel free to educate me. How can I fix this?
EDIT: Okay, I moved the methods into the UI, as mentioned by a comment. Here is what I have, but the sprite refuses to move:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Draw();
}
int X = 0;
internal void Draw()
{
updateInput();
pb_play.Location = new Point((pb_play.Location.X + X), 0);
Draw();
}
internal void updateInput()
{
if (Keyboard.IsKeyDown(Key.Right))
X = 5;
else if (Keyboard.IsKeyDown(Key.Left))
X = -5;
else
X = 0;
}
}

I used a timer to fix the issue:
internal void Draw()
{
pb_play.Location = new Point((pb_play.Location.X + X), (pb_play.Location.Y + Y));
}
internal void updateInput()
{
if (Keyboard.IsKeyDown(Key.Right))
X = 1;
else if (Keyboard.IsKeyDown(Key.Left))
X = -1;
else
X = 0;
if (Keyboard.IsKeyDown(Key.Up))
Y = -1;
else if (Keyboard.IsKeyDown(Key.Down))
Y = 1;
else
Y = 0;
}
private void timer1_Tick(object sender, EventArgs e)
{
updateInput();
Draw();
}

Related

The shape is not displayed on the form when I start working with threads(Window Forms)

where should I insert Graphics it to make the game work???
I want to develop a multithreaded application that simulates the movement of billiard balls on a gaming table. The behavior of each ball (i.e. calculating new coordinates and redrawing) is programmed as a separate thread. The usual physical laws apply on the game table - balls bounce off the walls and corners of the table so that the angle of incidence is equal to the angle of reflection, the only exception for this problem is the absence of interactions between the balls (i.e., simply put, they do not collide).
When starting the simulation process, each ball receives some (random) impulse, under the influence of which it moves by inertia, gradually stopping. When the ball stops, the corresponding flow should end. The application
makes sure that there is at least one thread that has not finished its work yet. When all the threads are completed, you need to issue the appropriate message. The program should provide the user with the ability to pause/continue or interrupt the motion simulation process.
To do this, I created everything that is above, and then I don't understand where to move a little
public partial class Form1 : Form
{
private List<Circle> circles = new List<Circle>();
private List<Thread> threads = new List<Thread>();
private bool pause = false;
public Form1()
{
InitializeComponent();
}
public void AddCircle()
{
Circle circle = new Circle();
circles.Add(circle);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
pause = !pause;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = CreateGraphics();
g.Clear(Color.White);
foreach (Circle circle in circles)
g.FillEllipse(new SolidBrush(circle.color), circle.X, circle.Y, circle.Weidth, circle.Heidth);
}
private void Form1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(t =>
{
AddCircle();
Thread.Sleep(30);
})
{ IsBackground = true };
threads.Add(thread);
thread.Start();
}
}
}
this is my class circle
public class Circle
{
public float x;
public float y;
public float heidth;
public float weidth;
public float dy;
public float dx;
public Color color;
public List<Color> colors = (new Color[] { Color.Pink, Color.Red, Color.Brown, Color.Black }).ToList();
public float X
{
set { x = value; }
get { return x; }
}
public float Y
{
set { y = value; }
get { return y; }
}
public float Heidth
{
set { heidth = value; }
get { return heidth; }
}
public float Weidth
{
set { weidth = value; }
get { return weidth; }
}
public float Dy
{
set { dy = value; }
get { return dy; }
}
public float Dx
{
set { dx = value; }
get { return dx; }
}
public Color Color
{
set { color = value; }
get { return color; }
}
public Circle()
{
Random random = new Random();
x = random.Next(10, 600);
y = random.Next(10, 500);
color = colors[random.Next(colors.Count)];
weidth = 10;
heidth = 10;
dx = random.Next(-50, 50);
dy = random.Next(-50, 50);
}
}
}

Snake. Roll back the coordinates of the snake to impact

I can’t realize the possibility of continuing the game after a collision. The snake should stop and start moving after clicking on one of the arrow buttons.
In a collision, a window appears about the loss, I need to continue the game.
I press the button and the following happens:
I don’t understand how I can save the coordinates of the snake just before the collision.
In the moveTimer_Tick method, all elements move, i.e. new coordinates have already appeared at the head and body, then there is a check for collisions with the wall and body. If they are found, a window appears about the loss.
New snake coordinates are not displayed. But after clicking the "Continue" button, an update occurs and the snake climbs to the border.
The question is: how can I save the coordinates of the snake, before the collision, and after continuing to start with them.
namespace Snake{
public partial class MainWindow : Window
{
//The field on which the snake lives
Entity field;
// snake head
Head head;
// whole snake
List<PositionedEntity> snake;
// apple
Apple apple;
//number of points
int score;
// Is movement paused
bool paused;
//time
DispatcherTimer moveTimer;
//constructor form
public MainWindow()
{
InitializeComponent();
snake = new List<PositionedEntity>();
//create field 600x600pixels
field = new Entity(600, 600, "pack://application:,,,/Resources/snake.png");
//create a timer that runs every 300 ms
moveTimer = new DispatcherTimer();
moveTimer.Interval = new TimeSpan(0, 0, 0, 0, 300);
moveTimer.Tick += new EventHandler(moveTimer_Tick);
}
//redraw screen method
private void UpdateField()
{
//update the position of the elements of the snake
foreach (var p in snake)
{
Canvas.SetTop(p.image, p.y);
Canvas.SetLeft(p.image, p.x);
}
//update the position of apple
Canvas.SetTop(apple.image, apple.y);
Canvas.SetLeft(apple.image, apple.x);
//points update
lblScore.Content = String.Format("{0}000", score);
}
//timer tick handler. All movement takes place here.
void moveTimer_Tick(object sender, EventArgs e)
{
// Do not update if movement is paused
if(paused) {
return;
}
//in the reverse order we move all the elements of the snake
foreach (var p in Enumerable.Reverse(snake))
{
p.move();
}
//we check that the head of the snake did not crash into the body
foreach (var p in snake.Where(x => x != head))
{
if (p.x == head.x && p.y == head.y)
{
//we lose
moveTimer.Stop();
GameOver.Visibility = Visibility.Visible;
btnRestart.Visibility = Visibility.Visible;
tbScore.Text = String.Format("SCORE: {0}000", score);
return;
}
}
//check that the head of the snake did not go out of the field
if (head.x < 40 || head.x >= 540 || head.y < 40 || head.y >= 540)
{
//we lose
moveTimer.Stop();
GameOver.Visibility = Visibility.Visible;
btnRestart.Visibility = Visibility.Visible;
tbScore.Text = String.Format("SCORE: {0}000", score);
return;
}
//check that the head of the snake crashed into an apple
if (head.x == apple.x && head.y == apple.y)
{
//increase the score
score++;
//move the apple to a new place
apple.move();
var part = new BodyPart(snake.Last());
canvas1.Children.Add(part.image);
snake.Add(part);
}
UpdateField();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// Unpause movement when any key is pressed
if(paused) {
paused = false;
}
switch (e.Key)
{
case Key.Up:
head.direction = Head.Direction.UP;
break;
case Key.Down:
head.direction = Head.Direction.DOWN;
break;
case Key.Left:
head.direction = Head.Direction.LEFT;
break;
case Key.Right:
head.direction = Head.Direction.RIGHT;
break;
}
}
// "Start"
private void button1_Click(object sender, RoutedEventArgs e)
{
btnStart.Visibility = Visibility.Hidden;
btnRestart.Visibility = Visibility.Hidden;
tBNotEnoughPoints.Visibility = Visibility.Hidden;
score = 0;
snake.Clear();
canvas1.Children.Clear();
// "Game Over"
GameOver.Visibility = Visibility.Hidden;
canvas1.Children.Add(field.image);
apple = new Apple(snake);
canvas1.Children.Add(apple.image);
head = new Head();
snake.Add(head);
canvas1.Children.Add(head.image);
moveTimer.Start();
UpdateField();
}
private void btnContinue_Click(object sender, RoutedEventArgs e)
{
if (score >= 2)
{
GameOver.Visibility = Visibility.Hidden;
btnRestart.Visibility = Visibility.Hidden;
score -= 2;
// Pause movement
paused = true;
moveTimer.Start();
UpdateField();
}
else
{
tBNotEnoughPoints.Visibility = Visibility.Visible;
}
}
public class Entity
{
protected int m_width;
protected int m_height;
Image m_image;
public Entity(int w, int h, string image)
{
m_width = w;
m_height = h;
m_image = new Image();
m_image.Source = (new ImageSourceConverter()).ConvertFromString(image) as ImageSource;
m_image.Width = w;
m_image.Height = h;
}
public Image image
{
get
{
return m_image;
}
}
}
public class PositionedEntity : Entity
{
protected int m_x;
protected int m_y;
public PositionedEntity(int x, int y, int w, int h, string image)
: base(w, h, image)
{
m_x = x;
m_y = y;
}
public virtual void move() { }
public int x
{
get
{
return m_x;
}
set
{
m_x = value;
}
}
public int y
{
get
{
return m_y;
}
set
{
m_y = value;
}
}
}
public class Apple : PositionedEntity
{
List<PositionedEntity> m_snake;
public Apple(List<PositionedEntity> s)
: base(0, 0, 40, 40, "pack://application:,,,/Resources/fruit.png")
{
m_snake = s;
move();
}
public override void move()
{
Random rand = new Random();
do
{
x = rand.Next(13) * 40 + 40 ;
y = rand.Next(13) * 40 + 40 ;
bool overlap = false;
foreach (var p in m_snake)
{
if (p.x == x && p.y == y)
{
overlap = true;
break;
}
}
if (!overlap)
break;
} while (true);
}
}
public class Head : PositionedEntity
{
public enum Direction
{
RIGHT, DOWN, LEFT, UP, NONE
};
Direction m_direction;
public Direction direction {
set
{
m_direction = value;
RotateTransform rotateTransform = new RotateTransform(90 * (int)value);
image.RenderTransform = rotateTransform;
}
}
public Head()
: base(280, 280, 40, 40, "pack://application:,,,/Resources/head.png")
{
image.RenderTransformOrigin = new Point(0.5, 0.5);
m_direction = Direction.NONE;
}
public override void move()
{
switch (m_direction)
{
case Direction.DOWN:
y += 40;
break;
case Direction.UP:
y -= 40;
break;
case Direction.LEFT:
x -= 40;
break;
case Direction.RIGHT:
x += 40;
break;
}
}
}
public class BodyPart : PositionedEntity
{
PositionedEntity m_next;
public BodyPart(PositionedEntity next)
: base(next.x, next.y, 40, 40, "pack://application:,,,/Resources/body.png")
{
m_next = next;
}
public override void move()
{
x = m_next.x;
y = m_next.y;
}
}
}
}
There is something to say about the design of your code, but if you don't care and you want a fast (and ugly) solution you can modify your PositionEntity in order to store old coordinates:
public class PositionedEntity : Entity
{
protected int m_x;
protected int m_y;
protected int m_oldX;
protected int m_oldY;
public PositionedEntity(int x, int y, int w, int h, string image)
: base(w, h, image)
{
m_x = x;
m_y = y;
m_oldX = x;
m_oldY = y;
}
public virtual void move() { }
public virtual void RestorePrevious()
{
m_x = m_oldX;
m_y = m_oldY;
}
public int x
{
get
{
return m_x;
}
set
{
m_oldX = m_x;
m_x = value;
}
}
public int y
{
get
{
return m_y;
}
set
{
m_oldY = m_y;
m_y = value;
}
}
}
When you have a collision you should call the RestorePrevious() on the head and on all the rest of the snake

Getting text to stay when changing scenes and then destroying when entering another

I'm creating a game designed for vision-impaired gamers. My score text currently shows up during the gameplay. Once you lose it loads a new scene (End screen), but I want the score to stay when the end scene is loaded and then have it reset to 0 when the game screen is loaded again, then removed if the player decides to go back to the main menu.
This is what loads the next scene.
public int amount;
public void ChangeScene(int changeTheScene)
{
SceneManager.LoadScene(changeTheScene);
}
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
amount += 1;
Debug.Log(amount);
if (amount == 10)
{
SceneManager.LoadScene(2);
}
}
}
}
And this is how i track the score
void Start()
{
count = 0;
SetCountText();
float x = Random.Range(325f, -600f);
float y = Random.Range(250f, -450f);
Debug.Log(x + "," + y);
prefab.GetComponent<RectTransform>().anchoredPosition = new Vector2(x, y);
loseObject.GetComponent<Lose>().amount = 0;
}
public void move()
{
float x = Random.Range(325f, -600f);
float y = Random.Range(250f, -450f);
Debug.Log(prefab.transform.position.x + "," + prefab.transform.position.y);
prefab.GetComponent<RectTransform>().anchoredPosition = new Vector2(x, y);
loseObject.GetComponent<Lose>().amount = 0;
count = count + 1;
SetCountText();
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
}
}
I'm not entirely sure if this would work, but to answer your question, I'm guessing this would do what you'd like.
using UnityEngine;
//This would be attached to said gameobject that displays the amount.
public class Amount : MonoBehaviour
{
public static Amount instance = null;
void Awake()
{
if (instance == null)
instance = this;
if (instance != this)
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
}
//Here would be what's needed to set the amount's parent.
public class SetThatAmountsParentToThisGameObject : MonoBehaviour
{
void SetAmountParent()
{
Amount.instance.transform.SetParent(transform);
}
}
//And here you would destroy said gameobject that displays the amount.
public class DestroyThatAmount : MonoBehaviour
{
void DestroyIt()
{
Destroy(Amount.instance.gameObject);
}
}
Be advised that I haven't tested this and therefor am not sure if this will actually work. I'm writing it as an answer because you asked for an example and code is much cleaner and easier to read in answers.

C# Singleton stackoverflow

I'm trying to make a game in which I use a statemachine.
The "GameState" creates the world (on entering) by calling getInstance() from the "World" class which is a singleton.
The World singleton has a 2D List with "Tile" objects (the world is made out of tiles). In the constructor of the World class the list is filled by a nested for loop which uses the SimpleTileFactory class to create tiles and puts them in the list.
Problem is that I get a StackOverflow. I debugged the code and found that the constructor of the World singleton is called more than once, which is probably causing the stack overflow. I can't find out why it's called more than once though and have the feeling I'm overlooking something simple. Is my singleton correct?
The Code is below.
Thanks in advance.
GameState Class
public partial class GameState : UserControl, IState<MainView>
{
private bool ready = false;
public GameState()
{
InitializeComponent();
}
public void enter(MainView owner)
{
this.Width = owner.Width;
this.Height = owner.Height;
this.Location = new Point(0, 0);
owner.Controls.Add(this);
World.getInstance();
this.ready = true;
}
public void update(MainView owner)
{
this.Refresh();
}
public void exit(MainView owner)
{
owner.Controls.Remove(this);
}
public bool isReady()
{
return this.ready;
}
private void GameState_Paint(object sender, PaintEventArgs e)
{
//for (int i = 0; i < World.getInstance().tiles.Count; i++)
//{
// for (int j = 0; j < World.getInstance().tiles[0].Count; j++)
// {
// //e.Graphics.DrawImage(new Image(), new Rectangle());
// }
//}
}
}
World Class
class World
{
private static World instance;
public GameResources gameResources;
public SimpleTileFactory tileFactory;
public List<List<Tile>> tiles = new List<List<Tile>>();
public Size worldSize = new Size(100, 100);
private World()
{
this.gameResources = new GameResources();
this.tileFactory = new SimpleTileFactory();
for (int i = 0; i < worldSize.Height; i++)
{
List<Tile> row = new List<Tile>();
for (int j = 0; j < worldSize.Width; j++)
{
row.Add(tileFactory.createTile(new Point(j, i)));
}
}
}
public static World getInstance()
{
if (instance == null)
{
instance = new World();
}
return instance;
}
}
SimpleTileFactory Class
class SimpleTileFactory
{
public SimpleResourceFactory resourceFactory = new SimpleResourceFactory();
private Random random = new Random();
private int maxNumOfResourcesPerTile = 5;
public SimpleTileFactory()
{
}
public Tile createTile(Point location)
{
//create tile
Tile tile = new Tile();
tile.location = location;
//give tile terrain type
Terrain terrain = new Terrain();
terrain.type = random.Next(0, World.getInstance().gameResources.terrainNames.Count);
terrain.name = World.getInstance().gameResources.terrainNames[terrain.type];
terrain.accessability = 1000;
//add resources to terrain
int numberOfResources = random.Next(0, maxNumOfResourcesPerTile + 1);
for (int i = 0; i < numberOfResources; i++)
{
terrain.resources.Add(resourceFactory.createTerrainResource(terrain.type));
}
tile.terrain = terrain;
return tile;
}
}
SimpleResourceFactory Class
class SimpleResourceFactory
{
public List<string> resourceNames = new List<string>();
public List<Image> resourceImages = new List<Image>();
private Random random = new Random();
public SimpleResourceFactory()
{
resourceNames.Add("asdfasfd");
resourceNames.Add("asdfasfd");
resourceNames.Add("asdfasfd");
}
public TerrainResource createTerrainResource(int terrainType)
{
TerrainResource resource = new TerrainResource();
resource.type = random.Next(0, resourceNames.Count);
resource.name = this.resourceNames[resource.type];
resource.amount = 100;
return resource;
}
}
Tile Class
class Tile
{
public Point location;
public Terrain terrain;
public Tile()
{
}
}
Terrain Class
class Terrain
{
public int type;
public string name;
public int accessability;
public List<TerrainResource> resources = new List<TerrainResource>();
public Terrain()
{
}
}
TerrainResource Class
class TerrainResource
{
public int type;
public string name;
public int amount;
public TerrainResource()
{
}
}
createTile is calling getInstance, and causing the overflow:
WpfApplication2.exe!WpfApplication2.SimpleResourceFactory.SimpleResourceFactory() Line 116 C#
WpfApplication2.exe!WpfApplication2.SimpleTileFactory.SimpleTileFactory() Line 76 C#
WpfApplication2.exe!WpfApplication2.World.World() Line 49 C#
WpfApplication2.exe!WpfApplication2.World.getInstance() Line 66 C#
WpfApplication2.exe!WpfApplication2.SimpleTileFactory.createTile(System.Windows.Point location) Line 95 C#
WpfApplication2.exe!WpfApplication2.World.World() Line 56 C#
WpfApplication2.exe!WpfApplication2.World.getInstance() Line 66 C#
WpfApplication2.exe!WpfApplication2.SimpleTileFactory.createTile(System.Windows.Point location) Line 95 C#
WpfApplication2.exe!WpfApplication2.World.World() Line 56 C#
WpfApplication2.exe!WpfApplication2.World.getInstance() Line 66 C#
WpfApplication2.exe!WpfApplication2.SimpleTileFactory.createTile(System.Windows.Point location) Line 95 C#
The problem was that createTile() was called within the World constructor. This way the World object isn't fully created yet when createTile() is executed which will then call getInstance() which in it's turn creates a new World (because it wasn't fully created yet) which calls createTile() again. It's an infinite loop.
I did a quick fix to check it by changing the World constructor and createTile() code as can be seen below. This is not the most beautiful way to solve it, so I'll probably just seperate GameResources from World.
private World()
{
this.gameResources = new GameResources();
this.tileFactory = new SimpleTileFactory();
for (int i = 0; i < this.worldSize.Height; i++)
{
List<Tile> row = new List<Tile>();
for (int j = 0; j < this.worldSize.Width; j++)
{
row.Add(tileFactory.createTile(new Point(j, i), this));
}
this.tiles.Add(row);
}
}
And the createTile method:
public Tile createTile(Point location, World world)
{
//create tile
Tile tile = new Tile();
tile.location = location;
//give tile terrain type
Terrain terrain = new Terrain();
terrain.type = random.Next(0, world.gameResources.terrainNames.Count);
terrain.name = world.gameResources.terrainNames[terrain.type];
terrain.accessability = 1000;
//add resources to terrain
int numberOfResources = random.Next(0, maxNumOfResourcesPerTile + 1);
for (int i = 0; i < numberOfResources; i++)
{
terrain.resources.Add(resourceFactory.createTerrainResource(terrain.type));
}
tile.terrain = terrain;
return tile;
}

Weird Behaviour when initiate a class

I'm working on a game, and I made all the building blocks. now I'm working on the game logic and rendering.
I have abstract Monster class and a class call GreenMonster that inherits from it.
Now the weird thing is, when I try to init a GreenMonster object.
when I do this:
private void initGreenMonsters()
{
for (int i = 0; i < greenMonsters.Length; i++)
{
greenMonsters[i] = new GreenMonster(new Point(0,40),new Size(40, 40));
}
}
every thing works like I planned and I can render the images on the form.
but when I try to init like that:
private void initGreenMonsters()
{
for (int i = 0; i < greenMonsters.Length; i++)
{
greenMonsters[i] = new GreenMonster();
greenMonsters[i].Position = new Point(0, 40);
greenMonsters[i].Size = new Size(40, 40);
}
}
I don't get any errors, and the app runs, but I can render the monsters.
This is the Monster class constructor and the Draw Method I use to draw a Monster:
public Monster(Point _startPosition,Size _size)
{
this.size = _size;
this.position = _startPosition;
}
public virtual void Draw(Graphics g)
{
Rectangle monsterRec = new Rectangle(position, size);
g.DrawImage(img, monsterRec);
}
and this is the GreenMonster class constructor:
public GreenMonster(Point _startPosition, Size _size)
: base(_startPosition, _size)
{
this.img = new Bitmap(SpaceInvadersGame.Properties.Resources.NormalMonster);
this.hp = 1;
this.speed = 1;
}
public GreenMonster()
{
this.img = new Bitmap(SpaceInvadersGame.Properties.Resources.NormalMonster);
this.hp = 1;
this.speed = 1;
}
the only thing that bothers me is, that when I'm looking at both ways I init the objects, it just looks the same..
I just can't find any different between in both of the ways.
someone have any idea how its different?
If you need more code so the question is more clear, I would be happy to add!
this is the Monster class and its properties
public abstract class Monster
{
protected Point position;
public Point Position { get { return position; } set { position = value; } }
protected Size size;
public Size Size { get { return size; } set { value = size; } }
public int speed;
protected Bitmap img;
protected int hp;
public int HP { get { return hp; } }
public void SetStartingPosition(int x, int y)
{
this.position = new Point(x, y);
}
public virtual void Draw(Graphics g)
{
Rectangle monsterRec = new Rectangle(position, size);
g.DrawImage(img, monsterRec);
}
}
You are setting your incoming value to the current size, rather than setting the current size to the incoming value, in the method below:
public Size Size { get { return size; } set { value = size; } }
should be
public Size Size { get { return size; } set { size = value; } }
Your code for Position looks OK though:
public Point Position { get { return position; } set { position = value; } }

Categories