I'm making a very simple android game but I am new at coding. I want my player to continuously go up and down the screen, but can't make it wordk.
public class DuckBehaviour : MonoBehaviour {
Vector3 velocity = Vector3.zero;
float speed = 1f;
float verticality;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (transform.position.y < Screen.height -10) {
velocity.y = 0.7f;
} else if (transform.position.y > 10) {
velocity.y = -0.7f;
}
transform.position += velocity * Time.deltaTime;
}
}
There appear to be two issues with the code. The first is that if the gameobject starts on screen as opposed to offscreen then its velocity will remain at Vector2.zero. The second issue is that Screen.height is in pixels but transform is in Unity's units. Hope this helps.
public class DuckBehaviour : MonoBehaviour {
Vector3 velocity = Vector3.zero;
float speed = 1f;
float verticality;
// Use this for initialization
void Start () {
velocity.y = 0.7f;
}
// Update is called once per frame
void Update () {
//Requires that an orthographic camera named "MainCamera" exists with y transform of 0
if (transform.position.y < -Camera.main.orthographicSize) {
velocity.y = 0.7f;
} else if (transform.position.y > Camera.main.orthographicSize) {
velocity.y = -0.7f;
}
transform.position += velocity * Time.deltaTime;
}
}
You could try something like this (taken from Unity forums - see here.
Beware, the code is not actually tested :)
public class DuckBehaviour : MonoBehaviour {
float speed = 1f;
float verticality;
Vector3 pointB;
IEnumerator Start () {
Vector3 pointA = transform.position;
while (true) {
yield return StartCoroutine(MoveObject(transform, pointA, pointB, 3.0));
yield return StartCoroutine(MoveObject(transform, pointB, pointA, 3.0));
}
}
IEnumerator MoveObject (Transform thisTransform, Vector3 startPos, Vector3 endPos, float time) {
float i = 0.0f;
float rate = 1.0f / time;
while (i < 1.0f) {
i += Time.deltaTime * rate;
thisTransform.position = Vector3.Lerp(startPos, endPos, i);
yield return null;
}
}
}
C# requires you to use the StartCoroutine method and any methods to be used as coroutines must return IEnumerator. This page explains how coroutines work.
Related
I have an object that moves forward and backwards. Just as it is about to move in the opposite direction, I am trying to add a very brief delay (1.0f) before it moves again.
public class PushPlayer : MonoBehaviour
{
public float moveAmount = 3.3f;
public float speed = 1.1f;
private Vector3 startPos;
void Start()
{
startPos = transform.position;
}
void Update()
{
Vector3 v = startPos;
v.z += moveAmount * Mathf.Sin(Time.time * speed);
transform.position = v;
}
}
I attempted to implement a coroutine in two different ways with one of them not working and the other making my entire game basically freeze. I tried to call the method again as well which I am not sure works at all however there were no results.
using System.Collections;
using UnityEngine;
public class PushPlayer : MonoBehaviour
{
public float moveAmount = 3.3f;
public float speed = 1.1f;
private Vector3 startPos;
[SerializeField] private float _delay = 1f;
void Start()
{
startPos = transform.position;
StartCoroutine(DoMoving());
}
private IEnumerator DoMoving()
{
while (true)
{
yield return DoCycle();
yield return new WaitForSeconds(_delay);
}
IEnumerator DoCycle()
{
var time = 0f;
while (time * speed < Mathf.PI * 2f)
{
Vector3 v = startPos;
v.z += moveAmount * Mathf.Sin(time * speed);
transform.position = v;
yield return null;
time += Time.deltaTime;
}
}
}
}
But it would be better to use dotween or dotween + unitask for async moving
The grounded state for my character controller flickers on and off constantly at what seems to be every frame. From what I know, it's supposed to check if the player is grounded through player.isGrounded, but something else is moving it back up.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCharacterController: MonoBehaviour {
static Animator anim;
public bool walking;
public GameObject playerModel, Hero;
//Transforms
public Transform playerCam, character, centerPoint;
private Vector3 moveDirection;
//character controller declaration
CharacterController player;
//Mouse Rotation
private float rotX, rotY;
//Mouse Y Position
public float mouseYPosition = 1f;
//Mouse Sensitivity
public float Sensitivity = 10f;
//Mouse Zoom
private float zoom;
public float zoomSpeed = 2;
//Clamping Zoom
public float zoomMin = -2f;
public float zoomMax = -10f;
public float rotationSpeed = 5f;
//Move Front Back left & Right
private float moveFB, moveLR;
//Movement Speed
public float Speed = 2f;
//Velocity of Gravity
public float verticalVelocity;
//Jump Distance
public float jumpDist = 5f;
//Multiple Jumps
int jumpTimes;
//To use with Dialogue Manager
public DialogueManager DiagM;
public AudioClip jumpSound;
public AudioClip HurtSound;
public AudioClip PunchSound;
AudioSource audioSource;
//knockback
public float knockBackForce;
public float knockBackTime;
private float knockBackCounter;
// Use this for initialization
void Start ()
{
//character controller
player = GameObject.Find("Player").GetComponent<CharacterController> ();
StartCoroutine(MyCoroutine(character));
anim = GetComponent<Animator>();
//mouse zoom
zoom = -3;
centerPoint.transform.position = playerCam.transform.position;
centerPoint.transform.parent = null;
audioSource = GetComponent<AudioSource>();
}
IEnumerator MyCoroutine (Transform character)
{
if (player.isGrounded == true)
{
anim.SetBool("isFalling",false);
//anim.SetBool("isIdling", true);
yield return new WaitForSeconds(0);
}
}
// Update is called once per frame
void Update ()
{
//Mouse Zoom Input
zoom += Input.GetAxis ("Mouse ScrollWheel") * zoomSpeed;
if (zoom > zoomMin)
zoom = zoomMin;
if (zoom < zoomMax)
zoom = zoomMax;
//Mouse Camera Input
playerCam.transform.localPosition = new Vector3 (0, 0, zoom);
//Mouse Rotation
rotX += Input.GetAxis ("Mouse X") * Sensitivity;
rotY -= Input.GetAxis ("Mouse Y") * Sensitivity;
//Clamp Camera
rotY = Mathf.Clamp (rotY, -60f, 60f);
playerCam.LookAt (centerPoint);
centerPoint.localRotation = Quaternion.Euler (rotY, rotX, 0);
//Movement Speed
if (knockBackCounter <= 0)
{
moveDirection = (transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal"));
moveDirection = moveDirection * Speed;
moveDirection.y = verticalVelocity;
player.Move(moveDirection * Time.deltaTime);
//Movement Rotation
centerPoint.position = new Vector3 (character.position.x, character.position.y + mouseYPosition, character.position.z);
//knockback disable
//Movement Input
if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
{
transform.rotation = Quaternion.Euler(0f, centerPoint.rotation.eulerAngles.y, 0f);
Quaternion turnAngle = Quaternion.LookRotation(new Vector3(moveDirection.x, 0f, moveDirection.z));
playerModel.transform.rotation = Quaternion.Slerp(playerModel.transform.rotation, turnAngle, Time.deltaTime * rotationSpeed);
if (player.isGrounded == true)
{
anim.SetBool("isWalking", true);
anim.Play("Running");
}
}
else
{
StartCoroutine(MyCoroutine(character));
}
if (Input.GetButtonDown("LHand"))
{
audioSource.PlayOneShot(PunchSound, 1F);
anim.Play("RPunch");
}
if (player.isGrounded == true)
{
jumpTimes = 0;
//verticalVelocity = -Physics.gravity.y * Time.deltaTime;
verticalVelocity = 0;
}
else
{
verticalVelocity += Physics.gravity.y * Time.deltaTime;
anim.SetBool("isWalking", false);
anim.SetBool("isFalling", true);
}
if (jumpTimes < 1)
{
if (Input.GetButtonDown("Jump"))
{
verticalVelocity += jumpDist;
anim.Play("Jump");
audioSource.PlayOneShot(jumpSound, 1F);
jumpTimes += 1;
}
}
}
else
{
knockBackCounter -= Time.deltaTime;
}
}
public void Knockback(Vector3 direction)
{
knockBackCounter = knockBackTime;
anim.Play("Jump");
audioSource.PlayOneShot(HurtSound, 50F);
moveDirection = direction * knockBackForce;
moveDirection.y = knockBackForce;
}
}
It looks like it has to do with the verticalVelocity lines, but so far I have only tried setting verticalVelocity = 0 and that works until I have actually moved the character. What could I change to stop the flickering?
Probably it is already solved, but the reason for that is that if you are using Character Controller you should apply gravity ALL the time to the character.
When the character collides with a object, it actually enters a little bit inside this object, then Unity pushes the character back away from the object, until it is no longer touching it. At this point, your gravity starts acting again, and re initiziling the cycle.
You need to apply gravity 100% of the time to create enough force to "balance" this fight with the floor. Could be a smaller "gravity" like 1. No need to be your gravity variable.
Also, on top of that, I like to add a "Coyote time", and make my on IsGrounded() method, as follows:
public bool IsGrounded()
{
return CoyoteTime < CoyoteTimeMax;
}
public void CoyoteControl()
{
if (CharController.isGrounded)
{
CoyoteTime = 0;
}
else
{
CoyoteTime += Time.deltaTime;
}
}
And then I call the CoyoteControl() on Update(), and I can call IsGrounded() whenever I need.
On the inspector I usually set the CoyoteTimeMax to 0.1 and it makes falls more smooth.
As per you comment. You should not determine if your player is grounded by checking an animation parameter. The best way is to use a RayCast(). So what you have to do:
Create a Layer named Ground, and add all the platforms in your
scene to that layer.
Create a bool variable
i.e
bool isGrounded;
Create a function to check if the character is grounded
Something like:
bool checkGrounded(){
return Physics.Raycast(transform.position, Vector3.down, 2f, 1 << LayerMask.NameToLayer("Ground")));
}
In this answer you can read about the involved parameters in the Raycast
Finally inside the update check if the player is grounded or not
Something like:
void Update(){
isGrounded = checkGrounded();
}
I have found that the isGrounded check can change over the course of the Update() function if you are checking it multiple times. Assigning it to a variable at the beginning of the function may solve the flickering issue.
void Update()
{
bool isGrounded = characterController.isGrounded;
...
I've been trying to figure this out for a few days now, and I'm very sure it has something to do with my code. What I want the enemy monster to do is to stop moving forward when the player right next to it and run the attack animation. What it actually does is run the attack animation while orbiting around the player like a planet, and you can't really outrun it.
I'm using Unity3d as the engine and my code is written in C#. It's very simple so I'm worried I'm missing something important.
public class enemyAITest : MonoBehaviour
{
public Transform player; // target
public float playerDistance; // determines how far from target before action takes place
public float rotationDamping; // determines how quickly rotation occurs
public float chaseSpeed; // determines how quickly to pursue target
public float wanderSpeed; // determines how quickly to move around map
public float maxDist;
static Animator anim;
Vector3 wayPoint;
void Awake()
{
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update ()
{
transform.position += transform.TransformDirection(Vector3.forward) * wanderSpeed * Time.deltaTime;
playerDistance = Vector3.Distance(player.position, transform.position);
while ((transform.position - wayPoint).magnitude < 3)
Wander();
if (playerDistance < 20f)
{
LookAtPlayer();
wanderSpeed = 0;
anim.SetBool("isIdle", true);
}
if (playerDistance < 10f)
{
Chase();
anim.SetBool("isIdle", false);
anim.SetBool("isWalking", false);
anim.SetBool("isRunning", true);
}
if(playerDistance < 1f)
{
wanderSpeed = 0;
anim.SetBool("isRunning", false);
anim.SetBool("isAttacking", true);
}
else anim.SetBool("isWalking", true);
}
void LookAtPlayer()
{
Quaternion rotation = Quaternion.LookRotation(player.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * rotationDamping);
wanderSpeed = 0;
}
void Chase()
{
Vector3 direction = player.position - transform.position;
direction.y = 0;
transform.Translate(Vector3.forward * chaseSpeed * Time.deltaTime);
}
void Wander()
{
Vector3 MonsterPosition = new Vector3(Random.Range(transform.position.x - maxDist, transform.position.x + maxDist), 1, Random.Range(transform.position.z - maxDist, transform.position.z + maxDist));
wayPoint.y = 1;
transform.LookAt(wayPoint);
//Debug.Log(wayPoint + " and " + (transform.position - wayPoint).magnitude);
}
}
Any advice will help (Please forgive the strange formatting, I was having trouble with keeping the entire Wander method and the on Awake line in the code block).
I'm trying to get the distance between my player, and the nearest object with the tag 'wall' however I can't seem to get it to work.
To my knowledge my code isn't working at all.
So my question is;
What am I doing wrong? Again, I want to find the distance from my player and the nearest object with the tag 'wall'. If I'm near a object with the tag 'wall' I want it to set the variable to true.(nearWall = true) then once I'm away from the object(About 10.0f) I want it back to false.(nearWall = false)
This is the code I have been working with.
using UnityEngine;
using System.Collections;
public class PlayerMotor : MonoBehaviour {
private CharacterController controller;
private Vector3 moveVector;
private float speed = 2.0f;
private float verticalVelocity = 0.0f;
private float gravity = 12.0f;
private bool nearWall;
public GameObject playerObject;
GameObject closestObject;
float distance = Mathf.Infinity;
public float distanceToWall = Mathf.Infinity;
private void Start() {
nearWall = false;
playerObject = GameObject.Find("Player");
distanceToWall = 0;
controller = GetComponent<CharacterController> ();
}
public void getNearestWall()
{
if (distance <= 10.0f) {
nearWall = true;
print ("Near wall!");
}
else
nearWall = false;
}
GameObject findNearestWall()
{
GameObject[]objectArray;
objectArray = GameObject.FindGameObjectsWithTag("wall");
Vector3 position = playerObject.transform.position;
foreach(GameObject currentObject in objectArray)
{
Vector3 distanceCheck = currentObject.transform.position - position;
float currentDistance = distanceCheck.sqrMagnitude;
if (currentDistance < distance)
{
closestObject = currentObject;
distance = currentDistance;
}
}
return closestObject;
}
private void Update()
{
findNearestWall ();
moveVector = Vector3.zero;
if (controller.isGrounded)
{
verticalVelocity = -0.5f;
}
else
{
verticalVelocity -= gravity * Time.deltaTime;
}
if (Input.GetMouseButton (0)) {
if (!nearWall) {
if (Input.mousePosition.x > Screen.width / 2)
moveVector.x = speed;
else
moveVector.x = -speed;
}
else
{
moveVector.x = transform.forward.x * speed;
transform.Rotate(new Vector3(0, -90, 0));
}
}
moveVector.y = verticalVelocity;
moveVector.z = transform.forward.z * speed;
controller.Move (moveVector * Time.deltaTime);
}
}
One thing is that you are not calling getNearestWall() method - which is actually changing the flag - anywhere.
And second why don't you just try:
currentDistance = Vector3.Distance(currentObject.transform.position, position);
When calculating distance
first of all you need to call getNearestWall(); inside the Update() method ( after findNearestWall() of course ). also what you are doing now is getting the minimal distance the player reached in the whole game. you might want to add distance = Mathf.Infinity; in top of findNearestWall() so it will something like this:
GameObject findNearestWall()
{
GameObject[] objectArray;
objectArray = GameObject.FindGameObjectsWithTag("wall");
distance = Mathf.Infinity;
Vector3 position = playerObject.transform.position;
foreach (GameObject currentObject in objectArray)
{
Vector3 distanceCheck = currentObject.transform.position - position;
float currentDistance = distanceCheck.sqrMagnitude;
if (currentDistance < distance)
{
closestObject = currentObject;
distance = currentDistance;
}
}
return closestObject;
}
now whenever you get near a wall it should print Near wall!
note:
also you are calling FindObjectsWithTag() at an Update method which might significantly drain your processing power. you might want to avoid that by declaring a private GameObject[] objectArray in the class.
and then use objectArray = GameObject.FindGameObjectsWithTag("wall"); once at Awake() or Start()
I am working on a Character Controller Script and everything is working fine but the problem is that once my player starts to fall it is so sudden and jerks down. I would like the player to gradually fall down, this is my character controller script -
using UnityEngine;
using System.Collections;
public class CharacterController : MonoBehaviour {
public float inputDelay = 0.1f;
public float forwardVel = 12;
public float rotateCel = 12;
public float JumpHeight = 20;
public Vector3 Gravity = new Vector3 (0, -180, 0);
public bool CanPress;
private float jumpTime;
public float _initialJumpTime = 0.4f;
//[HideInInspector]
public bool isGrounded;
Quaternion targetRotation;
Rigidbody rBody;
Vector3 forwardInput, turnInput;
public bool HasJumped;
public Quaternion TargetRotation
{
get {return targetRotation;}
}
// Use this for initialization
void Start () {
Physics.gravity = Gravity;
targetRotation = transform.rotation;
if (GetComponent<Rigidbody> ())
rBody = GetComponent<Rigidbody> ();
else {
Debug.LogError("Character Needs Rigidbody");
}
// forwardInput = turnInput = 0;
forwardInput = turnInput = Vector3.zero;
}
// Update is called once per frame
void Update () {
GetInput ();
//Turn ();
if (CanPress == true) {
if (Input.GetKeyDown (KeyCode.Space)) {
HasJumped = true;
jumpTime = _initialJumpTime;
}
}
if (HasJumped == true) {
rBody.useGravity = false;
jumpTime -= 1 * Time.deltaTime;
if (jumpTime > 0) {
Jump();
}
else {
HasJumped = false;
rBody.useGravity = true;
}
}
}
void GetInput() {
//forwardInput = Input.GetAxis ("Vertical");
//turnInput = Input.GetAxis ("Horizontal");
forwardInput = new Vector3 (Input.GetAxis ("Horizontal") * rotateCel, 0, Input.GetAxis ("Vertical") * forwardVel);
forwardInput = transform.TransformDirection (forwardInput);
if (Input.GetKeyUp (KeyCode.Space)) {
//HasJumped = false;
}
}
void Jump() {
Vector3 up = transform.TransformDirection (Vector3.up);
GetComponent<Rigidbody> ().AddForce (up * 5, ForceMode.Impulse);
}
void FixedUpdate() {
Run ();
}
void Run() {
if (Mathf.Abs (10) > inputDelay) {
//Move
//rBody.velocity = transform.forward * forwardInput * forwardVel;
rBody.velocity = forwardInput;
} else {
//zero velocity
rBody.velocity = Vector3.zero;
}
}
void Turn() {
// targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
// transform.rotation = targetRotation;
}
void OnTriggerEnter(Collider col) {
isGrounded = true;
CanPress = true;
}
void OnTriggerExit(Collider col) {
isGrounded = false;
CanPress = false;
}
}
My character has a Rigidbody attactches which uses gravity and has X,Y,Z constraints for Rotation.
The player goes up smoothly and falls down smoothly but the transition between the two is very abrupt and sudden.
Thanks for the help. :)
Okay, so I took your code and had a play.
I think the issue was that in your Run() function, you were altering the velocity of the rigidbody which was affecting your jumping.
I've taken that stuff out and improved your script slightly and tested it. Attach this to a capsule with a rigidbody on it, with a floor underneath with a box collider on and hit space, and you should get a smooth jump.
Your new(ish) script:
using UnityEngine;
using System.Collections;
public class CharacterController : MonoBehaviour
{
public float inputDelay = 0.1f;
public float forwardVel = 12;
public float rotateCel = 12;
public float jumpHeight = 10;
private float jumpTime;
public float _initialJumpTime = 0.4f;
//[HideInInspector]
public bool isGrounded;
Quaternion targetRotation;
Rigidbody rBody;
Vector3 forwardInput, turnInput;
public bool canJump;
public Quaternion TargetRotation
{
get { return targetRotation; }
}
void Start()
{
targetRotation = transform.rotation;
if (GetComponent<Rigidbody>())
rBody = GetComponent<Rigidbody>();
else
{
Debug.LogError("Character Needs Rigidbody");
}
// forwardInput = turnInput = 0;
forwardInput = turnInput = Vector3.zero;
}
void Update()
{
GetInput();
//Turn ();
if (Input.GetKeyDown(KeyCode.Space) && canJump)
{
rBody.AddForce(Vector3.up * jumpHeight, ForceMode.Impulse);
}
}
void GetInput()
{
//forwardInput = Input.GetAxis ("Vertical");
//turnInput = Input.GetAxis ("Horizontal");
forwardInput = new Vector3(Input.GetAxis("Horizontal") * rotateCel, 0, Input.GetAxis("Vertical") * forwardVel);
forwardInput = transform.TransformDirection(forwardInput);
}
void FixedUpdate()
{
//Run();
}
void Run()
{
//HERE YOU SET THE RIGIDBODYS VELOCITY, WHICH IS CAUSING YOUR JUMP TO NOT WORK PROPERLY. DO NOT MODIFY THE VELOCITY
//OF A RIGIDBODY
if (Mathf.Abs(10) > inputDelay)
{
//Move
//rBody.velocity = transform.forward * forwardInput * forwardVel;
rBody.velocity = forwardInput;
}
else
{
//zero velocity
rBody.velocity = Vector3.zero;
}
}
void Turn()
{
// targetRotation *= Quaternion.AngleAxis (rotateCel * turnInput * Time.deltaTime, Vector3.up);
// transform.rotation = targetRotation;
}
void OnCollisionEnter(Collision col)
{
isGrounded = true;
canJump = true;
}
void OnCollisionExit(Collision col)
{
isGrounded = false;
canJump = false;
}
}
Couple of points:
name your variables inThisKindOfFashion (jumpHeight, isOnGround, camelCaseExample), having variables beginning with a capital letter like Gravity and JumpHeight can get confusing.
as someone once answered on one of my questions, don't modify the velocity of a rigidbody unless you know what you are doing! Seems odd, but after following that advice I've never had a problem since!
In your script I have used OnCollision rather than OnTrigger. If you put a floor with a box collider underneath your capsule with a collider, rigidbody and this script on, your character will stop on the ground. If you use a trigger, he will fall through (at least in my experience!)
Happy coding! :-)
Edit
To respond to your comments:
"How do you suggest I move the player"
Movement can be done in a variety of different ways, but I usually use this one all the time unless I need to do something a bit differently:
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
transform.position += Vector3.left * speed * Time.deltaTime; //speed could be 5f, for example (f means float);
}
// then do the same for other directions, RightArrow -.right, UpArrow - .forward, DownArrow - .back
}
"How do I adjust how fast the player jumps"
You can alter the jumpHeight variable for a higher or smaller jump. If by faster you mean falls down faster, go to Edit>Project Settings>Physics> and change Y gravity to something smaller, such as -20.
Tutorials can be found here
They have a wide variety of tutorials, and even have ones that come with example projects so you can just put it together following the video.