Networking rotation sync - rotation

My Unity version is 5.2.3f1, I m trying to sync the rotation of a child gameobject, in local works perfectly fine but it doesnt show up in other clients. I tried everything I could find and nothing.
The reason of this is to rotate a FPS body, so, I m trying to rotate Spine2 (Rotate the camera is not my best solution). I m using a Mixamo character to test, in the end I will have Mixamo auto-rigged charscters so everything I make here will be compatible.
I tried to use the Network Transform Rigidbody 3D and it only sync the character itself, not Spine2, I have tried Network Transform Child, and an official skeleton sync.
In the script part, I have tried a lot of things, the most promising one was this:
[SyncVar]
private Quaternion syncPlayerRotation;
[SerializeField]
private Transform playerTransform;
[SerializeField]
private float lerpRate = 15f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void LateUpdate () {
TransmitRotations();
LerpRotations();
}
void LerpRotations()
{
if (!isLocalPlayer)
playerTransform.localRotation = Quaternion.Lerp(playerTransform.localRotation, syncPlayerRotation, Time.deltaTime * lerpRate);
}
[Command]
void CmdProvideRotationsToServer(Quaternion playerRot)
{
syncPlayerRotation = playerRot;
}
[Client]
void TransmitRotations()
{
if (isLocalPlayer)
{
CmdProvideRotationsToServer(playerTransform.localRotation);
}
}
Its from UNET tutorial series on youtube, Gamer To Game Developer user.
I attached it to Spine2 and still dont work, but when I attached it to the main character, it worked.
Also tried this:
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
Vector3 syncPosition = Vector3.zero;
if (stream.isWriting)
{
syncPosition = Spine.GetComponent<Rigidbody>().position;
stream.Serialize(ref syncPosition);
}
else
{
stream.Serialize(ref syncPosition);
Spine.GetComponent<Rigidbody>().position = syncPosition;
}
}
But I think it was for an older version of Unity.
To make the rotations I m using A Free Simple Smooth Mouselook
I edited it, this lines:
if (Input.GetMouseButton(1))
{
var xRotation = Quaternion.AngleAxis(-_mouseAbsolute.y, targetOrientation * Vector3.forward);
transform.localRotation = xRotation;
}
else
{
var xRotation = Quaternion.AngleAxis(-_mouseAbsolute.y, targetOrientation * Vector3.right);
transform.localRotation = xRotation;
}
Basicly, I changed Vector3.right to Vector3.forward and converted the Vector3.right only if the right mouse button is not pressed. The script is attached to Spine2 and its activated on the start if(isLocalPlayer) by script.
There's a pic of the current hierarchy:
(some cameras are there only to test, the main camera is FirstPersonCamera, extracted from the standard assets)
I noticed that if I debug log the Spine2 rotation, it only gives me values from 0 to 1.

Related

Changing the Speed of a motor in Processing/box2D

