Unity 2D Platformer - making my enemy not see through walls - unity3d

basicly i'm searching for an idea. How to make my Enemy patroling, but when it reaches the Player - it rush and deal damage, but in the same time when it reach the wall and player is standing behind the wall it Don't attack. You know - i don't want to let them see through walls.
I have made simple Game Object (rectangle) to point it's sight, it is working correctly but i want to improve some of it.
To make it quckier... i just want to make my enemies attack me but to not seen me througth walls
Some code:
[DamageFromEnemy.cs]
private void FixedUpdate()
{
isThatPlayer = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, PlayerLayer);
isThatWall = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, gameObject.GetComponent<EnemyScript>().WallLayer);
if (isThatWall == true && gameObject.GetComponent<EnemyScript>().movingRight == true)
{
PlayerDetector.transform.Translate(new Vector3(changePosX, 0, 0));
//playerDetectX -= PlayerDetector.transform.position.x; // Lowering size. Not Working
changePosX = (playerDetectX / 2) * (1 / enemyScaleX) + (enemyScaleX / 2) * (1 / enemyScaleX);
Debug.Log("pozycja x: " + changePosX);
}
if (isThatWall == true && gameObject.GetComponent<EnemyScript>().movingRight == false)
{
PlayerDetector.transform.Translate(new Vector3(- changePosX, 0, 0));
//playerDetectX -= PlayerDetector.transform.position.x; // Lowering size. Not Working
changePosX = (playerDetectX / 2) * (1 / enemyScaleX) + (enemyScaleX / 2) * (1 / enemyScaleX);
Debug.Log("pozycja x: " + changePosX);
}
DetectPlayer();
AttackTimer();
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(PlayerDetector.position, new Vector3(playerDetectX, playerDetectY));
}
[EnemyScript.cs]
void Update ()
{
trap = Physics2D.OverlapCircle(ColideDetector.position, detectorRadius, TrapLayer);
otherEnemy = Physics2D.OverlapCircle(ColideDetector.position, detectorRadius, EnemyLayer);
if (health <= 0)
{
Destroy(gameObject);
}
transform.Translate(Vector2.right * speed * Time.deltaTime );
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, distance);
RaycastHit2D wallInfoR = Physics2D.Raycast(wallDetection.position, Vector2.right, distance, WallLayer);
RaycastHit2D wallInfoL = Physics2D.Raycast(wallDetection.position, Vector2.left, -distance, WallLayer);
if (groundInfo.collider == false || trap == true || otherEnemy == true || wallInfoR == true || wallInfoL == true)
{
if(movingRight == true)
{
transform.eulerAngles = new Vector3(0, -180, 0);
movingRight = false;
}
else
{
transform.eulerAngles = new Vector3(0, 0, 0);
movingRight = true;
}
}
}
Some Gif Feedback
At last gifs frames you can see that it bugs sometimes.
public PlayerControls player;
public LayerMask WallLayer;
player = FindObjectOfType<PlayerControls>();
RaycastHit2D checkWallsToHero = Physics2D.Raycast(wallToHeroRay.position, player.transform.position, 150,WallLayer);
if (checkWallsToHero == true)
{
playerCheck = false;
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(PlayerDetector.position, new Vector3(playerDetectX, playerDetectY));
Gizmos.DrawLine(wallToHeroRay.position, player.transform.position);
}
[New Code sample - propably wrong]:
isThatPlayer = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, PlayerLayer);
isThatWall = Physics2D.OverlapBox(PlayerDetector.position, new Vector2(playerDetectX, playerDetectY), 0, gameObject.GetComponent<EnemyScript>().WallLayer);
RaycastHit2D checkWallsToHero = Physics2D.Raycast(wallToHeroRay.position, player.transform.position, 0, gameObject.GetComponent<EnemyScript>().WallLayer);
if (checkWallsToHero.collider != true /*&& isThatPlayer == true*/)
{
Debug.Log("Pierwszy state");
Debug.Log(checkWallsToHero.collider);
//Debug.Log(isThatPlayer);
//Debug.Log("Hit: " + checkWallsToHero.collider.gameObject.name);
playerCheck = false;
enemyAttackReady = false;
coolDownTimer = 0;
enemyAttackCD = 0;
}
else if (checkWallsToHero.collider == true && isThatPlayer == true)
{
Debug.Log(checkWallsToHero.collider);
Debug.Log("Drugi state");
ReadyToAttack(); //charging enemy
DetectPlayer(); //bool to true when OverlapBox hits player
AttackTimer(); //cd between enemy attacks
}

