Unity: Knockback my player along the Y-axis - c#

I don't think the Y-axis for my code is working. Iv'e tried increasing the yForceToAdd and the localScale.y but (when I collide with the object that has this script attached to it) my player only goes (when I collide at the top of the object) X=1, Y=1 or X=-1, Y=1 and not X=0, Y=1 as well. the same problem with the bottom of my object X=0, Y=-1 doesn't seem to work either. can someone help with this problem?
public float xForceToAdd;
public float yForceToAdd;
void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.tag == "Player")
{
//Store the vector 2 of the location where the initial hit happened;
Vector2 initialHitPoint = new Vector2(other.gameObject.transform.position.x, other.gameObject.transform.position.y);
float xForce = 0;
float yForce = 0;
//Grab our collided with objects rigibody
Rigidbody2D rigidForForce = other.gameObject.GetComponent < Rigidbody2D > ();
//Determine left right center of X hit
if (initialHitPoint.x > (this.transform.position.x + (this.transform.localScale.x / 3)))
{
xForce = 1;
}
else if (initialHitPoint.x < (this.transform.position.x - (this.transform.localScale.x / 3)))
{
xForce = -1;
}
else
{
xForce = 0;
}
if (initialHitPoint.y > (this.transform.position.y + (this.transform.localScale.y / 3)))
{
yForce = 1;
}
else if (initialHitPoint.y < (this.transform.position.y - (this.transform.localScale.y / 3)))
{
yForce = -1;
}
else
{
yForce = 0;
}
rigidForForce.velocity = new Vector2(xForce * xForceToAdd, yForce * yForceToAdd);
}
}

The logic in computing the margins where the hit is being registered is wrong. For example in this.transform.localScale.y / 3, the localScale.y with probably give you 1.0f, but what you meant inside the expression (this.transform.position.y + (this.transform.localScale.y / 3) is that you want the y-center of the object, plus one-third of it's height. However, this.transform.localScale.y will only give you a "multiplier" so to say. In a unscaled object, transfomr.localScale will be 1.0, so you would be adding transform.position.y + (1.0f / 3), which is probably not what you want. You must multipliy this with the actual height of the object to get what you want. This can be done by either relying on the Sprite or a Collider, e.g. a BoxCollider2D. Modified logic (I also divided by 3f instead of by 3 to make it a more accurate floating point division..):
public float xForceToAdd;
public float yForceToAdd;
void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.tag == "Player")
{
//Store the vector 2 of the location where the initial hit happened;
Vector2 initialHitPoint = new Vector2(other.gameObject.transform.position.x, other.gameObject.transform.position.y);
float xForce = 0;
float yForce = 0;
//Grab our collided with objects rigibody
Rigidbody2D rigidForForce = other.gameObject.GetComponent < Rigidbody2D > ();
//Get the width and height of this object by looking up the size of the box collider
//Alternatively, use constant values here or rely on the Sprite.
float width = GetComponent<BoxCollider2D>().size.x;
float height = GetComponent<BoxCollider2D>().size.y;
//Determine left right center of X hit
if (initialHitPoint.x > (this.transform.position.x + width * (this.transform.localScale.x / 3f)))
xForce = 1;
else if (initialHitPoint.x < (this.transform.position.x - width* (this.transform.localScale.x / 3f)))
xForce = -1;
else
xForce = 0;
if (initialHitPoint.y > (this.transform.position.y + height * (this.transform.localScale.y / 3f)))
yForce = 1;
else if (initialHitPoint.y < (this.transform.position.y - height * (this.transform.localScale.y / 3f)))
yForce = -1;
else
yForce = 0;
Debug.Log(string.Format("Hit Point X: {0}. Left Boundary: {1} Right Boundary: {2}, xForce = {3}", initialHitPoint.x, (this.transform.position.x - width*this.transform.localScale.x / 3f), (this.transform.position.x + width * (this.transform.localScale.x / 3f)), xForce));
rigidForForce.velocity = new Vector2(xForce * xForceToAdd, yForce * yForceToAdd);
}
}

Related

