C# Platform Collisions Not Working With Multiple Platforms - c#

Right now I'm trying to make a simple game editor in C#, however there's a problem with when the user adds more than one platform to the screen:
private void tmrRunGame_Tick(object sender, EventArgs e)
{
foreach(Platform plat in platList)
{
if (plat.getBounds().IntersectsWith(player.getBounds()))
{
tmrGravity.Stop();
isColliding = true;
}
else
{
isColliding = false;
}
}
if(player.getY() < 500 && !isJumping && !isColliding)
{
tmrGravity.Start();
}
else
{
tmrGravity.Stop();
}
}
This code only stops the user from falling through the last created platform, all of the ones before that the user is able to just fall right through. What makes this all the more confusing is that the program is detecting collisions for all of the platforms, but only doing what it's supposed to for one! It's very frustrating and any help is appreciated.
This is how I'm adding platforms if that helps in any way:
private void pbPlatformSelect_MouseClick(object sender, MouseEventArgs e)
{
Platform plat = new Platform(100, 10, 50, 50);
plat.drawTo(this);
platList.Add(plat);
}

Replace foreach loop with this code:
var playerBounds = player.GetBounds ();
isColliding = platList.Any (plat => plat.GetBounds ().IntersectsWith (playerBounds);
if (isColliding) tmrGravity.Stop ();
if you don't like LINQ, you can change you loop like this:
var playerBounds = player.GetBounds ();
isColliding = false;
foreach (var plat in platList) {
if (plat.GetBounds ().IntersectsWith (playerBounds)) {
isColliding = true;
tmrGravity.Stop ();
break;
}
}

I think you want to break out of the foreach loop once you determine you have collided with something. If you have 3 platforms, and you collide with the first, isColliding is true, but if it doesn't collide with the second platform, it will switch isColliding to false. In the end, whatever the intersection result of the last platform in the list is, is what isColliding's value will be.
So try putting 'break;' right after 'isColliding = true';
This is also an efficiency improvement because if you have 1,000 platforms and the player collides with the first one, we don't really care about the others (from what I can tell) and we save ourselves 999 iterations of the loop.

Related

I want to activate a same animation for few different objects trough FOR loop. Animation don't sync and go in random intervals. Here is the code:

So, firstly, my scene is made out of 9 empty objects each one having spikes that have animation to pop out of the floor. I am making a game where you should avoid spikes and other projectiles. I tested this first with sprite renderer and changing colors, it worked perfectly. But when I want to activate animations using trigger (animations start from empty game state and go to their animations, then after it finishes they return to normal). I've looked trough every thing I could think of and I could not solve this. It always starts animations for 4-6 different animations and start them at the same time, but for some reason: AFTER FIRST SHOWING, every single time after first time spikes appear, 2/3 out of 4/6 always show late but start at same time. Weirdly first time it always works greatly. Any thoughts on what may cause this?
void Update()
{
if (spikeTimer > 0)
spikeTimer -= Time.deltaTime;
if (spikeTimer<0)
{
Function();
spikeTimer = spikeCooldown;
}
}
public void Function()
{
int x = Random.Range(4, 6);
List<int> included = new List<int>();
while (included.Count < x)
{
int y = Random.Range(1, 10);
if (!included.Contains(y))
{
included.Add(y);
}
}
foreach (int i in included)
{
print("aktiviran je broj" + i);
Spikes[i - 1].GetComponent<Spike>().ActivateSpike();
}
}
Now this is the ActivateSpike method that all Spikes in the scene contain
public void ActivateSpike()
{
SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
if (sr.color != Color.black)
{
sr.color = Color.black;
}
else
sr.color = Color.red;
/* Animator animator = gameObject.GetComponent<Animator>();
animator.SetTrigger("Activate");*/
}
You can see that I tried changing the sprite to square and changing its color, and it works perfectly...

How can I fix this bug in my chess game where a move shows up on top of a piece?

I was making a chess game, and all is well except that for example, a pawn, shows a move marker on a piece in front of it (pawns cant move like that). The game won't let you move there, since the move marker code is separate from the actual move code and check.
I have already tried many different approaches, such as iterating through every piece and checking if each piece is in front of the selected piece, as well as making sure that each piece iterated through is not the selected piece.
if (pieceSelected && !finishedPlacingMoveMarkers)
{
if (selectedPiece.GetComponent<BlackPawn>())
{
if (selectedPiece.transform.position.y + 1 <= 3.5)
{
foreach (Transform child in pieces.transform)
{
if (child.tag == "Piece")
{
if (obj.position == new Vector3(selectedPiece.transform.position.x, selectedPiece.transform.position.y + 1) && child.position != selectedPiece.transform.position)
{
if (child.position == new Vector3(selectedPiece.transform.position.x, selectedPiece.transform.position.y + 1))
{
noMoveHighlight = true;
break;
}
else
{
noMoveHighlight = false;
}
}
}
}
if (!noMoveHighlight)
{
GameObject move1 = Instantiate(tileMoveHighlight);
move1.transform.parent = moveTileHighlights.transform;
move1.transform.position = new Vector3(selectedPiece.transform.position.x, selectedPiece.transform.position.y + 1, -0.9f);
}
}
finishedPlacingMoveMarkers = true;
}
}
I expect the results to look like this when i select the pawn:
But they look like this:
Please help!

Moving a object randomly without it being inside a wall - Unity 5

i am trying to make some types of pickups spawn inside a given area, although some usually get stuck within the walls, how would i fix this?
Code in question for moving objects
for (int x = 0; x < garbage.Length; x++)
{
if (x < 5)
{
garbage[x].transform.position = new Vector3(Random.Range(-33.0f, 30.0f), 2.35f, Random.Range(30.0f, -35.0f));
}
}
Fixed it using Physics.OverlapSphere. Thanks.
You could have a while loop inside your if statement, so it would be like
int attempts = 0;
while(garbage[x].transform.position == /*[the range of coordinates for the wall]*/ || attempts = 0)
{
garbage[x].transform.position = new Vector3(Random.Range(-33.0f, 30.0f), 2.35f, Random.Range(30.0f, -35.0f));
attempts += 1;
}
You can try OnCollisionStay to tackle this with collisions. OnCollisionStay can be very cpu heavy if not used carefully, so you may want to think of a better way if you can.
You will have to create a new script using the following code, which you will attach to your power-up prefab.
bool keepChecking = true;
void OnCollisionStay(Collision collision)
{
if(keepChecking)
{
if(collision.gameobject.tag == "Wall")
{
collision.gameobject.transform.position = new Vector3(Random.Range(-33.0f, 30.0f), 2.35f, Random.Range(30.0f, -35.0f));
}
else
{
keepChecking = false;
}
}
}
https://docs.unity3d.com/ScriptReference/Collider.OnCollisionStay.html
Read that link and make sure your objects have all the requirements. Your wall and Power-Up should have colliders, and at least one of these two should have a rigid body. None of these objects should be kinematic.
Let me know if this works for you.

Trigger's not responding how I want in unity 3d

I need help with a game I am creating. I am building the game with the Unity engine and am pretty new to C# coding. I am creating a 2d game where the player controls the color of a square and must change it to the correct color as when it passes a certain colored object. The player changes colors great and the objects are triggers. When a player passes the trigger if its not the right color the player dies. Well that works perfect but only for the first object the next one no matter the color of the player the object dies. I have tried if's in if statements and else if's I can't seem to figure it out. Your help would be greatly appreciated!
Here is the code for the player
void OnTriggerEnter (Collider other)
{
if (other.transform.tag == "Blue") {
blue = true;
}
else {
blue=false;
}
if (other.transform.tag == "Red") {
red = true;
}
else {
red =false;
}
if (other.transform.tag == "Blue" && GameObject.Find ("Blue").GetComponent<Blue> ().mb == false) {
yield return 0;
Die ();
} else if (other.transform.tag == "Red" && GameObject.Find ("Red").GetComponent<Red> ().mr == false) {
Die ();
}
}
Here is the code for each different colored object. This one happens to be blue.
void Update () {
if (GameObject.Find ("Player").GetComponent<Movement> ().blue == true && GameObject.Find ("Player").GetComponent<Movement> ().playerBlue == true) {
mb = true;
} else {
mb = false;
}
if (!GameObject.Find("Player").GetComponent<Movement>().blue) {
mb = false;
}
}
Your execution order is a little messy, that's probably why it's not working. Try to make all your logic follow one path, not two. Right now, you are:
(1)Colliding, (2) setting some boolean variables, (3)checking some variables, (4)optionally dying.
At a separate time in a separate class, set the boolean that was set in step 1 and setting the variable that's checked in step 3
This is what we call spaghetti code. It's all twisted together. Can you think of a way to untangle it, so the two bits of logic don't mutually depend on each other?
For example, I see in the latter block of code, you're checking whether the player is blue. Could you instead run that code when the player sets blue (or sets blue=false)?
Edit: I know this isn't strictly answering your question, but this untangling is the first step of the problem solving process.

Prevent collisions in an animated game

I have been trying to program a way of preventing my character from touching a wall so he couldn't go trough it but I can't find a proper way of doing like you can see in this video (that I recorded). Sorry about the (decent) mic quality : https://youtu.be/jhTSDgSXXa8. Also I said prevent the collision but rather it detects it and stops but you can go through.
The collision code is :
foreach (PictureBox pbMur in pbListeMurs)
{
if (pbCharacterCat.Bounds.IntersectsWith(pbMur.Bounds))
{
if (pbCharacterCat.Right > pbMur.Left)
{
bWalkRight = false;
bIdle = true;
}
}
}
Thank you ! :D
I'm not sure how you are using bIdle and walkRight, but these types of boolean flags are easy to get wrong and it turns your whole code into a complete mess as you typically try to plug holes and end up springing new ones in the process.
First of all, why do you even need them? Wouldn't this be enough?
var newPotentialCharacterBounds =
GetNewBounds(pbCharacterCat.Bounds, movementDirection);
var collidedWalls = pbListeMurs.Where(wall =>
wall.Bounds.IntersectsWith(newPotentialCharacterBounds));
if (!collidedWall.Any())
{
pbCharacterCat.Bounds = newPotentialCharacterBounds
}
//else do nothing
How does this work? Well, the premise is that your character can't start in an invalid position, and if it is never allowed to reach an invalid position then you never need to undo movements or reset positions.
I'd propose you create an enumeration that describes all possible directions:
enum Direction { Up, Down, Left, Right };
When the corresponding direction command is given, get the potential new position of the character (newPotentialCharacterBounds and GetNewBounds). If that position collides with anything, simply do nothing, if it doesn't, move!
UPDATE: Pseudocode follows:
//event handler for move right fires, and calls:
TryMove(pbCharacterCat, Direction.Right)
//event handler for move left fires and calls:
TryMove(pbCharacterCat, Direction.Left)
//etc.
private static Rectangle GetNewBounds(
Rectangle current, Direction direction)
{
switch (direction)
{
case Direction.Right:
{
var newBounds = current;
newBounds.Offset(horizontalDelta, 0);
return newBounds;
}
case Direction.Left:
{
var newBounds = current;
newBounds.Offset(-horizontalDelta, 0);
return newBounds;
}
//etc.
}
//uses System.Linq
private bool TryMove(Control ctrl, Direction direction)
{
var newBounds =
GetNewBounds(ctrl.Bounds, direction);
var collidedWalls = pbListeMurs.Where(wall =>
wall.Bounds.IntersectsWith(newBounds));
if (!collidedWall.Any())
{
ctrl.Bounds = newBounds;
return true;
}
//Can't move in that direction
Debug.Assert(collidedWall.Single); //sanity check
return false;
}
Becuase TryMove returns if the movement was successful or not, now you can leverage that information; different sound effects for instance, etc.

Categories