I've created an arm with a custom pivot in Unity which is essentially supposed to point wherever the mouse is pointing, regardless of the orientation of the player. Now, this arm looks weird when pointed to the side opposite the one it was drawn at, so I use SpriteRenderer.flipY = true to flip the sprite and make it look normal. I also have a weapon at the end of the arm, which is mostly fine as well. Now the problem is that I have a "FirePoint" at the end of the barrel of the weapon, and when the sprite gets flipped the position of it doesn't change, which affects particles and shooting position. Essentially, all that has to happen is that the Y position of the FirePoint needs to become negative, but Unity seems to think that I want the position change to be global, whereas I just want it to be local so that it can work with whatever rotation the arm is at. I've attempted this:
if (rotZ > 40 || rotZ < -40) {
rend.flipY = true;
firePoint.position = new Vector3(firePoint.position.x, firePoint.position.y * -1, firePoint.position.z);
} else {
rend.flipY = false;
firePoint.position = new Vector3(firePoint.position.x, firePoint.position.y * -1, firePoint.position.z);
}
But this works on a global basis rather than the local one that I need. Any help would be much appreciated, and I hope that I've provided enough information for this to reach a conclusive result. Please notify me should you need anything more. Thank you in advance, and have a nice day!
You can use RotateAround() to get desired behaviour instead of flipping stuff around. Here is sample code:
public class ExampleClass : MonoBehaviour
{
public Transform pivotTransform; // need to assign in inspector
void Update()
{
transform.RotateAround(pivotTransform.position, Vector3.up, 20 * Time.deltaTime);
}
}
Related
updated CODE .. the problem is that i cant move the ball only if i hold the E button than i use WASD or arrows to move the ball...and when i hold Q the camera 2 activates and i can move the ball with WASD or arrows...but with the right axis for that angle...is like ballance that game... i want to not hold the E or Q just to change the camera and move the ball corecctly for that angle with the right axis for the ball but not holding the cameras button
using UnityEngine;
using System.Collections;
public class controlPlayer : MonoBehaviour {
public float viteza ; // this is speed
;
void Start(){
}
void Update()
{
if(Input.GetKey(KeyCode.Q) ) // if i hold Q the camera 2 activates and with WASD i can move the ball
{
float miscaOrizontal = Input.GetAxis("Horizontal");
float miscaVertical = Input.GetAxis("Vertical");
Vector3 miscare = new Vector3(miscaVertical,0.0f,(-miscaOrizontal)); //also here i chande the axis for the camera 2
rigidbody.AddForce(miscare * viteza * Time.deltaTime);
}
if(Input.GetKey(KeyCode.E) ) // here when i press E the camera 1 activates and alos i can move the ball if i keep pressing E
{ float miscaOrizontal2 = Input.GetAxis("Horizontal");
float miscaVertical2 = Input.GetAxis("Vertical");
Vector3 miscare2 = new Vector3(miscaOrizontal2,0.0f,miscaVertical2); // here are the controls for the ball for the camera ..i had to change the axis here..
rigidbody.AddForce(miscare2 * viteza * Time.deltaTime);
}
}
}
}
Alright, so if I'm understanding you correctly, you want the ball to move in relation to which direction the camera is currently facing. As well as you don't want to have to hold down "Q" or "E" while you move your ball with WASD controls.
So there are a few things that I'd like to mention here, so we'll take them one at a time. First off, you shouldn't have "AddForce" inside of an Update call. Update is called every frame whenever it can. It's great for input, but generally you want to call it in "FixedUpdate" instead. It provides a better response across many devices. If you leave it in update, you can get inaccurate physics results, and missed collisions. There's a lot out there on this subject, so if you want to know more about it, then just google for a little while.
As for the code side, you want to store a reference to what camera you're using to avoid having to hold these buttons down.
What I mean is:
private Camera referencedCamera = null;
private void Start()
{
referencedCamera = camera1;
}
private void Update()
{
if(Input.GetKey(KeyCode.Q)) referencedCamera = camera2;
else if(Input.GetKey(KeyCode.E)) refrencedCamera = camera1;
}
This way you can reference which camera is being used, rather than a key input. Something else to look into is the "State Design Pattern". Below is a video over the "State Design Pattern." That is a great video tutorial series that Derek Banas put up on design patterns, extremely recommend watching them, but the state pattern could potentially solve this problem for you as well. So that should take care of not having to hold the button down in order to make the move. More or less, the buttons will now allow you to just switch which camera is currently being used.
https://www.youtube.com/watch?v=MGEx35FjBuo
So now that that is solved, you want to transform the input that you currently have, and you want to put it in terms of hte camera that is currently being used. So to avoid rewriting a lot of the code over and over again, just know that these two code snippets should be pieced together into one. So "referencedCamera" should be already defined in the code I'm about to write:
private void FixedUpdate()
{
if(referencedCamera != null)
{
float miscaOrizontal = Input.GetAxis("Horizontal");
float miscaVertical = Input.GetAxis("Vertical");
Vector3 miscare = referencedCamera.transform.TransformDirection(
new Vector3(miscaVertical, 0.0f, -miscaOrizontal));
rigidbody.AddForce(miscare * viteza * Time.deltaTime);
}
}
So now with this, is it's the same code, but there is a call to the referenced cameras transform to take the vector 3 from the input and put it in relation to the camera instead, and add the new relational vector to the object.
I also want to recommend you looking into events rather than if checks in the update function, but that is beyond the scope of the question. Hope this helps and any questions, don't hesitate to ask.
EDIT
After further discussion, we came across something that should also be mentioned. If your camera that you are referencing is angled, the force will be applied in that angle, so keep that in mind. If it is pointed towards an object downward, then forward relative to the camera will apply a force downward, and not entirely in what you may consider the forward direction. Thought it was worth mentioning.
I'm playing around with an FPS where I want my player(s) to be able to build/construct their own buildings from scratch. I've searched around for exisiting solutions/theories, but have so far been unable to find anything suitable to my needs. Please point me in the right direction if I've missed anything.
Where I am right now is that I have three prefabs; floor, wall and wall with a door opening. First I want to instantiate floor tiles which I then can put walls on, and hopefully being able to have the walls snap to the edges/corners of the floor tiles.
Can anyone please point me in the right direction for how to do this? Also, does my desired "work flow" at all make sense? Any pitfalls in there?
Thanks in advance!
UPDATE: Here's what I have in regards to instantiation prefabs, and while this works (except it's like I'm shooting walls), I would like the wall to snap to the corners/edges of the nearest floor (which has already been instantiated in the same fashion.
[RequireComponent (typeof (CharacterController))]
public class PlayerController : MonoBehaviour {
// Declare prefabs here
GameObject wallPrefab;
// Initialise variables before the game starts
void Awake () {
wallPrefab = (GameObject)Resources.Load( "WoodWall" );
}
// This happens every frame
void Update () {
if ( Input.GetButtonDown("Fire1") ) {
// Instantiate new wall
Instantiate( wallPrefab, cc.transform.position + cc.transform.forward + Vector3.up * 1.0f, wallPrefab.transform.rotation );
}
}
}
hmm... well one solution I can think of, is to have the wall raycast downwards in order to find a floor, then move to a predetermined position in relation to that floor (if it found any). Stick this in a script in the wall prefabs:
void Start()
{
var down = transform.TransformDirection (Vector3.down); //down might not actually be the down direction of your object, check to make sure
RaycastHit hit;
if (Physics.Raycast(transform.position, down, out hit) && hit.collider.gameObject.name == "myFloorName") //Maybe use tags here instead of name
{
Vector3 floorPos = hit.collider.gameObject.transform.position;
Vector3 floorSize = hit.collider.gameObject.transform.localScale;
this.transform.position = new Vector3(floorPos.x - floorSize.x/2, floorPos.y - this.tranform.localScale.y/2, floorPos.z); //These might need fiddling with to get right
}
}
void Update()
{
}
Vector3.down may not correspond to the down direction for the wall, since this can depend on the 3d model too, so you might need to fiddle with that. The position might also need fiddling with (this assumes that y corresponds to height, which might not be the case), but hopefully this gives you a rough idea of how it can be done. Also, if you don't know what the name of the floor object is, you could probably check by tags, which is probably easier.
If anything else needs clarifying, leave a comment and I'll get back to you
I have an issue with trying to get an 'object(character)' to walk around a cube (all sides) within Unity. Ive attached an image and video showing what i am trying to achieve. Im trying to show you visually rather than trying to explain. As the character drops over the edge it rotates 90 degrees and then the stands up like gravity has switched. Then the character can jump walk etc.
This is an example of someone else that posted a video showing exactly what im trying to achieve
I have looked through the forums and cant find what im after. i have tried to attach a diagram but the site wont let me. Any advice would be greatly appreciated!
Regards
Nick
You have a couple of options that I can think of.
One is to trigger the gravity change when the character exits one face of the cube to go to another. To achieve this you would have trigger zones on each edge and face and use a [Bob went from Face A to Edge ANorth -> Switch Gravity to go in X direction].
This would work for situations where the gravity switch must affect other objects too but be advantageous to your player (walking off the side makes an enemy fall off and die - for example.)
However, if you want all entities to stick to their relative sides then we need to make custom gravity! To do this is easier than you might think as gravity is simply a downward accelleration of 9.8. So turn off the engines native gravity and create a "personal gravity" component:
private Vector3 surfaceNormal;
private Vector3 personalNormal;
private float personalGravity = 9.8f;
private float normalSwitchRange = 5.0f;
public void Start()
{
personalNormal = transform.up; // Start with "normal" normal
rigidbody.freezeRotation = true; // turn off physics rotation
}
public void FixedUpdate()
{
// Apply force taking into account character normal as personal gravity:
rigidbody.AddForce(-personalGravity * rigidbody.mass * personalNormal);
}
Rotating your character and changing his normal is then up to you to suit your situation or game mechanic, whether you do that by raycasting if you're standing on a surface to detect when to change it or only want gravity to change when you hit a powerup or similar - experiment and see what works. Comment more if you have questions!
EDIT:
As an addition to the video you linked. You can keep a state variable on the jump state and raycast in each axis direction to check which face is nearest in the case of just rolling off.
public void Update()
{
// we don't update personal normals in the case of jumping
if(!jumping)
{
UpdatePersonalNormal();
}
}
public void UpdatePersonalNormal()
{
RaycastHit hit; //hit register
// list of valid normals to check (all 6 axis)
Ray[] rays =
{
Vector3.up, Vector3.down,
Vector3.left, Vector3.right,
Vector3.forward, Vector3.backward
};
//for each valid normal...
foreach(Ray rayDirection in rays)
{
//check if we are near a cube face...
if(Physics.Raycast(rayDirection , hit, normalSwitchRange)
{
personalNormal = hit.Normal; //set personal normal ...
return; // and return as we are done
}
}
}
Please keep in mind that the above is completely hand written and not tested but play with it and this pseudo start should give you a good idea of what to do.
I make a game in Unity3D (+2D ToolKit) for iOS.
It is 2d runner/platformer with side view. So on screen is moving background and obstacles. And we control up/down the main character to overcome obstacles.
The problem is that the moving picture has a visual lag. In other words, it moves jerkily or creates the tail area of the previous frames on iOS-devices. In XCode the number of frames is 30 and over.
I have objects 'plain' with the following script:
public class Move: Monobehavior
{
private float x;
public float Speed = 128.0f;
void Start()
{
x = transform.position.x;
}
void Update()
{
x += Time.DeltaTime *Speed;
Vector3 N = transform.position;
N.x = mathf.FloorInt(x);
transform.position = N;
}
}
The question is how to make the move of background smoother, without jerks and flicker on screen while playing? Maybe the problem is in framerate parameter.
Can anybody help me to find a solution?
I'd say it's the use of the FloorInt function which will move the background only in steps of 1 which is rather not smooth. It should get better when you comment that line out. Do you have any special reason why you are doing the FloorInt there?
The use of floor will definitely hurt your performance. Not only is it one more thing to calculate, but it is actually removing fidelity by removing decimals. This will definalty make the movement look 'jerky'. Also, update is not always called on the same time inteval, depending on what else is happening during that frame, so using Time.delaTime is highly recommended. Another thing, you do not need to set variables for x and Vector3 N, when you can update the transoms position like the code below. And if you have to, you sill only need to create one variable to update, and set your position to it. The code below just updates the players x position at a given rate, based on the amount of time that has passes since the last update. There should be no 'jerky' movement. (Unless you have a serious framerate drop);
public class Move: Monobehavior
{
public float Speed = 128.0f;
void Update()
{
transform.position =
(transform.position.x + (speed*Time.DeltaTime),
transform.position.y,
transform.position.z);
}
}
I have set up Unity navigation meshes (four planes), navigation agent (sphere) and set up automatic and manual off mesh links. It should now jump between meshes. It does jump between meshes, but it does that in straight lines.
In other words, when agent comes to an edge, instead of actually jumping up (like off mesh link is drawn) it just moves straight in line but a bit faster. I tried moving one plane higher than others, but sphere still was jumping in straight line.
Is it supposed to be like this? Is it possible to set up navigation to jump by some curve? Or should I try to implement that myself?
I came by this question, and had to dig through the Unity sample. I just hope to make it easier for people by extracting the important bits.
To apply your own animation/transition across a navmesh link, you need to tell Unity that you will handle all offmesh link traversal, then add code that regularly checks to see if the agent is on an offmesh link. Finally, when the transition is complete, you need to tell Unity you've moved the agent, and resume normal navmesh behaviour.
The way you handle link logic is up to you. You can just go in a straight line, have a spinning wormhole, whatever. For jump, unity traverses the link using animation progress as the lerp argument, this works pretty nicely. (if you're doing looping or more complex animations, this doesn't work so well)
The important unity bits are:
_navAgent.autoTraverseOffMeshLink = false; //in Start()
_navAgent.currentOffMeshLinkData; //the link data - this contains start and end points, etc
_navAgent.CompleteOffMeshLink(); //Tell unity we have traversed the link (do this when you've moved the transform to the end point)
_navAgent.Resume(); //Resume normal navmesh behaviour
Now a simple jump sample...
using UnityEngine;
[RequireComponent(typeof(NavMeshAgent))]
public class NavMeshAnimator : MonoBehaviour
{
private NavMeshAgent _navAgent;
private bool _traversingLink;
private OffMeshLinkData _currLink;
void Start()
{
// Cache the nav agent and tell unity we will handle link traversal
_navAgent = GetComponent<NavMeshAgent>();
_navAgent.autoTraverseOffMeshLink = false;
}
void Update()
{
//don't do anything if the navagent is disabled
if (!_navAgent.enabled) return;
if (_navAgent.isOnOffMeshLink)
{
if (!_traversingLink)
{
//This is done only once. The animation's progress will determine link traversal.
animation.CrossFade("Jump", 0.1f, PlayMode.StopAll);
//cache current link
_currLink = _navAgent.currentOffMeshLinkData;
//start traversing
_traversingLink = true;
}
//lerp from link start to link end in time to animation
var tlerp = animation["Jump"].normalizedTime;
//straight line from startlink to endlink
var newPos = Vector3.Lerp(_currLink.startPos, _currLink.endPos, tlerp);
//add the 'hop'
newPos.y += 2f * Mathf.Sin(Mathf.PI * tlerp);
//Update transform position
transform.position = newPos;
// when the animation is stopped, we've reached the other side. Don't use looping animations with this control setup
if (!animation.isPlaying)
{
//make sure the player is right on the end link
transform.position = _currLink.endPos;
//internal logic reset
_traversingLink = false;
//Tell unity we have traversed the link
_navAgent.CompleteOffMeshLink();
//Resume normal navmesh behaviour
_navAgent.Resume();
}
}
else
{
//...update walk/idle animations appropriately ...etc
Its recommended to solve your problems via animation. Just create a Jump animation for your object, and play it at the correct time.
The position is relative, so if you increase the Y-position in your animation it will look like the object is jumping.
This is also how the Unity sample is working, with the soldiers running around.
Not sure what version of unity you are using but you could also try this, I know it works just fine in 4:
string linkType = GetComponent<NavMeshAgent>().currentOffMeshLinkData.linkType.ToString();
if(linkType == "LinkTypeJumpAcross"){
Debug.Log ("Yeah im in the jump already ;)");
}
also just some extra bumf for you, its best to use a proxy and follow the a navAgent game object:
Something like:
AIMan = this.transform.position;
AI_Proxy.transform.position = AIMan;
And also be sure to use:
AI_Proxy.animation["ProxyJump"].blendMode = AnimationBlendMode.Additive;
If you are using the in built unity animation!
K, that's my good deed for this week.
Fix position in update()
if (agent.isOnOffMeshLink)
{
transform.position = new Vector3(transform.position.x, 0f, transform.position.z);
}