Find an angle to launch the projectile at to reach a specific point

So, Dani in his slightly new video -> "Making a Game, But I Only Have 3 Days" (https://youtu.be/S7Dl6ATRK2M) made a enemy which has a bow and arrow (at 5:39). I tried to recreate that but had no luck... I also can't find the website that he used... Today I found this https://physics.stackexchange.com/questions/56265/how-to-get-the-angle-needed-for-a-projectile-to-pass-through-a-given-point-for-t. It worked very well but still had problems if the target was far away and also it wasn't as accurate. The code so far is
float CalculateAngle()
{
float gravity = Physics.gravity.magnitude;
float deltaX = targetPositionMod.x - currentPosition.x;
float deltaY = targetPositionMod.y - currentPosition.y;
float RHSFirstPart = (velocity * velocity) / (gravity * deltaX);
float RHSSecondPart = Mathf.Sqrt(
((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY))
/ (gravity * gravity * deltaX * deltaX))
- 1);
float tanθ = RHSFirstPart - RHSSecondPart;
float angle = Mathf.Atan2(tanθ, 1) * Mathf.Rad2Deg;
if (angle < 0) return angle;
return -angle;
}
The -angle is because the forward axis starts points up when the x-rotation is negative (Unity). Maybe the reason of this not working as intended is that I am not that good at this kind of Physics (Part of that is me being only 14). Maybe the problem is in the code, maybe it is the formula. Any help is appreciated.
Thanks...
Edit:
The Archer class is:
using UnityEngine;
using System;
public class Archer : MonoBehaviour
{
[SerializeField] float velocity = default;
[SerializeField] Transform target = default;
[SerializeField] GameObject arrowPrefab = default;
[SerializeField] float coolDown = default;
Vector3 targetPositionMod;
Vector3 currentPosition;
Vector3 targetPosition;
float countDown = 0f;
void Start()
{
countDown = coolDown;
UpdateVariables();
}
void Update()
{
UpdateVariables();
SetAngle();
ShootBullet();
}
void UpdateVariables()
{
currentPosition = transform.position;
targetPositionMod = Mod(target.position);
targetPosition = target.position;
targetPosition.x /= 10;
targetPosition.y /= 10;
targetPosition.z /= 10;
countDown -= Time.deltaTime;
}
void SetAngle()
{
Vector3 direction = targetPosition - currentPosition;
Quaternion lookRotation = Quaternion.LookRotation(direction);
Vector3 rotation = lookRotation.eulerAngles;
rotation.x = (float) CalculateAngle();
transform.rotation = Quaternion.Euler(rotation.x, rotation.y, 0f);
}
void ShootBullet()
{
if (!(countDown <= 0f)) return;
countDown = coolDown;
GameObject arrow = Instantiate(arrowPrefab, transform.position, transform.rotation);
Rigidbody Rigidbody = arrow.GetComponent<Rigidbody>();
Rigidbody.AddForce(transform.forward * velocity, ForceMode.Impulse);
}
double CalculateAngle()
{
double gravity = Physics.gravity.magnitude;
double deltaX = targetPositionMod.x - currentPosition.x;
double deltaY = targetPositionMod.y - currentPosition.y;
double RHSFirstPart = (velocity * velocity) / (gravity * deltaX);
double RHSSecondPart = Math.Sqrt(
(((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY))
/ (gravity * gravity * deltaX * deltaX))
- 1));
double tanθ = RHSFirstPart - RHSSecondPart;
double angle = Math.Atan2(tanθ, 1) * Mathf.Rad2Deg;
if (angle < 0) return angle;
return -angle;
}
Vector3 Mod(Vector3 Vec)
{
if (Vec.x < 0) Vec.x -= 2 * Vec.x;
if (Vec.y < 0) Vec.y -= 2 * Vec.y;
if (Vec.z < 0) Vec.z -= 2 * Vec.z;
Vec.x /= 10;
Vec.y /= 10;
Vec.z /= 10;
return Vec;
}
}
Ok, as I can see, your implementation of formula from StackExchange is right, but you have to remember two things:
In unity there is a 3D world, so horizontal distance is not just pos1.x - pos2.x, but
Mathf.Sqrt( deltaX * deltaX + deltaZ * deltaZ ), where deltaX = targetPositionMod.x - currentPosition.x and deltaZ = targetPositionMod.z - currentPosition.z
In computer implementation you have no 100% accuracy of math, so some problems can appear because of computational accuracy. And it can have affect on big distances. You can try to use double instead of float or find another implementation for arctangent function (I think, this can really help). But try this (second) advice only if first didn't help. It's harder to implement and it slows computations a bit.
Algorithm:
Step 1: Set up a function that calculates the appropriate solution of a quadratic equation
a*x^2 + b*x + c = 0
double quadratic_root(a,b,c){
D = b^2 - 4*a*c
return ( - b - Math.Sqrt(D) ) / (2 * a)
}
Step 2: Input
current.x
current.y
current.z
target.x
target.y
target.z
velocity
gravity
Step 3: Calculate coefficients of the quadratic polynomial:
dist = Math.Sqrt( (target.x - current.x)^2 + (target.y - current.y)^2 )
a = gravity * dist^2 / (2 * velocity^2)
b = -dist
c = target.z - current.z + a
Step 4:
theta = Math.Atan2( quadratic_root(a,b,c), 1 )
Calculation behind the algorithm. You are in three space. The current position has coordinates
x = current.x
y = current.y
z = current.z
and the target has coordinates
x = target.x
y = target.y
z = target.z
Assume the angle between the initial velocity and the horizontal plane is theta. The magnitude of the projection of the distance between the current position and the target onto the horizontal $x,y-$plane is
dist = sqrt( (target.x - current.x)^2 - (target.y - current.y)^2 )
You are given the velocity magnitude velocity. Then, the speed with which the shadow (i.e. the orthogonal projection) of the arrow moves along the horizontal line between the source and the target is the magnitude of the shadow (i.e. the orthogonal projection) of the actual velocity
velocity * cos(theta)
The vertical speed of the arrow is then
velocity * sin(theta)
So the motion along dist follows the equation
dist = time * velocity * cos(theta)
and hence
time = dist / (velocity * cos(theta))
In the vertical direction, the motions is described by the equation
z = current.z + time * velocity * sin(theta) - time^2 * gravity / 2
You are interested in the time for which the arrow hits the target, which has vertical coordinate target.z, so
target.z = current.z + time * velocity * sin(theta) - time^2 * gravity / 2
The equation can be written as:
0 = - (target.z - current.z) + time * velocity * sin(theta) - time^2 * gravity / 2
We already know that
time = dist / (velocity * cos(theta))
so
0 = - (target.z - current.z) + dist * velocity * sin(theta) / (velocity * cos(theta)) - dist^2 * gravity / ( 2 * (velocity * cos(theta))^2 )
which can be slightly simplified to
0 = - (target.z - current.z) + dist * sin(theta) / cos(theta) - gravity * dist^2 / ( 2 * (velocity * cos(theta))^2 )
Because 1/( cos(theta)^2 ) = 1 + ( tan(theta) )^2 we obtain the quadratic in tan(theta) equation
a * ( tan(theta) )^2 + b * tan(theta) + c = 0
where
a = gravity * dist^2 / (2 * velocity^2)
b = - dist
c = target.z - current.z + a

