I have a project in class where I decided to make a DX Ball game in XNA, and have goten along quite well but now I'm stuck.
I have created a list of "bricks", that is rectangles, for my sprites to be positioned by and for my ball to collide with.
I have an idea to let all ball logic be in the ball class so now the fun part that I need help with. How to edit this list when the ball collides with one of the bricks. I want to delete the brick that has been hit, and I figure that will be okay since they are declared as individual bricks with individual coordinates.
I have found this question, and it answers the part of how to get things out of a list but not how to edit it.
Access List from another class
I was thinking about writing a Boolean function in the ball update field, since i don't need it to calculate every time it updates a frame. When collision is true it can cal the function that iterates through the list of bricks and delete the one the ball hit.
I'm not sure what I need to show from my ball class so there might be some if needed later on.
public struct BoundingBrick
{
public Vector2 brickPosision;
public double BrickW;
public double BrickH;
}
public BoundingBrick boundingBrick = new BoundingBrick();
boundingBrick.BrickW = 50;
boundingBrick.BrickH = 20;
boundingBrick.brickPosision.X = 50;
boundingBrick.brickPosision.Y = 50;
bricks = new List<Rectangle>();
for (var i = 0; i < 14; i++)
{
for (var j = 0; j < 12; j++)
{
bricks.Add(new Rectangle((int)boundingBrick.brickPosision.X + j * 50, (int)boundingBrick.brickPosision.Y + i * 20, (int)boundingBrick.BrickW, (int)boundingBrick.BrickH));
}
}
I've done this:
List bricks
Rectangle ball;
foreach (BoundingBrick brick in bricks.ToArray())
{
if (ball.rect.Intersects(brick.rect))
{
ball.CollideEffect();
brick.TakeDamage();
}
}
and in the TakeDamage Class from the brick:
public void TakeDamage(List<BoundingBrick> bricks)
{
lives -= 1;
if (lives <= 0)
{
bricks.remove(this)
}
}
The 'ToArray()' part will prevent it from crashing in the list.
Related
I want an array of game objects, each game object has a simple script to move it. I want a controlling script to be able to trigger the remote script by referencing the array coordinates / game object at that point.
I am missing something basic in referencing a "global" variable - so apologies in advance. I have spent several hours now reading and trying things out.
Example questions like here Accessing a variable from another script C#
or
https://answers.unity.com/questions/42843/referencing-non-static-variables-from-another-scri.html
I believe the array should be static as there is only one set of data, however I don't care if it isnt
CreateGrid.cs
public class CreateGrid : MonoBehaviour
{
public static GameObject[,] gridArray = new GameObject[5, 5];
public GameObject gridSpace;
// Start is called before the first frame update
void Start()
{
GenerateGrid();
}
void GenerateGrid()
{
for (int x = 0; x < 5; x++)
{
for (int z = 0; z < 5; z++)
{
gridArray[x, z] = Instantiate(gridSpace, new Vector3(x, 0, z), Quaternion.identity) as GameObject;
}
}
// test grid works
// gridArray[2, 2].transform.Translate(0.0f, 3.0f, 0.0f);
}
}
test code
public class Pulse : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
for (int x = 0; x < 5; x++)
{
CreateGrid.gridArray[x, 3].GetComponent<MoveObject>().StartBounce(5.0f);
}
}
}
The grid of objects works.
However the test code errors with Object reference not set to an instance of an object from the line
CreateGrid.gridArray[x, 3].GetComponent().StartBounce(5.0f);
specifically CreateGrid.gridArray
Given that I seem to be really struggling with a concept, please explain clearly.
Thanks
Unless you don't clearly define otherwise, you don't know when the Start method of two MonoBehaviours will run.
In your case, the Pulse's Start method is called before CreateGrid's.
To fix your problem, I advise you to call CreateGrid's Generate method inside the Awake method of the class.
I often use this method to initialize members of the class not relying on other classes instances and use the Start method to initialize members needing other instances to be self-initialized.
I'm working on a small game project for school in UNITY, specifically a clone of a snake game called Rattler Race. I'm pretty much a complete beginner with the engine, hence why I'm struggling a bit. The game we're suppose to make has to have 30 unique levels that have ascending complexity, something like this: Final level
My main problem at the moment is spawning food for the snake so it doesn't overlap with any inner walls or the borders.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnFood : MonoBehaviour
{
public GameObject FoodPrefab;
public Transform BorderTop;
public Transform BorderBottom;
public Transform BorderLeft;
public Transform BorderRight;
public Transform Obstacle;
Vector2 pos;
// Use this for initialization
void Start ()
{
for (int i = 0; i < 10; i++) {
Spawn();
}
}
void Spawn()
{
pos.x = Random.Range(BorderLeft.position.x + 5,BorderRight.position.x - 5);
pos.y = Random.Range(BorderBottom.position.y + 5, BorderTop.position.y - 5);
Instantiate(FoodPrefab, pos, Quaternion.identity);
}
// Update is called once per frame
void Update ()
{
}
}
The code is very simple ofcourse because at the moment the game field is empty with no obstacles:
Current state
However my problem is if I was to scale up that tiny red obstacle, like so:
Big Obstacle
The food would spawn behind it(every level has 10 food objects) and be impossible to get. My idea was to build levels off of one object(the "Obstacle") and its copies, I don't really know if that idea is sound yet but I wanted to try.
If theres any way or any method to spawn food objects in locations so they don't overlap with the obstacle, like to check if the space is already occupied or a method that checks if a would be food object intersects with an existing obstacle, I would be very grateful if someone teaches me, because I'm really lost at the moment.
Assuming your food is exactly one unit long, you could have a coroutine which would check if there is something around that food gameObject, if there isn't anything, you can spawn it.
public LayerMask layerMask; //Additional variable so you can control which layer you don't want to be detected in raycast
void Spawn(){
StartCoroutine(GameObjectExists());
}
IEnumerator GameObjectExists(){
do{
yield return null;
pos.x = Random.Range(BorderLeft.position.x + 5,BorderRight.position.x - 5);
pos.y = Random.Range(BorderBottom.position.y + 5, BorderTop.position.y - 5);
}while(Physics2D.OverlapCircle(new Vector2(pos), 1f, layerMask); //1f is the radius of your food gameObject.
Instantiate(FoodPrefab, pos, Quaternion.identity);
yield return null;
}
I need to draw a graph for my decibel app that I am making with Unity. The solution below works but is not as exact as my employer would like. Could I make this graph look more professional and exact? Basically I want the lines to be of equal width and prevent the line from going almost invisible like in the following pic: http://puu.sh/qjSvO/a51c11cef5.png
I was thinking about making a 2D texture and using SetPixel, but I am not sure if that is the correct way.
The graph is drawn on a canvas as part of an scalable UI.
public class Graph : MonoBehaviour {
public float graphWidth;
public float graphHeight;
LineRenderer newLineRenderer;
List<int> decibels;
int vertexAmount = 50;
float xInterval;
GameObject parentCanvas;
// Use this for initialization
void Start ()
{
parentCanvas = GameObject.Find("Canvas");
graphWidth = transform.Find("Linerenderer").GetComponent<RectTransform>().rect.width;
graphHeight = transform.Find("Linerenderer").GetComponent<RectTransform>().rect.height;
newLineRenderer = GetComponentInChildren<LineRenderer>();
newLineRenderer.SetVertexCount(vertexAmount);
xInterval = graphWidth / vertexAmount;
}
//Display 1 minute of data or as much as there is.
public void Draw(List<int> decibels)
{
if (decibels.Count == 0)
return;
float x = 0;
for (int i = 0; i < vertexAmount && i < decibels.Count; i++)
{
int _index = decibels.Count - i - 1;
float y = decibels[_index] * (graphHeight/130); //(Divide grapheight with the maximum value of decibels.
x = i * xInterval;
newLineRenderer.SetPosition(i, new Vector3(x - graphWidth / 2 , y - graphHeight / 2 , 0));
}
}
}
Using the editor, you can "cut" sprites into nine pieces, so that there is a texture for each side, a texture for each corner and a texture to fill it in. I would recommend using that to make it look good if you want it so. It is some time since i used it myself, but maybe you can find information on the Unity manual.
I have an object that will fire out projectiles, I was trying to use a list to spawn in the Rockets(projectiles) so I could delete them when they collide with an object. So I first create List<Rectangle> Rockets; I then add in a function for the rockets to be spawned in and fired constantly:
if (Time > 0.2)
{
Time = 0;
Rockets.Add(new Rectangle((int)Position.X, (int)Position.Y, rocketTexture.Width, rocketTexture.Height));
}
I then try to update them so they will move across the screen by doing a foreach:
foreach (Rectangle r in Rockets)
{
}
Question
This is where I get stuck, how do I call upon the x and y value inside the list of each Rocket so i can move it across the screen?
I may be thinking too hard about this and there is an easier way to create a large amount of projectiles and have them despawn when colliding with a way or when they go too far.
In game development, you'd rather implement a Rocket class with a update() method, in which you'd move the rocket by some speed_x and speed_y attribute. You would then in your main run() method check collisions by calling Rocket.getRect() (or just a .Rect property, which could be implemented in a parent class Entity or something).
That being said, i may not have understood the problem.
Here's a code example, hope it helps
class Rocket
{
int _life;
public Rocket(Vector2 position, Vector2 direction)
{
_position = position;
_direction = direction;
//life of rocket. Once it reaches zero the rocket is removed.
_life = 100;
}
Vector2 _position
public Vector2 Position
{
get
{
return _position;
}
}
Vector2 _velocity;
Vector2 Velocity
{
get
{
return _velocity;
}
}
public int Life
{
get
{
return _life;
}
}
public void Update(World world)
{
_life--;
_position += _velocity;
//could check for collisions here, eg:
foreach (Ship ship in world.Ships)
{
if (Intersects(ship))
{
//collision!
//destroy this rocket
_life = 0;
//damage the ship the rocket hit
ship.ApplyDamage(10);
return;
}
}
}
}
class Game
{
List<Rocket> _rockets = new List<Rocket>();
List<Rocket> _deadRockets = new List<Rocket>();
void Update(GameTime gameTime)
{
//.ToArray() is used here because the .net list does not allow items to be removed while iterating over it in a loop.
//But we want to remove rockets when they are dead. So .ToArray() means we are looping over the array not the
//list, so that means we are free to remove items from the list. basically it's a hack to make things simpler...
foreach (Rocket rocket in _rockets.ToArray())
{
//world is an object that contains references to everything on the map
//so that the rocket has access to that stuff as part of it's update
rocket.Update( world );
//if the rocket has run out of life then remove it from the list
if (rocket.Life <= 0)
_rockets.Remove(rocket);
}
}
void FireRocket(Vector2 from, Vector2 direction)
{
Rocket newRocket = new Rocket(from, direction);
_rockets.Add(newRocket);
}
}
do a for loop instead of a foreach loop. I also recommend using arrays(and make a Rocket class instead of just Vector2s).
for (int i = 0; i < Rockets.Count; i++)
{
Rockets[i] = new Rectangle(Rockets[i].X + 20, Rockets[i].Y + 20);
}
I am making asteroids, and I need them to rotate at different rates and directions to give the effect I want. Instead of creating 10+ different things for each one, I tried to do the
for (int i = 0; i < 25; i++)
{
AsteroidPositions[i] = new Vector2(1 * random.Next(800), 1 * random.Next(600));
}
and that seems to work out nicely for randomly generated positions. I can have 25 randomly generated asteroids on screen in different places at once. What it doesn't work for is the rotation, because it is a float and not a Vector2. I have tried to do something like this:
AsteroidRotation = MathHelper.Lerp(-0.5f, +0.5f, (float)random.NextDouble());
but that gives me the error of all of the on screen rocks randomly facing a single direction. and the same one as well. I can not add [i] to it because it says that it can not convert float to float[]. I also have this for the spriteBatch:
for (int i = 0; i < 25; i++)
{
spriteBatch.Draw(AsteroidTexture,
AsteroidPositions[i],
AsteroidSourceLocation,
Color.White,
AsteroidRotation,
AsteroidSourceOrigin,
1.0f,
SpriteEffects.None,
AsteroidLocation.Y / 720.0f);
}
so is there any way of me doing this? should I not be using the [i] method and use an array? if so, how?
Straight off the bat I would say using variables instead of a class to represent your asteroid is probably not a good idea. You mention in your title that what you have here is a duplicated object - this isn't even the case as you are not using any objects! Since, in your mind, you are visualising this asteroid as an object, you should be using a Class to contain it.
The reason why all of your asteroids face the same direction is because AsteroidRotation = MathHelper.Lerp(-0.5f, +0.5f, (float)random.NextDouble()); is a single value, the same value you use for every asteroid's rotation.
Equally, you can not simply use AsteroidRotation[i] as this would mean that AsteroidRotation is a collection of rotations where you can to access the i th value in your collection by using [i]. It is not a collection, it's a single float value.
Two ways of solving this:
1) Quick and easy. Not recommended. Not future proof. Will lead to bad habits.
Make your rotation values an array.
float[] asteroidRotation = new float[25];
for (int i = 0; i < 25; i++)
{
asteroidRotation[i] = MathHelper.ToRadians(random.Next(360));
// ToRadians() important, XNA does not work in degrees.
}
And then in your drawing code you need to use:
spriteBatch.Draw(AsteroidTexture,
AsteroidPositions[i],
AsteroidSourceLocation,
Color.White,
AsteroidRotation[i],
AsteroidSourceOrigin,
1.0f,
SpriteEffects.None,
AsteroidLocation.Y / 720.0f);
2) Create an Asteroid class. Good practice. Uses object-oreintated nature of C# / .Net.
Create an asteroid class which contains all the data and relevant methods for each. This combats your "instead of creating 10+ different things for each one".
A very quick class setup but it will get the job done:
public class Asteroid
{
public Texture2D Texture { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public float Rotation { get; set; }
public Rectangle SourceLocation { get; set; }
public Vector2 SourceOrigin { get; set; }
public Asteroid()
{
}
public void Draw(SpriteBatch sb)
{
sb.Draw(
Texture,
Position,
SourceLocation,
Color,
Rotation,
SourceOrigin,
1.0f,
SpriteEffects.None,
0f);
}
}
Create a list of asteroids and fill the list:
List<Asteroid> asteroids = new List<Asteroid>();
int numAsteroids = 25;
for (int i = 0; i < numAsteroids; i++)
{
Asteroid asteroid = new Asteroid();
asteroid.Texture = asteroidTexture;
asteroid.Position = new Vector2(1 * random.Next(800), 1 * random.Next(600));
asteroid.Color = Color.White;
asteroid.Rotation = MathHelper.ToRadians(random.Next(360));
asteroid.SourceLocation = new Rectangle(0, 0, 0, 0); // Fill me in
asteroid.SourceOrigin = new Vector2(0, 0); // Fill me in
asteroids.Add(asteroid);
}
Make sure you do this only once, ideally in other your game's LoadContent() or Initialize() method!
Then to draw:
foreach (Asteroid asteroid in asteroids)
{
asteroid.Draw(spriteBatch);
}
And that should be it. I don't think I've missed anything!
In the future this allows you to expand upon what asteroids can do extremely easily. You could create an Update() method that controls rotational speeds; have the asteroid move by giving them their own velocity.