if (Physics2D.Raycast2D
(wallToHeroRay.position,player.transform.position,out hit,10)
&&hit.transform.gameObject.tag == "Player")
{
RayHit = true;
}
else {
RayHit = false;
}
to use this you will have to tag your player as 'Player' then your ray will only give you a hit if it hits the player itself, and not a wall
Edit: this is code i threw together following #Draco18s's idea in the comments, if it works for you, tell him thank you. i just thought it made enough sense he should have put it as an answer

Related

Unity2D inconsistent AddForce

I just recently asked another question and I got answered really quick so I hope its the same with this one. Anyway, I'm making this 2D platformer (super-meat-boy like) and I've added in this cool 'Dash' ability which is triggered when you press Shift. It would add an x-axis force and a little bit of some y-axis force to give it more of a jump-like feel. However, the AddForce function is so inconsistent in the game. Sometimes, the y-axis force is larger than the x-axis and sometimes the x-axis is increased by half(??). The only reason I can think of why this happens is because I have increased the gravity for proper unrealistic but good looking jumping and slightly more increased when the player dashes. Or could it be that when I dash at the peak of my jump, there's a stronger force as compared to in the beginning of the dash? I'm so confused.
Here is everything that in the update() function.
void Update()
{
//Flipping and moving lightfeet
if (Input.GetKey(KeyCode.A))
{
anim.SetFloat("Horizontal", 1);
x = -1;
scale.x = -4;
rb.velocity = new Vector2(-speed, rb.velocity.y);
}
else if (Input.GetKey(KeyCode.D))
{
anim.SetFloat("Horizontal", 1);
x = 1;
scale.x = 4;
rb.velocity = new Vector2(speed, rb.velocity.y);
}
else //no keys pressed
{
anim.SetFloat("Horizontal", 0);
rb.velocity = new Vector2(0f, rb.velocity.y);
anim.SetBool("Sprint", false); //even after sprinting and then stopping before to jump, sprint anim wont play
}
transform.localScale = scale;
//Accumulating jump charge and increasing speed!
if (Input.GetKey(KeyCode.Space) && rb.velocity.y == 0f) //only if space is held down and there is no vertical movement
{
jumpAccumulator += Time.deltaTime * 25f; //accumulates jump power over time
if (jumpAccumulator >= maxJumpAccumulator) //maximum jump power
{
jumpAccumulator = maxJumpAccumulator;
}
speed *= sprintSpeed; //increase speed when charging up
if(speed >= maxSpeed) //maximum speed
{
speed = maxSpeed;
}
}
//Ground detection
groundHit = Physics2D.BoxCast(bcollider.bounds.center, bcollider.bounds.size, 0f, Vector2.down, 0.1f ,groundmask);
mapHit = Physics2D.BoxCast(bcollider.bounds.center, bcollider.bounds.size, 0f, Vector2.down, 0.1f, mapMask);
if (groundHit.collider != null || mapHit.collider != null) //When you on the ground!
{
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", false);
anim.SetBool("Dashed", false);
anim.SetBool("Fall", false);
canJump = true;
canDoubleJump = true;
canDash = false;
rb.gravityScale = 15; //nomral gravity scale
//animations for running or sprinting
if (speed <= initialspeed)
{
anim.SetBool("Sprint", false);
}
else if (speed > initialspeed && rb.velocity.x > initialspeed && rb.velocity.y == 0 || speed > initialspeed && rb.velocity.x < -initialspeed)
{
anim.SetBool("Sprint", true);
}
}
else if (groundHit.collider == null || mapHit.collider == null) //if LF is not on ground!
{
canJump = false;
anim.SetFloat("Horizontal", 0f);
}
//falling without jumping
if (rb.velocity.y < 0 && anim.GetBool("Jumped") == false && anim.GetBool("DoubleJumped") == false && anim.GetBool("Dashed") == false)
{
anim.SetBool("Fall", true);
anim.SetBool("Sprint", false);
canDash = true;
}
JumpDash();
}
void JumpDash()
{
//Jump
if (Input.GetKeyUp(KeyCode.Space) && canJump == true)
{
rb.velocity = Vector2.up * (jumpForce + jumpAccumulator);
anim.SetBool("Jumped", true);
anim.SetBool("DoubleJumped", false); //setting false to prevent bugs
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
canDash = true;
jumpAccumulator = 1;
}
//Double Jump
if(Input.GetKeyDown(KeyCode.W) && canJump == false && canDoubleJump == true)
{
rb.velocity = Vector2.up * jumpForce;
canDoubleJump = false;
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", true);
anim.SetBool("Dashed", false); //disabling dash animation so it doesn't play when dashing then double jumping (because conditions for both can be true at the same time)
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
anim.SetBool("Fall", false);
doubleJumpFX.Play();
DashFX.Stop();
}
//Dash
if(Input.GetKeyDown(KeyCode.LeftShift) && canDash == true)
{
rb.AddForce(new Vector2(dashForce * x, dashUpForce), ForceMode2D.Impulse);
rb.gravityScale += dashGravity; //increasing gravity for dashing
canDash = false;
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", false);
anim.SetBool("Dashed", true);
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
doubleJumpFX.Stop();
DashFX.Play();
}
}
void OnCollisionEnter2D(Collision2D collision)
{
Debug.Log("Collider: " + collision.collider.name);
if (collision.collider.name == "platform" || collision.collider.name == "mapColliders")
{
speed = initialspeed; //set speed to normal on hitting the ground (difference between this and raycast is this returns true for only one frame)
anim.SetBool("Dashed", false); //setting false to this anim here again to prevent buggy animations
anim.SetBool("Fall", false);
doubleJumpFX.Stop();
DashFX.Stop();
}
if (collision.collider.name == "Respawn area")
{
transform.position = new Vector2(-13f, 4f);
}
}
The inconstancy of AddForce is because you are adding onto the player's existing force. Have you tried cancelling out existing forces before calling AddForce? Just add the following line
rb.velocity = new Vector2 (0, 0);
in front of the AddForce function. Your dash function should look like this
//Dash
if(Input.GetKeyDown(KeyCode.LeftShift) && canDash == true)
{
rb.velocity = new Vector2 (0, 0);
rb.AddForce(new Vector2(dashForce * x, dashUpForce), ForceMode2D.Impulse);
rb.gravityScale += dashGravity; //increasing gravity for dashing
canDash = false;
anim.SetBool("Jumped", false);
anim.SetBool("DoubleJumped", false);
anim.SetBool("Dashed", true);
anim.SetBool("Sprint", false); //setting false to sprint here as well just to prevent bugs
doubleJumpFX.Stop();
DashFX.Play();
}

Move Object around a platform of tiles in Unity

I want to make a spinning spike to move around a platform made out of tiles like in the following
I have written every possible state on where to move when platform tiles block the spike's way. It would look something like this
for (int i = 0; i < platformTileMap.Length; i++)
{
if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(0, -1, 0))) // BOTTOM
{
moveX = moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(0, 1, 0))) // TOP
{
moveX = -moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(-1, -1, 0))) //BOT LEFT
{
if (moveDir == 1)
{
moveY = -1;
}
else moveX = moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(1, 1, 0))) //TOP RIGHT
{
if (moveDir == 1)
{
moveY = 1;
}
else moveX = -moveDir;
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(1, -1, 0))) // BOT RIGHT
{
if (moveDir == 1)
{
moveX = moveDir;
}
else
{
moveY = -1;
}
}
else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(-1, 1, 0))) // TOP LEFT
{
if (moveDir == -1)
{
moveY = 1;
}
else
{
moveX = -moveDir;
}
}
I feel like there has to be a more efficient way to solve this. Do I really have to write every possibility in if statements? Can I achieve this with pathfinding?
How about this
Use raycast
Place Empty GameObject and rotate spike when it arrives them
You could create an array of points to move to.
public Vector3[] movePoints;
You can set movePoints in inspector or in code (such as Start function) user choice
In the update loop lerp to the next point in sequence, when arrived pull the next point, unless we are at the end of the array then pull the first point in the array, rinse and repeat forever.
https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
Set this up properly once, when you make more blades and different configurations or want to change speed it will be ez pz.
For anyone interested. Here is how i solved it:
GridLayout platformGridLayout;
Grid platformGrid;
Tilemap[] platformTileMap;
[SerializeField] float rotationSpeed;
[SerializeField] float moveSpeed;
[SerializeField] private LayerMask platformLayerMask;
Vector3Int startPos;
Vector3Int currentCellPosition;
Vector3 raycastPlatformDir;
Vector3 raycastMoveDir;
float platformRaycastDist;
// Start is called before the first frame update
void Start()
{
movePoints = new List<Vector3Int>();
platformGridLayout = transform.parent.GetComponentInParent<GridLayout>();
platformGrid = transform.parent.GetComponentInParent<Grid>();
startPos = platformGridLayout.WorldToCell(transform.position);
Debug.Log("Cell Startposition: " + startPos);
PlatformToMoveOn();
GetStartRaycastDir();
platformRaycastDist = platformGridLayout.cellSize.x;
Debug.Log("CellCenterToWorld of Startposition: " + platformGrid.GetCellCenterWorld(startPos));
Debug.Log(platformGrid.GetCellCenterLocal(currentCellPosition + Vector3Int.FloorToInt(raycastPlatformDir) + Vector3Int.FloorToInt(raycastMoveDir)));
}
private void PlatformToMoveOn()
{
platformTileMap = new Tilemap[2];
platformTileMap[0] = GameObject.Find("Platform").GetComponent<Tilemap>();
platformTileMap[1] = GameObject.Find("MovingPlatform").GetComponent<Tilemap>();
}
private void GetStartRaycastDir()
{
for (int i = 0; i < platformTileMap.Length; i++)
{
if (platformTileMap[i].HasTile(startPos + new Vector3Int(0, -1, 0))) // BOTTOM
{
raycastPlatformDir = Vector3.down;
}
else if (platformTileMap[i].HasTile(startPos + new Vector3Int(0, 1, 0))) // TOP
{
raycastPlatformDir = Vector3.up;
}
else if (platformTileMap[i].HasTile(startPos + new Vector3Int(1, 0, 0))) // RIGHT
{
raycastPlatformDir = Vector3.right;
}
else if (platformTileMap[i].HasTile(startPos + new Vector3Int(-1, 0, 0))) // LEFT
{
raycastPlatformDir = Vector3.left;
}
}
raycastMoveDir = Quaternion.Euler(0, 0, 90) * raycastPlatformDir * Mathf.Sign(moveSpeed);
//raycastMoveDir = new Vector3(raycastPlatformDir.y, raycastPlatformDir.x) * Mathf.Sign(moveSpeed);
}
// Update is called once per frame
void Update()
{
MoveSpike();
}
private void MoveSpike()
{
currentCellPosition = platformGridLayout.WorldToCell(transform.position); // + raycastPlatformDir * platformGridLayout.cellSize.y / 2;
// Debug.Log(cellPosition);
//Debug.Log(raycastMoveDir);
transform.Rotate(0, 0, 300 * rotationSpeed * Time.deltaTime);
RaycastHit2D raycastMove = Physics2D.Raycast(platformGrid.GetCellCenterLocal(currentCellPosition),raycastMoveDir,0.01f,platformLayerMask);
RaycastHit2D raycastPlatform = Physics2D.Raycast(platformGrid.GetCellCenterLocal(currentCellPosition), raycastPlatformDir, platformRaycastDist, platformLayerMask);
Debug.DrawRay(transform.position, raycastMoveDir * 0.01f, Color.red);
Debug.DrawRay(transform.position, raycastPlatformDir * platformRaycastDist, Color.green);
if (currentCellPosition != startPos) { // Check on Platform corners
Debug.Log("Checking");
if (raycastMove.collider != null)
{
// reassign raycastsdirections
RotateRaycastDirections(1);
Debug.Log("Spike Collision");
}
else if (raycastPlatform.collider == null)
{
RotateRaycastDirections(-1);
Debug.Log("Spike on Platform");
}
startPos = currentCellPosition;
}
/*transform.position = Vector3.MoveTowards(transform.position,
platformGrid.GetCellCenterLocal(currentCellPosition + Vector3Int.FloorToInt(raycastPlatformDir) + Vector3Int.FloorToInt(raycastMoveDir)), moveSpeed * Time.deltaTime); */
transform.Translate(raycastMoveDir.x * Mathf.Abs(moveSpeed) * Time.deltaTime, raycastMoveDir.y * Mathf.Abs(moveSpeed) * Time.deltaTime, 0, Space.World);
}
private void RotateRaycastDirections(int angle)
{
raycastPlatformDir = Quaternion.Euler(0, 0, 90) * raycastPlatformDir * angle * Mathf.Sign(moveSpeed);
raycastMoveDir = Quaternion.Euler(0, 0, 90) * raycastMoveDir * angle * Mathf.Sign(moveSpeed);
// raycastPlatformDir = new Vector3(raycastPlatformDir.y, raycastPlatformDir.x) * angle;
//raycastMoveDir = new Vector3(raycastMoveDir.y, raycastMoveDir.x) * -angle;
}
Edit:
This doesnt work on moving Platforms though. Any ideas how i could fix that? I tried changing the raycast position to the tilemapscentercell position but it doesnt work.

Collider triggers firing on launch

I have a "zone", with four borders; north, east, south and west. On these borders, I have 2d colliders, like this :
So, on a zone, I would have four instances of this, for each border. In the script for GridBorderController, I have this :
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == Const.TAG_PLAYER)
{
print("enter " + gridBorderSide.ToString());
/*var pos = new Vector3(20, 20, 0);
var zoneInstance = Instantiate(this, pos, Quaternion.identity, this.transform);
var tileMaker = zoneInstance.transform.GetChild(0);
var terrainDrawer = tileMaker.GetComponent<TerrainDrawer>();
print(terrainDrawer.sprites.Length);*/
}
}
When I launch the game, I create an instance of this zone, and this is what I get in my console :
This is how I start the controller :
void Start()
{
boxCollider2D = GetComponent<BoxCollider2D>();
terrainDrawer = GetComponentInParent<TerrainDrawer>();
collider = GetComponent<Collider2D>();
collider.enabled = false;
var gridRadius = terrainDrawer.gridRadius;
float borderOffset = borderWidth / 2;
switch (gridBorderSide)
{
case GridBorderSide.North:
case GridBorderSide.South:
{
boxCollider2D.size = new Vector2(gridRadius/2 , borderWidth);
if(gridBorderSide == GridBorderSide.North)
{
boxCollider2D.transform.position += new Vector3(0, (gridRadius / 4) - (borderOffset));
}
else
{
boxCollider2D.transform.position -= new Vector3(0, (gridRadius / 4) - (borderOffset));
}
break;
}
case GridBorderSide.East:
case GridBorderSide.West:
{
boxCollider2D.size = new Vector2(borderWidth, gridRadius / 2);
if (gridBorderSide == GridBorderSide.East)
{
boxCollider2D.transform.position += new Vector3((gridRadius / 4) - (borderOffset), 0 );
}
else
{
boxCollider2D.transform.position -= new Vector3((gridRadius / 4) - (borderOffset), 0);
}
break;
}
}
collider.enabled = true;
}
When I walk over the collider with my player, it does fire as well, so I know that part works, but can anyone explain the me why the triggers fire immediately on launch?

Making a volleyball game, overlap not working

I'm making a 2D game on Unity and I created an overlap to see if the ball is on the hit area. However, whenever I push the hit button, the ball is hit even if it is away of the player. I am sending the code for the Player, which contains what is needed so far, to see what may have gone wrong. Supposedly with the foreach hitCollider in hitColliders it should be fixed but it is not working I and just canĀ“t wrap my mind around it.
public int speed;
public bool estoyFloor, subiendo, bajando;
public bool canRight, canLeft;
public bool canMove;
public float posYinit;
public Vector3 posInitPlayer;
bool m_Started;
public LayerMask m_LayerMask;
public GameObject volleyBall;
// Use this for initialization
void Start () {
m_Started = true;
}
void FixedUpdate()
{
Collider2D[] hitColliders = Physics2D.OverlapBoxAll(gameObject.transform.position, transform.localScale / 2, 0);
foreach (Collider2D hitCollider in hitColliders)
{
if (Input.GetButtonDown("Fire1"))
{
volleyBall.GetComponent<Rigidbody2D>().velocity = Vector3.zero;
volleyBall.GetComponent<Rigidbody2D>().AddForce(new Vector3(300, 500));
}
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
if (m_Started)
Gizmos.DrawWireCube(transform.position, transform.localScale / 2);
}
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1"))
canMove = true;
if (Input.GetAxisRaw("Horizontal") > 0 && canRight)
transform.position += Vector3.right * speed * Time.deltaTime;
if (Input.GetAxisRaw("Horizontal") < 0 && canLeft)
transform.position += Vector3.left * speed * Time.deltaTime;
if (Input.GetButtonDown("Jump") && estoyFloor)
{
subiendo = true;
posYinit = transform.position.y;
}
if (transform.position.y > posYinit + 2.5f)
{
subiendo = false;
bajando = true;
}
if (!estoyFloor && !subiendo)
bajando = true;
Debug.DrawLine(transform.position, transform.position + new Vector3(0, -1, 0), Color.red);
Debug.DrawLine(transform.position, transform.position + new Vector3(0.8f, 0, 0), Color.red);
Debug.DrawLine(transform.position, transform.position + new Vector3(1.5f, 0, 0), Color.red);
RaycastHit2D[] hitDown = Physics2D.LinecastAll(transform.position, transform.position + new Vector3(0, -1, 0));
RaycastHit2D[] hitsRight = Physics2D.LinecastAll(transform.position, transform.position + new Vector3(0.8f, 0, 0));
RaycastHit2D[] hitsLeft = Physics2D.LinecastAll(transform.position, transform.position + new Vector3(1.5f, 0, 0));
estoyFloor = false;
foreach (RaycastHit2D hit in hitDown)
{
if (hit.collider.name == "Floor")
{
bajando = false;
estoyFloor = true;
}
}
canRight = true;
foreach (RaycastHit2D hit in hitsRight)
{
if (hit.collider.tag == "Wall")
canRight = false;
}
canLeft = true;
foreach (RaycastHit2D hit in hitsLeft)
{
if (hit.collider.tag == "Wall")
canLeft = false;
}
if (subiendo)
transform.position += Vector3.up * speed * Time.deltaTime;
if (bajando)
transform.position += Vector3.down * speed * Time.deltaTime;
}
Your overlap box is probably colliding with the player it is on. Because you do not check if the collider belonged to the volleyball in your loop, you are hitting the ball no matter what. Try to get the transform from the collider and check its tag to see if it is a volleyball before adding force to the ball and see if that works. You could also use a layermask on your Overlap box check as well to ensure only volleyballs get detected.

