I have been using LineRender and a shader (mobile/particles/additive) to create a laser pointer. However, it seems that in Unity 2018.2.* there is a bug where it doesn't render the shader properly. Is there a workaround or another way to create a laser pointer that goes from a solid color and then fades to transparency.
using UnityEngine;
using System.Collections;
using EasyInputVR.Core;
using System;
using UnityEngine.VR;
namespace EasyInputVR.StandardControllers
{
[AddComponentMenu("EasyInputGearVR/Standard Controllers/StandardLaserPointer")]
public class StandardLaserPointer : MonoBehaviour
{
public float heightOffset = 0f;
public Material laserMaterial;
public Color laserStartColor;
public Color laserEndColor;
public float laserDistance = .5f;
public GameObject reticle;
public float reticleDistance = 5f;
public Color reticleColor;
public bool UIRaycast;
public UnityEngine.EventSystems.EasyInputModule InputModule;
public bool colliderRaycast;
public LayerMask layersToCheck;
bool laserInteraction = true;
GameObject laserPointer;
LineRenderer line;
RaycastHit rayHit;
Vector3 end;
Vector3 offsetPosition;
Vector3 initialPosition = EasyInputConstants.NOT_VALID;
Vector3 initialReticleSize;
Vector3 uiHitPosition;
GameObject lastHitGameObject;
Vector3 lastRayHit;
public void OnEnable()
{
EasyInputHelper.On_Motion += localMotion;
}
public void OnDestroy()
{
EasyInputHelper.On_Motion -= localMotion;
}
void Start()
{
laserPointer = this.gameObject;
if (reticle != null)
{
initialReticleSize = reticle.transform.localScale;
}
line = laserPointer.AddComponent<LineRenderer>();
line.material = laserMaterial;
#if UNITY_5_3 || UNITY_5_4
line.SetWidth(0.01f, 0.01f);
line.SetVertexCount(2);
line.SetColors(laserStartColor, laserEndColor);
#endif
#if UNITY_5_5
line.startColor = laserStartColor;
line.endColor = laserEndColor;
line.startWidth = .01f;
line.endWidth = .01f;
line.numPositions = 2;
#endif
#if !(UNITY_5_3 || UNITY_5_4 || UNITY_5_5)
line.startColor = laserStartColor;
line.endColor = laserEndColor;
line.startWidth = .01f;
line.endWidth = .01f;
line.positionCount = 2;
#endif
if (laserPointer.transform.parent == null)
initialPosition = laserPointer.transform.position;
}
void localMotion(EasyInputVR.Core.Motion motion)
{
if (laserPointer == null || !this.gameObject.activeInHierarchy)
return;
if (reticle != null)
{
reticle.SetActive(true);
}
// If not Oculus Rift
if (UnityEngine.XR.XRDevice.model != "Oculus Rift CV1")
{
// Adjust position of the laser
offsetPosition = motion.currentPos;
offsetPosition.y += heightOffset;
if (laserPointer.transform.parent == null)
laserPointer.transform.localPosition = initialPosition + offsetPosition;
else
laserPointer.transform.localPosition = offsetPosition;
}
laserPointer.transform.localRotation = motion.currentOrientation;
if (motion.currentPos != Vector3.zero && laserInteraction == true)
{
line.enabled = true;
if (reticle != null) {
reticle.SetActive(true);
}
}
else
{
//not valid so disable and don't bother with the raycast so return
line.enabled = false;
if (reticle != null)
reticle.SetActive(false);
return;
}
end = EasyInputConstants.NOT_VALID;
//origin
line.SetPosition(0, laserPointer.transform.position);
if (colliderRaycast && Physics.Raycast(laserPointer.transform.position, laserPointer.transform.forward, out rayHit, reticleDistance, layersToCheck))
{
end = rayHit.point;
if (rayHit.transform != null && rayHit.transform.gameObject != null)
{
// MARKER
// If thing being hit is visible
if (rayHit.transform.gameObject.GetComponent<MeshRenderer>().enabled)
{
// MARKER added
reticle.SetActive(true);
if (lastHitGameObject == null)
{
//we weren't hitting anything before and now we are
EasyInputUtilities.notifyEvents(rayHit, lastRayHit, lastHitGameObject, true, true, false, laserPointer.transform);
}
else if (lastHitGameObject == rayHit.transform.gameObject)
{
//we are hitting the same object as last frame
EasyInputUtilities.notifyEvents(rayHit, lastRayHit, lastHitGameObject, true, false, false, laserPointer.transform);
}
else if (lastHitGameObject != rayHit.transform.gameObject)
{
//we are hitting a different object than last frame
EasyInputUtilities.notifyEvents(rayHit, lastRayHit, lastHitGameObject, true, true, true, laserPointer.transform);
}
lastHitGameObject = rayHit.transform.gameObject;
lastRayHit = rayHit.point;
}
else
{
// MARKER
reticle.SetActive(false);
}
}
}
//endpoint
//line.SetPosition(1, end);
if (end != EasyInputConstants.NOT_VALID)
{
if (reticle != null)
{
reticle.transform.position = end;
reticle.transform.localScale = initialReticleSize * .6f * (Mathf.Sqrt((end - laserPointer.transform.position).magnitude / reticleDistance));
}
if ((end - laserPointer.transform.position).magnitude < laserDistance)
{
line.SetPosition(1, end);
}
else
{
line.SetPosition(1, laserPointer.transform.position + laserPointer.transform.forward * laserDistance);
}
}
else
{
//didn't hit anything
if (colliderRaycast)
{
//raycast enabled but didn't hit anything
if (lastHitGameObject != null)
{
EasyInputUtilities.notifyEvents(rayHit, lastRayHit, lastHitGameObject, false, false, true, laserPointer.transform);
lastHitGameObject = null;
lastRayHit = EasyInputConstants.NOT_VALID;
}
}
if (reticle != null)
{
reticle.transform.position = laserPointer.transform.position + laserPointer.transform.forward * reticleDistance;
reticle.transform.localScale = initialReticleSize;
}
line.SetPosition(1, laserPointer.transform.position + laserPointer.transform.forward * laserDistance);
}
if (reticle != null)
reticle.GetComponent<MeshRenderer>().material.color = reticleColor;
//UI based interactions
if (UIRaycast && InputModule != null && (motion.currentPos != Vector3.zero))
{
InputModule.setUIRay(laserPointer.transform.position, laserPointer.transform.rotation, reticleDistance);
uiHitPosition = InputModule.getuiHitPosition();
if (uiHitPosition != EasyInputConstants.NOT_VALID && (end == EasyInputConstants.NOT_VALID || (end - laserPointer.transform.position).magnitude > (uiHitPosition - laserPointer.transform.position).magnitude))
{
if ((uiHitPosition - laserPointer.transform.position).magnitude < reticleDistance)
{
reticle.transform.position = uiHitPosition;
reticle.transform.localScale = initialReticleSize * .6f * (Mathf.Sqrt((uiHitPosition - laserPointer.transform.position).magnitude / reticleDistance));
}
}
}
}
public void setInitialScale(Vector3 scale)
{
initialReticleSize = scale;
}
public void startLaser()
{
laserInteraction = true;
}
public void stopLaser()
{
laserInteraction = false;
}
}
}
So I feel stupid ... the issue was caused by an issue caused by a color being completely set to transparent. After fixing it I no longer had the issue I was facing. So, in other words, it wasn't a shader issue but human error when it comes to copying and pasting a color hex code ... Face Palm
Related
I'm new to using Unity and C# and I've been working on creating a movement system for a 2D platformer, and I've decided I want to switch to the new Unity Input System (because I can't find good information on the old one as all the search results I get are for the new one). I have it downloaded and installed and have watched a ton of videos but can't get any inputs to actually work in my game.
Here is the code which I need help translating:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class CharacterLogic : MonoBehaviour
{
private bool playerIsAlive = true;
Vector2 movementInput;
bool jumpInput;
bool doubleJumpInput;
private float sprintTimer;
private bool isSprinting;
private int jumpsRemaining = 1;
private bool facingRight = true;
private bool isGrounded;
private bool wallJumping = false;
[Header("Collision")]
public BoxCollider2D playerCollider;
public LayerMask jumpableGround;
[Header("Movement")]
public Rigidbody2D characterBody;
public float runSpeed = 7;
public float maxSpeed = 10;
public float jumpStrength = 11;
[Header("Camera Tracking")]
public CameraScript mainCamera;
public float zoomSpeed;
public float ZoomAmount;
public float maxZoomAmount;
[Header("Wall Jump System")]
public Transform frontCheck;
public float wallSlidingSpeed;
public float checkRadius;
public float xWallForce;
public float yWallForce;
public float wallJumpTime;
bool isTouchingFront;
bool wallSliding;
[Header("Animation Settings")]
public Animator animator;
private string currentState;
//Animation States
const string PLAYER_IDLE = "Idle";
const string PLAYER_RUN = "Running";
const string PLAYER_SPRINT = "Sprinting";
const string PLAYER_JUMP = "Jumping";
const string PLAYER_WALLSLIDE = "Wallslide";
[Header("Inputs")]
public PlayerInput playerInput;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
movementInput.x = Input.GetAxisRaw("Horizontal");
movementInput.y = Input.GetAxisRaw("Vertical");
isGrounded = Physics2D.BoxCast(playerCollider.bounds.center, playerCollider.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
if (Input.GetButtonDown("Jump"))
{
if (!isGrounded)
{
if (wallSliding)
{
jumpsRemaining += -1;
}else if (jumpsRemaining > 0)
{
jumpInput = true;
doubleJumpInput = true;
}
}
else if (isGrounded)
{
jumpInput = true;
}
// Wall jump
if (!facingRight)
{
if (movementInput.x > 0 && wallSliding == true)
{
wallJumping = true;
}
}else if (facingRight)
{
if (movementInput.x < 0 && wallSliding == true)
{
wallJumping = true;
}
}
}
}
void FixedUpdate()
{
// Flip the character sprite's direction
if (facingRight == false && movementInput.x > 0 && !wallSliding && (isGrounded || doubleJumpInput))
{
Flip();
} else if (facingRight == true && movementInput.x < 0 && !wallSliding && (isGrounded || doubleJumpInput))
{
Flip();
}
// Jump
if (jumpInput && playerIsAlive && wallSliding != true)
{
Jump();
}
// Run
if (movementInput.x != 0 && playerIsAlive && wallSliding == false)
{
Run();
if (characterBody.velocity.x == maxSpeed)
{
mainCamera.xOffset = 6;
//mainCamera.ZoomOut(maxZoomAmount, zoomSpeed);
}else if (characterBody.velocity.x == -maxSpeed)
{
mainCamera.xOffset = -6;
}
else
{
if (movementInput.x > 0)
{
mainCamera.xOffset = 4;
}else if (movementInput.x < 0)
{
mainCamera.xOffset = -4;
}
}
}
// Idle
if (((movementInput.x == 0) && (movementInput.y == 0)) && playerIsAlive && wallSliding == false)
{
Idle();
ChangeAnimationState(PLAYER_IDLE);
}
// Reset sprint timer
if (movementInput.x == 0)
{
sprintTimer = 0;
mainCamera.xOffset = 0;
}
// Reset double jump
if (isGrounded)
{
jumpsRemaining = 1;
}
// Detect wall collisions
isTouchingFront = Physics2D.OverlapCircle(frontCheck.position, checkRadius, jumpableGround);
if (isTouchingFront == true && !isGrounded && Input.GetButton("Fire1"))
{
wallSliding = true;
}
else
{
wallSliding = false;
}
if (wallSliding && !wallJumping)
{
WallSlide();
ChangeAnimationState(PLAYER_WALLSLIDE);
}
if (wallJumping == true)
{
ChangeAnimationState(PLAYER_JUMP);
Invoke("SetWallJumpingToFalse", wallJumpTime);
characterBody.velocity = new Vector2(xWallForce * movementInput.x, yWallForce);
Flip();
}
//Debug.Log(jumpsRemaining);
}
/// <summary>
/// This function sets the character's velocity in the Y axis to the value of `jumpStrength`,.
/// It also preserves the character's current velocity along the Y axis.
/// </summary>
public void Jump()
{
//Debug.Log("Normal Jump");
jumpsRemaining += -1;
Vector2 velocity = characterBody.velocity;
if ((velocity.x > 0 && movementInput.x > 0) || (velocity.x < 0 && movementInput.x < 0))
{
}
else
{
if (movementInput.x > 0)
{
velocity.x = 7;
}
else if (movementInput.x < 0)
{
velocity.x = -7;
}
}
velocity.y = jumpStrength;
characterBody.velocity = velocity;
jumpInput = false;
if (doubleJumpInput == true)
{
doubleJumpInput = false;
}
if (!isGrounded)
{
ChangeAnimationState(PLAYER_JUMP);
}
}
/// <summary>
/// This function sets the character's velocity in the X axis to the value of `runSpeed`.
/// It also preserves the character's current velocity along the Y axis.
/// </summary>
public void Run()
{
sprintTimer += Time.deltaTime;
Vector2 velocity = characterBody.velocity;
if (sprintTimer > 2 && characterBody.velocity.x != 0)
{
if (isGrounded)
{
if (movementInput.x > 0)
{
velocity.x = maxSpeed;
isSprinting = true;
ChangeAnimationState(PLAYER_SPRINT);
}
else if (movementInput.x < 0)
{
velocity.x = -maxSpeed;
isSprinting = true;
ChangeAnimationState(PLAYER_SPRINT);
}
} else
{
if (isSprinting == false)
{
if (velocity.x > 0)
{
velocity.x = runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
else if (velocity.x < 0)
{
velocity.x = -runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
}
}
}
else
{
if (movementInput.x > 0 && isGrounded)
{
velocity.x = runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
else if (movementInput.x < 0 && isGrounded)
{
velocity.x = -runSpeed;
isSprinting = false;
ChangeAnimationState(PLAYER_RUN);
}
}
characterBody.velocity = velocity;
}
public void Idle()
{
characterBody.velocity = new Vector2(0, characterBody.velocity.y);
}
private void Flip()
{
facingRight = !facingRight;
Vector3 scaler = transform.localScale;
scaler.x *= -1;
transform.localScale = scaler;
}
private void WallSlide()
{
//Flip();
characterBody.velocity = new Vector2(characterBody.velocity.x, Mathf.Clamp(characterBody.velocity.y, -wallSlidingSpeed, float.MaxValue));
}
private void ChangeAnimationState(string newState)
{
// Stop the same animation from interrupting itself
if (currentState == newState) return;
//Play the animation
animator.Play(newState);
// Reassign the current state to the new state
currentState = newState;
}
private void SetWallJumpingToFalse()
{
wallJumping = false;
jumpsRemaining = 1;
}
public void OnJump(InputAction.CallbackContext value)
{
Debug.Log("Jump");
}
public void OnMovement(InputAction.CallbackContext value)
{
Vector2 inputMovement = value.ReadValue<Vector2>();
Debug.Log("Jump");
}
}
If anyone can help dumb this down for me I'd be eternally grateful. As you can see from the last two functions, I am trying to trigger unity events, assign the events to functions and write to the Debug.log so that I can see it's working. For instance currently, it should say "Jump" when I press the button I've mapped to "Jump" in the action map, but in reality it just triggers the old input manager stuff normally and the new stuff does nothing.
I have the PlayerInput class correctly attached to the CharacterLogic script in the inspector, and I believe everything is set up correctly with the events calling the right action map and function from my code (screenshot attached)
Help?
I have tried following every guide I could see on youtube and they were overly complicated and I couldn't see how I could translate how my old input system was working over to their methods.
Yeah I figured out the actual issue. When you create a control scheme, you are given the "option" to add a requirement. It's not optional, if you don't add a requirement, it won't work. That should really be made a mandatory field.
I'm developing a game where the character moves along a predefined path and I want to use the A* algorithm to look for this path. The script I have to do this movement is this one, to look for the path:
public class PathManager : MonoBehaviour {
public float walkSpeed = 5.0f;
public LayerMask mask;
public List<Waypoint> allWayPoints = new List<Waypoint>();
private Stack<Vector3> currentPath;
private Vector3 currentWaypointPosition;
private float moveTimeTotal;
private float moveTimeCurrent;
private Transform cam;
private void Start() {
cam = Camera.main.transform;
}
void Update() {
if (currentPath != null && currentPath.Count > 0) {
if (moveTimeCurrent < moveTimeTotal) {
moveTimeCurrent += Time.deltaTime;
if (moveTimeCurrent > moveTimeTotal)
moveTimeCurrent = moveTimeTotal;
Vector3 temp = currentPath.Peek();
temp.y = 1;
currentWaypointPosition.y = 1;
transform.position = Vector3.Lerp(currentWaypointPosition, temp, moveTimeCurrent / moveTimeTotal);
} else {
currentWaypointPosition = currentPath.Pop();
if (currentPath.Count == 0)
Stop();
else {
moveTimeCurrent = 0;
moveTimeTotal = (currentWaypointPosition - currentPath.Peek()).sqrMagnitude / walkSpeed;
}
}
}
if (Input.GetButtonDown("Fire1")) {
Stop();
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(cam.transform.position, ray.direction, out hit)) {
Debug.Log(hit.collider);
Waypoint temp = hit.collider.GetComponent<Waypoint>();
Vector3 location = temp.GetCurrentPosition();
Debug.Log(location);
NavigateTo(location);
}
}
}
public void NavigateTo(Vector3 destination)
{
currentPath = new Stack<Vector3> ();
var currentNode = FindClosestWaypoint (transform.position);
var endNode = FindClosestWaypoint (destination);
if (currentNode == null || endNode == null || currentNode == endNode)
return;
var openList = new SortedList<float, Waypoint> ();
var closedList = new List<Waypoint> ();
openList.Add (0, currentNode);
currentNode.previous = null;
currentNode.distance = 0f;
while (openList.Count > 0)
{
currentNode = openList.Values[0];
openList.RemoveAt (0);
var dist = currentNode.distance;
closedList.Add (currentNode);
if (currentNode == endNode){
break;
}
foreach (var neighbor in currentNode.neighbors)
{
if (closedList.Contains (neighbor) || openList.ContainsValue (neighbor))
continue;
neighbor.previous = currentNode;
neighbor.distance = dist + (neighbor.transform.position - currentNode.transform.position).sqrMagnitude;
var distanceToTarget = (neighbor.transform.position - endNode.transform.position).sqrMagnitude;
openList.Add (neighbor.distance + distanceToTarget, neighbor);
}
}
if (currentNode == endNode) {
while (currentNode.previous != null){
currentPath.Push (currentNode.transform.position);
currentNode = currentNode.previous;
}
currentPath.Push (transform.position);
}
}
public void Stop() {
currentPath = null;
moveTimeTotal = 0;
moveTimeCurrent = 0;
currentWaypointPosition = Vector3.zero;
}
private Waypoint FindClosestWaypoint(Vector3 target){
GameObject closest = null;
float closestDist = Mathf.Infinity;
foreach (var waypoint in allWayPoints) {
var dist = (waypoint.transform.position - target).sqrMagnitude;
if (dist < closestDist) {
closest = waypoint.gameObject;
closestDist = dist;
}
}
if (closest != null){
return closest.GetComponent<Waypoint> ();
}
return null;
}
}
And this other script on the "walkable" elements:
public class Waypoint : MonoBehaviour {
public List<Waypoint> neighbors;
[Range(0.1f, .5f)]
public float range = 0.1f;
public Waypoint previous;
public float distance;
public bool active = true;
public Vector3 GetCurrentPosition() {
return (transform.position + transform.up - transform.up * 0.5f);
}
void OnDrawGizmos() {
if (neighbors == null)
return;
Gizmos.color = Color.red;
Gizmos.DrawSphere(GetCurrentPosition(), range);
Gizmos.color = Color.blue;
foreach (var neighbor in neighbors) {
if (neighbor != null)
Gizmos.DrawLine (GetCurrentPosition(), neighbor.GetCurrentPosition());
}
}
}
However, I have two problems using this code, the first problem is, I can only put two directions to move, and the second problem is that I can't add obstacles on the way.
I'm calling the Loop() function through the editor inspector button On Click event.
When clicking the button twice each time it's changing the loop flag state false and true.
I want that it will work when changing in the inspector the bool flag so it will change the button state colors green and red. Now it's working only when clicking the button it's changing the button colors and the flag state in the inspector but when changing the flag loop in the inspector it's not changing the colors in the Loop() function.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class MoveOnCurvedLines : MonoBehaviour
{
public LineRenderer lineRenderer;
public float speed;
public bool go = false;
public bool moveToFirstPositionOnStart = false;
public float rotSpeed;
public bool loop = false;
public bool changeDir = false;
public bool pingPong = false;
public bool stop = false;
public bool random = false;
public int currentCurvedLinePointIndex;
public TextMeshProUGUI lastWaypointText;
public TextMeshProUGUI countWaypointText;
public Text loopText;
private Vector3[] positions;
private Vector3[] pos;
private int index = 0;
private bool goForward = true;
private List<GameObject> curvedLinePoints = new List<GameObject>();
private int numofposbetweenpoints;
private bool getPositions = false;
int randomIndex;
int curvedPointsIndex;
private bool atLastOne = false;
private bool changeDirOnce = true;
// Start is called before the first frame update
void Start()
{
curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();
if (curvedLinePoints != null && curvedLinePoints.Count > 0)
{
transform.rotation = curvedLinePoints[1].transform.rotation;
}
if (random)
GetNewRandomIndex();
if (lastWaypointText != null)
{
lastWaypointText.text = "Last Waypoint : " + (curvedPointsIndex + 1).ToString();
}
if (countWaypointText != null)
{
countWaypointText.text = "Waypoints Count : " + curvedLinePoints.Count.ToString();
}
Loop();
}
Vector3[] GetLinePointsInWorldSpace()
{
if (lineRenderer != null)
{
positions = new Vector3[lineRenderer.positionCount];
//Get the positions which are shown in the inspector
lineRenderer.GetPositions(positions);
}
//the points returned are in world space
return positions;
}
// Update is called once per frame
void Update()
{
if (lineRenderer != null)
{
if (curvedLinePoints.Count > 0)
{
for (int i = 0; i < curvedLinePoints.Count; i++)
{
if (curvedLinePoints[i].transform.hasChanged)
{
getPositions = false;
}
}
}
if (lineRenderer.positionCount > 0 && getPositions == false)
{
pos = GetLinePointsInWorldSpace();
numofposbetweenpoints = pos.Length / curvedLinePoints.Count;
if (moveToFirstPositionOnStart == true)
{
transform.position = pos[index];
}
getPositions = true;
}
if (go == true && lineRenderer.positionCount > 0)
{
Move();
Vector3 targetDirection = (curvedLinePoints[c].transform.position - transform.position).normalized;
curvedLinePoints[c].transform.localRotation = Quaternion.LookRotation(targetDirection);
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, curvedLinePoints[c].transform.localRotation, Time.deltaTime * rotSpeed);
}
if (curvedLinePoints.Count > 1)
{
var dist = Vector3.Distance(transform.position, curvedLinePoints[curvedPointsIndex].transform.position);
if (dist < 0.1f)
{
if (curvedPointsIndex < curvedLinePoints.Count - 1)
{
curvedPointsIndex++;
if (lastWaypointText != null)
{
lastWaypointText.text = "Last Waypoint : " + curvedPointsIndex.ToString();
}
}
else
{
if (lastWaypointText != null)
{
lastWaypointText.text = "Last Waypoint : " + (curvedPointsIndex + 1).ToString();
}
curvedPointsIndex = 0;
}
currentCurvedLinePointIndex = curvedPointsIndex;
}
}
}
}
int counter = 0;
int c = 1;
void Move()
{
if (pingPong && index + 30 <= pos.Length - 1)
{
transform.position = Vector3.Lerp(pos[index + 30], pos[index], Mathf.PingPong(Time.time, 1));
}
else
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
if (changeDir && goForward && changeDirOnce)
{
goForward = false;
changeDirOnce = false;
}
if (changeDir == false && goForward == false && changeDirOnce == false)
{
goForward = true;
changeDirOnce = true;
}
Vector3 oldPos = newPos;
newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
atLastOne = index >= pos.Length - 1;
if (!atLastOne)
{
index++;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else
{
if (stop && index == pos.Length - 1)
{
break;
}
else
{
if (loop)
{
index = 0;
}
else
{
index--;
goForward = false;
}
}
}
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne)
{
index--;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else
{
if (stop && index == 0)
{
break;
}
else
{
if (loop)
{
index = pos.Length - 1;
}
else
{
index++;
goForward = true;
}
}
}
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
}
void GetNewRandomIndex()
{
randomIndex = UnityEngine.Random.Range(0, curvedLinePoints.Count);
}
public void Loop()
{
var c = loopText.GetComponent<Text>();
loop = !loop;
if (loop)
{
c.color = Color.green;
}
else
{
c.color = Color.red;
}
loopText.text = loop.ToString();
}
}
I'm programming 2D Platformer I had problem/issue/weird situation - name it like you want. First of all, on my base Scene I have 4 Blobs (like on picture):
View from my Scene:
The thing is: When I hit the biggest one it gets damage bo no knockback, the smaller one above got knock back effect and no damage. Every one of them are on Enemy Tag and Enemy Layer.
Funny Thing - when only one of them is on Enemy Layer and Tag, it gets correct effect (damage + knockback). Is it scripting issue or I messed something up in Unity.
PS. Another Funny Thing - when I set every Blob being on Enemy Layer and Tag. And I hit directly (and exactly) the one above me (with yellow arrow). It behaves correctly... So I'm even move confused.
My Code (Sorry it's compacted to one big file because of testing) Fighting and Moving
[PlayerControls.cs] :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityEngine.Animations;
using UnityEngine.SceneManagement;
public class PlayerControls : MonoBehaviour
{
private float moveHoriz;
public float speed;
public bool grounded;
private float crouch;
public bool crouching;
private Rigidbody2D rb;
bool sliding;
public float slideTimer;
public float maxSlideTime;
public float jumpForce;
public bool facingRight = true;
public bool isDoubleJump = true;
public LayerMask whatIsGround;
public float groundRadius;
public Transform GroundCheck;
public Transform CeilingCheck;
private bool ceiled;
public Transform NearGroundCheck;
private bool isGroundNear;
private int extraJumps;
public int extraJumpValues;
private bool jumping;
private bool attack1;
private bool attack2;
private bool attack3;
private bool airAttack1;
public bool goodOrder1;
public bool goodOrder2;
public bool goodOrder3;
public bool badOrder2;
public bool badOrder3;
public bool combo;
public float comboDuration;
public float comboEndup = 1;
private bool shootBow;
public bool reloadBow = true;
public int reloadTime = 1;
public Transform attackPos;
public float attackRange;
public LayerMask whatIsEnemy;
public int damage;
private EnemyScript enemy;
public Animator animator;
// Use this for initialization
void Start()
{
extraJumps = extraJumpValues;
rb = GetComponent<Rigidbody2D>();
enemy = GameObject.FindGameObjectWithTag("Enemy").GetComponent<EnemyScript>();
}
// Update is called once per frame
void Update()
{
animator.SetFloat("Speed", Mathf.Abs(moveHoriz));
animator.SetBool("Grounded", grounded);
animator.SetFloat("vertSpeed", rb.velocity.y);
animator.SetInteger("isDoubleJump", extraJumps);
animator.SetBool("Crouch", crouching);
animator.SetBool("isSliding", sliding);
animator.SetFloat("stopSliding", slideTimer);
animator.SetBool("isGroundNear", isGroundNear);
animator.SetBool("comboAttack", combo);
animator.SetFloat("comboDuration", comboDuration);
animator.SetBool("reloadBow", reloadBow);
animator.SetFloat("reloadTime", reloadTime);
animator.SetBool("goodOrder1", goodOrder1);
animator.SetBool("goodOrder2", goodOrder2);
animator.SetBool("goodOrder3", goodOrder3);
animator.SetBool("badOrder2", badOrder2);
animator.SetBool("badOrder3", badOrder3);
moveHoriz = Input.GetAxisRaw("Horizontal");
crouch = Input.GetAxisRaw("Crouch");
RangeAttack();
OrderCheck();
Crouch();
if (grounded != true)
{
jumping = true;
sliding = false;
slideTimer = 0;
}
if (grounded == true)
{
jumping = false;
extraJumps = extraJumpValues;
}
if (Input.GetKeyDown(KeyCode.UpArrow) && extraJumps > 0)
{
jumping = true;
rb.velocity = Vector2.up * jumpForce;
extraJumps--;
}
else if (Input.GetKeyDown(KeyCode.UpArrow) && extraJumps == 0 && grounded == true)
{
rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKeyDown(KeyCode.H))
{
Die();
}
}
void FixedUpdate()
{
grounded = Physics2D.OverlapCircle(GroundCheck.position, groundRadius, whatIsGround);
ceiled = Physics2D.OverlapCircle(CeilingCheck.position, groundRadius, whatIsGround);
isGroundNear = Physics2D.OverlapCircle(NearGroundCheck.position, groundRadius, whatIsGround); ;
rb.velocity = new Vector2(moveHoriz * speed, rb.velocity.y);
Move();
Flip();
Sliding();
Combo();
HandleInput();
HandleAttacks();
DealDmg();
ResetValues();
}
void Move()
{
rb.velocity = new Vector2(moveHoriz * speed, rb.velocity.y);
}
// Flip (or better said Rotate) Character.
void Flip()
{
if ((moveHoriz < 0 && facingRight == true) || (moveHoriz > 0 && facingRight == false))
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
void Crouch()
{
if ((crouch != 0 || ceiled == true) && grounded == true)
{
crouching = true;
}
else
{
crouching = false;
}
if (crouching)
{
speed = 10;
}
else
{
speed = 15;
}
}
void Sliding()
{
//If statement to check if player is sliding to maxSlide capacity
if (Input.GetButtonDown("Crouch") && speed > 0)
{
slideTimer = 0f;
sliding = true;
if (slideTimer >= maxSlideTime && sliding == true || moveHoriz == 0)
{
sliding = false;
animator.SetBool("isSliding", false);
crouching = true;
animator.SetBool("Crouch", false);
}
}
if (slideTimer < maxSlideTime && moveHoriz == 0 && crouch > 0)
{
sliding = false;
animator.SetBool("isSliding", false);
animator.SetBool("Crouch", true);
crouching = true;
}
if (sliding)
{
speed = 25;
slideTimer += Time.deltaTime;
if (slideTimer >= maxSlideTime || jumping == true)
{
sliding = false;
animator.SetBool("isSliding", false);
speed = 15;
}
if (facingRight == true)
{
rb.velocity = Vector2.right * speed;
}
else if (facingRight != true)
{
rb.velocity = Vector2.left * speed;
}
}
}
void HandleAttacks()
{
if (attack1 == true)
{
goodOrder1 = true;
goodOrder2 = false;
goodOrder3 = false;
}
if (attack2 == true)
{
goodOrder1 = false;
goodOrder2 = true;
goodOrder3 = false;
}
if (attack3 == true)
{
goodOrder1 = false;
goodOrder2 = false;
goodOrder3 = true;
}
if (airAttack1)
{
animator.SetTrigger("airAttack1");
attackRange = 1;
}
}
private void HandleInput()
{
if (Input.GetButtonDown("Attack1"))
{
attack1 = true;
}
else if (Input.GetButtonUp("Attack1"))
{
attack1 = false;
}
if (Input.GetButtonDown("Attack2"))
{
attack2 = true;
}
else if (Input.GetButtonUp("Attack2"))
{
attack2 = false;
}
if (Input.GetButtonDown("Attack3"))
{
attack3 = true;
}
else if (Input.GetButtonUp("Attack3"))
{
attack3 = false;
}
if (grounded == false && (Input.GetButtonDown("Attack1") || Input.GetButtonDown("Attack2") || Input.GetButtonDown("Attack3")))
{
airAttack1 = true;
attack1 = false;
}
if (airAttack1 == true && grounded == true)
{
airAttack1 = false;
}
}
void OrderCheck()
{
// First sequence attack
if (grounded == true && attack1 == true && comboDuration > 0)
{
goodOrder1 = true;
}
else if (goodOrder1 != true && grounded == true && attack2 == true && comboDuration <= 0)
{
badOrder2 = true;
}
// Second sequence attack
if (grounded == true && attack2 == true && comboDuration > 0)
{
goodOrder2 = true;
}
else if (goodOrder1 != true && grounded == true && attack3 == true && comboDuration <= 0)
{
badOrder3 = true;
}
// Third sequence attack
if (grounded == true && attack3 == true && comboDuration > 0)
{
goodOrder3 = true;
}
else if (goodOrder2 != true && grounded == true && goodOrder1 != true && comboDuration > 0)
{
badOrder3 = true;
}
// Clear if badOrder's achived
if (badOrder2 == true || badOrder3 == true)
{
goodOrder1 = false;
goodOrder2 = false;
goodOrder3 = false;
}
}
void Combo()
{
if (attack1 == true)
{
comboDuration = comboEndup;
}
/*if ((goodOrder1 == true || goodOrder2 == true || goodOrder3 == true) || (badOrder2 == true || badOrder3 == true))
{
comboDuration = comboEndup;
}*/
// comboEndup = 1; - reminder
if (comboDuration > 0)
{
comboDuration -= Time.deltaTime;
combo = true;
}
if (comboDuration <= 0 || (badOrder2 == true || badOrder3 == true))
{
comboDuration = 0;
combo = false;
goodOrder1 = false;
goodOrder2 = false;
goodOrder3 = false;
badOrder2 = false;
badOrder3 = false;
}
}
void ResetValues()
{
if (badOrder2 == true || badOrder3 == true)
{
badOrder2 = false;
badOrder3 = false;
}
airAttack1 = false;
if (gameObject.GetComponent<PlayerControls>().grounded == true && airAttack1 == true)
{
airAttack1 = false;
}
}
private void RangeAttack()
{
if (grounded == true && Input.GetButtonDown("Ranged"))
{
animator.SetTrigger("shootBow");
reloadBow = false;
attack1 = false;
attack2 = false;
attack3 = false;
}
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(attackPos.position, attackRange);
}
public void DealDmg()
{
if (attackPos.gameObject.activeSelf == true)
{
Collider2D[] enemiesToDamage = Physics2D.OverlapCircleAll(attackPos.position, attackRange, whatIsEnemy);
for (int i = 0; i < enemiesToDamage.Length; i++)
{
enemiesToDamage[i].GetComponent<EnemyScript>().TakeDmg(damage);
if (facingRight == true)
{
gameObject.GetComponent<EnemyScript>().EnemyRB.AddForce(transform.up * 500 + transform.right * 500);
}
else if (facingRight == false)
{
gameObject.GetComponent<EnemyScript>().EnemyRB.AddForce(transform.up * 500 + (transform.right * 500) * -1);
}
attackPos.gameObject.SetActive(false);
}
}
}
void Die()
{
SceneManager.LoadScene(0);
}
}
Enemy Movement [EnemyScript.cs]:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyScript : MonoBehaviour {
public float speed;
public float distance;
public int health;
public bool movingRight = true;
public Transform groundDetection;
public Rigidbody2D EnemyRB;
public bool trap;
public LayerMask TrapLayer;
public Transform ColideDetector;
public float detectorRadius;
public BoxCollider2D CheckHeadBounce;
// Use this for initialization
void Start ()
{
EnemyRB = gameObject.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update ()
{
trap = Physics2D.OverlapCircle(ColideDetector.position, detectorRadius, TrapLayer);
if (health <= 0)
{
Destroy(gameObject);
}
transform.Translate(Vector2.right * speed * Time.deltaTime );
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, distance);
if (groundInfo.collider == false || trap == true)
{
if(movingRight == true)
{
transform.eulerAngles = new Vector3(0, -180, 0);
movingRight = false;
}
else
{
transform.eulerAngles = new Vector3(0, 0, 0);
movingRight = true;
}
}
}
public void HeadBounce()
{
}
public void TakeDmg(int damage)
{
health -= damage;
Debug.Log("damage TAKEN!");
}
}
It's a gif to show what is going on
PlayerInspector - PlayerScript
Enemy Inspector - EnemyScript
You don't use the right reference of EnemyScript inside DealDmg. In the loop, you first call TakDmg on the enemy found from OverlapCircleAll, then you call AddForce on gameObject.GetComponent<EnemyScript>().EnemyRB.
Within this context, gameObject refer to the GameObject the running script is attached to (PlayerControl.cs here). You need to apply the force on the rigidbody of the gameobject inside the collision array enemisToDamage, just like you did with TakeDmg.
Here is a possible solution.
public void DealDmg()
{
if (attackPos.gameObject.activeSelf == true)
{
Collider2D[] enemiesToDamage = Physics2D.OverlapCircleAll(attackPos.position, attackRange, whatIsEnemy);
for (int i = 0; i < enemiesToDamage.Length; i++)
{
EnemyScript enemyScript = enemiesToDamage[i].GetComponent<EnemyScript>();
enemyScript.TakeDmg(damage);
if (facingRight == true)
{
enemyScript.GetComponent<RigidBody>().AddForce(transform.up * 500 + transform.right * 500);
}
else if (facingRight == false)
{
enemyScript.GetComponent<RigidBody>().AddForce(transform.up * 500 + (transform.right * 500) * -1);
}
attackPos.gameObject.SetActive(false);
}
}
}
I'm making a 2D platform fighter but I've looked all over the internet and I'm not sure i can find what I'm looking for. I'm trying to make a melee attack to when you hit R-click on the mouse it dashes in the direction you are walking.
Ill try and figure out knock-back or dmg later. Any help with the movement of the script?
I'll list my current movement code below.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace NinjaController {
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Collider2D))]
public class NinjaController : MonoBehaviour {
private Rigidbody2D RBody { get; set; }
[SerializeField]
private PhysicsParams physicsParams;
public Vector2 Velocity { get { return(RBody.velocity); } }
public Vector2 VelocityRelativeGround { get { return(Velocity / PhysicsParams.onGroundMaxVelHorizontal); } }
private float timeRealLastGroundCollision = 0;
private float timeRealLastWallLeftCollision = 0;
private float timeRealLastWallRightCollision = 0;
public bool IsOnGround {
get {
return GetIsColliding(timeRealLastGroundCollision);
}
}
public bool IsOnWallLeft {
get {
return GetIsColliding(timeRealLastWallLeftCollision);
}
}
public bool IsOnWallRight {
get {
return GetIsColliding(timeRealLastWallRightCollision);
}
}
public bool IsInAir { get { return isPlayerInAir; } }
private bool GetIsColliding(float timeLastCollision) {
return(Time.realtimeSinceStartup < timeLastCollision + 0.05f);
}
private Vector2 currentVelocity = Vector2.zero;
private Vector2 currentForce = Vector2.zero;
private float EntityMass { get { return(PhysicsParams.playerMass); } }
private bool isPlayerInAir = false;
private bool keyJumpRetrigger = false;
private bool keyJumpPressed = false;
private bool isPlayerOnWall = false;
public PhysicsParams PhysicsParams {
get { return physicsParams; }
set { physicsParams = value; }
}
public Vector2 CurrentForce { get { return currentForce; } }
public bool IsOnWall { get { return isPlayerOnWall; } }
private List<Renderer> allRenderers;
public List<Renderer> AllRenderers { get { return allRenderers; } }
public Vector3 Position {
get {
return transform.position;
}
set {
transform.position = value;
}
}
public Vector2 Position2D {
get {
return transform.position;
}
set {
transform.position = value;
}
}
public void Awake() {
RBody = GetComponent<Rigidbody2D>();
allRenderers = new List<Renderer>(GetComponentsInChildren<Renderer>(true));
}
public void Update() {
//let's reset forces to 0 and then add regular gravitation
SimResetForce();
SimAddForce(new Vector2(0, PhysicsParams.gameGravity) * EntityMass);
//process key input (like jumping key pressed, etc...)
ProcessInput();
//simulate position and velocity based on all acting forces
ComputeVelocity(Time.deltaTime);
//collision detection with static world
isPlayerOnWall = IsOnWallLeft || IsOnWallRight;
isPlayerInAir = IsOnGround == false;
}
private void SimResetForce() {
currentForce = Vector2.zero;
}
private void SimAddForce(Vector2 force) {
currentForce += force;
}
private void ComputeVelocity(float dt) {
currentVelocity += (currentForce / EntityMass) * dt;
//let's cap the speed in case its higher than the max
if (isPlayerInAir) {
currentVelocity.x = Mathf.Clamp(currentVelocity.x, -PhysicsParams.inAirMaxVelHorizontal, PhysicsParams.inAirMaxVelHorizontal);
} else {
currentVelocity.x = Mathf.Clamp(currentVelocity.x, -PhysicsParams.onGroundMaxVelHorizontal, PhysicsParams.onGroundMaxVelHorizontal);
}
RBody.velocity = currentVelocity;
}
private void ProcessInput() {
bool isKeyDownJump = Input.GetButton("Jump");
float inputAxisX = Input.GetAxisRaw("Horizontal");
bool isKeyDownLeft = inputAxisX < -0.5f;
bool isKeyDownRight = inputAxisX > 0.5f;
//-----------------
//JUMPING LOGIC:
//player is on ground
if (isPlayerInAir == false) {
//in case the player is on ground and does not press the jump key, he
//should be allowed to jump
if (isKeyDownJump == false) {
keyJumpRetrigger = true;
}
//did player press down the jump button?
if (isKeyDownJump == true && keyJumpRetrigger == true) {
keyJumpPressed = true;
keyJumpRetrigger = false;
//when pressing jump on ground we set the upwards velocity directly
currentVelocity = new Vector2(currentVelocity.x, PhysicsParams.jumpUpVel);
}
} else if (isPlayerOnWall == true) {
//let's allow jumping again in case of being on the wall
if (isKeyDownJump == false) {
keyJumpRetrigger = true;
}
if (currentVelocity.y < 0) {//apply friction when moving downwards
SimAddForce(new Vector2(0, PhysicsParams.wallFriction) * EntityMass);
}
if (currentVelocity.y < PhysicsParams.wallFrictionStrongVelThreshold) {//apply even more friction when moving downwards fast
SimAddForce(new Vector2(0, PhysicsParams.wallFrictionStrong) * EntityMass);
}
if (isKeyDownJump == true && keyJumpRetrigger == true) {
keyJumpPressed = true;
keyJumpRetrigger = false;
//in case we are moving down -> let's set the velocity directly
//in case we are moving up -> sum up velocity
if (IsOnWallLeft == true) {
if (currentVelocity.y <= 0) {
currentVelocity = new Vector2(PhysicsParams.jumpWallVelHorizontal, PhysicsParams.jumpWallVelVertical);
} else {
currentVelocity = new Vector2(PhysicsParams.jumpWallVelHorizontal, currentVelocity.y + PhysicsParams.jumpWallVelVertical);
}
} else if (IsOnWallRight == true) {
if (currentVelocity.y <= 0)
currentVelocity = new Vector2(-PhysicsParams.jumpWallVelHorizontal, PhysicsParams.jumpWallVelVertical);
else
currentVelocity = new Vector2(-PhysicsParams.jumpWallVelHorizontal, currentVelocity.y + PhysicsParams.jumpWallVelVertical);
}
}
}
//did player lift the jump button?
if (isKeyDownJump == false) {
keyJumpPressed = false;
}
//let's apply force in case we are holding the jump key during a jump.
if (keyJumpPressed == true) {
SimAddForce(new Vector2(0, PhysicsParams.jumpUpForce) * EntityMass);
}
//however let's stop doing that as soon as we fall down after the up-phase.
if (keyJumpPressed == true && currentVelocity.y <= 0) {
keyJumpPressed = false;
}
//let's apply additional gravity in case we're in air moving up but not holding the jump button
if (keyJumpPressed == false && isPlayerInAir == true && currentVelocity.y > 0) {
SimAddForce(new Vector2(0, PhysicsParams.jumpGravity) * EntityMass);
}
//-----------------
//IN AIR SIDEWAYS:
if (isPlayerInAir == true) {
//steering into moving direction (slow accel)
if (isKeyDownLeft == true && currentVelocity.x <= 0)
SimAddForce(new Vector2(-PhysicsParams.inAirMoveHorizontalForce, 0) * EntityMass);
else if (isKeyDownRight == true && currentVelocity.x >= 0)
SimAddForce(new Vector2(PhysicsParams.inAirMoveHorizontalForce, 0) * EntityMass);
//steering against moving direction (fast reverse accel)
else if (isKeyDownLeft == true && currentVelocity.x >= 0)
SimAddForce(new Vector2(-PhysicsParams.inAirMoveHorizontalForceReverse, 0) * EntityMass);
else if (isKeyDownRight == true && currentVelocity.x <= 0)
SimAddForce(new Vector2(PhysicsParams.inAirMoveHorizontalForceReverse, 0) * EntityMass);
}
//-----------------
//ON GROUND SIDEWAYS:
if (isPlayerInAir == false) {
//steering into moving direction (slow accel)
if (isKeyDownLeft == true && currentVelocity.x <= 0)
SimAddForce(new Vector2(-PhysicsParams.onGroundMoveHorizontalForce, 0) * EntityMass);
else if (isKeyDownRight == true && currentVelocity.x >= 0)
SimAddForce(new Vector2(PhysicsParams.onGroundMoveHorizontalForce, 0) * EntityMass);
//steering against moving direction (fast reverse accel)
else if (isKeyDownLeft == true && currentVelocity.x >= 0)
SimAddForce(new Vector2(-PhysicsParams.onGroundMoveHorizontalForceReverse, 0) * EntityMass);
else if (isKeyDownRight == true && currentVelocity.x <= 0)
SimAddForce(new Vector2(PhysicsParams.onGroundMoveHorizontalForceReverse, 0) * EntityMass);
//not steering -> brake due to friction.
else if (isKeyDownLeft != true && isKeyDownRight != true && currentVelocity.x > 0)
SimAddForce(new Vector2(-PhysicsParams.groundFriction, 0) * EntityMass);
else if (isKeyDownLeft != true && isKeyDownRight != true && currentVelocity.x < 0)
SimAddForce(new Vector2(PhysicsParams.groundFriction, 0) * EntityMass);
//in case the velocity is close to 0 and no keys are pressed we should make the the player stop.
//to do this let's first undo the prior friction force, and then set the velocity to 0.
if (isKeyDownLeft != true && isKeyDownRight != true && currentVelocity.x > 0 && currentVelocity.x < PhysicsParams.groundFrictionEpsilon) {
SimAddForce(new Vector2(PhysicsParams.groundFriction, 0) * EntityMass);
currentVelocity.x = 0;
} else if (isKeyDownLeft != true && isKeyDownRight != true && currentVelocity.x < 0 && currentVelocity.x > -PhysicsParams.groundFrictionEpsilon) {
SimAddForce(new Vector2(-PhysicsParams.groundFriction, 0) * EntityMass);
currentVelocity.x = 0;
}
}
}
public void ResetVelocity() {
currentVelocity = Vector2.zero;
}
public void OnCollisionStay2D(Collision2D collision) {
foreach (ContactPoint2D contactPoint in collision.contacts) {
if (GetIsVectorClose(new Vector2(0, 1), contactPoint.normal)) {
timeRealLastGroundCollision = Time.realtimeSinceStartup;
currentVelocity.y = Mathf.Clamp(currentVelocity.y, 0, Mathf.Abs(currentVelocity.y));
}
if (GetIsVectorClose(new Vector2(1, 0), contactPoint.normal)) {
timeRealLastWallLeftCollision = Time.realtimeSinceStartup;
currentVelocity.x = Mathf.Clamp(currentVelocity.x, 0, Mathf.Abs(currentVelocity.x));
}
if (GetIsVectorClose(new Vector2(-1, 0), contactPoint.normal)) {
timeRealLastWallRightCollision = Time.realtimeSinceStartup;
currentVelocity.x = Mathf.Clamp(currentVelocity.x, -Mathf.Abs(currentVelocity.x), 0);
}
if(GetIsVectorClose(Vector2.down, contactPoint.normal)) {
currentVelocity.y = Mathf.Clamp(currentVelocity.y, -Mathf.Abs(currentVelocity.y), 0);
}
}
}
private bool GetIsVectorClose(Vector2 vectorA, Vector2 vectorB) {
return(Mathf.Approximately(0, Vector2.Distance(vectorA, vectorB)));
}
public void OnLifeChanged (int life, Vector2 contactVector) {
const float forceEnemyCollision = 15.0f;
currentVelocity = contactVector.normalized * forceEnemyCollision;
}
public void ResetPlayer() {
currentVelocity = Vector2.zero;
}
}
}
For dashing, it will be something along the line of:
bool isDashing;
float currentDashTime = 0; // How long in seconds since the dash started.
float dashTime = 1f; // How long in seconds will the dash be.
float dashSpeed = 10f;
private void Update()
{
if (Input.GetMouseButtonDown(1)) // Right click
{
if (!isDashing) StartCoroutine(Dash());
}
}
private IEnumerator Dash()
{
isDashing = true;
currentDashTime = 0;
Vector2 facingDirection = new Vector2(transform.right.x, transform.right.y)
rb2d.AddForce(facingDirection * dashSpeed);
while (currentDashTime < dashTime)
{
currentDashTime += Time.deltaTime;
yield return null;
}
// If you want the character to stop after dashing ends.
// rb.velocity = Vector2.zero;
isDashing = false;
}
As for melee attacks, I'll recommend looking into 2D Raycasts, provided your enemies have colliders on them. You can raycast before you start dashing so you know what you will collide with during the dash beforehand.
RaycastHit2D hit = Physics2D.Raycast(transform.position, facingDirection);
if (hit.collider != null)
{
// Check for enemy, damage the enemy... etc.
}
Use Physics2D.RaycastAll if you want to get all enemies hit along a line. Physics2D.RayCast only returns the first collider hit.