2d Trajectory Line Prediction not acurate

I'm current facing a problem where in my trajectory line is very inaccurate
Please see the attached image below
Here's where it goes
Here's my code so far
private void Start()
{
line = new GameObject[maxDots];
for (int i = 0; i < line.Length; i++)
{
var go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
go.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
line[i] = go;
}
startPos = transform.position;
}
on my OnMouseUp is for shooting the ball
//TEMPORARY
private void OnMouseUp()
{
// Disable IsKenematic
GetComponent<Rigidbody2D>().isKinematic = false;
// Add the Force
Vector2 dir = startPos - (Vector2)transform.position;
GetComponent<Rigidbody2D>().AddForce(dir * force);
//Remove the script (not the gameobject)
Destroy(this);
}
And on my OnMouseDrag is for the ball to keep in radius cause I set a limit for the dragging of the ball
private void OnMouseDrag()
{
DisplayLine();
//Convert mouse potision to world position
Vector2 p = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//Keep it in a certain radius
float radius = 1.8f;
Vector2 dir = p - startPos;
if (dir.sqrMagnitude > radius)
{
dir = dir.normalized * radius;
//Set position
transform.position = startPos + dir;
}
}
Here's my method of displaying the line
void DisplayLine()
{
line[0].transform.position = transform.position;
Vector3 v3 = transform.position;
float y = (forces * (home - transform.position)).y;
float t = 0.0f;
v3.y = 0.0f;
for(int i = 1; i < line.Length; i++)
{
v3 += forces * (home - transform.position) * spacing;
t += spacing;
v3.y = y * t + 0.5f * Physics2D.gravity.y * t * t + transform.position.y;
line[i].transform.position = v3;
}
}
What I am trying to do is that create a trajectory prediction line for my game I know I am almost there but still couldn't get the exact output that I want. Could someone help me. Thank you.
Use the same function to calculate both.
Then you won't have the problem also any change on trajectory calculation results in only one change not two.
Solved it
line[0].transform.position = transform.position;
Vector2 v2 = transform.position;
float y = (force *( startPos - (Vector2)transform.position)).y;
float t = 0.0f;
v2.y = 0.0f;
for(int i = 1; i < line.Length; i++)
{
v2 += force * (startPos - (Vector2)transform.position) * spacing;
t += spacing;
v2.y = y * t + 0.5f * Physics2D.gravity.y * t * t + transform.position.y;
line[i].transform.position = v2;
}
I need to change from vector3 to vector2 so I need to cast (vector2) between those transform.positions.y

