I have the following code for a simple 2d game. The game is lit by a directional light at the moment, which lights both the background and the player.
public class BlockSpawner : MonoBehaviour
{
public GameObject blockPrefab; // a purple cube
public Vector2 spawnSizeMinMax;
private double _secondsBetweenSpawns = 0.5;
private float _nextSpawnTime;
private void Update()
{
if (Time.time > _nextSpawnTime)
{
_nextSpawnTime = (float) (Time.time + _secondsBetweenSpawns);
float spawnSize = Random.Range(spawnSizeMinMax.x, spawnSizeMinMax.y);
Vector3 spawnPosition =
new Vector3(
Random.Range(Player.screenHalfWidth - spawnSize, -Player.screenHalfWidth + spawnSize),
Player.screenHalfHeight + spawnSize,
5
);
GameObject block = Instantiate(blockPrefab, spawnPosition, Quaternion.identity);
block.transform.parent = transform;
block.transform.localScale = Vector2.one * spawnSize;
block.transform.Rotate(new Vector3(0, 0, Random.Range(-20, 20)));
}
}
}
When I drag the prefab onto the scene it appears as a 3d red cube. When I use this code to spawn it, it appears as a 2d black square and does not respond to lighting at all. In every other way it behaves as expected.
Is there some way to make it accept light? I've tried everything in the inspector.
Edit: Here are some screenshots
As you noticed, it's because you have a zero component in the scale. You should calculate the local scale so that no component is zero. You can do this by using Vector3.one instead of Vector2.one in your assignment:
block.transform.parent = transform;
block.transform.localScale = Vector3.one * spawnSize;
block.transform.Rotate(new Vector3(0, 0, Random.Range(-20, 20)));
Having a zero-componented scale defies certain assumptions that the lighting calculations have when the engine is determining whether a surface is being hit by light or not.
Related
I am a freshman design student and they've asked us to create a game on unity3D without much training on it so needless to say I don't know much except for the super basic stuff. I don't know anything about c# and I've been having an issue making a gameobject teleport. I've spent 6 hours searching for a solution online and the only conclusion I got to was that my object is probably having issues teleporting because of the way I am controlling it - something to do with the controller remembering the last position before the teleport and returning to it. I have no idea how to fix it though.
So this is what my scene looks like: I have a sphere as my character, I move it to this other object that has a collider as trigger which then teleports my sphere to a different point (black object) on the terrain. As soon as my object reaches there, it starts sliding back to the point where the teleport happened. I even tried edit > project settings > physics > auto sync transforms as many suggested that and it worked for them.
This is the code by which I control my player:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyPlayer : MonoBehaviour
{
public float speed = 1;
public float spacing = 1;
private Vector3 pos;
// Use this for initialization
void Awake()
{
pos = transform.position;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
pos.x += spacing;
if (Input.GetKeyDown(KeyCode.S))
pos.x -= spacing;
if (Input.GetKeyDown(KeyCode.D))
pos.z -= spacing;
if (Input.GetKeyDown(KeyCode.A))
pos.z += spacing;
transform.position = Vector3.MoveTowards(transform.position, pos, speed * Time.deltaTime);
}
}
and I also have a camera that follows the sphere using this code
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;
}
}
and I have another code on the camera that makes me be able to look around using my mouse
using UnityEngine;
using System.Collections;
public class FlyCamera : MonoBehaviour
{
/*
Writen by Windexglow 11-13-10. Use it, edit it, steal it I don't care.
Converted to C# 27-02-13 - no credit wanted.
Simple flycam I made, since I couldn't find any others made public.
Made simple to use (drag and drop, done) for regular keyboard layout
wasd : basic movement
shift : Makes camera accelerate
space : Moves camera on X and Z axis only. So camera doesn't gain any height*/
float mainSpeed = 700.0f; //regular speed
float shiftAdd = 950.0f; //multiplied by how long shift is held. Basically running
float maxShift = 2000.0f; //Maximum speed when holdin gshift
float camSens = 0.25f; //How sensitive it with mouse
private Vector3 lastMouse = new Vector3(255, 255, 255); //kind of in the middle of the screen, rather than at the top (play)
private float totalRun = 1.0f;
void Update()
{
lastMouse = Input.mousePosition - lastMouse;
lastMouse = new Vector3(-lastMouse.y * camSens, lastMouse.x * camSens, 0);
lastMouse = new Vector3(transform.eulerAngles.x + lastMouse.x, transform.eulerAngles.y + lastMouse.y, 0);
transform.eulerAngles = lastMouse;
lastMouse = Input.mousePosition;
//Mouse camera angle done.
//Keyboard commands
float f = 0.0f;
Vector3 p = GetBaseInput();
if (Input.GetKey(KeyCode.LeftShift))
{
totalRun += Time.deltaTime;
p = p * totalRun * shiftAdd;
p.x = Mathf.Clamp(p.x, -maxShift, maxShift);
p.y = Mathf.Clamp(p.y, -maxShift, maxShift);
p.z = Mathf.Clamp(p.z, -maxShift, maxShift);
}
else
{
totalRun = Mathf.Clamp(totalRun * 0.5f, 1f, 1000f);
p = p * mainSpeed;
}
p = p * Time.deltaTime;
Vector3 newPosition = transform.position;
if (Input.GetKey(KeyCode.Space))
{ //If player wants to move on X and Z axis only
transform.Translate(p);
newPosition.x = transform.position.x;
newPosition.z = transform.position.z;
transform.position = newPosition;
}
else
{
transform.Translate(p);
}
}
private Vector3 GetBaseInput()
{ //returns the basic values, if it's 0 than it's not active.
Vector3 p_Velocity = new Vector3();
if (Input.GetKey(KeyCode.W))
{
p_Velocity += new Vector3(0, 0, 1);
}
if (Input.GetKey(KeyCode.S))
{
p_Velocity += new Vector3(0, 0, -1);
}
if (Input.GetKey(KeyCode.A))
{
p_Velocity += new Vector3(-1, 0, 0);
}
if (Input.GetKey(KeyCode.D))
{
p_Velocity += new Vector3(1, 0, 0);
}
return p_Velocity;
}
}
Please let me know if there's a specific part of my code that I need to edit to resolve this or alternatively if you have a different code that won't give me this issue, that would make my life so much easier. If I need to edit something or you're sharing a code, please respond with the complete (corrected) code because otherwise I will just be even more confused.
I know this is a super long post and I am sorry but I am really desperate. It's been really hard studying online and basically having to teach myself all of this. This is for a final project so I will really appreciate any help you can throw my way. Thank you for reading and thanks for any help in advance.
EDIT: The teleport code is executing fine because I do teleport to the chosen location, I just end up sliding back to the point which I teleported from.
This is the teleporting code I am using.
using UnityEngine;
using System.Collections;
public class Teleport : MonoBehaviour
{
public GameObject ui;
public GameObject objToTP;
public Transform tpLoc;
void Start()
{
ui.SetActive(false);
}
void OnTriggerStay(Collider other)
{
ui.SetActive(true);
if ((other.gameObject.tag == "Player") && Input.GetKeyDown(KeyCode.E))
{
objToTP.transform.position = tpLoc.transform.position;
}
}
void OnTriggerExit()
{
ui.SetActive(false);
}
}
Ok, so the main reason why your character is drifting back to original position is that the pos variable in the MyPlayer script stays the same after teleporting.
Remedy for that will be changing pos variable from Teleport script after objToTP.transform.position = tpLoc.transform.position;. Something like objToTP.gameobject.GetComponent<MyPlayer>().pos = tpLoc.transform.position;
But make sure that objToTP has component MyPlayer and pos in MyPlayer is public.
Once again: it's a simple way to resolve your problem. In a real project you should create more flexible architecture, but that's a different story.
I believe that you sliding back because you moving player with transform.position = Vector3.MoveTowards in Update().
And you moving it to coordinates that was got from your input
I made the script bellow for the camera to follow the player, but I don't want it to follow him on his X axis. So it should follow the player smoothly only on his Z axis. Any suggestions?
Camera Script:
public Transform Ball;
public float SmoothSpeed = 0.125f;
public Vector3 offset;
bool MoveCamera = true;
void Start () {
}
public void FixedUpdate () {
if(MoveCamera == true){
Vector3 desiredPosition = Ball.position + offset;
Vector3 SmoothedPosition = Vector3.Lerp(transform.position, desiredPosition, SmoothSpeed);
transform.position = SmoothedPosition;
}
if (transform.position.z >= 2f)
{
MoveCamera = false;
}
}
What about only changing the z component?
public void FixedUpdate () {
if(MoveCamera == true){
Vector3 desiredPosition = new Vector3(0, Ball.position.y + offset.y, Ball.position.z + offset.z);
Vector3 SmoothedPosition = Vector3.Lerp(transform.position, desiredPosition, SmoothSpeed);
transform.position = SmoothedPosition;
}
if (transform.position.z >= 2f)
{
MoveCamera = false;
}
}
public gameObject toFollow;
Vector3 camDistance;
public void Start(){
camDistance = toFollow.transform.position-Camera.main.position;
}
public void Update(){
Vector3 following = new Vector3(Camera.main.x,Camera.main.z,toFollow.transform.position.z-Camera.main.position.z);
Camera.main.transform.position = following;
}
i just threw this together so it may require a few tweaks, but it should get you where you need to go. alternatively.... you can add a rigidbody to the camera, and in the inspector tick the boxes for constraints on the x and y axis. this will allow it to move only on the z (if you go this route remember to turn of the gravity for the cameras rigidbody as well)
Anybody in 2019 need a camera to be offset a specific position from their 3d character? Here is an easy solution! Attach this script to the camera you want to follow the player. Select the player as your target in the Unity editor.
This script sets the new position of the camera to
(EDIT: Where did the LaTeX go?)
$v = <targetPosition.x + xOffset, targetPosition.y + yOffset, targetPosition.z + zOffset>$
Benefits of this script:
Camera orientation does not change, even if character turns (because camera is not parented to the player).
Works regardless of player position
Limitations:
- Because camera orientation is fixed, you need to make sure that your character is not obscured by scenery.
- This style of camera control is best-suited for a 3rd person orthographic projection.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour
{
public Transform target;
Vector3 targetPos;
void Update()
{
targetPos = target.position;
transform.position = new Vector3(targetPos.x + 10f, targetPos.y + 8.571067812f, targetPos.z - 10f);
// transform.LookAt(target.transform);
}
}
My use-case required an orthographic projection. Orthographic angles are usually at a 30 degree angle of declination, so my offset is back 10 units, over 10 units, and up half that hypotenuse (that is, up 10*sqrt2 * 1/2). I also bumped the y-position up by the character's height (1.5 units), which I thought would give a better center for the camera target. This gives a y-offset of about 8.571067812.
I am trying to make a simple game where I am shooting a projectile when the user touches the screen, I first spawn 8 projectiles (sprites) and when the user touches the screen I would like the top projectile to fly in the touch direction. I was able to do this; However, every time I shoot, the projectile goes in the wrong direction, here is an image which will illustrate the issue.
Obviously the image is still here but the object will continue flying until it goes out of the screen and then gets destroyed.
Here is the code snippet that handles this
GameplayController.cs
if (Input.GetMouseButtonDown(0))
{
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
position = Camera.main.ScreenToWorldPoint(position);
GameObject target;
target = new GameObject();
target.transform.position = position;
Arrow comp = currentArrows[0].GetComponent<Arrow>();
comp.setTarget(target.transform);
comp.GetComponent<Arrow>().arrowSpeed = 12;
comp.GetComponent<Arrow>().shoot = true;
currentArrows.RemoveAt(0);
Destroy(target);
}
I know I am getting the mouse input here and not the phone touch and that's fine for me, later I will convert it to the touch input.
Arrow.cs
public bool shoot = false;
public float arrowSpeed = 0.0f;
public Vector3 myDir;
public float speed = 30.0f;
private Transform target;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(shoot)
{
transform.position += transform.right * arrowSpeed * Time.deltaTime;
}
}
public void setTarget(Transform targetTransform)
{
this.target = targetTransform;
Vector3 vectorToTarget = target.position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * speed);
}
private void OnBecameInvisible()
{
print("Disappeared");
Destroy(gameObject);
Gameplay.instance.isShooting = false;
}
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
I think that your problem is that you're getting the screen coordinates by click, not the world coordinates, which is actually two different things. In order to direct your projectile correctly you need to convert your screen coordinates to world like it's done here.
The next thing is how you move the projectile:
transform.position += transform.right * arrowSpeed * Time.deltaTime;
You're moving the projectile to the right and then rotating it somehow. Maybe you should try to move it with Vector3.Lerp, which will be easier and rotate it with Transform.LookAt.
I want to move an instance of a gameObject along the outline of another gameobject. Its a 2D Project in Unity.
My current Code:
Vector3 mousePosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(new Vector2(mousePosition.x, mousePosition.y), new Vector2(player.transform.position.x, player.transform.position.y));
if (hit.collider != null && hit.collider.gameObject.tag == "Player") {
if (!pointerInstance) {
pointerInstance = Instantiate(ghostPointer, new Vector3(hit.point.x, hit.point.y, -1.1f), Quaternion.identity);
} else if(pointerInstance) {
pointerInstance.gameObject.transform.position = new Vector3(hit.point.x, hit.point.y, -1.1f);
pointerInstance.gameObject.transform.eulerAngles = new Vector3(0f, 0f, hit.normal.x);
}
}
Unfortunately, the gameObject doesn't rotate towards the mouse and the position on the left side of the playerObject is also sometimes off. I tried to use Instantiate() with Quaternion.LookRotation(hit.normal), but no luck either.
Here a rough sketch of what I want to achieve:
Any help is appreciated. Thanks!
it's better to use Mathematical way instead of physical way(Raycasting),because in raycasting you have to throw ray several time for checking hit point and rotate your object,it makes lag in your game.
Attach this script to your instantiated object:
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour
{
public Transform Player;
void Update()
{
//Rotating Around Circle(circular movement depend on mouse position)
Vector3 targetScreenPos = Camera.main.WorldToScreenPoint(Player.position);
targetScreenPos.z = 0;//filtering target axis
Vector3 targetToMouseDir = Input.mousePosition - targetScreenPos;
Vector3 targetToMe = transform.position - Player.position;
targetToMe.z = 0;//filtering targetToMe axis
Vector3 newTargetToMe = Vector3.RotateTowards(targetToMe, targetToMouseDir, /* max radians to turn this frame */ 2, 0);
transform.position = Player.position + /*distance from target center to stay at*/newTargetToMe.normalized;
//Look At Mouse position
var objectPos = Camera.main.WorldToScreenPoint(transform.position);
var dir = Input.mousePosition - objectPos;
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg);
}
}
Useful explanations
Atan2:
atan2(y,x) gives you the angle between the x-axis and the vector (x,y), usually in radians and signed such that for positive y you get an angle between 0 and π, and for negative y the result is between −π and 0.
https://math.stackexchange.com/questions/67026/how-to-use-atan2
Returns the angle in radians whose Tan is y/x.
Return value is the angle between the x-axis and a 2D vector starting at zero and terminating at (x,y).
https://docs.unity3d.com/ScriptReference/Mathf.Atan2.html
Mathf.Rad2Deg:
Radians-to-degrees conversion constant (Read Only).
This is equal to 360 / (PI * 2).
[SOLVED]
I've been following the Learn To Code By Making Games course (Block Breaker Section) from Udemy and I have a flippin' annoying issue. My paddle doesn't clamp properly to the values I put in. I would have had no trouble with this but I decided that I want a small menu on the left side with a speed controller, sound controller and lives. This means I cant just say that I want the paddle to stop on the edge of the screen.
Observed Behavior:
The paddle does not constrain itself to the area I put in. As the screen size changes the paddle will either go off the screen or will be stopped somewhere like the middle of the screen.
What I Want It To Do:
I want the paddle to stop when it hits the edge of my menu on the left and to stop when it hits the screen on the right. I also want this to stay the same as my screen size changes. So basically I need a mathematic equation that can determine these points and it needs to be able to adjust based on the screen size.
Here is my code for the paddle:
using UnityEngine;
using System.Collections;
public class Paddle : MonoBehaviour {
public Texture texture;
public void Update () {
Vector3 paddlePos = new Vector3 (0.5f, this.transform.position.y , 0f);
float mousePosInBlocks = Input.mousePosition.x;
paddlePos.x = Mathf.Clamp(mousePosInBlocks, //Left Vaule, //Right Value);
this.transform.position = paddlePos;
}
}
this happens because Input.mousePosition returns position of mouse on screen, not in world space. just convert mousePosition into world position, and then assign its value to mousePosInBlocks.
using UnityEngine;
using System.Collections;
public class Paddle : MonoBehaviour {
public Texture texture;
public void Update () {
Vector3 paddlePos = new Vector3 (0.5f, this.transform.position.y , 0f);
float mousePosInBlocks = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
paddlePos.x = Mathf.Clamp(mousePosInBlocks, leftValue, rightValue);
this.transform.position = paddlePos;
}
}
Edit: Sorry, not WorldToScreenPoint, ScreenToWorldPoint
Try just setting the paddlePos to the new vector you're creating (in world space):
public Texture texture; // if needed for something outside this code
private Vector3 paddlePos;
private float mousePosInBlocks;
private float xValue;
private float leftValue;
private float rightValue;
public void Update () {
mousePosInBlocks = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
//compute leftValue on this line
//compute rightValue on this line
xValue = Mathf.Clamp(mousePosInBlocks, leftValue, rightValue);
paddlePos = new Vector3 (xValue, transform.position.y , 0f);
transform.position = paddlePos;
}
EDIT Based on updated question title, the following should work:
public Texture texture; // if needed for something outside this code
private Vector3 playerPosOnScreen;
private float mousePosInBlocks;
public void Update () {
playerPosOnScreen = Camera.main.WorldToScreenPoint(transform.position);
if (playerPosOnScreen.x > Screen.Width) {
transform.position = Camera.main.ScreenToWorldPoint (new Vector3 (Screen.Width, transform.position.y, transform.position.z);
} else if (playerPosOnScreen.x < 0f) {
transform.position = Camera.main.ScreenToWorldPoint (new Vector3 (0f, transform.position.y, transform.position.z);
}
}
Try something like this: (pseudo code, untested, to give you an idea)
Please check the comment for each step.
public void Update () {
// left bound
Vector3 left = Camera.main.ViewPortToScreenPoint(new Vector3(0f, 0f, 0f));
// Menu width
left.x += fmyMenuWidth; // Width of menu
// Right bound
Vector3 right= Camera.main.ViewPortToScreenPoint(new Vector3(1f, 1f, 0f));
// Temporary position vector
Vector3 paddlePos = Vector3.zero;
// capture mouse x
float mouseX = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
// capture mouse y
float mouseY= Camera.main.ScreenToWorldPoint(Input.mousePosition).y;
// Combine and limit the position's X-value, should not go off screen menu's width---->screen's width
paddlePos.x = Mathf.Max(Mathf.Min(right.x, mouseX), left.x);
// Combine and limit the position's Y-value, should not go off screen 0---->screen's height
paddlePos.y = Mathf.Max(Mathf.Min(right.y, mouseY), left.y);
// Finally set the bounded position
this.transform.position = paddlePos;
}