I am making a game where a player runs around collecting Kiwis. I want the point counter to increment by only one each time. What I have so far is that the pointer increments, but keeps incrementing. i.e. when the player touches a kiwi the counter keeps on increasing by 1.
Here is the Intersect method:
public void Intersect(Rectangle playerRect, SpriteBatch spriteBatch)
{
foreach (Rectangle kiwiRect in kiwiRectangle.Except(collectedKiwis))
{
if (kiwiRect.Intersects(playerRect))
{
collectedKiwis.Add(kiwiRect);
isCollected = true;
}
else
{
spriteBatch.Draw(kiwiTexture, kiwiRect, Color.White);
}
}
}
And here are the Update and Draw methods:
public void Update()
{
points = "Points: " + counter;
if (isCollected)
{
counter++;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.DrawString(pointCounter, points, new Vector2(500, 10), Color.Red);
}
Well, you should check for 2 conditions at least:
If player is currently intersected with kiwi
If that kiwi hasn't already been collected (isCollected prop i suppose)
So if you are intersected and kiwi isn't yet collected, you set isCollected flag and increase counter. On the next Update() run you will skip that kiwi (if you haven't deleted it yet or want to perform some animation) as you've already set isCollected flag, like:
if (Intersect(...) && !isCollected)
{
counter++;
isCollected=true;
}
Though this approach answers your question, i advice you to think about the whole game logic you will want to implement, for ex. how are all of the kiwis will be managed and how to check only active kiwis for intersection to improve performance :)
Related
Context
Hello, currently creating a clone of "Crossy Road" and what I'm trying to do is to spawn my moving object called "Vehicle" at a random speed and rate of spawn. This is also applicable to "Plank", but I will start first with the vehicle. So far, everything is working fine as intended for the game mechanics, but I would like to finalize with this issue so it is fully functional in terms of playability.
Problem
My issue now is I 3 different spawns objects: grass, river, and road. Each object holds other objects (let's call it spawners) depending of what field is being spawn. For example, if grass field object is spawned, it will spawn trees depending in a random varied selection. Another example is with road field. When the road is spawned, a vehicle will be spawned from either left or right in its current initial position. This vehicle will moves as intended with a random speed, but not with the original spawn position and rate (as shown in the GIF. The vehicle spawns in the middle of the road and not in the beginning of the left/right road).
As far I'm aware, my rate is currently unused because it is not the main issue I want to solve. However, the issue now is with the transform position not working as I have pictured in my head. So what is happening is that when the road is spawned again, the vehicle is spawned in the middle of the trajectory instead of resetting to the beginning.
Also, I have noticed that when I print the vehicle object, the Z-axis has a weird number compared to the original position.
Attempts done
I have been thinking that maybe it is the way I have set everything up. I have 4 vehicle objects with a child object called "Tank". However, in each vehicle object, I'm using SetActive(...) only and not really reusing the object itself to the beginning. Later on, I want to organize this spaghetti code and optimize it (e.g ObjectPool to spawn my roads and other GameObjects after hitting a certain range, adding a player range detection to spawn a field to name a few).
To be honest, my whole code feels bloated for something simple. This will be fixed once everything is working accordingly.
Code (DISCLAIMER: there is the possibility that there are unused variables)
SpawnManager.cs (some links provided too from learning to make this)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
** Weighted randomness: https://forum.unity.com/threads/random-numbers-with-a-weighted-chance.442190/
** Scriptable Object Weight spawn example: https://www.youtube.com/watch?v=FCksj9ofUgI&ab_channel=LlamAcademy
** From scratch loot tables with Scriptable Objects to make a loot table: https://www.youtube.com/watch?v=tX3RWsVLnzM&ab_channel=GregDevStuff
** Creating a random with an animation curve: https://www.youtube.com/watch?v=zw1OERK5xvU&ab_channel=HamzaHerbou
** Random Vehicle position spawn (maybe this can help me): https://stackoverflow.com/questions/51312481/move-spawn-object-to-random-position
*/
public class SpawnManager : MonoBehaviour
{
public GameObject Player;
public Spawn[] Field;
public GameObject[] SpawnObjectTrees;
public GameObject[] SpawnObjectVehicles; //different vehicles
public GameObject[] SpawnObjectPlanks; //3 sizes (small, medium, large)
private PlayerControl2 playerControlScript;
private int distancePlayer;
private int toggle;
private bool keepSpawning;
bool vehicleFlag = false;
bool plankFlag = false;
public float randomNumSpawn;
void Awake()
{
keepSpawning = true;
playerControlScript = GameObject.Find("PlayerObject").GetComponent<PlayerControl2>();
InvokeRepeating("Spawner", 3f, randomNumSpawn);
}
void Update()
{
if (Input.GetButtonDown("up") && !playerControlScript.gameOver)
SpawnField();
}
void Spawner()
{
bool activeLeft = false;
bool activeRight = false;
if (vehicleFlag)
{
print(initialObjectSpawn);
for (int i = 0; i < SpawnObjectVehicles.Length; i++)
{
print($"{SpawnObjectVehicles[i]}: {SpawnObjectVehicles[i].transform.position}"); //Here I get the weird position.z values pretty wonky
toggle = Random.Range(0, 2);
if (toggle == 1 && !activeLeft)
{
activeLeft = true;
SpawnObjectVehicles[i].SetActive(true);
}
if (toggle == 0 && !activeRight)
{
activeRight = true;
SpawnObjectVehicles[i].SetActive(true);
}
else
SpawnObjectVehicles[i].SetActive(false);
}
}
}
void SpawnField()
{
//I want to spawn the vehicles, planks, and trees in sets accordingly to the field (grass, river, road)
//For vehicles and planks, they can move horizontally from either -z or z boundaries
//NOTE: keepSpawning may be useless if i have a playerControlScript.gameOver already in here
if (keepSpawning)
{
distancePlayer += 3;
Vector3 intPos = new Vector3(0, 0, 0);
int i = Random.Range(0, 1000);
for (int j = 0; j < Field.Length; j++)
{
if (i >= Field[j].minProbabilityRange && i <= Field[j].maxProbabilityRange)
{
intPos = new Vector3(distancePlayer, -1f, 0);
GameObject Surface = Instantiate(Field[j].spawnField);
if (Surface.CompareTag("Grass"))
TreeToggle();
if (Surface.CompareTag("Road"))
{
vehicleFlag = true;
VehicleToggle();
}
// if (Surface.CompareTag("River")) this will be the same as vehicle
// {
// plankFlag = true;
// PlankToggle();
// }
//Add spawn for vehicles and planks with given spawnrate/spawn intervals
Surface.transform.position = intPos;
vehicleFlag = false;
plankFlag = false;
}
}
}
}
void TreeToggle()
{
int counter = 0;
for (int i = 0; i < SpawnObjectTrees.Length; i++)
{
int toggle = Random.Range(0, 2); //[0, 2)
if (toggle == 1 && counter < 5) //True and when there are already 5-4 trees to toggle
{
counter++;
SpawnObjectTrees[i].SetActive(true);
}
else //fills the rest to inactive Trees
SpawnObjectTrees[i].SetActive(false);
}
}
void VehicleToggle()
{
// I have Left and Right with 2 vehicles in each. My goal is to setActive one of them each side at a time with a different interval spawnrate and speed
Spawner();
}
void PlankToggle()
{
Spawner();
}
}
[System.Serializable]
public class Spawn
{
public GameObject spawnField;
public float minProbabilityRange = 0.0f;
public float maxProbabilityRange = 0.0f;
}
Hierarchy/Inspector
If there is any information you want to know, feel free to ask and I will make a quick edit to fulfill these goals. Again, thank you for your time and appreciate it :D I hope you are having a good day!
I am having a problem retrieving touch input on my XNA game. Here is my starting code:
TouchCollection touchPositions;
List<Vector2> touchReleases = new List<Vector2>();
Then this is my update code:
protected override void Update(GameTime gameTime)
{
// Other update logic here
touchReleases.Clear();
foreach (TouchLocation tl in touchPositions)
{
if (tl.State == TouchLocationState.Released)
touchReleases.Add(tl.Position);
}
base.Update(gameTime);
}
The idea is to load all of the releases into a Vector2 list. Then (during the draw code) a function checks for a release to do stuff.
EDIT: I tested this using Guide.BeginShowMessageBox() during the foreach loop. It popped up every time I released.
bool released = false;
foreach (TouchLocation tl in touchPositions)
{
// checks to see if the button is being hovered on
}
foreach (Vector2 tr in touchReleases)
{
if (PointInArea(tr, new Rectangle((int)position.X, (int)position.Y, buttonimage[0].Width, buttonimage[0].Height)))
{
released = true;
break;
}
}
return released;
The PointInArea function checks to see if a Vector2 is in a Rectangle. I know this function is working right.
What's funny is that the buttons respond to releases about once every 4 taps. Does anyone know why this is?
I have made a game similar to asteroids and I have made an array of Asteroids controlled by an int count which i have made spawn 10 asteroids to the screen when the game starts.
What I'm wondering is how can I get the asteroids to spawn infinitely. I'm thinking of using a loop and have tried:
if (asteroidcount <= 5)
{
asteroidcount += 10;
}
But that doesn't seem to work. I am also using Visual Studio Express C# 2010
I think you need to try a different approach. First you will need an asteroid class where you can store positions and other variables you may need.
public class Asteroid
{
public Vector2 Velocity;
public Vector2 Position;
public Asteroid(Vector2 velocity, vector2 position)
{
Velocity = velocity;
Position = position;
}
}
Now add this List to your game, it will store all the asteroids. The reason I chose this over an array is it is much easier to change the size depending on how many asteroids you have.
List<Asteroid> Asteroids = new List<Asteroid>();
Now you can spawn 10 asteroids like this at the begining of your game
for (int i = 0; i<10;i++)
{
Asteroids.Add(new Asteroid(new Vector2(0,10), new Vector2(50,50)));
}
That will make an asteroid at position 50,50 with velocity of 10, so if you use my update code below it will move down with that velocity.
Now, for your actual problem, we need to spawn more when their are not enough (Player destroyed them I assume)
So, in your update method:
while (Asteroids.Count <5) //If there are less than 5 asteroids, add more
{
Asteroids.Add(new Asteroid(new Vector2(0,10), new Vector2(50,50)));
//Same thing as before, add asteroid
}
And there you go!
Here are some extra tips
If you want to draw all your asteroids, you need to make a method for it
public void DrawAsteroid(Asteroid a)
{
spriteBatch.Draw(ASTEROID TEXTURE, a.Position, Color.White);
spriteBatch.End();
}
now in your Draw() method you can add this
spriteBatch.Begin();
foreach (Asteroid a in Asteroids) //Draw each astroid
{
DrawAsteroid(a);
}
spriteBatch.End();
And you can use a simlar approach if you want to update all of the asteroids.
In Update(),
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
foreach (Asteroid a in Asteroids) //Update each astroid
{
UpdateAsteroid(a, elapsed);
}
And the method,
public void UpdateAsteroid(Asteroid a, float elapsed)
{
a.Position += a.Velocity * elapsed;
}
It's hard to answer without more code or info about how your game works, but a guess would be this: You probably want to put more logic into a larger game loop and add more asteroids in every frame or time step in the game if the amount drops below a certain amount.
bool running = true;
while (running)
{
// Handle input etc
// Handle game logic
// Spawn more asteroids if there are too few of them!
if (asteroidcount <= 5)
{
asteroidcount += 10;
}
// Render
}
I'm having trouble with touch/multitouch input.
I want to draw a small rectangle, 100x100 in dimensions, wherever the user presses (mission accomplished) but I also want them to move as the user moves his fingers (that's not happening atm).
I'm also getting weird behaviour besides the not-moving part, let's say I touch first with my thumb, then with my middle finger. Two cubes appear bellow each finger, but if I remove the finger I place first (thumb in this scenario) the cube under the finger I placed second (middle finger) will disappear and the one where my thumb was will still be there. I guess this issue will solve itself once I get this to update correctly whenever there is movement.
This are the Draw and Update snippets. Any help appreciated:
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
TouchCollection touchLocations = TouchPanel.GetState();
i = 0;
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
pos[i] = touchLocation.Position;
}
i++;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
for (j = 0; j < i; j++)
{
spriteBatch.Draw(whiteRectangle, new Rectangle(((int)pos[j].X - 50), ((int)pos[j].Y - 50), 100, 100), Color.Chocolate);
}
spriteBatch.End();
base.Draw(gameTime);
}
I would recommend using a Dictionary assuming you want to associate touch locations to their position. The key should be the TouchLocation.Id
TouchLocation.Id will remain the same for a given interaction. There is no guarantee that the order of TouchLocations will be the same from one frame to another, so you have to use their ID and not the order they appear in the collection.
I'm a bit late on this, but well here is what was wrong and how I solve it...
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
pos[i] = touchLocation.Position;
}
i++;
}
I guess I was sleepy when I wrote this part of the code (nothing good happens after 2 AM... not even good code) I don't know why I was checking if the location state was pressed... that's why it didn't move when I move... first frame it is indeed pressed but once you start moving it it's .Moved ... all in all, removed that if and it works like a charm...
foreach (TouchLocation touchLocation in touchLocations)
{
pos[i] = touchLocation.Position;
i++;
}
All in all now it behaves as intended.
Cheers!
i just got into game development and XNA and was following a tutorial and decided to try and add in a bound area for a floor. In the tutorial the sprite could move freely and i wanted to have a stopping point for it, so i added a statement to part of the input method
if (aCurrentKeyboardState.IsKeyDown(Keys.Down) == true)
{
if (this.Position.Y == 420)
{
MOVE_DOWN = 0;
mDirection.Y = MOVE_DOWN;
}
else
{
mSpeed.Y = PLAYER_SPEED;
MOVE_DOWN = 1;
mDirection.Y = MOVE_DOWN;
}
}
MOVE_DOWN is my variable for the y change, if it = 0, there is no movement, 1 it moves down, -1 it moves up.
this worked only if the position of the bounds(420) was equal to the position that my sprite started out at, other than that it doesnt work.
i think its because the position isnt updating correctly. i dont know ive tried a lot of things and am pretty new with XNA and game development. Any help would be greatly appreciated.
Here is the update method for my player sprite
public void Update(GameTime theGameTime)
{
KeyboardState aCurrentKeyboardState = Keyboard.GetState();
UpdateMovement(aCurrentKeyboardState);
mPreviousKeyboardState = aCurrentKeyboardState;
base.Update(theGameTime, mSpeed, mDirection);
}
and here is the update for the base class
public void Update(GameTime theGameTime, Vector2 theSpeed, Vector2 theDirection)
{
Position += theDirection * theSpeed * (float)theGameTime.ElapsedGameTime.TotalSeconds;
}
If 'Position' is a Vector2, then it is using floats of the X & Y components.
For practical purposes, a float will rarely equal a whole number due to floating point rounding errors.
if (this.Position.Y == 420)//will never return true
should be changed to:
if (this.Position.Y < 420)
{
this.Position = 420;
//other stuff you have
}