This question already has answers here:
CS0120: An object reference is required for the nonstatic field, method, or property 'foo'
(9 answers)
Closed 6 years ago.
i have a private method is ball.cs class in witch i want to modify a bool type from margins.cs class, but i get the Error An object reference is required for the non-static field, method, or property 'PingPong.Margins.win'.
Can someone help me with this?
this is the ball class code :
namespace PingPong
{
public class Ball
{
private PictureBox ball;
Random rand= new Random();
Player leftSidePlayer, rightSidePlayer;
int xSpeed, ySpeed;
public Ball(PictureBox aBall, Player leftSidePlayer, Player rightSidePlayer)
{
this.ball = aBall;
this.leftSidePlayer = leftSidePlayer;
this.rightSidePlayer = rightSidePlayer;
xSpeed = 1;
ySpeed = 2;
resetBall();
}
internal void processmove()
{
var bottom = Margins.bottomOfWorld - ball.Height;
DoMove();
if(ball.Location.Y >= bottom || ball.Location.Y <= Margins.topOfWorld)
{
ySpeed *= -1;
}
if (ball.Location.X <= Margins.leftOfWorld)
{
Score(leftSidePlayer);
}
else if (ball.Location.X >= Margins.rightOfWorld - ball.Width)
{
Score(rightSidePlayer);
}
if ((leftSidePlayer.paddle.Bounds.IntersectsWith(ball.Bounds)) || (rightSidePlayer.paddle.Bounds.IntersectsWith(ball.Bounds)))
{
xSpeed *= -1;
if ((ySpeed <= 6 && ySpeed >=-6) && (xSpeed <= 5 && xSpeed >=-5) )
{
if(ySpeed < 0)
{
ySpeed -= 1;
}else
{
ySpeed += 1;
}
if (xSpeed < 0)
{
xSpeed -= 1;
}
else
{
xSpeed += 1;
}
}
}
}
private int DoMove()
{
var bottom = Margins.bottomOfWorld - ball.Height;
ball.Location = new Point(ball.Location.X + xSpeed, Math.Max(Margins.topOfWorld, Math.Min(bottom, ball.Location.Y + ySpeed)));
return bottom;
}
private void Score(Player winningPlayer)
{
winningPlayer.scoreNumber++;
if(winningPlayer.scoreNumber == 7)
{
if(winningPlayer == leftSidePlayer )
{
Margins.win = true;
}else if(winningPlayer == rightSidePlayer)
{
Margins.win = false;
}
}
resetBall();
}
private void resetBall()
{
ball.Location = new Point((Margins.leftOfWorld + Margins.rightOfWorld) / 2, (Margins.bottomOfWorld + Margins.topOfWorld) / 2);
do
{
xSpeed = rand.Next(-3, 3);
ySpeed = rand.Next(-3, 3);
} while(Math.Abs(xSpeed) + Math.Abs(ySpeed) <= 3);
}
}
}
and this is the margins class code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PingPong
{
public class Margins
{ //Marimea ferestrei 1000; 600
public const int topOfWorld = 0, bottomOfWorld = 560, leftOfWorld =0, rightOfWorld = 1000;
public bool? win = null;
}
}
the error i get is in private void score when i use the margins.win = true
and margins.win = false .
You have a class with some static (or constant) variables now. Next to that, there is the instance variable win. That means you have to create an instance of Margins in order to get or set it.
If you really need a static class since there can always be just one Margins instance, make the class and its variables static:
public static class Margins
{ //Marimea ferestrei 1000; 600
public const int topOfWorld = 0, bottomOfWorld = 560, leftOfWorld =0, rightOfWorld = 1000;
public static bool? win = null;
}
If not, make a proper instance of Margins:
private Margins margins = new Margins();
this.margins.win = true;
Related
I am so confessed right now I don't even know how to properly form this question.
I have some code (as shown below) that is run on a different thread with the variable i not being referenced anywhere else that could interfere with it here. I just don't understand what is happening to cause this error, I put some watchers down with visual studio code and the values all seem to be fine and in range but almost randomly out of nowhere I will get this error.
Is it possible that this is caused by another section of code despite to my best knowledge being completely isolated from it? I even went as far to rename all other uses of i to different letters and I still get this problem.
Is it just something with for loops?
Am I somehow modifying i without even know it?
I just don't even know what to ask.
Here is the full code
`
using SFML.Graphics;
using SFML.Window;
using System.Diagnostics;
using System.Numerics;
namespace RenderEngine
{
public class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
PhysicsEngine re = new PhysicsEngine();
for (int i = 0; i < 100; i++)
{
Debug.WriteLine(i);
}
}
}
public class PhysicsEngine
{
Solver solver = new Solver();
public void RenderEngine2()
{
ContextSettings settings = new ContextSettings();
settings.AntialiasingLevel = 8;
RenderWindow window = new RenderWindow(new VideoMode(2000, 1000), "Poop", Styles.Default, settings);
SFML.Graphics.Color color = new SFML.Graphics.Color(0, 0, 0, 0);
window.SetVerticalSyncEnabled(true);
CircleShape shape = new CircleShape(5);
shape.FillColor = new SFML.Graphics.Color(0, 0, 255, 255);
window.Closed += handelclose;
int drawcount = 0;
while (window.IsOpen)
{
window.Clear(color);
window.DispatchEvents();
try
{
foreach (Partical partical in solver.Particals)
{
shape.Position = new SFML.System.Vector2f((partical.position.X), (partical.position.Y));
window.Draw(shape);
drawcount++;
}
drawcount = 0;
}
catch
{
Debug.WriteLine("notready yet");
}
window.Display();
}
void handelclose(object sender, EventArgs e)
{
window.Close();
Environment.Exit(Environment.ExitCode);
}
}
List<Partical> todraw = new List<Partical>();
void EngineLoop()
{
while (true)
{
foreach (Partical partical in solver.Particals)
{
int x = (int)Math.Round(partical.position.X/10);
int y = (int)Math.Round(partical.position.Y/10);
List<int> ts = solver.Grid[x, y];
if (ts != null)
{
for (int brokenint = 0; brokenint < ts.Count; brokenint++)
{
Debug.WriteLine(partical.ID);
Debug.WriteLine(ts[brokenint]);
if (partical.ID != ts[brokenint])
{
Vector2 pos = new Vector2(partical.ID, ts[brokenint]);
if (solver.Collision.Count > 0)
{
if (!solver.Collision.Contains(pos))
solver.Collision.Add(pos);
}
else
{
solver.Collision.Add(pos);
}
}
}
}
}
}
}
private int particalcount = 10;
bool canstart = false;
public PhysicsEngine()
{
Parallel.Invoke(() =>
{
while (!canstart) { Thread.Sleep(100); }
Debug.WriteLine("third thread");
RenderEngine2();
},
() =>
{
while (!canstart) { Thread.Sleep(100); }
Debug.WriteLine("engine started");
EngineLoop();
},
() =>
{
Debug.WriteLine("first thread");
PhysicsLoop(this);
}
);
}
void PhysicsLoop(PhysicsEngine PhyEng)
{
int frames = 0;
long second = 0;
PhysicsStart(PhyEng);
Thread.Sleep(1000);
Stopwatch sw = Stopwatch.StartNew();
solver.startupdate();
while (true)
{
sw.Start();
todraw = solver.Particals;
solver.update();
frames++;
if (second != (Stopwatch.GetTimestamp() / Stopwatch.Frequency))
{
second = (Stopwatch.GetTimestamp() / Stopwatch.Frequency);
Debug.WriteLine(frames);
frames = 0;
}
sw.Stop();
sw.Reset();
if (sw.ElapsedMilliseconds < 15)
Thread.Sleep(15 - (int)sw.ElapsedMilliseconds);
}
}
void PhysicsStart(PhysicsEngine phyeng)
{
for (int i = 0; i < 210; i++)
{
for (int j = 0; j < 110; j++)
{
solver.Grid[i,j] = new List<int>();
}
}
Random rand = new Random();
for (int i = 0; i < particalcount; i++)
{
Partical partical = new Partical();
partical.position = new Vector2(rand.Next(0, 2000), rand.Next(0, 1000));
partical.oldposition = partical.position;
partical.ID = i;
int x1 = (int)Math.Round((partical.position.X + 5) / 10);
int y1 = (int)Math.Round((partical.position.Y + 5) / 10);
int x2 = (int)Math.Round((partical.position.X - 5) / 10);
int y2 = (int)Math.Round((partical.position.Y - 5) / 10);
solver.Grid[x1, y1].Add(partical.ID);
solver.Grid[x2, y1].Add(partical.ID);
solver.Grid[x1, y2].Add(partical.ID);
solver.Grid[x2, y2].Add(partical.ID);
solver.Particals.Add(partical);
}
canstart = true;
}
}
public class Partical
{
public Vector2 position = new Vector2(0, 0);
public Vector2 oldposition = new Vector2(0, 0);
public Vector2 acceleration = new Vector2(0, 0);
Vector2 zero = new Vector2(0, 0);
public int ID = new int();
public void updatePosition(float sub)
{
Vector2 velocity = position - oldposition;
oldposition = position;
position = position + (velocity * 0.9f) + acceleration * sub;
acceleration = zero;
}
public void accelerate(Vector2 accel)
{
acceleration = acceleration + accel;
}
}
public class Solver
{
public List<Partical> Particals = new List<Partical>();
public List<Vector2> Collision = new List<Vector2>();
public List<int>[,] Grid = new List<int>[2100,1100];
public void update()
{
int subcount = 8;
float sub = 1f / (float)subcount;
for (int i = 0; i < subcount; i++)
{
applyGravity(sub);
updatePositions(sub);
for (int j = 0; j < Collision.Count; j++)
{
solvecolisions((int)Collision[j].X, (int)Collision[j].Y);
}
Collision.Clear();
}
}
public void startupdate()
{
applyGravity(0.5f);
updatePositions(0.5f);
applyGravity(0.5f);
updatePositions(0.5f);
}
void updatePositions(float sub)
{
foreach (Partical partical in Particals)
{
partical.updatePosition(sub);
int x1 = (int)Math.Round((partical.oldposition.X + 5) / 10);
int y1 = (int)Math.Round((partical.oldposition.Y + 5) / 10);
int x2 = (int)Math.Round((partical.oldposition.X - 5) / 10);
int y2 = (int)Math.Round((partical.oldposition.Y - 5) / 10);
Grid[x1,y1].Remove(partical.ID);
Grid[x2,y1].Remove(partical.ID);
Grid[x1,y2].Remove(partical.ID);
Grid[x2,y2].Remove(partical.ID);
x1 = (int)Math.Round((partical.position.X + 5) / 10);
y1 = (int)Math.Round((partical.position.Y + 5) / 10);
x2 = (int)Math.Round((partical.position.X - 5) / 10);
y2 = (int)Math.Round((partical.position.Y - 5) / 10);
Grid[x1,y1].Add(partical.ID);
Grid[x2,y1].Add(partical.ID);
Grid[x1,y2].Add(partical.ID);
Grid[x2,y2].Add(partical.ID);
}
}
void applyGravity(float sub)
{
float gravitystrangth = -0.1f;
foreach (Partical partical in Particals)
{
float a = partical.position.Y;
float b = partical.position.X;
b -= 1000;
a -= 500;
double angle = Math.Atan2(a, b);
float newA = gravitystrangth * (float)(Math.Sin(angle));
float newB = gravitystrangth * (float)(Math.Sin((Math.PI / 180) * 90 - angle));
Vector2 gravity = new Vector2(newB, newA);
partical.accelerate(gravity);
}
}
void solvecolisions(int id1, int id2)
{
Partical part = Particals[id1];
Partical part2 = Particals[id2];
if (part != part2)
{
Vector2 colisionaxis = part.position - part2.position;
float dist = colisionaxis.Length();
if (dist < 10)
{
Vector2 n = colisionaxis / dist;
float delta = 10 - dist;
part.position += 0.5f * delta * n;
part2.position -= 0.5f * delta * n;
}
}
}
public List<Partical> GetParticals()
{
return Particals;
}
}
}
`
You ts list depends on solver.Grid[x,y]. I am sure that some of your code that is not visible on the screen makes some changes of solver.Grid, probably deletes some times, or replaces them. This is what causing the error.
So I'm playing around with the BouncyGame. I made it so that when you start the game you need to press the screen for it to start. I would like to implement this whenever you play a new round as well. I tried to reuse this att the bottom of my code but it made it extremely laggy.
// Register for touch events
var touchListener = new CCEventListenerTouchAllAtOnce();
touchListener.OnTouchesEnded = OnTouchesEnded;
touchListener.OnTouchesMoved = OnTouchesEnded;
AddEventListener(touchListener, this);
}
void OnTouchesEnded(List<CCTouch> touches, CCEvent touchEvent)
{
if (touches.Count > 0)
{
Schedule(RunGameLogic);
scoreLabel.Text = "Score: 0";
paddleSprite.RunAction(new CCMoveTo(.1f, new CCPoint(touches[0].Location.X, paddleSprite.PositionY)));
}
}
I have no idea how to do this, tried for 2 hours with 0 results. Any suggestions are welcome.
Here's the full code.
using System;
using System.Collections.Generic;
using CocosSharp;
using Microsoft.Xna.Framework;
namespace CocosSharpGameTest
{
public class IntroLayer : CCLayerColor
{
// Define a label variable
CCLabel scoreLabel;
CCSprite paddleSprite, ballSprite;
public IntroLayer() : base(CCColor4B.Black)
{
// create and initialize a Label
scoreLabel = new CCLabel("Tap to GO!", "Arial", 80, CCLabelFormat.SystemFont);
// add the label as a child to this Layer
scoreLabel.PositionX = 50;
scoreLabel.PositionY = 1000;
scoreLabel.AnchorPoint = CCPoint.AnchorUpperLeft;
AddChild(scoreLabel);
paddleSprite = new CCSprite("paddle.png");
AddChild(paddleSprite);
ballSprite = new CCSprite("ball.png");
AddChild(ballSprite);
}
protected override void AddedToScene()
{
base.AddedToScene();
// Use the bounds to layout the positioning of our drawable assets
CCRect bounds = VisibleBoundsWorldspace;
// position the label on the center of the screen
paddleSprite.PositionX = 100;
paddleSprite.PositionY = 100;
ballSprite.PositionX = 320;
ballSprite.PositionY = 640;
// Register for touch events
var touchListener = new CCEventListenerTouchAllAtOnce();
touchListener.OnTouchesEnded = OnTouchesEnded;
touchListener.OnTouchesMoved = OnTouchesEnded;
AddEventListener(touchListener, this);
}
void OnTouchesEnded(List<CCTouch> touches, CCEvent touchEvent)
{
if (touches.Count > 0)
{
Schedule(RunGameLogic);
scoreLabel.Text = "Score: 0";
paddleSprite.RunAction(new CCMoveTo(.1f, new CCPoint(touches[0].Location.X, paddleSprite.PositionY)));
}
}
float ballXVelocity;
float ballYVelocity;
// How much to modify the ball's y velocity per second:
const float gravity = 140;
int score = 0;
void RunGameLogic(float frameTimeInSeconds)
{
// This is a linear approximation, so not 100% accurate
ballYVelocity += frameTimeInSeconds * -gravity;
ballSprite.PositionX += ballXVelocity * frameTimeInSeconds;
ballSprite.PositionY += ballYVelocity * frameTimeInSeconds;
bool overlap = ballSprite.BoundingBoxTransformedToParent.IntersectsRect(paddleSprite.BoundingBoxTransformedToParent);
bool movingDown = ballYVelocity < 0;
if (overlap && movingDown)
{
ballYVelocity *= -1;
const float minXVelocity = -300;
const float maxXVelocity = 300;
ballXVelocity = CCRandom.GetRandomFloat(minXVelocity, maxXVelocity);
score++;
scoreLabel.Text = "Score: " + score;
}
float ballRight = ballSprite.BoundingBoxTransformedToParent.MaxX;
float ballLeft = ballSprite.BoundingBoxTransformedToParent.MinX;
float screenRight = VisibleBoundsWorldspace.MaxX;
float screenLeft = VisibleBoundsWorldspace.MinX;
bool shouldReflectXVelocity =
(ballRight > screenRight && ballXVelocity > 0) ||
(ballLeft < screenLeft && ballXVelocity < 0);
if (shouldReflectXVelocity)
{
ballXVelocity *= -1;
}
if (ballSprite.PositionY < VisibleBoundsWorldspace.MinY)
{
ballSprite.PositionX = 320;
ballSprite.PositionY = 640;
ballXVelocity = 0;
ballYVelocity = 0;
ballYVelocity *= -1;
scoreLabel.Text = "Score: 0";
score = 0;
}
}
}
}
Thanks in advance!
Figured it out!
There is an "Unschedule" Method built into Cocossharp.
Ref. https://developer.xamarin.com/api/namespace/CocosSharp/
I just added
Unschedule(RunGameLogic);
at the very en of my RunGameLogic method under
if (ballSprite.PositionY < VisibleBoundsWorldspace.MinY)
So once the ballSprite is out of bounds it will Unschedule what i Scheduled in my OntouchesEnded method. That means the code goes back to listening for touches.
Might have made some errors, but this is as best I could figure it out and it works!
How do I close a GUI-menue when clicking outside of it?
What would be the smartest way to do it?
Here a picture of a two-stage GUI example:
And the belonging code, feel free to use it for your own purpose:
using UnityEngine;
using System.Data;
using Mono.Data.SqliteClient;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using UnityEngine.EventSystems;
public class menue2 : MonoBehaviour
{
private Vector2 scrollViewVector = Vector2.zero;
static int menueWidth = 125;
static int menueHeight = 25;
Rect dropDownRect1 = new Rect(0,0,menueWidth,menueHeight);
Rect dropDownRect2 = new Rect (menueWidth, menueHeight, 170, menueHeight);
// Menue Level 1
public static string[] list = {"Navigation","Setup Ordner", "Optionen Ordner", "Setup Dateien", "Optionen Dateien", "blabla"};
// Menue Level 2
public static string[] camSetup = {"Kamera Zoom Min.", "Kamera Zoom Max.", "Kamera Geschw. Normal", "Kamera Geschw. Schnell"};
public static string[] setupOrdner = {"Farbe = ","Höhe = ","setupFolder3","setupFolder4","setupFolder5","setupFolder6"};
public static string[] optionenOrdner = {"setupFolder1","setupFolder2","setupFolder3","setupFolder4","setupFolder5","set upFolder6"};
public static string[] setupDatei = {"oooooo","ppp","üüüüüüüüü","qqqqqq","nnnnnnn","mmmm"};
public static string[] optionenDatei = {"wwwww","eeeee","rrrrr","tttt","zzzzzzz","uuuuuu"};
public static string[] blabla = {"aaaaa","ssssss","gggg","ddddd","jjjjjj","hhhhh"};
public static string[][] listCollection = {camSetup, setupOrdner, optionenOrdner, setupDatei, optionenDatei, blabla};
int indexNumber;
int indexNumber2;
int level = 0;
string lastClicked = null;
public GameObject other;
void OnGUI()
{
if (GUI.Button (new Rect ((dropDownRect1.x), dropDownRect1.y, dropDownRect1.width, dropDownRect1.height), "Setup")) {
if (level == 0) {
level = 1;
lastClicked = "Setup";
} else if (level > 0)
level = 0;
}
if (level >= 1) {
for (int index = 0; index < list.Length; index++) {
if (GUI.Button (new Rect (0, (index * 25 + dropDownRect1.height), dropDownRect1.width, dropDownRect1.height), list [index])) {
indexNumber = index;
level = 2;
lastClicked = (list [index]);
}
}
if (level == 2 || level == 3) {
for (int index = 0; index < camSetup.Length; index++) {
if (GUI.Button (new Rect (menueWidth, ((indexNumber * menueHeight) + (index * menueHeight) + menueHeight), menueWidth, menueHeight), listCollection [indexNumber] [index])) {
indexNumber2 = index;
level = 3;;
lastClicked = (listCollection [indexNumber] [index]);
}
}
}
}
if (Input.GetMouseButtonUp (0)) {
print (lastClicked);
}
}
}
Thanks a lot for any help!
I stayed with scripting my GUI in the end and found a quite simple solution.
void closeMenue()
{
Vector2 mousePosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
if (Input.GetMouseButtonDown (0) && mousePosition.x > Screen.width/2 || Input.GetMouseButtonDown (0) && mousePosition.y < Screen.height/2)
{
level = 0; // closing everything
}
}
So I simply check for the cursor position.. here adjusted to a menue on the top left.
But the allowed area can easily be changed to the personal situation of course.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm writing a simple console based game. In the game, I have two functions that should move two things - A paddle and a ball.
But when I use two loops that have Thread.sleep, the game doesn't work. How can I use the two loops with Thread.sleep and get it to run properly?
My code:
class Program
{
static void Ball()
{
}
static void Main(string[] args)
{
int x = 10; int y = 10;
int dx = 1; int dy = 1;
ConsoleKeyInfo Exit = new ConsoleKeyInfo();
do
{
Console.SetCursorPosition(x, y);
Console.WriteLine(" ");
x += dx;
y += dy;
Console.SetCursorPosition(x, y);
Console.Write("*");
Thread.sleep(95);
if (x > 77) dx = -dx;
if (x < 2) dx = -dx;
if (y > 22) dy = -dy;
if (y < 2) dy = -dy;
} while (true);
int a = 2;
int b = 23;
int da = 1;
Console.SetCursorPosition(a, b);
Console.Write(" ");
if (Console.KeyAvailable)
{
ConsoleKeyInfo k = Console.ReadKey(true);
if (k.Key == ConsoleKey.LeftArrow) a = a - da;
else if (k.Key == ConsoleKey.RightArrow) a = a + da;
if (a > 78) a = -da;
if (a < 2) a = -da;
Thread.Sleep(200);
}
Console.SetCursorPosition(a, b);
Console.Write("~~~~~~~~~~");
}
}
When I run the example code you provided, the application will run. That is to say, the ball (*) will move around the screen. Are you expecting the ball to move on the screen, and the paddle to be drawn and move when an arrow is pressed? If so, you should look at how you are looping. The issue I see is that you have a loop that draws the ball and your loop will never ends, and therefore your code will not draw the paddle and/or reflect your arrow key changes. Is your expectation also for the Thread.Sleep to pause the loop and allow you to draw/move the paddle?
UPDATE:
namespace ConsoleGame
{
class Ball {
private static Ball _instance;
private int _a = 10, _b = 10;
private int _dx = 1, _dy = 1;
private int _timer = 0;
private int _milliseconds = 1000;
private Ball() { }
public static Ball Instance {
get {
if(_instance == null) {
_instance = new Ball();
}
return _instance;
}
}
/// <summary>
/// Move the ball on screen
/// </summary>
/// <param name="speed">The refresh/draw speed of the screen</param>
public void Move(int speed) {
if (_timer >= _milliseconds) {
// Set the cursor position to the current location of the ball
Console.SetCursorPosition(_a, _b);
// Clear the ball from the screen
Console.WriteLine(" ");
_a += _dx;
_b += _dy;
// Set a new locatio for the ball
Console.SetCursorPosition(_a, _b);
// Draw the new ball location on screen
Console.Write("*");
if (_a > 77) _dx = -_dx;
if (_a < 2) _dx = -_dx;
if (_b > 22) _dy = -_dy;
if (_b < 2) _dy = -_dy;
} else {
_timer = _timer + speed;
}
}
}
class Paddle {
private int _x = 2, _y = 23, _da = 1;
public int x {
get {
if (_x > (Console.BufferWidth - "~~~~~~~~~~".Length)) x = -_da;
if (_x < 2) x = -_da;
if (_x < 0) x = 2;
return _x;
}
set { _x = value; }
}
private static Paddle _instance;
private Paddle() { }
public static Paddle Instance {
get {
if (_instance == null) {
_instance = new Paddle();
}
return _instance;
}
}
/// <summary>
/// Move the Paddle on screen
/// </summary>
/// <param name="direction">Direction to move the paddle (Left = -1, Right = 1, Do Not Move = 0)</param>
public void Move(int direction) {
Console.SetCursorPosition(x, _y);
Console.Write(" ");
x = x - direction;
Console.SetCursorPosition(x, _y);
Console.Write("~~~~~~~~~~");
}
}
class Program {
private static int PaddleDirection = 0;
static void Main(string[] args) {
Thread ConsoleKeyListener = new Thread(new ThreadStart(ListerKeyBoardEvent));
ConsoleKeyListener.Name = "KeyListener";
ConsoleKeyListener.Start();
//ConsoleKeyListener.IsBackground = true;
int speed = 50;
do {
Console.Clear();
Ball.Instance.Move(speed);
Paddle.Instance.Move(PaddleDirection);
PaddleDirection = 0; // You can remove this line to make the paddle loop left/right on the screen after key press.
Thread.Sleep(speed);
} while (true);
}
private static void ListerKeyBoardEvent() {
do {
ConsoleKeyInfo k = Console.ReadKey(true);
if (k.Key == ConsoleKey.LeftArrow) PaddleDirection = 1;
else if (k.Key == ConsoleKey.RightArrow) PaddleDirection = -1;
else PaddleDirection = 0;
Console.ReadKey(false);
} while (true);
}
}
}
I am trying to make a slider puzzle game and I keep getting the error "NullReferenceException was unhandled" when I call myBoard.paint(e.Graphics) in my form1. Please help me!!!
Here is my code for Form1 (Let me know if I need to post some of my other classes code):
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;
using System.Diagnostics;
namespace SliderPuzzle
{
public partial class Form1 : Form
{
private int tileSize;
private int rowsCols;
private SlidePuzzle myBoard;
private Stopwatch timer;
private int moveCount;
public Form1()
{
InitializeComponent();
pictureBox1.TabIndex = 3;
pictureBox1.Size = new Size(100, 50);
pictureBox1.Location = new Point(16, 71);
pictureBox1.BackColor = Color.PaleGreen;
pictureBox1.BorderStyle = BorderStyle.Fixed3D;
pictureBox1.TabStop = false;
tileSize = imageList1.ImageSize.Width;
rowsCols = 3;
pictureBox1.Width = rowsCols * tileSize;
pictureBox1.Height = rowsCols * tileSize;
}
public void initGame()
{
myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1);
timer = new Stopwatch();
moveCount = 0;
timer.Start();
}
private void Form1_Load(object sender, EventArgs e)
{
initGame();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
this.myBoard.paint(e.Graphics);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (myBoard.move(e.Y / tileSize, e.X / tileSize))
++moveCount;
Refresh();
if (!myBoard.winner())
return;
timer.Stop();
if (MessageBox.Show(string.Format("You won!!\nIt took you {0} moves and {1:F2} seconds.\nPlay again?", (object)moveCount, (object)timer.Elapsed.TotalSeconds), "Game Over", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
{
Close();
}
else
{
initGame();
Refresh();
}
}
}
}
Update #1: Okay, so I moved myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1); to my constructor, but now none of the images are showing up on it. Here is what It looks like vs what it is supposed to look like:
Edit #2: Okay, I moved it back to where it was before and put
if (this.myBoard != null)
this.myBoard.paint(e.Graphics);
instead, and it works a little better and looks better as well. But the images not showing up is still a problem.
Edit #3: Here is the SliderPuzzle.Paint Code:
public void paint(Graphics g)
{
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
this.myGrid.get(new Location(r, c)).paint(g);
}
}
Edit #4: Here is the code for the SliderPuzzle Class:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace SliderPuzzle
{
internal class SlidePuzzle
{
private static Random rand = new Random();
private int myTileSize;
private BoundedGrid myGrid;
private ImageList myImages;
private Location myBlankLoc;
static SlidePuzzle()
{
}
public SlidePuzzle(int rowsCols, int tileSize, ImageList images)
{
this.myTileSize = tileSize;
this.myGrid = new BoundedGrid(rowsCols, rowsCols);
this.myImages = images;
this.myBlankLoc = new Location(rowsCols - 1, rowsCols - 1);
this.initBoard();
}
private void initBoard()
{
int index1 = 0;
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
{
this.myGrid.put(new Location(r, c), new Tile(index1, this.myTileSize, new Location(r, c), this.myImages.Images[index1]));
++index1;
}
}
for (int index2 = 0; index2 < 1000; ++index2)
{
Location adjacentLocation = this.myBlankLoc.getAdjacentLocation(SlidePuzzle.rand.Next(4) * 90);
if (this.myGrid.isValid(adjacentLocation))
{
this.swap(this.myBlankLoc, adjacentLocation);
this.myBlankLoc = adjacentLocation;
}
}
}
public bool move(int row, int col)
{
Location loc1 = new Location(row, col);
if (Math.Abs(this.myBlankLoc.getRow() - row) + Math.Abs(this.myBlankLoc.getCol() - col) != 1)
return false;
this.swap(loc1, this.myBlankLoc);
this.myBlankLoc = loc1;
return true;
}
public bool winner()
{
int num = 0;
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
{
if (this.myGrid.get(new Location(r, c)).getValue() != num)
return false;
++num;
}
}
return true;
}
private void swap(Location loc1, Location loc2)
{
Tile tile1 = this.myGrid.put(loc2, this.myGrid.get(loc1));
Tile tile2 = this.myGrid.put(loc1, tile1);
tile1.setLocation(loc1);
tile2.setLocation(loc2);
}
public void paint(Graphics g)
{
for (int r = 0; r < this.myGrid.getNumRows(); ++r)
{
for (int c = 0; c < this.myGrid.getNumCols(); ++c)
this.myGrid.get(new Location(r, c)).paint(g);
}
}
}
}
Update #5: Here is the Tile Class:
using System.Drawing;
namespace SliderPuzzle
{
internal class Tile
{
private int myValue;
private int mySize;
private Location myLoc;
private Image myImage;
public Tile(int value, int tileSize, Location loc, Image img)
{
this.myValue = value;
this.mySize = tileSize;
this.myLoc = loc;
this.myImage = img;
}
public int getValue()
{
return this.myValue;
}
public void setLocation(Location newLoc)
{
this.myLoc = newLoc;
}
public void paint(Graphics g)
{
g.DrawImage(this.myImage, this.myLoc.getCol() * this.mySize, this.myLoc.getRow() * this.mySize);
}
}
}
Edit #6: Here is the Location Class:
namespace SliderPuzzle
{
internal class Location
{
public const int LEFT = -90;
public const int RIGHT = 90;
public const int HALF_LEFT = -45;
public const int HALF_RIGHT = 45;
public const int FULL_CIRCLE = 360;
public const int HALF_CIRCLE = 180;
public const int AHEAD = 0;
public const int NORTH = 0;
public const int NORTHEAST = 45;
public const int EAST = 90;
public const int SOUTHEAST = 135;
public const int SOUTH = 180;
public const int SOUTHWEST = 225;
public const int WEST = 270;
public const int NORTHWEST = 315;
private int row;
private int col;
public Location(int r, int c)
{
this.row = r;
this.col = c;
}
public int getRow()
{
return this.row;
}
public int getCol()
{
return this.col;
}
public Location getAdjacentLocation(int direction)
{
int num1 = (direction + 22) % 360;
if (num1 < 0)
num1 += 360;
int num2 = num1 / 45 * 45;
int num3 = 0;
int num4 = 0;
if (num2 == 90)
num3 = 1;
else if (num2 == 135)
{
num3 = 1;
num4 = 1;
}
else if (num2 == 180)
num4 = 1;
else if (num2 == 225)
{
num3 = -1;
num4 = 1;
}
else if (num2 == 270)
num3 = -1;
else if (num2 == 315)
{
num3 = -1;
num4 = -1;
}
else if (num2 == 0)
num4 = -1;
else if (num2 == 45)
{
num3 = 1;
num4 = -1;
}
return new Location(this.getRow() + num4, this.getCol() + num3);
}
public bool equals(Location other)
{
if (this.getRow() == other.getRow())
return this.getCol() == other.getCol();
else
return false;
}
public int hashCode()
{
return this.getRow() * 3737 + this.getCol();
}
public int compareTo(Location otherLoc)
{
if (this.getRow() < otherLoc.getRow())
return -1;
if (this.getRow() > otherLoc.getRow())
return 1;
if (this.getCol() < otherLoc.getCol())
return -1;
return this.getCol() > otherLoc.getCol() ? 1 : 0;
}
public string toString()
{
return "(" + (object)this.getRow() + ", " + (string)(object)this.getCol() + ")";
}
}
}
Edit #7: Here is the last class, the BoundedGrid Class:
using System;
using System.Collections.Generic;
namespace SliderPuzzle
{
internal class BoundedGrid
{
private Tile[,] occupantArray;
public BoundedGrid(int rows, int cols)
{
this.occupantArray = new Tile[rows, cols];
}
public int getNumRows()
{
return this.occupantArray.GetLength(0);
}
public int getNumCols()
{
return this.occupantArray.GetLength(1);
}
public bool isValid(Location loc)
{
if (0 <= loc.getRow() && loc.getRow() < this.getNumRows() && 0 <= loc.getCol())
return loc.getCol() < this.getNumCols();
else
return false;
}
public List<Location> getOccupiedLocations()
{
List<Location> list = new List<Location>();
for (int r = 0; r < this.getNumRows(); ++r)
{
for (int c = 0; c < this.getNumCols(); ++c)
{
Location loc = new Location(r, c);
if (this.get(loc) != null)
list.Add(loc);
}
}
return list;
}
public Tile get(Location loc)
{
if (!this.isValid(loc))
throw new Exception("Location " + (object)loc + " is not valid");
else
return this.occupantArray[loc.getRow(), loc.getCol()];
}
public Tile put(Location loc, Tile obj)
{
if (!this.isValid(loc))
throw new Exception("Location " + (object)loc + " is not valid");
if (obj == null)
throw new NullReferenceException("obj == null");
Tile tile = this.get(loc);
this.occupantArray[loc.getRow(), loc.getCol()] = obj;
return tile;
}
public Tile remove(Location loc)
{
if (!this.isValid(loc))
throw new Exception("Location " + (object)loc + " is not valid");
Tile tile = this.get(loc);
this.occupantArray[loc.getRow(), loc.getCol()] = (Tile)null;
return tile;
}
}
}
Edit #8: When I click on the picturebox, the program crashes and it says the the timer.Stop(); in form1 gives me a NullReferenceException!!!
Edit #9: Okay, THAT worked... I have found that the images still do not show up, but I think that they are never being placed on the grid. When I click on the grid ( still has no images) It says that I have won. This should only display after I move the tiles into the correct order. Any idea what is going on?
Edit #10: My program finally works now! It turns out I had something missplaced in the constructor of form1, now everything works! The images show up and everything! How cool is that!!!
THANK YOU EVERYONE FOR YOU CONTRIBUTIONS, I WILL NOW GET A GREAT GRADE ON MY SCHOOL PROJECT!
This is one of those problems that will give you headaches. Trying to nail down the exact sequence of events is fine, when you can guarantee that the events are never going to be invoked out of sequence. Unfortunately the Paint event is one that gets fired at all sorts of odd times, any may be fired even before the Load event.
The only real answer is to never rely on events being fired in a particular sequence. Always check that your myBoard object is valid before trying to paint it:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (this.myBoard != null)
this.myBoard.paint(e.Graphics);
}
And yes, as others have noted, it is better to create all of your objects as soon as possible - in the constructor for instance, which is what a constructor is for after all. Even then, you can still get events being fired by actions in the constructor that will ruin your whole day. Your even handlers should be set as late as possible in the constructor code to account for this.
Rule(s) of thumb:
if you're creating custom objects that will be used in event handlers, always try to create and initialize them prior to calling InitializeComponent in the constructor.
Wire up your event handlers as late as possible, especially for things like Paint - it won't be useful before your constructor is done, so do it last in the constructor.
Your actual Form1_Load event never gets called (the one where you are initializing your board).
Add this code at the end of the Form1 constructor this.Load +=Form1_Load;
Your pictureBox1.Paint event is raised before your Form1.Load event. Move
myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1);
to your constructor and you should be fine.