Im having a hardtime how to remove an item in Multidimensional array. I am trying to create a breakout game. The only problem left though is that once the tile is gone i want to start again my game. But i cant figure out if how many are gone in my brick. I plan that when a certain counter reach to zero i will start again but i cant remove a 2d array. Im just setting the visible of each tile to false but not actually removing them..
here is my brick class
public Rectangle Location
{
get { return location; }
}
public int ID { get; set; }
public Brick(Texture2D texture, Rectangle location, int id)
{
this.texture = texture;
this.location = location;
ID = id;
}
public void CheckCollision(Ball ball, int i)
{
if (visible && ball.getBounds().Intersects(location))
{
visible = false;
ball.brickCollision();
}
}
public void Draw(SpriteBatch spriteBatch)
{
if (visible)
{
// gc.checker.Add(ID);
spriteBatch.Draw(texture, location, Color.White);
}
}
my other class related to brick
Brick[,] bricks;
private Texture2D b;
public void loadBricks(Texture2D b, int x, int y)
{
bricks = new Brick[x, y];
this.b = b;
for (int row = 0; row < y; row++)
{
for (int col = 0; col < x; col++)
{
bricks[col, row] = new Brick(b, new Rectangle(row * b.Width, col * b.Height, b.Width - 2, b.Height),row);
}
}
}
public void update(Ball ball)
{
foreach (Brick brick in bricks)
{
brick.CheckCollision(ball, bricks.Length);
}
}
public void drawBrick(SpriteBatch batch)
{
foreach (Brick brick in bricks)
{
//debugconsole("brck",brick);
brick.Draw(batch);
}
}
in my game class i only call the class thats related to brick. Any ideas?? thanks
Here is my ball class
public Ball(Texture2D ball, Vector2 speed, GraphicsDevice g, Rectangle p)
{
this.ball = ball;
ballSpeed = speed;
this.g = g;
this.p = p;
ballRect = new Rectangle((int)ballPosition.X, (int)ballPosition.Y, ball.Width, ball.Height);
}
public void Update(Paddle p)
{
x = p.getBounds().X;
y = p.getBounds().Y;
collidedBrick = false; // prevent removing too many bricks at one collision
ballmove();//move the ball
wallCollision();// check the ball and wall collision
paddCollision(p); // check paddle and ball collision
}
public void Update()
{
throw new NotImplementedException();
}
public void Draw(SpriteBatch batch)
{
batch.Draw(ball, ballRect, Color.White);
}
#region Collisions
public void wallCollision()
{
if (ballPosition.X < 0) //ball collide on left side screen
{
ballSpeed.X *= -1;
ballPosition.X = 0;
}
if (ballPosition.X > getScreenSize().Width - ballRect.Width) // ball collide on right side of screen
{
ballSpeed.X *= -1;
ballRect.X = getScreenSize().Width - ballRect.Width;
}
if (ballPosition.Y < 0)// ball collide on top edge of screen
{
ballSpeed.Y *= -1;
ballRect.Y = 0;
}
if (ballPosition.Y > getScreenSize().Height + ballRect.Height)
{
spacePress = false;
}
}
public void brickCollision()
{
if (!collidedBrick)
{
ballSpeed.Y *= -1;
collidedBrick = true;
counter++;
}
}
public void paddCollision(Paddle p)
{
if (p.getBounds().Intersects(ballRect))
{
ballPosition.Y = p.getBounds().Y - ball.Height;
ballSpeed.Y *= -1;
}
}
}
Why don't you use a dynamic array for that, so you can remove the bricks on the fly? Bricks that are removed from the list won't be drawn/updated and the memory they hold will be released because no other references would remain. I you absolutely must use a pseudo-matrix when loading the bricks, you can do something like:
List<Bricks> bricks;
public void loadBricks(Texture2D b, int x, int y)
{
bricks = new List<Bricks>();
for(int i = 0; i < (x * y); i++)
bricks.Add(new Brick(b, new Rectangle(b.Width * i / x, b.Height * (i % y), b.Width - 2, b.Height), i % y));
}
You could loop through all of your bricks and check their visible property:
bool endGame = true;
for (int row = 0; row < y; row++)
{
for (int col = 0; col < x; col++)
{
if (bricks[col, row].visible)
{
endGame = false;
}
}
}
if (endGame)
{
// End your game here
}
But this means that you will be repeatedly looping over all of your bricks to check if it's time to end the game or not. Not very efficient.
Instead, why not just track a integer _visibleBrickCount, set it to the number of bricks in your game at the start, and reduce it by one every time you call ball.BrickCollision()? Then, when it reaches zero, you know all the bricks are gone.
Related
I have a method that is supposed to generate a certain number of Vector3 at a distance not less than specified.
// Generate random point based on plane area
public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
{
float entireArea = 0f;
List<AreasWeight> areasWeights = new List<AreasWeight>();
List<Vector3> positions = new List<Vector3>();
foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
{
entireArea += plane.GetArea();
}
foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
{
float weight = plane.GetArea() / entireArea;
int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
areasWeights.Add(new(plane, weight, numOfPositionsInArea));
}
foreach (AreasWeight areaWeight in areasWeights)
{
for (int i = 0; i < areaWeight.NumOfPointsInArea; i++)
{
Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
foreach (Vector3 position in positions)
{
int attempts = 1;
while ((position - generatedPoint).magnitude < minDistanceBetweenPositions)
{
generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
attempts++;
if (attempts > 2000)
{
Debug.Log("Can't generate all positions.");
break;
}
}
}
positions.Add(generatedPoint);
}
}
return positions;
}
Get random point method:
public Vector3 GetRandomPointOnPlane()
{
float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));
return new(xPosition, DownPoint.y + 0.002f, zPosition);
}
But when i Instantiate objects based on these Vector3. Objects still have a distance less than the specified. What am i doing wrong?
I found a solution. The problem was a bad loop structure. When the algorithm confirmed that the distance was too small and generated a new one, it did not check whether the generated position had a gap from the previous positions on the list. It only confirmed that the gap was preserved and the program continued to execute.
I moved the code that makes sure that the distances are saved to the public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions) method in the GeneratorPlane class. I also added a private Vector3 PickRandomPos() method to it, just to return the generated position.
Methods in the public class GeneratorPlane:
public Vector3 GetRandomPointOnPlane(List<Vector3> alreadyGeneratedPoints, float minDistnaceBetweenPositions)
{
if (alreadyGeneratedPoints.Count != 0)
{
int attemps = 1;
bool pointFound = false;
Vector3 posToReturn = new();
while (!pointFound)
{
pointFound = true;
posToReturn = PickRandomPos();
foreach (Vector3 position in alreadyGeneratedPoints)
{
if (Vector3.Distance(position, posToReturn) < minDistnaceBetweenPositions)
{
pointFound = false;
attemps++;
if (attemps > 2000)
{
Debug.LogError("Points cannot be generated. Too little available space");
return Vector3.zero;
}
break;
}
}
}
return posToReturn;
}
else
{
Debug.Log("First point generated");
return PickRandomPos();
}
}
private Vector3 PickRandomPos()
{
float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));
return new(xPosition, DownPoint.y + 0.002f, zPosition);
}
Method to generate and return a certain number of items:
public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
{
float entireArea = 0f;
List<AreasWeight> areasWeights = new();
List<Vector3> positions = new();
foreach (GeneratorPlane plane in PlanesGenerator.GetCollectionAsList())
{
entireArea += plane.GetArea();
}
foreach (GeneratorPlane plane in PlanesGenerator.GetCollectionAsList())
{
float weight = plane.GetArea() / entireArea;
int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
areasWeights.Add(new(plane, weight, numOfPositionsInArea));
}
foreach (AreasWeight areaWeight in areasWeights)
{
for (int i = 0; i < areaWeight.NumOfPointsInArea; i++)
{
Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane(positions, minDistanceBetweenPositions);
positions.Add(generatedPoint);
}
}
return positions;
}
On the original code if you generate a point 2000 times you actually keep the last generatedPoint, and as you mentioned you don't actually cross check the whole list of positions, only the remaining positions.
Although you have solved your problem and posted a solution, I took the liberty of doing a simple script with the same end, I will share it here in hopes its useful for you or others.
This solution will not fill any area, its only making sure no two objects are at shorter distance than specified.
In my tests, with 50 nPoints only 10/20 points are instantiated before a point takes over 2000 attempts and consequently conclude the search for points. Although this will depend on the ratio between spawnLimits and nPoints.
[SerializeField]
GameObject trunkPrefab;
List<Vector3> positions;
//input variables
int nPoints = 50;
float minDistance = 2.5f;
int spawnLimits = 20;
void Start()
{
positions = new();
for (int i = 0; i < nPoints; i++)
{
Vector3 position = Vector3.zero;
bool newPosition = true;
int attempts = 0;
do
{
//first generation will be automatically added to the list
position = new(Random.Range(-spawnLimits, spawnLimits), .5f, Random.Range(-spawnLimits, spawnLimits));
if (positions.Count < 1)
{
break;
}
//every position will be compared here,
//if any position is too close from then new position
//"newPosition" is set to false and we try again from the start.
for (int p = 0; p < positions.Count; p++)
{
if (Vector3.Distance(position, positions[p]) < minDistance)
{
newPosition = false;
attempts++;
if (attempts > 2000)
{
Debug.Log("Max attempts reached.");
return;
}
break;
}
}
} while (!newPosition);
//adding a random rotation
Vector3 rotation = new(Random.Range(80, 100), Random.Range(0, 179), 0);
Instantiate(trunkPrefab, position, Quaternion.Euler(rotation));
positions.Add(position);
}
}
I am taking Vector2 as touch postion,and i want to search for same Vector2 in list where i already added all positions rounded by 1 decimal f.e 0.5.But now they never seems to be same,I guess the vector taken from transform position has more decimals than 1.So how can i fix it.
Using debug i see that both list contains same values,but comparing them and trying deleting duplicates,doesnt work.
public class skriptaPozicija : MonoBehaviour
{
List<Vector2> listaV1;
List<Sprite> slike1t;
public List<Vector2> daseNeponovi;
int randomBroj;
public GameObject instantacija;
GameObject oznacenaSl;
Vector3 skala;
public GameObject povecalo;
// Start is called before the first frame update
void Start()
{
StartCoroutine(postavkeSLova());
List<Vector2> daseNeponovi=new List<Vector2>();
}
// Update is called once per frame
void Update()
{
// RemoveDuplicates();
}
public void klikNaPoziciju()
{
randomBroj = Random.Range(0,slike1t.Count);
// Debug.Log("broj itema u slici"+HintoviMale.slikeT.Count);
oznacenaSl = Instantiate(instantacija,listaV1[randomBroj] , Quaternion.identity) as GameObject;
oznacenaSl.transform.localScale = new Vector3(WordsGrid.skalaPrefaba.x,
WordsGrid.skalaPrefaba.y, 0);
oznacenaSl.GetComponent<SpriteRenderer>().sprite = slike1t[randomBroj];
Destroy(oznacenaSl, 3f);
slike1t.RemoveAt(randomBroj);
listaV1.RemoveAt(randomBroj);
if (slike1t.Count <= 0)
{
povecalo.SetActive(false);
}
for(int i = 0; i < daseNeponovi.Count; i++)
{
Debug.Log(daseNeponovi[i]);
}
for (int i = 0; i < listaV1.Count; i++)
{
Debug.Log(listaV1[i]);
}
listaV1.Add(new Vector2(2, 2));
daseNeponovi.Add(new Vector2(2, 2));
}
IEnumerator postavkeSLova()
{
yield return new WaitForSeconds(0.1f);
slike1t = new List<Sprite>();
for (int i = 0; i < HintoviMale.slike.Count; i++)
{
slike1t.Add(HintoviMale.slike[i]);
}
listaV1 = new List<Vector2>();
for (int i = 0; i < HintoviMale.pozicijaV.Count; i++)
{
listaV1.Add(HintoviMale.pozicijaV[i]);
}
}
public void RemoveDuplicates()
{
foreach (Vector2 item in daseNeponovi)
{
if (listaV1.Contains(item))
{
listaV1.Remove(item);
}
}
}
public void refreshList()
{
slike1t = new List<Sprite>();
listaV1 = new List<Vector2>();
for (int i = 0; i < HintoviMale.slike.Count; i++)
{
slike1t.Add(HintoviMale.slike[i]);
}
listaV1 = new List<Vector2>();
for (int i = 0; i < HintoviMale.pozicijaV.Count; i++)
{
listaV1.Add(HintoviMale.pozicijaV[i]);
}
}
}
I am taking Vector2 as touch postion,and i want to search for same Vector2 in list where i already added all positions rounded by 1 decimal f.e 0.5.But now they never seems to be same,I guess the vector taken from transform position has more decimals than 1.So how can i fix it.
I'm trying to make a "Mania" style game(like guitar hero). But i can't seem to get the Movement of the "notes" to work, I keep the notes in a queue and I dequeue the last note and change it's position to the top again. But for some reason it doesen't work with my "goodcubes". only the normal ones
The problem seems to be that the instead of moving the "goodCube" to the correct position it instead changes the transform of the prefab.
All "notes" are referred to as "Cubes" in script
for (int i = 0; i < backlog; i++)//how many rows to spawn
{
goodCubes.Enqueue(Instantiate(goodcube));
for (int j = 0; j < columns - 1; j++)
{
badCubes.Enqueue(Instantiate(cube));
}
}
//I check the player input and if it corresponds with a note in the correct row
//I have tested so both true and false option gets called
if (i == position)
{
GameObject good = goodCubes.Dequeue();
good.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
goodCubes.Enqueue(goodcube);
}
else
{
GameObject badCube = badCubes.Dequeue();
badCube.transform.position = spawnPoint;`enter code here`
spawnPoint += new Vector2(1 * rowOffset, 0);
badCubes.Enqueue(badCube);
}
The full script
public int columus;
public GameObject cube;
public GameObject goodcube;
public event Action moveCubes;
[SerializeField] private int score = 0;
[SerializeField] private float rowOffset = 1;
[SerializeField] private float heightDifference = 1;
[SerializeField] private int backlog = 4;
private float SpawnHeight;
Queue<int> positions = new Queue<int>();
Queue<GameObject> badCubes = new Queue<GameObject>();
Queue<GameObject> goodCubes = new Queue<GameObject>();
private void Start()
{
for (int i = 0; i < backlog; i++)
{
goodCubes.Enqueue(Instantiate(goodcube));
for (int j = 0; j < columus - 1; j++)
{
badCubes.Enqueue(Instantiate(cube));
}
}
for (int i = 0; i < backlog; i++)
{
positions.Enqueue(SpawnRow(i * heightDifference));
}
}
int SpawnRow(float y)
{
int position = UnityEngine.Random.Range(0, columus);
Vector2 spawnPoint = new Vector2(-columus * rowOffset / 2f, y);
for (int i = 0; i < columus; i++)
{
if (i == position)
{
GameObject goodCube = goodCubes.Dequeue();
goodCube.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
goodCubes.Enqueue(goodcube);
}
else
{
GameObject badCube = badCubes.Dequeue();
badCube.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
badCubes.Enqueue(badCube);
}
}
return position;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.D))
{
UpdateScore(0);
}
else if (Input.GetKeyDown(KeyCode.F))
{
UpdateScore(1);
}
else if (Input.GetKeyDown(KeyCode.J))
{
UpdateScore(2);
}
else if (Input.GetKeyDown(KeyCode.K))
{
UpdateScore(3);
}
} //inputcheck
private void UpdateScore(int input)
{
if (positions.Dequeue() == input)
{
moveCubes?.Invoke();
positions.Enqueue(SpawnRow(backlog * heightDifference + 1 * heightDifference));
score++;
}
else
{
moveCubes?.Invoke();
positions.Enqueue(SpawnRow(backlog * heightDifference + 1 * heightDifference));
score--;
}
}
I truly believe your issue is a typo in your code. That usually happens when you have variables with the same name. Your issue is that you are enqueuing the prefab goodcube and not the goodCube object:
GameObject goodCube = goodCubes.Dequeue();
goodCube.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
//******HERE YOU ARE ENQUEUEING THE PREFAB goodcube AND NOT goodCube as your variable name suggests two lines above this line*****
goodCubes.Enqueue(goodCube);//INSTEAD OF goodCubes.Enqueue(goodcube);
I have private int variable called _scoreTotal
and I have assign a new public variable called score to pass the private varible _scoreTotal to the public static scores.
So I need to access this value from other script.
This is my code:
using UnityEngine;
using System.Collections;
using Holoville.HOTween;
/// <summary>
/// This class is the main entry point of the game it should be attached to a gameobject and be instanciate in the scene
/// Author : Pondomaniac Games
/// </summary>
public class Main : MonoBehaviour {
public static int score;
public GameObject _indicator; //The indicator to know the selected tile
public GameObject[, ] _arrayOfShapes; //The main array that contain all games tiles
private GameObject _currentIndicator; //The current indicator to replace and destroy each time the player change the selection
private GameObject _FirstObject; //The first object selected
private GameObject _SecondObject; //The second object selected
public GameObject[] _listOfGems; //The list of tiles we cant to see in the game you can remplace them in unity's inspector and choose all what you want
public GameObject _emptyGameobject; //After destroying object they are replaced with this one so we will replace them after with new ones
public GameObject _particleEffect; //The object we want to use in the effect of shining stars
public GameObject _particleEffectWhenMatch; //The gameobject of the effect when the objects are matching
public bool _canTransitDiagonally = false; //Indicate if we can switch diagonally
public int _scoreIncrement; //The amount of point to increment each time we find matching tiles
private int _scoreTotal = 0; //The score
private ArrayList _currentParticleEffets = new ArrayList(); //the array that will contain all the matching particle that we will destroy after
public AudioClip MatchSound; //the sound effect when matched tiles are found
public int _gridWidth; //the grid number of cell horizontally
public int _gridHeight; //the grid number of cell vertically
// Use this for initialization
void Start() {
//Initializing the array with _gridWidth and _gridHeight passed in parameter
_arrayOfShapes = new GameObject[_gridWidth, _gridHeight];
//Creating the gems from the list of gems passed in parameter
for (int i = 0; i <= _gridWidth - 1; i++) {
for (int j = 0; j <= _gridHeight - 1; j++) {
var gameObject = GameObject.Instantiate(_listOfGems[Random.Range(0, _listOfGems.Length)] as GameObject, new Vector3(i, j, 0), transform.rotation) as GameObject;
_arrayOfShapes[i, j] = gameObject;
}
}
//Adding the star effect to the gems and call the DoShapeEffect continuously
InvokeRepeating("DoShapeEffect", 1f, 0.21F);
}
// Update is called once per frame
void Update() {
float score = _scoreTotal;
Main.score++;
bool shouldTransit = false;
//Detecting if the player clicked on the left mouse button and also if there is no animation playing
if (Input.GetButtonDown("Fire1") && HOTween.GetTweenInfos() == null) {
Destroy(_currentIndicator);
//The 3 following lines is to get the clicked GameObject and getting the RaycastHit2D that will help us know the clicked object
//Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (hit.transform != null)
{ //To know if the user already selected a tile or not yet
if (_FirstObject == null) _FirstObject = hit.transform.gameObject;
else {
_SecondObject = hit.transform.gameObject;
shouldTransit = true;
}
_currentIndicator = GameObject.Instantiate(_indicator, new Vector3(hit.transform.gameObject.transform.position.x, hit.transform.gameObject.transform.position.y, -1), transform.rotation) as GameObject;
//If the user select the second tile we will swap the two tile and animate them
if (shouldTransit)
{
//Getting the position between the 2 tiles
var distance = _FirstObject.transform.position - _SecondObject.transform.position;
//Testing if the 2 tiles are next to each others otherwise we will not swap them
if (Mathf.Abs(distance.x) <= 1 && Mathf.Abs(distance.y) <= 1)
{ //If we dont want the player to swap diagonally
if (!_canTransitDiagonally)
{
if (distance.x != 0 && distance.y != 0)
{
Destroy(_currentIndicator);
_FirstObject = null;
_SecondObject = null;
return;
}
}
//Animate the transition
DoSwapMotion(_FirstObject.transform, _SecondObject.transform);
//Swap the object in array
DoSwapTile(_FirstObject, _SecondObject, ref _arrayOfShapes);
}
else
{
_FirstObject = null;
_SecondObject = null;
}
Destroy(_currentIndicator);
}
}
}
//If no animation is playing
if (HOTween.GetTweenInfos() == null)
{
var Matches = FindMatch(_arrayOfShapes);
//If we find a matched tiles
if (Matches.Count > 0)
{//Update the score
_scoreTotal += Matches.Count * _scoreIncrement;
score += Matches.Count * _scoreIncrement;
foreach(GameObject go in Matches) {
//Playing the matching sound
GetComponent<AudioSource>().PlayOneShot(MatchSound);
//Creating and destroying the effect of matching
var destroyingParticle = GameObject.Instantiate(_particleEffectWhenMatch as GameObject, new Vector3(go.transform.position.x, go.transform.position.y, -2), transform.rotation) as GameObject;
Destroy(destroyingParticle, 1f);
//Replace the matching tile with an empty one
_arrayOfShapes[(int)go.transform.position.x, (int)go.transform.position.y] = GameObject.Instantiate(_emptyGameobject, new Vector3((int)go.transform.position.x, (int)go.transform.position.y, -1), transform.rotation) as GameObject;
//Destroy the ancient matching tiles
Destroy(go, 0.1f);
}
_FirstObject = null;
_SecondObject = null;
//Moving the tiles down to replace the empty ones
DoEmptyDown(ref _arrayOfShapes);
}
//If no matching tiles are found remake the tiles at their places
else if (_FirstObject != null
&& _SecondObject != null
) {
//Animate the tiles
DoSwapMotion(_FirstObject.transform, _SecondObject.transform);
//Swap the tiles in the array
DoSwapTile(_FirstObject, _SecondObject, ref _arrayOfShapes);
_FirstObject = null;
_SecondObject = null;
}
}
//Update the score
(GetComponent(typeof(TextMesh))as TextMesh).text = _scoreTotal.ToString();
}
// Find Match-3 Tile
private ArrayList FindMatch(GameObject[, ] cells)
{//creating an arraylist to store the matching tiles
ArrayList stack = new ArrayList();
//Checking the vertical tiles
for (var x = 0; x <= cells.GetUpperBound(0); x++)
{
for (var y = 0; y <= cells.GetUpperBound(1); y++)
{
var thiscell = cells[x, y];
//If it's an empty tile continue
if (thiscell.name == "Empty(Clone)") continue;
int matchCount = 0;
int y2 = cells.GetUpperBound(1);
int y1;
//Getting the number of tiles of the same kind
for (y1 = y + 1; y1 <= y2; y1++)
{
if (cells[x, y1].name == "Empty(Clone)" || thiscell.name != cells[x, y1].name) break;
matchCount++;
}
//If we found more than 2 tiles close we add them in the array of matching tiles
if (matchCount >= 2)
{
y1 = Mathf.Min(cells.GetUpperBound(1), y1 - 1);
for (var y3 = y; y3 <= y1; y3++)
{
if (!stack.Contains(cells[x, y3]))
{
stack.Add(cells[x, y3]);
}
}
}
}
}
//Checking the horizontal tiles , in the following loops we will use the same concept as the previous ones
for (var y = 0; y < cells.GetUpperBound(1) + 1; y++)
{
for (var x = 0; x < cells.GetUpperBound(0) + 1; x++)
{
var thiscell = cells[x, y];
if (thiscell.name == "Empty(Clone)") continue;
int matchCount = 0;
int x2 = cells.GetUpperBound(0);
int x1;
for (x1 = x + 1; x1 <= x2; x1++)
{
if (cells[x1, y].name == "Empty(Clone)" || thiscell.name != cells[x1, y].name) break;
matchCount++;
}
if (matchCount >= 2)
{
x1 = Mathf.Min(cells.GetUpperBound(0), x1 - 1);
for (var x3 = x; x3 <= x1; x3++)
{
if (!stack.Contains(cells[x3, y]))
{
stack.Add(cells[x3, y]);
}
}
}
}
}
return stack;
}
// Swap Motion Animation, to animate the switching arrays
void DoSwapMotion(Transform a, Transform b)
{
Vector3 posA = a.localPosition;
Vector3 posB = b.localPosition;
TweenParms parms = new TweenParms().Prop("localPosition", posB).Ease(EaseType.EaseOutQuart);
HOTween.To(a, 0.25f, parms).WaitForCompletion();
parms = new TweenParms().Prop("localPosition", posA).Ease(EaseType.EaseOutQuart);
HOTween.To(b, 0.25f, parms).WaitForCompletion();
}
// Swap Two Tile, it swaps the position of two objects in the grid array
void DoSwapTile(GameObject a, GameObject b, ref GameObject[, ] cells)
{
GameObject cell = cells[(int)a.transform.position.x, (int)a.transform.position.y];
cells[(int)a.transform.position.x, (int)a.transform.position.y] = cells[(int)b.transform.position.x, (int)b.transform.position.y];
cells[(int)b.transform.position.x, (int)b.transform.position.y] = cell;
}
// Do Empty Tile Move Down
private void DoEmptyDown(ref GameObject[, ] cells)
{ //replace the empty tiles with the ones above
for (int x = 0; x <= cells.GetUpperBound(0); x++)
{
for (int y = 0; y <= cells.GetUpperBound(1); y++)
{
var thisCell = cells[x, y];
if (thisCell.name == "Empty(Clone)")
{
for (int y2 = y; y2 <= cells.GetUpperBound(1); y2++)
{
if (cells[x, y2].name != "Empty(Clone)")
{
cells[x, y] = cells[x, y2];
cells[x, y2] = thisCell;
break;
}
}
}
}
}
//Instantiate new tiles to replace the ones destroyed
for (int x = 0; x <= cells.GetUpperBound(0); x++)
{
for (int y = 0; y <= cells.GetUpperBound(1); y++)
{
if (cells[x, y].name == "Empty(Clone)")
{
Destroy(cells[x, y]);
cells[x, y] = GameObject.Instantiate(_listOfGems[Random.Range(0, _listOfGems.Length)] as GameObject, new Vector3(x, cells.GetUpperBound(1) + 2, 0), transform.rotation) as GameObject;
}
}
}
for (int x = 0; x <= cells.GetUpperBound(0); x++)
{
for (int y = 0; y <= cells.GetUpperBound(1); y++)
{
TweenParms parms = new TweenParms().Prop("position", new Vector3(x, y, -1)).Ease(EaseType.EaseOutQuart);
HOTween.To(cells[x, y].transform, .4f, parms);
}
}
}
//Instantiate the star objects
void DoShapeEffect()
{
foreach(GameObject row in _currentParticleEffets)
Destroy(row);
for (int i = 0; i <= 2; i++)
_currentParticleEffets.Add(GameObject.Instantiate(_particleEffect, new Vector3(Random.Range(0, _arrayOfShapes.GetUpperBound(0) + 1), Random.Range(0, _arrayOfShapes.GetUpperBound(1) + 1), -1), new Quaternion(0, 0, Random.Range(0, 1000f), 100)) as GameObject);
}
}
A static field can not reference an instance field. What you can do is change _scoreTotal to be a public static.
However it seems like you design is flawed - if you have two instances of Main then you can only have ONE static score variable but TWO _scoreTotal. To which one would you reference? If you can only have one instance of Main then consider changing all your variables to static or make it a Singleton.
I have a monogame project, where I want to move the player based on the the keyboard input. But my code just makes the movement super fast.
I tried around with different speed limits and checked if it might work if with different GameTime properties.
Where is the problem with my code?
public class Map {
private Map() {
Position = new Vector2(0, 0);
}
public string Data { get; set; }
public string[][] MapData { get; set; }
public ContentManager Content { get; set; }
public SpriteBatch SpriteBatch { get; set; }
public Vector2 Position { get; set; }
private Vector2 ArrayPosition;
private readonly int Speed_X = 40;
private readonly int Speed_Y = 32;
public static Map Parse(string path) {
var map = new Map();
var stream = TitleContainer.OpenStream(Path.Combine("Content", path));
using (var sr = new StreamReader(stream)) {
map.Data = sr.ReadToEnd();
}
var lines = map.Data.Split(new string[1] { Environment.NewLine }, StringSplitOptions.None);
var mapHeight = lines.Count();
map.MapData = new string[mapHeight][];
for (int i = 0; i < lines.Count(); i++) {
var elements = lines[i].Split(';');
map.MapData[i] = elements;
}
return map;
}
public void DrawMap(SpriteBatch spriteBatch, ContentManager content, GameTime gametime) {
this.SpriteBatch = spriteBatch;
this.Content = content;
for (int y = 0; y < MapData.Count(); y++) {
var current = MapData[y];
for (int x = 0; x < current.Count(); x++) {
switch (current[x]) {
case "e":
drawEnemy(x, y);
break;
case "P":
case ".":
drawTile(x, y);
break;
case "w":
drawWall(x, y);
break;
}
}
}
drawPlayer();
}
public void Move(Direction pdirection, GameTime gametime) {
var direction = Vector2.Zero;
var speed = Vector2.Zero;
var y = Math.Floor(this.ArrayPosition.Y);
var x = Math.Floor(this.ArrayPosition.X);
switch (pdirection) {
case Direction.Up:
if (y > 0 && y < 16) {
direction = new Vector2(0, -1);
speed.Y = Speed_Y;
}
break;
case Direction.Down:
if (y < 16 && y >= 0) {
direction = new Vector2(0, 1);
speed.Y = Speed_Y;
}
break;
case Direction.Left:
if (x > 0 && x < 16) {
direction = new Vector2(-1, 0);
speed.X = Speed_X;
}
break;
case Direction.Right:
if (x < 16 && x >= 0) {
direction = new Vector2(1, 0);
speed.X = Speed_X;
}
break;
}
ArrayPosition = (this.Position + (direction * speed)) / new Vector2(Speed_X, Speed_Y);
var newPosition = this.Position + (direction * speed * gametime.ElapsedGameTime.Milliseconds);
if (this.MapData[(int)Math.Floor(ArrayPosition.Y)][(int)Math.Floor(ArrayPosition.X)] != "w") {
this.Position = newPosition;
}
}
private void drawPlayer() {
var x = Position.X;
var y = Position.Y;
drawTile((int)x, (int)y);
var texture = Content.Load<Texture2D>("Sprites/player");
this.SpriteBatch.Draw(texture, new Vector2(x, y), Color.White);
}
private void drawEnemy(int x, int y) {
drawTile(x, y);
drawTexture(Content.Load<Texture2D>("Sprites/enemy"), x, y);
}
private void drawTile(int x, int y) {
drawTexture(Content.Load<Texture2D>("Tiles/grass"), x, y);
}
private void drawWall(int x, int y) {
drawTexture(Content.Load<Texture2D>("Tiles/wall"), x, y);
}
private void drawTexture(Texture2D texture, int x, int y) {
var rectangle = new Rectangle(x * 40, y * 32, 40, 32);
this.SpriteBatch.Draw(texture, rectangle, Color.White);
}
}
You should be using the TotalSeconds property instead of Milliseconds in GameTime.ElapsedGameTime. The latter is an int which is not useful for fractional computations whereas the former is a double which is. Due to it being an int it also explains why your movement is very fast.
In your Move() method change this line:
var newPosition = this.Position +
(direction * speed *
gametime.ElapsedGameTime.Milliseconds);
...to:
var newPosition = this.Position +
(direction * speed *
gametime.ElapsedGameTime.TotalSeconds);
However contrary to what the other poster says, it is not necessary to perform a deltatime=0; because ElapsedGameTime is defined as:
The amount of elapsed game time since the last update - MSDN
You don't want to go resetting time intervals as they will just lead to animation which is not particularly smooth.
Tell me more
Your First Game - XNA Game Studio in 2D
use something like this in function Move:
float deltatime=0;
public void Move(Direction pdirection, GameTime gametime) {
deltaTime= (float)gameTime.ElapsedGameTime.TotalSeconds;
//calculate your object position using deltatime
}