I've been making some simple games using processing and box2D using The Nature of Code as a resource.
My problem is I have gotten to a point where I have these windmills that go clockwise/counterclockwise depending on the speed of the motor (I am using PI/2 and -PI*2). I want to have it so that the user can change this speed from positive and negative by pressing a key or mouse button. Looking around online people and the box2D documentation are saying to use the function void SetMotorSpeed(float speed);, however I am not having luck figuring out how to implement this. I've tried a few ways I can think but no luck.
Currently I have this in my main file ("s" is the name of the instance of the windmill):
// Click the mouse to switch speed of motor
void mousePressed() {
s.SetMotorSpeed(s.speed);
}
And I have this in the file for the windmill:
//Set Motor Speed
void SetMotorSpeed(float speed){
speed = speed * -1;
}
This doesn't work though.
I'm fairly new to coding and this is my first post on stack-overflow so my apologies if I have done anything wrong in how I'm asking or presenting this question. I'm open to suggestions both code and etiquette wise!
Here is the code for the entire windmill:
class Seesaw {
// object is two boxes and one joint
RevoluteJoint joint;
// float speed = PI*2;
Box box1;
Box box2;
float speed = PI*2;
Seesaw(float x, float y) {
// Initialize locations of two boxes
box1 = new Box(x, y-20, 120, 10, false);
box2 = new Box(x, y, 10, 40, true);
// Define joint as between two bodies
RevoluteJointDef rjd = new RevoluteJointDef();
Vec2 offset = box2d.vectorPixelsToWorld(new Vec2(0, 60));
rjd.initialize(box1.body, box2.body, box1.body.getWorldCenter());
// Turning on a motor (optional)
rjd.motorSpeed = PI*2; // how fast?
rjd.maxMotorTorque = 1000.0; // how powerful?
rjd.enableMotor = true; // is it on?
// Create joint
joint = (RevoluteJoint) box2d.world.createJoint(rjd);
}
// Turn the motor on or off
void toggleMotor() {
joint.enableMotor(!joint.isMotorEnabled());
}
boolean motorOn() {
return joint.isMotorEnabled();
}
void SetMotorSpeed(float speed){
speed = -speed;
}
void display() {
box2.display();
box1.display();
// Draw anchor just for debug
Vec2 anchor = box2d.coordWorldToPixels(box1.body.getWorldCenter());
fill(255, 0, 0);
stroke(0);
ellipse(anchor.x, anchor.y, 4, 4);
}
}
The change in speed should be communicated to the joint. Try this:
void SetMotorSpeed(float speed) {
s.joint.setMotorSpeed(speed); // edited, processing/java uses camel-case
}
you might also be a bit more careful about naming variables. In your original post you use the same name for the local variable and the member variable, which has not the wanted effect. Most people use some naming convention for member variable to avoid this kind of very common error. Like for instance have all member variables all start with "_"
void SetMotorSpeed(float speed) {
_speed = -speed; // speed is local!
}

Algorithm about playing animations of multiple objects

