I am trying to set up control of Player game object by UI buttons.
2d top down view scene.
I want to transfer Player object smoothly on fixed distance (0.8 for Axix X for left-right direction and 2.4 for up-down)when I release left/right/up/down ui buttons.
Here i found code for smooth movement but there Player is moving all the time while ui button is pressed.
Can you help me to make it move on mouse up (pointer up) and to move for public x= 0.8f for left/right, and public y = 2.4f for up/down
And at the same time i want to use different speed (peblic) for moves on x and y Axis
Its ok if it should be totally other script using smth like transform.translate
Kindly guide to for any possible solution for this. Thanks
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class PlayerControl : MonoBehaviour
{
float movX;
float movY;
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
movX = CrossPlatformInputManager.GetAxisRaw("Horizontal");
movY = CrossPlatformInputManager.GetAxisRaw("Vertical");
rb.velocity = new Vector2(movX * 1, movY * 1);
}
}
This script can be moved by the WASD keys.
This should move your gameObject by the requested amount over x amount of time(speed).
Currently it can be only moved when it'S reached its destionation but you can easily modify this :), by stopping the coroutine
using System.Collections;
using UnityEngine;
public class PlayerControl : MonoBehaviour
{
// We gonna move by WASD keys
[Header("Speed & Movement settings")]
[SerializeField]
float Speed = 2.0f;
[SerializeField]
float movSpeedX = 0.8f;
[SerializeField]
float movSpeedY = 2.4f;
bool ReachedTarget = true;
void Update()
{
if (ReachedTarget)
{
Vector2 dest = Vector2.zero;
Vector2 currentPos = transform.position;
if (Input.GetKeyUp(KeyCode.W))
{
dest = currentPos + (Vector2.up * movSpeedY);
StartCoroutine(moveTo(dest, Speed));
}
else if (Input.GetKeyUp(KeyCode.S))
{
dest = currentPos + (Vector2.down * movSpeedY);
StartCoroutine(moveTo(dest, Speed));
}
else if (Input.GetKeyUp(KeyCode.D))
{
dest = currentPos + (Vector2.right * movSpeedX);
StartCoroutine(moveTo(dest, Speed));
}
else if (Input.GetKeyUp(KeyCode.A))
{
dest = currentPos + (Vector2.left * movSpeedX);
StartCoroutine(moveTo(dest, Speed));
}
}
}
// Time to take is in seconds
IEnumerator moveTo(Vector2 TargetPosition, float TimetoTake)
{
Vector2 originalPosition = transform.position;
float Time_taken = 0f;
ReachedTarget = false;
while (Time_taken < 1)
{
Time_taken += Time.deltaTime / TimetoTake;
// Interpolating between the original and target position this basically provides your "speed"
transform.position = Vector2.Lerp(originalPosition, TargetPosition, Time_taken);
yield return null;
}
Time_taken = 0;
transform.position = TargetPosition;
ReachedTarget = true;
}
}
I can't find any documentation of CrossPlatformInputManager, and I know nothing about it. But if you need to get the event of "release a key" instead of "press the key", try this: Input.GetKeyUp.
Description
Returns true during the frame the user releases the key identified by
name.
You need to call this function from the Update function, since the
state gets reset each frame. It will not return true until the user
has pressed the key and released it again.
For the list of key identifiers see Conventional Game Input. When
dealing with input it is recommended to use Input.GetAxis and
Input.GetButton instead since it allows end-users to configure the
keys.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
void Update()
{
if (Input.GetKeyUp("space"))
{
print("Space key was released");
}
}
}
If you want to stop the rigid body, you need to reset its velocity to
zero. Or you can use
Rigidbody2D.MovePosition
to move it a certain distance.
Parameters
position The new position for the Rigidbody object.
Description
Moves the rigidbody to position.
Moves the rigidbody to the specified position by calculating the
appropriate linear velocity required to move the rigidbody to that
position during the next physics update. During the move, neither
gravity or linear drag will affect the body. This causes the object to
rapidly move from the existing position, through the world, to the
specified position.
Because this feature allows a rigidbody to be moved rapidly to the
specified position through the world, any colliders attached to the
rigidbody will react as expected i.e. they will produce collisions
and/or triggers. This also means that if the colliders produce a
collision then it will affect the rigidbody movement and potentially
stop it from reaching the specified position during the next physics
update. If the rigidbody is kinematic then any collisions won't affect
the rigidbody itself and will only affect any other dynamic colliders.
2D rigidbodies have a fixed limit on how fast they can move therefore
attempting to move large distances over short time-scales can result
in the rigidbody not reaching the specified position during the next
physics update. It is recommended that you use this for relatively
small distance movements only.
It is important to understand that the actual position change will
only occur during the next physics update therefore calling this
method repeatedly without waiting for the next physics update will
result in the last call being used. For this reason, it is recommended
that it is called during the FixedUpdate callback.
Note: MovePosition is intended for use with kinematic rigidbodies.
// Move sprite bottom left to upper right. It does not stop moving.
// The Rigidbody2D gives the position for the cube.
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour
{
public Texture2D tex;
private Vector2 velocity;
private Rigidbody2D rb2D;
private Sprite mySprite;
private SpriteRenderer sr;
void Awake()
{
sr = gameObject.AddComponent<SpriteRenderer>();
rb2D = gameObject.AddComponent<Rigidbody2D>();
}
void Start()
{
mySprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100.0f);
velocity = new Vector2(1.75f, 1.1f);
sr.color = new Color(0.9f, 0.9f, 0.0f, 1.0f);
transform.position = new Vector3(-2.0f, -2.0f, 0.0f);
sr.sprite = mySprite;
}
void FixedUpdate()
{
rb2D.MovePosition(rb2D.position + velocity * Time.fixedDeltaTime);
}
}
Both documents have an example.
Or you don't want to user keyboard but UI buttons, try this: IPointerDownHandler and IPointerUpHandler
Description
Interface to implement if you wish to receive OnPointerDown callbacks.
Detects ongoing mouse clicks until release of the mouse button. Use
IPointerUpHandler to handle the release of the mouse button.
//Attach this script to the GameObject you would like to have mouse clicks detected on
//This script outputs a message to the Console when a click is currently detected or when it is released on the GameObject with this script attached
using UnityEngine;
using UnityEngine.EventSystems;
public class Example : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
//Detect current clicks on the GameObject (the one with the script attached)
public void OnPointerDown(PointerEventData pointerEventData)
{
//Output the name of the GameObject that is being clicked
Debug.Log(name + "Game Object Click in Progress");
}
//Detect if clicks are no longer registering
public void OnPointerUp(PointerEventData pointerEventData)
{
Debug.Log(name + "No longer being clicked");
}
}
Related
I am trying to create a minigame similar to the fishing mechanism in Stardew Valley. I have two boundaries which are empty objects positioned at each end of a rectangle to keep the fish and the hook inside of the zone. When I run my script, the fish spawns at the bottom boundary and moves up instead of the position it is initially in. The hook generates at the bottom boundary and doesn't move upon user input.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishingMiniGame : MonoBehaviour
{
//Make the Egg move
[Header("Fishing Area")]
[SerializeField] Transform topBounds;
[SerializeField] Transform bottomBounds;
[Header("Fish Settings")]
[SerializeField] Transform Fish;
[SerializeField] float smoothMotion = 3f;
[SerializeField] float fishTimeRandomizer = 3f;
float fishPosition;
float fishSpeed;
float fishTimer;
float fishTargetPosition;
[Header("Hook Settinds")]
[SerializeField] Transform Hook;
[SerializeField] float HookSize = .18f;
[SerializeField] float HookSpeed = .1f;
[SerializeField] float HookGravity = .05f;
float hookPosition;
float hookPullVelocity;
private void FixedUpdate()
{
MoveFish();
MoveHook();
}
private void MoveHook()
{
if(Input.GetMouseButtonDown(0))
{
//increase our pull velocity
hookPullVelocity += HookSpeed * Time.deltaTime; //raises out hook
}
hookPullVelocity -= HookGravity * Time.deltaTime;
hookPosition += hookPullVelocity;
hookPosition = Mathf.Clamp(hookPosition, 0, 1); //keep the jook withon bounds
Hook.position = Vector3.Lerp(bottomBounds.position, topBounds.position, hookPosition);
}
private void MoveFish()
{
//based on timer, pick random position
//move fish to that position smoothly
fishTimer -= Time.deltaTime;
if(fishTimer < 0)
{
//pick a new target position
//reset timer
fishTimer = Random.value * fishTimeRandomizer;
fishTargetPosition = Random.value;
}
fishPosition = Mathf.SmoothDamp(fishPosition, fishTargetPosition, ref fishSpeed, smoothMotion);
Fish.position = Vector3.Lerp(bottomBounds, topBounds, fishPosition);
}
}
Well, first, making all the code in one script will be confuse. Try giving that fish its own script and game object.
Plus, take a look into Lerp. I think you are missundertanding how to use it. It takes 3 parameters with a being the original Vector3, so your current hook or fish position, b is your Vector3 target position, and t is the step or timestep. Should be delta or delta*someMultiplier.
What #MickyD said is also true, input should be performed during Update(), but that will not fix you code. Update(), FixedUpdate() and LateUpdate() are kinda the same but they run always in that order: Update -> FixedUpdate -> LateUpdate. So keep that in mind.
By the way, your gravity aplies every frame, so your hook is fighting against it even when you are lifting, resulting in half the force being neutralized. Making the gravity only apply on an else after your input will give you a much clear control of forces.
NavmeshAgent player not parallel to slope of hill when moving over hill. On plane surface its going smoothly.
See Video
Below Image properties of navMesh and player
https://ibb.co/fijmoV
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class SampleAgentScript : MonoBehaviour {
public Transform target ;
NavMeshAgent agent;
// private static bool start1=false , start2=false, start3;
// Use this for initialization
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
//if white button click moves to targer-1
agent.SetDestination(target.position);
}
}
I am not sure if NavmeshAgent is supposed to do that for you. This looks like something you're supposed to do manually.
You can correct the rotation of the character to match the slope by performing a raycast downwards and obtaining the normal of the hit point. After obtaining the normal of the hit point, you can then calculate the new rotation with that normal hit point. There are many ways to do that calculation but using Quaternion.FromToRotation and lerping the rotation with Quaternion.Lerp seems to work best.
Finally, make sure to the raycast is only done to Objects you considered as a "Hill" or "Ground". You can do this with the bitwise operation on the layer the "Hill" or "Ground" objects are placed on. The example below assumes that the Objects you consider as "Hill" or "Ground" are on a layer called "Hill".
//Reference of the moving GameObject that will be corrected
public GameObject movingObject;
//Offset postion from where the raycast is cast from
public Vector3 originOffset;
public float maxRayDist = 100f;
//The speed to apply the corrected slope angle
public float slopeRotChangeSpeed = 10f;
void Update()
{
//Get the object's position
Transform objTrans = movingObject.transform;
Vector3 origin = objTrans.position;
//Only register raycast consided as Hill(Can be any layer name)
int hillLayerIndex = LayerMask.NameToLayer("Hill");
//Calculate layermask to Raycast to.
int layerMask = (1 << hillLayerIndex);
RaycastHit slopeHit;
//Perform raycast from the object's position downwards
if (Physics.Raycast(origin + originOffset, Vector3.down, out slopeHit, maxRayDist, layerMask))
{
//Drawline to show the hit point
Debug.DrawLine(origin + originOffset, slopeHit.point, Color.red);
//Get slope angle from the raycast hit normal then calcuate new pos of the object
Quaternion newRot = Quaternion.FromToRotation(objTrans.up, slopeHit.normal)
* objTrans.rotation;
//Apply the rotation
objTrans.rotation = Quaternion.Lerp(objTrans.rotation, newRot,
Time.deltaTime * slopeRotChangeSpeed);
}
}
I am very new to Unity and I never coded in C# before neither have I used Unity in the past. All I know is Java and Python. I knew Java since senior year of high school now I am a sophomore in college. I made my project, which consists of my human character, which is supposed to shoot bullets at 12 jaguars. I already implemented all of this from the 2d UFO sample Unity gives us. I have a png picture for my bullet. I really do not know how to implement a bullet. I am required to have the bullet shoot out in two directions. I am starting off gradually by learning how to basic shoot (one direction). I referred to this link and added it to my program and it will not compile after I added the bullet code. I create a sphere into the Unity program as the website said to do and I set the image as the png bullet.
https://unity3d.com/learn/tutorials/temas/multiplayer-networking/shooting-single-player
Now here is my code. I downloaded the free latest version of Unity by the way. My game is 2D by the way. It is just cartoons.
using UnityEngine;
using System.Collections;
//Adding this allows us to access members of the UI namespace including Text.
using UnityEngine.UI;
public class CompletePlayerController : MonoBehaviour {
public float speed; //Floating point variable to store the player's movement speed.
public Text countText; //Store a reference to the UI Text component which will display the number of pickups collected.
public Text winText; //Store a reference to the UI Text component which will display the 'You win' message.
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
private int count; //Integer to store the number of pickups collected so far.
public GameObject bulletPrefab;
public Transform bulletSpawn;
// Use this for initialization
void Start()
{
//Get and store a reference to the Rigidbody2D component so that we can access it.
rb2d = GetComponent<Rigidbody2D> ();
//Initialize count to zero.
count = 0;
//Initialze winText to a blank string since we haven't won yet at beginning.
winText.text = "";
//Call our SetCountText function which will update the text with the current value for count.
SetCountText ();
}
//FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
void FixedUpdate()
{
//Store the current horizontal input in the float moveHorizontal.
float moveHorizontal = Input.GetAxis ("Horizontal");
//Store the current vertical input in the float moveVertical.
float moveVertical = Input.GetAxis ("Vertical");
//Use the two store floats to create a new Vector2 variable movement.
Vector2 movement = new Vector2 (moveHorizontal, moveVertical);
//Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
rb2d.AddForce (movement * speed);
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
if (Input.GetKeyDown(KeyCode.Space))
{
Fire();
}
}
void Fire()
{
// Create the Bullet from the Bullet Prefab
var bullet = (GameObject)Instantiate (
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);
// Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;
// Destroy the bullet after 2 seconds
Destroy(bullet, 2.0f);
}
public override void OnStartLocalPlayer ()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
}
//OnTriggerEnter2D is called whenever this object overlaps with a trigger collider.
void OnTriggerEnter2D(Collider2D other)
{
//Check the provided Collider2D parameter other to see if it is tagged "PickUp", if it is...
if (other.gameObject.CompareTag ("PickUp"))
{
//... then set the other object we just collided with to inactive.
other.gameObject.SetActive(false);
transform.localScale += new Vector3(0.1f, 0.1f, 0);
//Add one to the current value of our count variable.
count = count + 1;
//Update the currently displayed count by calling the SetCountText function.
SetCountText ();
}
}
//This function updates the text displaying the number of objects we've collected and displays our victory message if we've collected all of them.
void SetCountText()
{
//Set the text property of our our countText object to "Count: " followed by the number stored in our count variable.
countText.text = "Count: " + count.ToString ();
//Check if we've collected all 12 pickups. If we have...
if (count >= 12)
//... then set the text property of our winText object to "You win!"
winText.text = "You win!";
}
}
Other class
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour {
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start ()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate ()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
You need to follow all the steps in the tutorial link you shared. Looks like you have copied pieces of code and used it in your controller class. OnStartLocalPlayer is marked as overridden, but it is not in Monobehaviour. It is defined in NetworkBehaviour. You have an error due to this. As mentioned in the other comments, the console error tells you where the problem is.
I am having an issue with my character which is not jumping at all. I am new to Unity, but I made sure to apply the script to the player and adjust the speed, I did not touch the Rigidbody 2D. If any one can help me figure our the issue, it will be much appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
public float moveSpeed;
public float jumpSpeed;
public bool grounded = false;
private Rigidbody2D rb;
void Start() {
rb = GetComponent<Rigidbody2D>();
}
void Update () {
transform.Translate (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0, 0);
if (grounded)
{
if (Input.GetButtonDown ("Jump"))
{
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
}
void OnCollisionEnter2D (Collision2D coll){
if (coll.transform.tag == "Ground")
{
grounded = true;
}
}
}
Inspector window of the Player GameObject
Inspector window of the Ground GameObject
Your problem is you haven't tag the Ground GameObject as so. So in the OnCollisionEnter2D the character detects the collision, but the if (coll.transform.tag == "Ground") will never be true. So it means the character can't be grounded
Since to be grounded is the first condition to check if the player pressed the Jump key. It is impossible it will ever jump
if (grounded)
{
if (Input.GetButtonDown ("Jump"))
{
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
To solve this issue: You need to tag the Ground GameObject as so. In case you are not sure how to do that, on the Tag menu, create (if it doesnt exist already) a new tag called Ground. Then assign in that same menu the Ground Tag to the Ground GameObject. Here you can learn how in case you need a visual reference:
https://docs.unity3d.com/Manual/Tags.html
Edit: You can try this script if everything fails. It should work. I used my self some time ago, I cleaned the code so to leave only what you need to move the character in the x and y axis. Hope to have included everything you need:
public class CharacterController2D : MonoBehaviour {
// LayerMask to determine what is considered ground for the player
public LayerMask whatIsGround;
// Transform just below feet for checking if player is grounded
public Transform groundCheck;
// store references to components on the gameObject
Transform transform;
Rigidbody2D rigidbody;
bool isGrounded = false;
float vy;
float vx;
public float jumpForce = 600f;
void Awake () {
transform = GetComponent<Transform> ();
rigidbody = GetComponent<Rigidbody2D> ();
}
void Update()
{
// determine horizontal velocity change based on the horizontal input
vx = Input.GetAxisRaw ("Horizontal");
vy = rigidbody.velocity.y;
// Check to see if character is grounded by raycasting from the middle of the player
// down to the groundCheck position and see if collected with gameobjects on the
// whatIsGround layer
isGrounded = Physics2D.Linecast(transform.position, groundCheck.position, whatIsGround);
if(isGrounded && Input.GetButtonDown("Jump")) // If grounded AND jump button pressed, then allow the player to jump
{
DoJump();
}
// Change the actual velocity on the rigidbody
rigidbody.velocity = new Vector2(_vx * MoveSpeed, _vy);
}
//Make the player jump
void DoJump()
{
// reset current vertical motion to 0 prior to jump
vy = 0f;
// add a force in the up direction
rigidbody.AddForce (new Vector2 (0, jumpForce));
}
}
So things to take into account:
Instead of tag the ground, you create a layer with everything you
consider ground. That will include possible platforms the character
may jump over. Pass as a parameter this layer to the script in the
inspector
You need to place an empty GameObject in the feet of the character.
You will drag and drop that GameObject in the editor onto the
groundCheck public variable.
Instead of OnTriggerEnter, you will use Physics2D.Linecast which
will trave a line from the position of the character to under its
feet (where you should have place the Transform mentioned in the
previous step) and if in the middle there is an element of the
groundLayer, it means the character will be grounded.
Let me know if anything is not clear or if you find some bug.
As mentioned your problem is deffinetly that your missing to tag your ground object :)
A tip: What i like to do when i have problems like this is to use the unitys Debug.Log() to locate where the problem is it. It will let you know easily in the console what code is run and which is not. Try do the following:
void Update () {
transform.Translate (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0, 0);
if (grounded)
{
Debug.Log("Is grounded");
if (Input.GetButtonDown ("Jump"))
{
Debug.Log("Jump clicked");
rb.AddForce (Vector2.up * jumpSpeed);
grounded = false;
}
}
}
My game is a topdown zombie shooter and whenever the zombies get to the player they bunch up underneath them, to the point where the player can just walk over the zombies. I noticed that when I check isKinematic on the Rigidbody the zombies cant push the player up to go underneath him, so they just run into him(which is what I want). Despite this I am then unable to move. How can i fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMoving1 : MonoBehaviour {
public float moveSpeed;
private Rigidbody myRigidbody;
private Vector3 moveInput;
private Vector3 moveVelocity;
private Camera mainCamera;
public GunController theGun;
void Start () {
myRigidbody = GetComponent <Rigidbody>();
mainCamera = FindObjectOfType<Camera>();
}
// Update is called once per frame
void Update () {
moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical"));
moveVelocity = moveInput * moveSpeed;
Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayLength;
if(groundPlane.Raycast(cameraRay,out rayLength))
{
Vector3 pointToLook = cameraRay.GetPoint(rayLength);
transform.LookAt(new Vector3(pointToLook.x,transform.position.y,pointToLook.z));
}
if (Input.GetMouseButtonDown(0))
theGun.isFiring = true;
if (Input.GetMouseButtonUp(0))
theGun.isFiring = false;
}
void FixedUpdate(){
myRigidbody.velocity = moveVelocity;
}
}
With isKinematic == true You can't change object position through rigidbody, You can only change transform.position.
I think it could be better, if You set isKinematic to false and add stopping distance to enemies, so they can't get too close to player.
Being that your player can no longer be effected by the physics engine, you'd have to manipulate the object's transform manually. Your script isn't ideally setup for it currently, but if I was to hack it into it and try to make it work it would look something like this:
(you can change it from fixedUpdate to update if you're no longer utilizing the physics engine)
void update(){
float x = Input.GetAxisRaw("Horizontal")* Time.Deltatime;
float z = Input.GetAxisRaw("Vertical") * Time.Deltatime;
transform.position = new Vector3(transform.position.x+x,0,transform.position.z+z);
Another way of doing this is to lock the position of Y for the player (assuming Y is the positive "up" direction). isKinimatic is best when you want to move the player or objects around yourself.
I would say upping the mass is better in this case, and you can keep isKinematic unchecked in this case then too. Also apply the lock for Y movement (again if it is the "up" direction from the plane)
Let me know what your solution is regardless, I've had some issues in the past as well with these types of events happening