- Home /
2D movement with transform.translate and collision detection...?
Hi there, this might end up as a long question but I'll try to provide as much information as possible.
I'm looking for a bit of help with collision detection. I'm prototyping a 2D top down roguelike. At the moment I have a Player cube that can move up, down, left and right, one square at a time. Every time they move there is a chance to spawn an enemy from an enemyPrefab. If the enemy is within a certain distance of the player, the enemy will move towards the player one square at a time every time the player moves (every turn). This all works reasonably well but all movement is done with transform.translate.
At present the enemies will move towards the player and then come to occupy the same square as the player. What I would like them to do is stop in the adjacent square instead and then spend subsequent turns attacking the player, additionally if the player attempts to move onto the square occupied by the enemy I want them to instead attack the enemy. Once the enemy is dead the player can move over their square.
I'm assuming to do the things I want, I'm going to need collision detection, am I right? After doing some research it would appear that collision detection doesn't seem to work with transform.translate, is that correct?
Does anyone have any advice for how I could proceed?
Thanks.
Answer by DESTRUKTORR · Apr 21, 2013 at 09:16 PM
Check if the distance between the player's position and the enemy's position is equal to the distance for one square. This check will be different, depending on whether diagonal moves are legal, in your game. If they are, it should look something like this:
if(Vector2.Distance(transform.position, player.transform.position) > gridDistance)
{
//move toward player
}
if diagonal movements are -illegal- (in other words, you only want the units moving along the cardinal directions), simply check distance like this:
float xDist = Mathf.Abs(transform.position.x - player.transform.position.x);
float yDist = Mathf.Abs(transform.position.y - player.transform.position.y);
if((xDist > gridDistance && yDist < 0.01f)
|| (yDist > gridDistance && xDist < 0.01f))
{
//move toward player
}
Your second suggestion works excellently for my enemies. They now stop in whatever player adjacent square they land in and i've added a debug log for the moment to say they're attacking. So thank you very much.
$$anonymous$$y problem now is that if I move my player towards the enemy, they will land in the same square as the enemy.
So would I be able to use oncollisionenter to block movement onto an enemy square and ins$$anonymous$$d attack? Or do I need to find a different code solution for my player?
There's a good number of ways you could handle that, just as there are likely several ways to handle the problem I discussed in my answer. Just checking distances tends to be easier, and more reliable than collision checks, I$$anonymous$$O. However, I'm guessing you're saying that if you select the adjacent square (or one within attack range) that is occupied by an enemy, that you want to attack them, in s$$anonymous$$d of moving to that square? Assu$$anonymous$$g you're running this with a 2-directional grid, you may want to use the "On$$anonymous$$ouseDown" method from within a monobehaviour attached to the grid tile. As well, it would simplify the problem if each tile kept track of whether or not a unit occupied its space (and had an object reference to that unit). For example:
void On$$anonymous$$ouseDown()
{
float distance = Vector3.Distance(transform.position, player.transform.position);
if(Input.Get$$anonymous$$ouseDown(0) && distance <= maxDistancePlayerCanTravel)
{
if(occupyingUnit && occupyingUnit is Enemy && distance <= player.maxAttackRange)
{
//Player attacks enemy
}
else if(!occupyingUnit)
{
//Player moves to space
}
else
{
//You would only need this else if there was
//something else to do, here. Otherwise, omit it.
}
}
}
[edit] However, to calculate the distance the player would need to travel, if you're using a 2-directional grid, this can be a bit easier. It would look roughly like this (just calculating distance, not including the rest of the above code):
int distance = (int)$$anonymous$$athf.Abs(this.x - player.currentTile.x + this.y - player.currentTile.y);
Be aware that this will give you the number of tiles needed for the player to move from their current position to the target tile, not the euclidian distance between those tiles (which is what Vector3.Distance(Vector3 start, Vector3 end)
gives us, which is not accurate if diagonal movements are illegal, or if movements are incremented by grid spaces, and not decimal distance).
Your answer
Follow this Question
Related Questions
Enemies Jump at Random with Coroutines 2d (C#) Error. 0 Answers
OnCollision2D will not work for me 1 Answer
Bullet hit the collider of a child object 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers