Hello im having a hard time trying to enable and disable the kinematic of a rigidbody 2d i have been doing some experiments but nothing seems to work out This is the code without my experiments on how to enable and disable
for the backgrounf im a doing a puzzle game 2d it uses the box collider 2d to match the pieces, i have many piecesand i want them to fall off with gravity , touch them and drag them to their spot , for that purpose i added a rigid body and it works perfectly for the falll , but i need it to be kinematic so i can drag it
[SerializeField]
private Transform El_carmenPlace;
private Vector2 initialPosition;
private float deltaX, deltaY;
public static bool locked;
private void Update()
{
if (Input.touchCount > 0 && !locked)
{
Touch touch = Input.GetTouch(0);
Vector2 touchPos = Camera.main.ScreenToWorldPoint(touch.position);
switch (touch.phase)
{
case TouchPhase.Began:
if (GetComponent<Collider2D>() == Physics2D.OverlapPoint(touchPos))
{
deltaX = touchPos.x - transform.position.x;
deltaY = touchPos.y - transform.position.y;
}
break;
case TouchPhase.Moved:
if (GetComponent<Collider2D>() == Physics2D.OverlapPoint(touchPos))
transform.position = new Vector2(touchPos.x - deltaX, touchPos.y - deltaY);
break;
case TouchPhase.Ended:
initialPosition = transform.position;
if (Mathf.Abs(transform.position.x - El_carmenPlace.position.x) <= 0.5f &&
Mathf.Abs(transform.position.y - El_carmenPlace.position.y) <= 0.5f)
{
transform.position = new Vector2(El_carmenPlace.position.x, El_carmenPlace.position.y);
locked = true;
}
else
{
transform.position = new Vector2(initialPosition.x, initialPosition.y);
}
break;
}
}
}
}
i have try the enable disable ragdoll , scripts that unity post , i created an empty object and tried to add the piece of the puzzle , but i cant? is using rigidbody 2d dunno if it coutns as a rigid body...
Basically i fixed the two major problems , now for the wiinning part im using if (ALtzayanca.locked && Huamantla.locked && El_carmen.locked) , i want to use a tag or something so when everthing is locked , you win
[SerializeField]
private Transform HuamantlPlace;
private float deltaX, deltaY;
public static bool locked;
//use this for initialiozation
void Start()
{
}
private void Update()
{
if (Input.touchCount > 0 && !locked)
{
Touch touch = Input.GetTouch(0);
Vector2 touchPos = Camera.main.ScreenToWorldPoint(touch.position);
switch (touch.phase)
{
case TouchPhase.Began:
if (GetComponent<Collider2D>() == Physics2D.OverlapPoint(touchPos))
{
gameObject.GetComponent<Rigidbody2D>().isKinematic = true;
deltaX = touchPos.x - transform.position.x;
deltaY = touchPos.y - transform.position.y;
}
break;
case TouchPhase.Moved:
if (GetComponent<Collider2D>() == Physics2D.OverlapPoint(touchPos))
transform.position = new Vector2(touchPos.x - deltaX, touchPos.y - deltaY);
break;
case TouchPhase.Ended:
if (Mathf.Abs(transform.position.x - HuamantlPlace.position.x) <= 0.5f &&
Mathf.Abs(transform.position.y - HuamantlPlace.position.y) <= 0.5f)
{
this.gameObject.GetComponent<Rigidbody2D>().isKinematic = true;
transform.position = new Vector2(HuamantlPlace.position.x, HuamantlPlace.position.y);
this.gameObject.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezePositionY;
locked = true;
}
else
{
this.gameObject.GetComponent<Rigidbody2D>().isKinematic = false;
}
break;
}
}
}
}
Related
I am creating a clone of Billiards and I cannot work out how to stop the player from interacting with and launching the ball while it is still moving; below is my attempt. I have placed an if statement that checks whether the ball is moving on both the mouseDrag and mouseUp functions. I have also tried using isSleeping() but this caused the ball to not move at all.
If possible I would like to apply this method to all of the balls and not just the cue ball; so that all balls have to have stopped before any actions may happen. This is currently in my "player" script, if I should move it a GameManager script please let me know.
private void Update()
{
speed = rb.velocity.magnitude;
if (speed < 0.5)
{
rb.velocity = new Vector3(0, 0, 0);
}
}
void OnMouseDrag()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = true;
currDistance = Vector3.Distance(mousePointA.transform.position, transform.position);
if (currDistance <= 3f)
{
spaceLimit = currDistance;
}
else
{
spaceLimit = maxDistance;
}
shootPower = Mathf.Abs(spaceLimit) * shootPowervar;
Vector3 dimxy = mousePointA.transform.position - transform.position;
float difference = dimxy.magnitude;
mousePointB.transform.position = transform.position + ((dimxy / difference) * currDistance * -1);
mousePointB.transform.position = new Vector3(mousePointB.transform.position.x, mousePointB.transform.position.y, -0.8f);
shootDirection = Vector3.Normalize(mousePointA.transform.position - transform.position);
}
else
{
}
}
void OnMouseUp()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = false;
arrow.GetComponent<SpriteRenderer>().enabled = false;
circle.GetComponent<SpriteRenderer>().enabled = false;
Vector3 push = shootDirection * shootPower * -1;
GetComponent<Rigidbody2D>().AddForce(push, ForceMode2D.Impulse);
}
else
{
}
}
if your test speed == 0 is not functional, you could record the last position of the ball, and set a boolean isMoving = true, if actual position of ball is different thant the last, then record the lastposition and so on
Vector3 LastPosition;
bool isMoving;
void Update()
{
isMoving = BallPosition == LastPosition;
:
:
}
void OnMOuseDrag()
{
if(!isMoving) return;
}
void OnMOuseUp()
{
if(!isMoving) return;
}
I've set up my swipe controls to transform my player left/right/up/down and I've restricted the movement on 3 lines; -1, 0, 1. Everything works fine but the movement is not smooth at all and the player seems to be "teleporting" from one position to another. I wanted to smooth the movement by playing the animation but the result was that the animation was being played after the player has changed his position.
Is there any way to play the animation while the player is changing his position or a way to smooth the movement so it looks right ?
I've tried everything and now I'm stuck with the problem, please help
Here's my code
public class SwipeControls : MonoBehaviour {
public float speed = 5.0f;
private Vector3 startpos; // start position
private Vector3 endpos; //end position
public int pozioma = 0;
public int pionowa = 0;
Animator anim;
void Start() {
GetComponent<Animator>();
}
void Update() {
foreach (Touch touch in Input.touches) {
Vector3 newPosition;
if (touch.phase == TouchPhase.Began) {
startpos = touch.position;
endpos = touch.position;
}
if (touch.phase == TouchPhase.Moved) {
endpos = touch.position;
}
if (touch.phase == TouchPhase.Ended) {
newPosition = transform.position;
if (Mathf.Abs(startpos.y - endpos.y) > Mathf.Abs(startpos.x - endpos.x)) {
if ((startpos.y - endpos.y) > 100 && pionowa > -1) //swipe down
{
pionowa--;
newPosition.y -= speed;
transform.position = newPosition;
anim.SetTrigger("Flydown");
}
if ((startpos.y - endpos.y) < -100 && pionowa < 1) //swipe up
{
pionowa++;
newPosition.y += speed;
transform.position = newPosition;
anim.SetTrigger("Flyup");
}
}
else {
if ((startpos.x - endpos.x) > 100 && pozioma > -1) //swipe left
{
pozioma--;
newPosition.z -= speed;
transform.position = newPosition;
anim.SetTrigger("Flyleft");
}
}
if ((startpos.x - endpos.x) < -100 && pozioma < 1) //swipe right
{
pozioma++;
newPosition.z += speed;
transform.position = newPosition;
anim.SetTrigger("Flyright");
}
}
}
}
}
Modify your code instead of using just
transform.position = newPosition;
in all position use
transform.position = Vector3.Lerp(transform.position, newPosition, smooth * Time.deltaTime);
where smooth is float variable assign it required value may be 0.5f or whatever you want
Note : What it actually does is that it makes game object to move little based on smooth value, every frame
Note that we do not know your animator setup. If in those animation clips there is anywhere a keyframe for the position then the animator will always overrule anything done by scripts!
Instead of setting the new position immediately you could use a Coroutine with StartCoroutine like (also fixing some coding styles)
public class SwipeControls : MonoBehaviour
{
// Flag for ignoring input until current animation finished
private bool routineRunning;
// Configure in the Inspector distance to swipe
// in unity units
[SerializeField] private float swipeDistance = 5;
// configure this in the Inspector
// How long should the swiping take in seconds
[SerializeField] private float swipeDuration = 1;
private Vector3 _startpos; // start position
private Vector3 _endpos; //end position
public int pozioma = 0;
public int pionowa = 0;
private Animator _anim;
private void Start()
{
GetComponent<Animator>();
}
private void Update()
{
// Ignore any Input while a routine is running
if (routineRunning) return;
foreach (var touch in Input.touches)
{
switch (touch.phase)
{
case TouchPhase.Began:
_startpos = touch.position;
_endpos = touch.position;
break;
case TouchPhase.Moved:
_endpos = touch.position;
break;
case TouchPhase.Ended:
if (Mathf.Abs(_startpos.y - _endpos.y) > Mathf.Abs(_startpos.x - _endpos.x))
{
if (_startpos.y - _endpos.y > 100 && pionowa > -1) //swipe down
{
pionowa--;
StartCoroutine(MoveSmooth(Vector3.up * -1, swipeDuration));
_anim.SetTrigger("Flydown");
}
else if (_startpos.y - _endpos.y < -100 && pionowa < 1) //swipe up
{
pionowa++;
StartCoroutine(MoveSmooth(Vector3.up, swipeDuration));
_anim.SetTrigger("Flyup");
}
}
else
{
if (_startpos.x - _endpos.x > 100 && pozioma > -1) //swipe left
{
pozioma--;
StartCoroutine(MoveSmooth(Vector3.forward * -1, swipeDuration));
_anim.SetTrigger("Flyleft");
}
else if (_startpos.x - _endpos.x < -100 && pozioma < 1) //swipe right
{
pozioma++;
StartCoroutine(MoveSmooth(Vector3.forward, swipeDuration));
_anim.SetTrigger("Flyright");
}
}
break;
}
}
}
private IEnumerator MoveSmooth(Vector3 direction, float duration)
{
routineRunning = true;
var currentPosition = transform.localPosition;
var targetPosition = currentPosition + direction * swipeDistance;
var timePassed = 0f;
do
{
// Additionally add some ease in and out to the movement to get
// even smoother movement
var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / duration);
// Interpolate the position between currentPosition and targetPosition
// using the factor between 0 and 1
transform.localPosition = Vector3.Lerp(currentPosition, targetPosition, lerpFactor);
// increase by time since last frame
timePassed += Time.deltaTime;
// let this frame render and go on from
// here in the next frame
yield return null;
} while (timePassed <= duration);
// To avoid over or undershooting in the end set a fixed value
transform.localPosition = targetPosition;
routineRunning = false;
}
}
I don't know why you are using y+= and z+= .. it seems to me that it meeans the Camera is facing left in your scene e.g. with rotation = 0, -90, 0 and e.g. position = 10, 0, 0 than this should be the result (Note I copied the same code into if(GetMouseButtonDown(0)) etc in order to simulate the touch on the PC.)
I cannot seem to find a way to collide the player with objects that are supposed to stop the player. For example, when I move the player up to a wall of trees, it just moves through them (and bounces away from the grid alignment slightly) like the player were a ghost.
And below is the code I'm using as far as Player's movement is concerned:
using System.Collections;
using UnityEngine;
public class PlayerMovement : Character {
Direction currentDir;
Vector2 input;
bool IsMoving = false;
Vector3 startpos;
Vector3 endpos;
float t;
public Sprite upsprite;
public Sprite rightsprite;
public Sprite downsprite;
public Sprite leftsprite;
public float walkSpeed = 3f;
public bool isAllowedToMove = true;
private Rigidbody2D myRB;
void Start()
{
isAllowedToMove = true;
myRB = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
protected override void Update () {
if (! IsMoving && isAllowedToMove) {
input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (Mathf.Abs(input.x) > Mathf.Abs(input.y))
input.y = 0;
else
input.x = 0;
if (input != Vector2.zero) {
if (input.x < 0) {
currentDir = Direction.Left;
}
if (input.x > 0) {
currentDir = Direction.Right;
}
if (input.y < 0) {
currentDir = Direction.Down;
}
if (input.y > 0) {
currentDir = Direction.Up;
}
switch (currentDir) {
case Direction.Up:
gameObject.GetComponent<SpriteRenderer>().sprite = upsprite;
break;
case Direction.Right:
gameObject.GetComponent<SpriteRenderer>().sprite = rightsprite;
break;
case Direction.Down:
gameObject.GetComponent<SpriteRenderer>().sprite = downsprite;
break;
case Direction.Left:
gameObject.GetComponent<SpriteRenderer>().sprite = leftsprite;
break;
}
StartCoroutine (Move (transform));
}
myRB.velocity = new Vector2 (Input.GetAxisRaw ("Horizontal") * walkSpeed, myRB.velocity.y);
myRB.velocity = new Vector2 (myRB.velocity.x, Input.GetAxisRaw ("Vertical") * walkSpeed);
if (Input.GetAxisRaw ("Horizontal") < 0.5f && Input.GetAxisRaw ("Horizontal") > -0.5f)
{
myRB.velocity = new Vector2 (0f, myRB.velocity.y);
}
if (Input.GetAxisRaw ("Vertical") < 0.5f && Input.GetAxisRaw ("Vertical") > -0.5f)
{
myRB.velocity = new Vector2(myRB.velocity.y, 0f);
}
}
base.Update ();
}
public IEnumerator Move(Transform entity)
{
IsMoving = true;
startpos = entity.position;
t = 0;
endpos = new Vector3(startpos.x + System.Math.Sign(input.x), startpos.y + System.Math.Sign(input.y), startpos.z);
while(t < 1f)
{
t += Time.deltaTime * walkSpeed;
entity.position = Vector3.Lerp(startpos, endpos, t);
yield return null;
}
IsMoving = false;
yield return 0;
}
}
enum Direction
{
Up,
Right,
Down,
Left
}
Other things to note are that I made sure to use Rigidbody2D and Box Collider2D components, and I made sure to make the Gravity scale 0 for the player and froze the rotation from the Z axis. Also, I did use Tiled and Tiled2Unity extensions to create the tiles you see in game, despite the preinstalled tilemap assets being a decent choice to create 2d game worlds.
Forgive me if it seems too long, but I can't seem to figure out what the problem is with the collision detection. Can anyone help?
My intention is to make my character wall jump/climb/slide, I got the sliding part working fine, but if he jumps while wall sliding, he should "bounce" back to the wall, the problem is that I can't balance the forces. In all tutorial I saw, it is simply a matter of detecting if the character is wall sliding, and if he is and he jumps, then you add a force oposite to the wall.
This is not working for me, because if I add enough force to make him jump, he goes way too fast and the player can barely see he jumped, he just sees that the character is now higher on the wall. If I add a smaller amount of force, it isn't enough to make a considerable jump and the player would have to hit space a thousand times to make him go up a few centimeters on the wall.
Any help is appreciated, I already tried a lot of things, even tried to freeze the controls, set gravity scale to 0 and make the character fo to the right points using MoveTowards, that is how desperate I am.
I'm also really new to Unity so I might be missing something really simple.
Here is a gif showing the character's behavior:
https://imgur.com/a/TgUHzP6
And here is the relevant parts of my character's script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TheBot : MonoBehaviour {
public float speed;
public int jumpForce;
public Transform groundCheck;
public Transform meleeCheck;
public Transform bulletSpawner;
public LayerMask layerGround;
public float meleeCoolDown;
public float meleeDamage;
private Rigidbody2D body;
private Animator anim;
private Dash dashController;
private Shooter shotController;
private float unloadWaitingTime = 3;
private float idleGunTime = 0;
private bool facingRight = true;
private bool onGround = true;
private bool jumping = false;
private bool attacking = false;
private bool dead = false;
private bool isGunLoaded = false;
private bool isGunLoading = false;
private bool isGunUnloading = false;
private bool takingDamage = false;
private bool dashing = false;
private bool isWallSliding = false;
private float wallJumpTime = 0f;
private Vector3[] wallJumpControlPoint;
// Use this for initialization
void Start () {
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
dashController = GetComponent<Dash>();
shotController = GetComponent<Shooter>();
}
// Update is called once per frame
void Update () {
PlayAnimations();
CheckIfGrounded();
checkIfWallSliding();
dashing = dashController.IsDashing();
if (Input.GetButtonDown("Jump") && (onGround || isWallSliding) && !isGunLoading && !jumping && !takingDamage){
jumping = true;
wallJumpControlPoint = new Vector3[3];
wallJumpControlPoint[0] = body.position;
wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
}
if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
Attack();
}
if(Input.GetButtonDown("Ranged") && !attacking && !isGunLoading && onGround){
Shoot();
}
if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
}
if(isGunLoaded){
idleGunTime += Time.deltaTime;
if (idleGunTime >= unloadWaitingTime){
UnloadGun();
}
}
}
void FixedUpdate(){
if(!takingDamage){
float move = Input.GetAxis("Horizontal");
//while charachter is wall sliding, slowly fall
if (isWallSliding){
body.velocity = new Vector2(body.velocity.x, -0.7f);
}
if(!dashing){
if(onGround){
//if not dashing on on ground, walk with normal speed
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
body.velocity = new Vector2(move * (speed * 0.7f), body.velocity.y);
}
}
if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
//control direction character is facing
Flip();
}
if (jumping){
if(isWallSliding){
body.velocity = new Vector2(30, 20);
} else {
body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
//if is moving while jumping, reduce jump height
body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
}
onGround = false;
jumping = false;
}
}
}
void CheckIfGrounded(){
onGround = false;
Collider2D[] collisionResults = new Collider2D[2];
int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
for (int i=0; i <objectsBeneath; i++ ){
if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
onGround = true;
}
}
}
void checkIfWallSliding(){
if (!onGround){
RaycastHit2D[] ray = new RaycastHit2D[1];
int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";
isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) || (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
} else {
isWallSliding = false;
if (body.velocity.y > 10){
body.velocity = new Vector2(body.velocity.x, 5);
}
}
}
public void Die(){
dead = true;
}
}
As you've attempted before, you will need to reduce your horizontal jump acceleration/velocity on the jump.
When you wall jump, you'll be pressing towards the wall. And as your code is currently, while you are in the air, your horizontal velocity is set to be in the direction you press. This makes any horizontal movement from the wall jump very hard to see, unless it's large enough to push you very far in one frame.
This (as well as the change we discussed in the comments) is why your previous attempts with low walljump magnitudes didn't work.
To fix this, you have to change how your air control works. One way of going about it is making it add a clamped modifier to your horizontal velocity instead of setting it directly to the target velocity.
if(!dashing){
if(onGround){
//if not dashing on on ground, walk with normal speed
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
float airControlAccelerationLimit = 0.5f; // Higher = more responsive air control
float airSpeedModifier = 0.7f; // the 0.7f in your code, affects max air speed
float targetHorizVelocity = move
* speed
* airSpeedModifier; // How fast we are trying to move horizontally
float targetHorizChange = targetHorizVelocity
- body.velocity.x; // How much we want to change the horizontal velocity
float horizChange = Mathf.Clamp(
targetHorizChange ,
-airControlAccelerationLimit ,
airControlAccelerationLimit ); // How much we are limiting ourselves
// to changing the horizontal velocity
body.velocity = new Vector2(body.velocity.x + horizChange, body.velocity.y);
}
}
Here it is, in your code, along with making sure we only update velocity once OR use AddForce per FixedUpdate call. And we also change the wallsliding slowdown code to only activate if the player is about to go down faster than the wallslide speed.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TheBot : MonoBehaviour {
public float speed;
public int jumpForce;
public Transform groundCheck;
public Transform meleeCheck;
public Transform bulletSpawner;
public LayerMask layerGround;
public float meleeCoolDown;
public float meleeDamage;
private Rigidbody2D body;
private Animator anim;
private Dash dashController;
private Shooter shotController;
private float unloadWaitingTime = 3;
private float idleGunTime = 0;
private bool facingRight = true;
private bool onGround = true;
private bool jumping = false;
private bool attacking = false;
private bool dead = false;
private bool isGunLoaded = false;
private bool isGunLoading = false;
private bool isGunUnloading = false;
private bool takingDamage = false;
private bool dashing = false;
private bool isWallSliding = false;
private float wallJumpTime = 0f;
private Vector3[] wallJumpControlPoint;
// Use this for initialization
void Start () {
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
dashController = GetComponent<Dash>();
shotController = GetComponent<Shooter>();
}
// Update is called once per frame
void Update () {
PlayAnimations();
CheckIfGrounded();
checkIfWallSliding();
dashing = dashController.IsDashing();
if (Input.GetButtonDown("Jump") && (onGround || isWallSliding) && !isGunLoading && !jumping && !takingDamage){
jumping = true;
wallJumpControlPoint = new Vector3[3];
wallJumpControlPoint[0] = body.position;
wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
}
if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
Attack();
}
if(Input.GetButtonDown("Ranged") && !attacking && !isGunLoading && onGround){
Shoot();
}
if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
}
if(isGunLoaded){
idleGunTime += Time.deltaTime;
if (idleGunTime >= unloadWaitingTime){
UnloadGun();
}
}
}
void FixedUpdate(){
if(!takingDamage){
float move = Input.GetAxis("Horizontal");
//while charachter is wall sliding, slowly fall
if (isWallSliding && !jumping && body.velocity.y < -0.7f){
body.velocity = new Vector2(body.velocity.x, -0.7f)
}
if(!dashing){
if(onGround){
//if not dashing on on ground, walk with normal speed
body.velocity = new Vector2(move * speed, body.velocity.y);
} else {
//if character is not on ground, reduce the speed so he doesn't jump too far away
float airControlAccelerationLimit = 0.5f; // Higher = more responsive air control
float airSpeedModifier = 0.7f; // the 0.7f in your code, affects max air speed
float targetHorizVelocity = move
* speed
* airSpeedModifier; // How fast we are trying to move horizontally
float targetHorizChange = targetHorizVelocity
- body.velocity.x; // How much we want to change the horizontal velocity
float horizChange = Mathf.Clamp(
targetHorizChange ,
-airControlAccelerationLimit ,
airControlAccelerationLimit ); // How much we are limiting ourselves
// to changing the horizontal velocity
body.velocity = new Vector2(body.velocity.x + horizChange, body.velocity.y);
}
}
if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
//control direction character is facing
Flip();
}
if (jumping){
if(isWallSliding){
body.velocity = new Vector2(body.velocity.x + 0.25f * jumpForce, jumpForce);
} else {
body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
//if is moving while jumping, reduce jump height
body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
}
onGround = false;
jumping = false;
}
}
}
void CheckIfGrounded(){
onGround = false;
Collider2D[] collisionResults = new Collider2D[2];
int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
for (int i=0; i <objectsBeneath; i++ ){
if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
onGround = true;
}
}
}
void checkIfWallSliding(){
if (!onGround){
RaycastHit2D[] ray = new RaycastHit2D[1];
int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";
isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) || (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
} else {
isWallSliding = false;
}
}
public void Die(){
dead = true;
}
}
I have this problem which I have been trying to figure out for quite some time already. The code I have below is almost complete. I just need to add this additional feature it should work how I want it to work.
So what I want to implement into the code is the make alertedLock false when !withinRange.
But for some reason no matter how i do it. It doesnt work. Because the problem i have is that, when i implement some kind of code to do that, everything goes back to normal.
Thanks in advance.
Edit
The script should be doing this:
If player !withinRange && !withinAngle of enemy then, enemy.color.blue;
If player is not within Range for enemy to detect and player is not within certain Angle for enemy to detect. It means, player is not detected by enemy. So we use Color.Blue to represent that.
If player !withinRange && withinAngle of enemy then, enemy.color.blue;
If player is not within Range for enemy to detect and player is within Angle for enemy to detect. It means, player is still not detect by enemy. So we use Color.Blue to represent that.
If player withinRange && !withinAngle of enemy then, enemy.color.red;
If player is within Range for enemy to detect and player is not within Angle for enemy to detect player. It means, enemy has detected something within Range but doesnt meet all the requirements, that is, withinAngle = true. So in this case we use Color.Red to represent that.
If player withinRange && withinAngle of enemy then, enemy.color.green;
If player is within Range for enemy to detect and player is within Angle for enemy to detect player. It means, player has successfully killed the the enemy. Therefore, using Color.Green to represent that.
If player withinRange && touchRestrictedRaycast of enemy then, enemy.color.magenta (forever) unless !withinRange && !withinAnge
If player is within Range for enemy to detect and player is not within Angle for enemy to detect player. But however then hits the raycast, touchRestrictedRaycast. This will make a lock. So the player cant kill the enemy from a invalid position. So when this happens, the player can no longer kill the enemy. Unless the player is totally out of Range of the enemies detection.
The problem is 5. I dont know how to code 5.
Edit
When i tried to code it outside the forloop , that is,
if (alertedLock && !withinRange) {
alertedLock = false;
}
Does doesnt solve the problem. It returns the solution to where alertedLock is always false
Even when i try to apply it inside the for loop. Such like,
if(withinRange) {
// Inside
if(alertedLock) {
gameObject.renderer.material.color = Color.magenta;
}
if(!alertedLock) {
if(enemyAngleTLUP || enemyAngleTLLEFT) {
alertedLock = true;
}
if(withinAngle) {
gameObject.renderer.material.color = Color.green;
}
if(!withinAngle) {
gameObject.renderer.material.color = Color.red;
}
}
}
if (!withinRange){
if(alteredLock) {
alertedLock = false;
}
}
There is a problem when i do this, its because once it detects the first raycast detection. It ignores the rest, and so it has this color state problem.
I found out this problem on my earlier questions, here:
https://gamedev.stackexchange.com/questions/90329/raycast-flashing-problem
Edit
alertedLock is just a bool which determines when the player has touched the restricted raycast. Due to the fact the player can only kill the enemy from a certain range and angle (withinRange && withinAngle). This is why we have alertedLock.
However, when alertedLock is true. It can only be turned off when the player isnt within the kill range of the enemy (!withinRange)
using UnityEngine;
using System.Collections;
public class Script_v2 : MonoBehaviour {
// Player Properties
private GameObject player;
public Vector3 playerSize;
private Vector3 playerTransform;
public Vector3 playerTransformTL;
public Vector3 playerTransformTR;
public Vector3 playerTransformBL;
public Vector3 playerTransformBR;
private Vector3 newPlayerTransformTL;
private Vector3 newPlayerTransformTR;
private Vector3[] playerRaycastPoints;
// Enemy Properties
private Vector3 enemyTransformTL;
private Vector3 enemyTransformTR;
private Vector3 enemyTransformBL;
private Vector3 enemyTransformBR;
public float distance;
public Vector3 enemySize;
// Detection Alerts
public bool outOfVision;
public bool alerted;
public bool alertedLock;
public bool withinRange;
public bool withinAngle;
public bool dead;
Ray ray;
RaycastHit hit;
// Use this for initialization
void Start () {
playerRaycastPoints = new Vector3[4];
distance = 3f;
player = GameObject.FindGameObjectWithTag ("Player");
}
// Update is called once per frame
void Update () {
enemyTransformTL = new Vector3 (transform.position.x - 0.5f, transform.position.y + 0.5f, transform.position.z);
enemyTransformTR = new Vector3 (transform.position.x + 0.5f, transform.position.y + 0.5f, transform.position.z);
enemyTransform_TL_TR ();
Reference_Player_Transform_Points ();
Player_Transform_Points_Detection ();
Debug.Log (alerted + " " + alertedLock);
}
void OnDrawGizmos() {
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere (new Vector3(transform.position.x - 0.5f, transform.position.y + 0.5f, transform.position.z), distance);
//Gizmos.DrawWireSphere (new Vector3(transform.position.x + 0.5f, transform.position.y + 0.5f, transform.position.z), distance);
}
public void enemyTransform_TL_TR() {
if (alertedLock && !withinRange) {
alertedLock = false;
}
if (!alertedLock) {
gameObject.renderer.material.color = Color.blue;
}
for (int i = 0; i < playerRaycastPoints.Length; i++) {
double enemyAngleTL = Mathf.Atan2(playerRaycastPoints[i].y - ( transform.position.y + 0.5f ),
playerRaycastPoints[i].x - ( transform.position.x - 0.5f )) * 180f / 3.14159265f;
//Debug.Log (enemyAngleTL);
double enemyAngleTR = Mathf.Atan2 (playerRaycastPoints[i].y - (transform.position.y + 0.5f),
playerRaycastPoints[i].x - (transform.position.x + 0.5f)) * 180f / 3.14159265f;
Vector3 directionTL = (playerRaycastPoints[i] - enemyTransformTL).normalized;
Ray rayTL = new Ray(enemyTransformTL, directionTL);
RaycastHit hitTL;
Vector3 directionTR = (playerRaycastPoints[i] - enemyTransformTR).normalized;
Ray rayTR = new Ray (enemyTransformTR, directionTR);
RaycastHit hitTR;
withinRange = Physics.Raycast (rayTL, out hitTL, distance);
withinAngle = enemyAngleTL > 90 && enemyAngleTL < 180;
RaycastHit hitTPUP;
RaycastHit hitTPLEFT;
bool enemyAngleTLUP = Physics.Raycast(enemyTransformTL, Vector3.up, out hitTPUP, distance);
bool enemyAngleTLLEFT = Physics.Raycast(enemyTransformTL, Vector3.left, out hitTPLEFT, distance);
Debug.DrawRay(enemyTransformTL, Vector3.up * distance);
Debug.DrawRay(enemyTransformTL, Vector3.left * distance);
if(withinRange) {
// Inside
if(alertedLock) {
gameObject.renderer.material.color = Color.magenta;
}
if(!alertedLock) {
if(enemyAngleTLUP || enemyAngleTLLEFT) {
alertedLock = true;
}
if(withinAngle) {
gameObject.renderer.material.color = Color.green;
}
if(!withinAngle) {
gameObject.renderer.material.color = Color.red;
}
}
}
}
}
private void Reference_Player_Transform_Points() {
playerSize = player.transform.localScale;
playerTransformTL = new Vector3(player.transform.position.x - (playerSize.x / 2),
player.transform.position.y + playerSize.y / 2,
player.transform.position.z);
playerTransformTR = new Vector3(player.transform.position.x + (playerSize.x / 2),
player.transform.position.y + playerSize.y / 2,
player.transform.position.z);
playerTransformBL = new Vector3(player.transform.position.x - (playerSize.x / 2),
player.transform.position.y - playerSize.y / 2,
player.transform.position.z);
playerTransformBR = new Vector3(player.transform.position.x + (playerSize.x / 2),
player.transform.position.y - playerSize.y / 2,
player.transform.position.z);
playerRaycastPoints [0] = playerTransformTL;
playerRaycastPoints [1] = playerTransformTR;
playerRaycastPoints [2] = playerTransformBL;
playerRaycastPoints [3] = playerTransformBR;
/*
Debug.Log (playerTransformTL);
Debug.Log (playerTransformTR);
Debug.Log (playerTransformBL);
Debug.Log (playerTransformBR);
*/
}
private void Player_Transform_Points_Detection() {
float eTLpTL = Vector3.Distance (enemyTransformTL, playerTransformTL);
float eTLpTR = Vector3.Distance (enemyTransformTL, playerTransformTR);
float eTLpBL = Vector3.Distance (enemyTransformTL, playerTransformBL);
float eTLpBR = Vector3.Distance (enemyTransformTL, playerTransformBR);
float eTRpTL = Vector3.Distance (enemyTransformTR, playerTransformTL);
float eTRpTR = Vector3.Distance (enemyTransformTR, playerTransformTR);
float eTRpBL = Vector3.Distance (enemyTransformTR, playerTransformBL);
float eTRpBR = Vector3.Distance (enemyTransformTR, playerTransformBR);
float eTLMin = Mathf.Min (eTLpTL, eTLpTR, eTLpBL, eTLpBR);
if (eTLMin == eTLpTL) {
newPlayerTransformTL = playerTransformTL;
// Debug.Log("eTLpTL");
}
else if(eTLMin == eTLpTR) {
newPlayerTransformTL = playerTransformTR;
// Debug.Log("eTLpTR");
}
else if(eTLMin == eTLpBL) {
newPlayerTransformTL = playerTransformBL;
// Debug.Log("eTLpBL");
}
else if(eTLMin == eTLpBR) {
newPlayerTransformTL = playerTransformBR;
// Debug.Log("eTLpBR");
}
float eTRMin = Mathf.Min (eTRpTL, eTRpTR, eTRpBL, eTRpBR);
if(eTRMin == eTRpTL) {
newPlayerTransformTR = playerTransformTL;
// Debug.Log("eTRpTL");
}
else if(eTRMin == eTRpTR) {
newPlayerTransformTR = playerTransformTR;
// Debug.Log("eTRpTR");
}
else if(eTRMin == eTRpBL) {
newPlayerTransformTR = playerTransformBL;
// Debug.Log("eTRpBL");
}
else if(eTRMin == eTRpBR) {
newPlayerTransformTR = playerTransformBR;
// Debug.Log("eTRpBR");
}
}
}