How can I set the newPositions distance to be shorter closer to the original squadMembers positions?

I have 3 formations:
In each formation I'm calculating new positions to move to and add them to the List newPositions.
private void FormationTriangle()
{
newpositions = new List<Vector3>();
int height = Mathf.CeilToInt((Mathf.Sqrt(8 * squadMembers.Count + 1f) - 1f) / 2);
int slots = (int)(height * (height + 1f) / 2f);
float verticalModifier = 1.25f; // * 1.25f to increase horizontal space
float horizontalModifier = 0.8f; // * 0.8f to decrease "vertical" space
float width = 0.5f * (height - 1f);
Vector3 startPos = new Vector3(width * horizontalModifier, 0f, (float)(height - 1f) * verticalModifier);
int finalRowCount = height - slots + squadMembers.Count;
for (int rowNum = 0; rowNum < height && newpositions.Count < squadMembers.Count; rowNum++)
{
for (int i = 0; i < rowNum + 1 && newpositions.Count < squadMembers.Count; i++)
{
float xOffset = 0f;
if (rowNum + 1 == height)
{
// If we're in the last row, stretch it ...
if (finalRowCount != 1)
{
// Unless there's only one item in the last row.
// If that's the case, leave it centered.
xOffset = Mathf.Lerp(
rowNum / 2f,
-rowNum / 2f,
i / (finalRowCount - 1f)
) * horizontalModifier;
}
}
else
{
xOffset = (i - rowNum / 2f) * horizontalModifier;
}
float yOffset = (float)rowNum * verticalModifier;
Vector3 position = new Vector3(
startPos.x + xOffset, 0f, startPos.y - yOffset);
newpositions.Add(position);
}
}
move = true;
formation = Formation.Square;
}
private Vector3 FormationSquarePositionCalculation(int index) // call this func for all your objects
{
float posX = (index % columns) * gaps;
float posY = (index / columns) * gaps;
return new Vector3(posX, posY);
}
private void FormationSquare()
{
newpositions = new List<Vector3>();
quaternions = new List<Quaternion>();
for (int i = 0; i < squadMembers.Count; i++)
{
Vector3 pos = FormationSquarePositionCalculation(i);
//squadMembers[i].transform.position = new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y);
squadMembers[i].transform.Rotate(new Vector3(0, -90, 0));
newpositions.Add(new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y));
}
move = true;
squareFormation = true;
formation = Formation.Circle;
}
private Vector3 FormationCirclePositionCalculation(Vector3 center, float radius, int index, float angleIncrement)
{
float ang = index * angleIncrement;
Vector3 pos;
pos.x = center.x + radius * Mathf.Sin(ang * Mathf.Deg2Rad);
pos.z = center.z + radius * Mathf.Cos(ang * Mathf.Deg2Rad);
pos.y = center.y;
return pos;
}
private void FormationCircle()
{
newpositions = new List<Vector3>();
quaternions = new List<Quaternion>();
Vector3 center = transform.position;
float radius = (float)circleRadius / 2;
float angleIncrement = 360 / (float)numberOfSquadMembers;
for (int i = 0; i < numberOfSquadMembers; i++)
{
Vector3 pos = FormationCirclePositionCalculation(center, radius, i, angleIncrement);
var rot = Quaternion.LookRotation(center - pos);
if (Terrain.activeTerrain == true)
pos.y = Terrain.activeTerrain.SampleHeight(pos);
pos.y = pos.y + yOffset;
newpositions.Add(pos);
quaternions.Add(rot);
}
move = true;
squareFormation = false;
formation = Formation.Triangle;
}
Then I'm moving the squadMembers to the newPositions:
private void MoveToNextFormation()
{
if (randomSpeed == false)
{
if (step.Length > 0)
step[0] = moveSpeed * Time.deltaTime;
}
for (int i = 0; i < squadMembers.Count; i++)
{
squadMembers[i].transform.LookAt(newpositions[i]);
if (Vector3.Distance(squadMembers[i].transform.position, newpositions[i]) > 30f)
{
if (randomSpeed == true)
{
squadMembers[i].transform.position =
Vector3.MoveTowards(squadMembers[i].transform.position, newpositions[i], step[i]);
}
else
{
squadMembers[i].transform.position =
Vector3.MoveTowards(squadMembers[i].transform.position, newpositions[i], step[0]);
}
}
if (Vector3.Distance(squadMembers[i].transform.position, newpositions[i]) < threshold)
{
if (squareFormation == true)
{
Vector3 degrees = new Vector3(0, 0, 0);
Quaternion quaternion = Quaternion.Euler(degrees);
squadMembers[i].transform.rotation = Quaternion.Slerp(squadMembers[i].transform.rotation, quaternion, rotateSpeed * Time.deltaTime);
}
else
{
squadMembers[i].transform.rotation = Quaternion.Slerp(squadMembers[i].transform.rotation, quaternions[i], rotateSpeed * Time.deltaTime);
}
}
}
}
But if I want that the squadMembers will not move at all but will change to the next formation on the same position they are ? Or maybe to move just a little bit for example to distance 20 or 5 or 30 or 300 ?
I tried to add a distance check for the move:
if (Vector3.Distance(squadMembers[i].transform.position, newpositions[i]) > 30f)
So they are changing to the next formation when the distance more then 30.
But then the formation is not looking good. If for example it's the square formation the formation after they finished moving looks like a wave.
Screenshot example:
Wave formation