Character is not colliding with other other objects in Unity3D

I'm working on a game right now (first 3D styled game), and I have a problem with my character colliding. I have a Player object, which has another object(s) as the real moveable characters (now I have only one). I have rigidbody and box collider too attached to my character. I have made a level (with hand-placed platforms), and I would like avoid my character of falling of the platforms, while the user control it. I have tried to place a cube on the side of the platform(s), with box collider attached to it, but the character not detect the colliding for some reasons. I would like my character to be stopped by the collider "cube", but it doesn't happen.
I use this script to move my object (attached to my character Player object) :
public class Bounce : MonoBehaviour {
float lerpTime;
float currentLerpTime;
float perc = 1;
Vector3 startPos;
Vector3 endPos;
bool firstInput;
public bool justJump;
public GameObject player;
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
if (perc == 1) {
lerpTime = 1;
currentLerpTime = 0;
firstInput = true;
justJump = true;
}
}
startPos = gameObject.transform.position;
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));
}
if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f));
}
if (firstInput == true) {
currentLerpTime += Time.deltaTime * 5;
perc = currentLerpTime / lerpTime;
gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
if (perc > 0.8f) {
perc = 1;
}
if (Mathf.Round(perc) == 1) {
justJump = false;
}
}
}
void OnCollisionEnter(Collision collision) {
Debug.Log("!!!!!!!");
}
}
And I use this script on the character itself: (to rotate and animate it)
Code (csharp):
public class AnimationController : MonoBehaviour {
Animator anim;
public GameObject thePlayer;
// Use this for initialization
void Start () {
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
Bounce bounceScript = thePlayer.GetComponent<Bounce>();
if (bounceScript.justJump == true) {
anim.SetBool("Jump", true);
}
else {
anim.SetBool("Jump", false);
}
if (Input.GetButtonDown("right")) {
//transform.rotation *= Quaternion.Euler(0,30,0);
transform.RotateAround(transform.position, Vector3.up, 90);
}
if (Input.GetButtonDown("left")) {
transform.Rotate (0, -90, 0, 0);
}
}
}
It's only colliding when the cube not isKinematic, but it doesn't stop my player from getting through the cube for some reason.
I have read some sites about problems like this, but nothing helped yet.
It would be great if you can give me any code improvements :)
EDIT1:
Sorry, for answering so late, I couldn't do anything with my game in the last few days. Today I have tried to do something with raycasts, you can see my code, for my first try just in the update method:
void Update () {
if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) {
if (perc == 1) {
lerpTime = 1;
currentLerpTime = 0;
firstInput = true;
justJump = true;
}
}
startPos = gameObject.transform.position;
/* if (Input.GetButtonDown("right") && gameObject.transform.position == endPos) {
//endPos = new Vector3(transform.position.x + 0.5f, transform.position.y, transform.position.z);
}
if (Input.GetButtonDown("left") && gameObject.transform.position == endPos) {
endPos = new Vector3(transform.position.x - 0.5f, transform.position.y, transform.position.z);
}*/
Vector3 fwd = player.transform.TransformDirection(Vector3.forward);
RaycastHit objectHit;
if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
if (objectHit.collider.tag == "Wall") {
Debug.Log("WALL RAYCAST HIT!");
}
}
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));
}
if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) {
//endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, -1f));
}
if (firstInput == true) {
currentLerpTime += Time.deltaTime * 5;
perc = currentLerpTime / lerpTime;
gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc);
if (perc > 0.8f) {
perc = 1;
}
if (Mathf.Round(perc) == 1) {
justJump = false;
}
}
}
With this I can get the Debug Log WALL RAYCAST HIT 2-3 times at a time, but only once. As I move the character it won't appear again, for some reason (I think it should because the update method is called in every frame).
Although when I place it in the Input.GetButtonDown("up") method, it won't log anything:
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
fwd = player.transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(player.transform.position, fwd, out objectHit, 2)) {
if (objectHit.collider.tag == "Wall") {
Debug.Log("WALL RAYCAST HIT!");
}
}
endPos = transform.position + player.transform.rotation * (new Vector3(0, 0, 1f));
}
When you update the transform.position you actually "teleport" yout object to the new position. Even when you do this smoothly, using something like the Lerp function, as you do on your move script, Unity understands that you are teleporting your object to a new coordinate.
This is not wrong, All games work like that. Functions like Lerp just create the ilusion of movement, so the player fell like the character actually moved from one point to another.
What is happening is that your script keeps telling the character to move to a new position, despite any objects on its path. The collision happens, but your Update function still places the character on ints new position.
I can think of two possible ways for you to solve this:
Create an OnCollisionEnter() function for your Move script that somehow stops your movement. By creating a flag like you did with the firstInput you could achieve this.
Instead of updating your transform.position you could use a rigidbody to handle the movement and collisions for your. This way, everytime you need to move your character you will need to add some velocity to the character rigidbody, instead of directly updating the transform.position.
Since your character doesn't move in a constant way, but in a "one step at a time" way, I think the first solution is a better suitted for you.
The code will be something like this
void OnCollisionenter(Collision collision)
{
collided = true;
}
and the end of your Move script should be updated to
if(!collided)
{
if (firstInput == true) {
currentLerpTime += Time.deltaTime * 5;
perc = currentLerpTime / lerpTime;
transform.position = Vector3.Lerp(startPos, endPos, perc);
if (perc > 0.8f) {
perc = 1;
}
if (Mathf.Round(perc) == 1) {
justJump = false;
}
}
}
else
{
// Remember to reset this when you stop your character
endPos = transform.position;
collided = false;
}
This time I couldn't test the code before writting it here, so you may need to do some changes before it works.
ps: I don't think you need your firstInput variable. Once it is set to true, you never set it to false again. Also, the Input.GetButtonDown() function will only return true on the first frame a button is pressed wich is what I guess you intended when you created firstInput.
ps2: My solution added a collided boolean attribute to your class, so don't forget to add a line private bool collided; with your other class attributes. Also, read that chapter about the state machine pattern I recommended you on your other question. Creating this kind of control attribute suach as the collided boolean is not a good practice and if you had implemented a state machine this could be avoided.
Hey I had a similar problem i was using an animated model from Mixamo.com and I notices that for some strange reason the character didn't collide with boundaries despite having collider, for some reason it didn't work until i added a CharacterController to my model instead of a collider just search for the CharacterController and add it as you would add any script or rigid body to your game object.
Hope it Works XD Greetings