I'm currently working on a project that instantiates 3d models on my scene and allows the user to play their animation on button click. However, in my current code, it only plays the animation of the first object it detects even tho there are other objects around. I want to play the animation of all objects on the scene. This is part of my current code. This is the method that will fire up once the button is clicked.
public void PlayAnimation()
{
if (GameObject.FindGameObjectWithTag ("3DObject).name.Contains ("Spidey"))
{
int spideyAnimation = Random.Range(0, spideyAnimations.Length);
GameObject.FindGameObjectWithTag ("3DObject").GetComponent<Animation> ().Play (spideyAnimations[spideyAnimation]);
}
if (GameObject.FindGameObjectWithTag ("3DObject").name.Contains("Dino"))
{
int dinoAnimation = Random.Range(0, dinoAnimations.Length);
GameObject.FindGameObjectWithTag ("3DObject").GetComponent<Animation> ().Play (dinoAnimations[dinoAnimation]);
}
}
You can try something like this:
var arr = GameObject.FindGameObjectsWithTag ("3DObject");
foreach (var o in arr) {
if (o.name.Contains ("Spidey")) {
// play spideyAnimation
} else if (o.name.Contains ("Dino")) {
// play dino animation
}
}
Your current code will only find the first object, because you're calling GameObject.FindGameObjectWithTag and not GameObject.FindGameObjectsWithTag
UnityDocs - GameObject.FindGameObjectsWithTag

Blender Car Model Rotate wheel turn wheel together

I have imported a Benz car model from Blender to OGRE. I am trying to rotate the wheels.
I have 2 requirements. Rotate the wheel like the car is running and rotate the wheel left and right as it is turning based on the steering wheel. I can successfully do it separately but when I do it together, I am getting wrong results.
Before I imported the model from Blender, I made 4 local pivot points for the wheels based on the center(Using set Pivot point based on 3D point cursor option in Blender).
In OGRE, after I imported the model, I parsed the entire scene manager and found the 4 wheel nodes and named as left front, left back, right front and right back nodes. It is as below.
void ogreWindow::makeNodes( )
{
Ogre::SceneNode::ChildNodeIterator it = mSceneMgr->getRootSceneNode()-
>getChildIterator();
QString _name;
while (it.hasMoreElements())
{
Ogre::Node* node_ = it.getNext();
Ogre::String _name=node_->getName();
QString ssss = QString::fromUtf8(_name.c_str());
qDebug()<<"Entities are "<<ssss;
if(ssss=="WheelRightBack_transform2")
{
rotateNodeBackWheel_Right = mSceneMgr->getSceneNode("WheelRightBack_transform2");
m_RotateWheeel = true;
}
if(ssss=="WheelleftBack_transform12")
{
rotateNodeBackWheel_Left = mSceneMgr->getSceneNode("WheelleftBack_transform12");
m_RotateWheeel = true;
}
if(ssss=="Wheel_LeftFront_transform15")
{
rotateNodeFrontWheel_Right = mSceneMgr->getSceneNode("Wheel_LeftFront_transform15");
turnNodeFrontWheel_Right = mSceneMgr->getSceneNode("Wheel_LeftFront_transform15");
m_RotateWheeel = true;
}
if(ssss=="WheelRightFront_transform3")
{
rotateNodeFrontWheel_Left = mSceneMgr->getSceneNode("WheelRightFront_transform3");
turnNodeFrontWheel_Left = mSceneMgr->getSceneNode("WheelRightFront_transform3");
m_RotateWheeel = true;
}
}
}
Then In framerenderingQueued funciton, I am indefenitely calling a rotate function as below:
bool ogreWindow::frameRenderingQueued(const Ogre::FrameEvent& fe)
{
if(m_RotateWheeel)
{
RotateWheel();
}
.......
.......
}
Where the rotateWheel() is as below
void ogreWindow::RotateWheel()
{
//Working with Euler rotation
//Section 1
if(rotateNodeBackWheel_Left)
rotateNodeBackWheel_Left->yaw(Ogre::Radian(0.01),Ogre::Node::TransformSpace::TS_LOCAL);
if(rotateNodeBackWheel_Right)
rotateNodeBackWheel_Right->yaw(Ogre::Radian(0.01),Ogre::Node::TransformSpace::TS_LOCAL);
if(rotateNodeFrontWheel_Left)
rotateNodeFrontWheel_Left->yaw(Ogre::Radian(0.01),Ogre::Node::TransformSpace::TS_LOCAL);
if(rotateNodeFrontWheel_Right)
rotateNodeFrontWheel_Right->yaw(Ogre::Radian(0.01),Ogre::Node::TransformSpace::TS_LOCAL);
//Section 2
if(isTurning)
{
if(rotateNodeFrontWheel_Right)
rotateNodeFrontWheel_Right->roll(Ogre::Radian(turningRadius),Ogre::Node::TransformSpace::TS_LOCAL);
if(rotateNodeFrontWheel_Right)
rotateNodeFrontWheel_Right->roll(Ogre::Radian(turningRadius),Ogre::Node::TransformSpace::TS_LOCAL);
}
isTurning = false;
}
So the problems I am facing is described below,
a) When I do section 1 alone, the wheel is rotating smoothly
b) When I do section 2 alone, the wheel will be rendered as turned - OK fine
c) When I do section 1 and section 2 together, OK it is rendering with the wheel rotating and wheel turned in "turnRadius" degree.(Image attached-A.png)
d) But If I try to change the value of turnRadius at run time, it is getting crazy.
The side view is as below
I am changing the value of turnRadius as below. I call this function from 2 button clicks from UI.
void ogreWindow::turnFrontWheelLeft(Ogre::Real radius)
{
//turningRadius-=0.1;
turningRadius = -0.1;
isTurning = true;
}
void ogreWindow::turnFrontWheelRight(Ogre::Real radius)
{
//turningRadius+=0.1;
turningRadius = 0.1;
isTurning = true;
}
I understand the problem is the axis issue. How can I make it perfect? I want to do the turn and rotate "rotations" together.
It is working now. I created sub-nodes and did the transforms separately.
http://www.ogre3d.org/forums/viewtopic.php?f=1&t=92364&sid=e21b8189a3defe7ae1c3c4c3b7c4cc57

Scale UI for multiple resolutions/different devices

I have a quite simple unity GUI that has the following scheme :
Where Brekt and so are buttons.
The GUI works just fine on PC and is on screen space : overlay so it is supposed to be adapted automatically to fit every screen.
But on tablet the whole GUI is smaller and reduced in the center of the screen, with huge margins around the elements (can't join a screenshot now)
What is the way to fix that? Is it something in player settings or in project settings?
Automatically scaling the UI requires using combination of anchor,pivot point of RecTransform and the Canvas Scaler component. It is hard to understand it without images or videos. It is very important that you thoroughly understand how to do this and Unity provided full video tutorial for this.You can watch it here.
Also, when using scrollbar, scrollview and other similar UI controls, the ContentSizeFitter component is also used to make sure they fit in that layout.
There is a problem with MovementRange. We must scale this value too.
I did it so:
public int MovementRange = 100;
public AxisOption axesToUse = AxisOption.Both; // The options for the axes that the still will use
public string horizontalAxisName = "Horizontal"; // The name given to the horizontal axis for the cross platform input
public string verticalAxisName = "Vertical"; // The name given to the vertical axis for the cross platform input
private int _MovementRange = 100;
Vector3 m_StartPos;
bool m_UseX; // Toggle for using the x axis
bool m_UseY; // Toggle for using the Y axis
CrossPlatformInputManager.VirtualAxis m_HorizontalVirtualAxis; // Reference to the joystick in the cross platform input
CrossPlatformInputManager.VirtualAxis m_VerticalVirtualAxis; // Reference to the joystick in the cross platform input
void OnEnable()
{
CreateVirtualAxes();
}
void Start()
{
m_StartPos = transform.position;
Canvas c = GetComponentInParent<Canvas>();
_MovementRange = (int)(MovementRange * c.scaleFactor);
Debug.Log("Range:"+ _MovementRange);
}
void UpdateVirtualAxes(Vector3 value)
{
var delta = m_StartPos - value;
delta.y = -delta.y;
delta /= _MovementRange;
if (m_UseX)
{
m_HorizontalVirtualAxis.Update(-delta.x);
}
if (m_UseY)
{
m_VerticalVirtualAxis.Update(delta.y);
}
}
void CreateVirtualAxes()
{
// set axes to use
m_UseX = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyHorizontal);
m_UseY = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyVertical);
// create new axes based on axes to use
if (m_UseX)
{
m_HorizontalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(horizontalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_HorizontalVirtualAxis);
}
if (m_UseY)
{
m_VerticalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(verticalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_VerticalVirtualAxis);
}
}
public void OnDrag(PointerEventData data)
{
Vector3 newPos = Vector3.zero;
if (m_UseX)
{
int delta = (int)(data.position.x - m_StartPos.x);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.x = delta;
}
if (m_UseY)
{
int delta = (int)(data.position.y - m_StartPos.y);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.y = delta;
}
transform.position = new Vector3(m_StartPos.x + newPos.x, m_StartPos.y + newPos.y, m_StartPos.z + newPos.z);
UpdateVirtualAxes(transform.position);
}

Use parameters for variable animation

I'd like to animate my Score-GUI text counting up to a variable value but there are two things in my way:
1: How can I animate to a variable instead of a fixed value?
2: Why can't I add own properties (like int) to my script and animate them?
For #2 I created a property in my script. Yet the editor won't show it in the AddProperty-dialog (as shown below):
public int currentScore = 0;
public int score {
get { return currentScore; }
set { this.currentScore += value; }
}
EDIT: The animator is set up in the most basic way:
Since you only have 1 Animation. An Animator is irrelevant to the solution. This is tested and working. Now you need to make the Animation a Legacy type to get this working because we are not going to use the Animator.
Click the Animation on the Project -> look at the upper right section of the Inspector view, there is a little button there which will drop down a selection. "Debug" then Check the Legacy.
Set your Animation to whatever you want. I force the WrapMode in the script to be wrap mode once. So it will only play once.
Now in the Animation Component make sure you select the Animation that you want by default or it wont work. Cause we only use anim.Play(); Without parameters meaning, run the default animation that is set.
I created a Text UI and added an Animation that alpha is 0 from the start and at the end point making it 1. You have to do that on your own.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class MyScore : MonoBehaviour {
// Use this for initialization
public int currentScore = 0;
public GameObject Myscore; // Drag the GameObject that has the Animation for your score.
public Text myScoreText; //Drag in the Inspector the Text object to reference
public Animation anim;
public int score
{
get { return currentScore; }
set { this.currentScore += value; }
}
void Start()
{
anim = Myscore.GetComponent<Animation>(); // Reference the Animation Component.
anim.wrapMode = WrapMode.Once; // Legacy animation Set to play once
AddScore();
}
public void AddScore()
{
score += 10;
myScoreText.text = score.ToString();
anim.Play();
Debug.Log("Current Score is "+ score);
Invoke("AddScore", 2);
}
}
Good luck.

Resources