Separation Steering Algorithm

Ok so this site has helped me alot before i had an account, but now the net is not helping me so i'll post it myself :)
I am looking (i am yet another one) to do something like this:
tinykeep.com/dungen/
Now the first step(Generating the rooms , goes well), but this is the first time ever I encounter Flocking behaviour algorithms, and my maths really arent that terrific.
So i tried and came up with a non working algorithm, what i did is started from next standard separation algorithm: gamedevelopment.tutsplus.com/tutorials/the-three-simple-rules-of-flocking-behaviors-alignment-cohesion-and-separation--gamedev-3444 (sorry for this text but it wouldn't let me post more than 2 links without 10 rep), And changed it to my liking. Like i said before it's really not doing anything, if i find how i'll post some debug results.
Here's my code:
class Room {
Vector3 position;
Vector3 size;
int area;
public Room(Vector3 position, Vector3 size, int area) : this(position, size){
this.area = area;
}
public Room(Vector3 position, Vector3 size){
this.position = position;
this.size = size;
if(area != null)
this.area = (int)(size.x * size.z);
}
public Vector3 GetPosition(){
return position;
}
public Vector3 GetSize(){
return size;
}
public void SetPosition(Vector3 position){
this.position = position;
}
public Boolean TooCloseTo(Room room){
return position.x + size.x / 2 > room.GetPosition().x - room.GetSize().x / 2 || position.z + size.z / 2 > room.GetPosition().z - room.GetSize().z / 2 ||
position.x - size.x / 2 < room.GetPosition().x + room.GetSize().x / 2 || position.z - size.z / 2 < room.GetPosition().z + room.GetSize().z / 2;
}
public override string ToString ()
{
return string.Format ("[Room]\nPosition:{0}\nSize:{1}\nArea:{2}", position, size, area);
}
}
These are part of the Mapgenerator class, the rest of this class works fine and seems unimportant to me, but if you feel the need to see it, let me know and i'll post it.
void SeparateRooms(){
foreach (Room room in rooms) {
//Debug.Log (room);
Vector3 oldPos = room.GetPosition ();
Vector3 separation = computeSeparation (room);
//Debug.Log (separation);
Vector3 newPos = new Vector3 (oldPos.x += separation.x, oldPos.y, oldPos.z += separation.z);
room.SetPosition (newPos);
//Debug.Log (room);
}
}
Vector3 computeSeparation(Room agent) {
int neighbours = 0;
Vector3 v = new Vector3 ();
foreach (Room room in rooms) {
if (room != agent) {
if (agent.TooCloseTo (room)) {
v.x += Difference(room, agent, "x");
v.z += Difference(room, agent, "z");
neighbours++;
}
}
}
if (neighbours == 0)
return v;
v.x /= neighbours;
v.z /= neighbours;
v.x *= -1;
v.z *= -1;
v.Normalize ();
return v;
}
float Difference(Room room, Room agent, string type){
switch (type) {
case "x":
float xBottom = (room.GetPosition ().x + room.GetSize ().x / 2) - (agent.GetPosition ().x - agent.GetSize ().x / 2);
float xTop = (agent.GetPosition ().x + agent.GetSize ().x / 2) - (room.GetPosition ().x - room.GetSize ().x / 2);
return xBottom > 0 ? xBottom : xTop;
break;
case "z":
float xRight= (room.GetPosition ().z + room.GetSize ().z / 2) - (agent.GetPosition ().z - agent.GetSize ().z / 2);
float xLeft= (agent.GetPosition ().z + agent.GetSize ().z / 2) - (room.GetPosition ().z - room.GetSize ().z / 2);
return xRight > 0 ? xRight : xLeft;
default:
return 0;
break;
}
}
I was expecting the difference to be numbers like 4.0 and 8.0 and so on, instead i get 0.9 and 0.3 and so on, i'll copy an output:
Debug log
I hope that is readable.
Explanation: Each three lines are the info about the room:
1. the original room
2. the (what's supposed to be the) overlap between the room and the next
3. the new position of the room
EDIT: Ok thanks to the comments i'm getting pretty normal results for overlap now, but the rooms are still overlapping after i run the algorithm, i think this might have to do something with only iterating once over every room... Any comments on that?
I really hope some of you might be able to point me in the right direction, or tell me what is wrong in my reasoning.
Thank you!
EDIT: Filling up rooms:
public void Generate(int level) {
int levelModifier = (int)(Math.Round ((double)Mathf.Log (level, 2.5f),1) * 10);
int mean = 25;
int SD = 5;
for (int i = 0; i < 30 + levelModifier; i++) {
Vector3 position = getPInCircle (20);
int area = (int)SimpleRNG.GetNormal (mean, SD);
if (area < mean - SD)
continue;
Vector3 size = calculateSize (area);
Room room = new Room (position, size);
rooms.Add (room);
}
SeparateRooms ();
}
Vector3 calculateSize(int area) {
float k = UnityEngine.Random.Range (2.0f, area / 2.0f);
float l = area / k;
int shortSide;
int longSide;
if (Mathf.Round (k) > Mathf.Round (l)) {
shortSide = Mathf.RoundToInt (k);
longSide = Mathf.RoundToInt (l);
} else {
shortSide = Mathf.RoundToInt (l);
longSide = Mathf.RoundToInt (k);
}
//Debug.Log (shortSide);
//Debug.Log (longSide);
Vector3 size;
if (SimpleRNG.GetUniform () < 0.5) {
size = new Vector3 (Actualise(shortSide), 0, Actualise(longSide));
} else {
size = new Vector3 (Actualise(longSide), 0, Actualise(shortSide));
}
return size;
}
The SimpleRNG is John D. Cook's Namespace, open for download at www.codeproject.com/Articles/25172/Simple-Random-Number-Generation

Unity: Knockback my player

I have this script attached to an object, if my player encounters that object it will be knocked back. I have six directions on which it will be knocked back. This image will show you the different direction of which my player may get knock back. My problem: X=0,Y=1 (up) and X=0,Y=-1 (down) doesn't work, however every other velocity works. How can I also include the directions of X=0,Y=1 and X=0,Y=-1. Thank you and here is my code:
public class Knockback: MonoBehaviour
{
public float xForceToAdd;
public float yForceToAdd;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
//Store the vector 2 of the location where the initial hit happened;
Vector2 initialHitPoint = new Vector2(other.gameObject.transform.position.x, other.gameObject.transform.position.y);
float xForce = 0;
float yForce = 0;
//Grab our collided with objects rigibody
Rigidbody2D rigidForForce = other.gameObject.GetComponent < Rigidbody2D > ();
//Determine left right center of X hit
if (initialHitPoint.x > (this.transform.position.x + (this.transform.localScale.x / 3)))
{
xForce = 1;
}
else if (initialHitPoint.x < (this.transform.position.x - (this.transform.localScale.x / 3)))
{
xForce = -1;
}
else
{
xForce = 0;
}
if (initialHitPoint.y > (this.transform.position.y + (this.transform.localScale.y / 3)))
{
yForce = 1;
}
else if (initialHitPoint.y < (this.transform.position.y - (this.transform.localScale.y / 3)))
{
yForce = -1;
}
else
{
yForce = 0;
}
rigidForForce.velocity = new Vector2(xForce * xForceToAdd, yForce * yForceToAdd);
}
}
}
Most probably, it doesn't see the if statements of y part. Use else if for all if statements after the first one. Try this:
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
//Store the vector 2 of the location where the initial hit happened;
Vector2 initialHitPoint = new Vector2(other.gameObject.transform.position.x, other.gameObject.transform.position.y);
float xForce = 0;
float yForce = 0;
//Grab our collided with objects rigibody
Rigidbody2D rigidForForce = other.gameObject.GetComponent < Rigidbody2D > ();
//Determine left right center of X hit
if (initialHitPoint.x > (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y > (this.transform.position.y + (this.transform.localScale.y / 3)))
{
xForce = 1;
yForce = 1;
}
else if (initialHitPoint.x > (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y < (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = 1;
yForce = -1;
}
else if (initialHitPoint.x < (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y > (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = -1;
yForce = 1;
}
else if (initialHitPoint.x < (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y < (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = -1;
yForce = -1;
}
else if (initialHitPoint.x > (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y == (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = 1;
yForce = 0;
}
else if (initialHitPoint.x < (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y == (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = -1;
yForce = 0;
}
else if (initialHitPoint.x == (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y < (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = 0;
yForce = -1;
}
else if (initialHitPoint.x == (this.transform.position.x + (this.transform.localScale.x / 3))
&& initialHitPoint.y > (this.transform.position.y - (this.transform.localScale.y / 3)))
{
xForce = 0;
yForce = 1;
}
else
{
xForce = 0;
yForce = 0;
}
rigidForForce.velocity = new Vector2(xForce * xForceToAdd, yForce * yForceToAdd);
}
}

Categories