How to make Trajectory Predictor on my ball? - unity3d

hey guys , So as you can see i made a robot arm grab a slingshot's objectholder with a ball in it. My arm pulls it any direction I want it but I wanted the user to know which box is going to be shot at.

If you're applying an impulse force (or velocity) to your ball and there is gravity in your world, your item will follow the Projectile motion;
Here you can find details about it:
https://en.wikipedia.org/wiki/Projectile_motion

There are basically two main options
calculating it yourself
This is probably way better for performance especially if you want a really simple trajectory preview without accounting for any collision etc
refer to linked article. But it basically comes down to
and would need slightly rework from 2D to 3D physics, should be trivial though since the important part about the Y axis basically stays the same.
You would
Call this simulation with according supposed shoot direction and velocity
Visualize the tracked positions e.g. in a LineRenderer
Physics.Simulate
This allows you to run physics updates manually all within a single frame and actually let the Physics engine handle it all for you
This costs of course a lot of performance but you get all collisions etc accounted for automatically without getting a headache
You would
Make a snapshot of all Rigid bodies in your scene - in order to reset after the simulation
Simulate the desired amount of physics steps (XY seconds ahead) while keeping track of the simulated data
reset everything to the state tracked in step 1
use the simulated data from step 2 to visualize e.g. with a LineRenderer
This might look somewhat like e.g.
public class Prediction : MonoBehaviour
{
public LineRenderer line;
public Rigidbody tracked;
private Rigidbody[] allRigidbodies;
private void Awake()
{
allRigidbodies = FindObjectsOfType<Rigidbody>();
}
private void LateUpdate()
{
// Wherever you would get this from
Vector3 wouldApplyForce;
// Step 1 - snapshot
// For simplicity reasons for now just the positions
// using some Linq magic
var originalPositions = allRigidbodies.ToDictionary(item => item, item => item.position);
// Step 2 - Simulate e.g. 2 seconds ahead
var trackedPositions = new Vector3 [(int) (2 / Time.fixedDeltaTime)];
Physics.autoSimulation = false;
tracked.AddForce(wouldApplyForce);
for(var i = 0; i < trackedPositions.Length; i++)
{
Physics.Simulate(Time.fixedDeltaTime);
trackedPositions[i] = tracked.position;
}
// Step 3 - reset
foreach (var kvp in originalPositions)
{
kvp.Key.position = kvp.Value;
}
Physics.autoSimulate = true;
// Step 4 - Visualize
line.positionCount = trackedPositions.Length;
line.SetPositions(trackedPositions);
}
}
Of course we won't talk about performance here ^^

Related

Best way to create a 2d top down race track procedurally

I am attempting to create a 2d top-down car racing game. This game will have a random road map each time the player plays the game. I have thought about doing this in two different ways: A tilemap, or just generate the roads by placing different prefabs (straight roads, turns, etc). I have decided to go with the prefab route.
The way I believe it should work is to have prefab square "tiles" which have their own colliders set on the edges so I can tell if a player goes off the track in which case they blow up. I would have a MapGenerator Script which will generate an initial random map by keeping track of the last tile placed (including its location and road type: left turn, straight, right, etc). This script will then keep adding onto the road randomly as the player gets closer and closer to the end which makes it an infinite road.
I just want to know if this is just not efficient or if I am thinking of this completely wrong.
Here are a couple of images showing my road tiles which I made in photoshop and then one prefab for a straight road (take note of the colliders on its edges).
A similar game to one I want to make is Sling Drift which I can provide the link if you want. I don't know the policy on adding links to forum chat.
Also, here is my code for the map generator:
//Type of tyle, types are normal (straight road or horizontal road) and turns
public enum MapTileType
{
NORMAL,
N_E,
N_W,
S_E,
S_W
}
//structure for holding the last tile location and its type.
public struct TypedTileLocation
{
public TypedTileLocation(Vector2 pos, MapTileType tyleType)
{
m_tileType = tyleType;
m_position = pos;
}
public Vector2 m_position;
public MapTileType m_tileType;
}
public class MapGenerator : MonoBehaviour
{
//Map Tiles
public GameObject m_roadTile;
public GameObject m_turnNorthWestTile;
//holds all the tiles made in the game
private List<GameObject> m_allTiles;
//Map Tile Widths and Height
private float m_roadTileWidth, m_roadTileHeight;
//Used for generating next tile
TypedTileLocation m_lastTilePlaced;
private void Awake()
{
//store the initial beginning tile location (0,0)
m_lastTilePlaced = new TypedTileLocation(new Vector2(0,0), MapTileType.NORMAL);
//set height and width of tiles
m_roadTileWidth = m_roadTile.GetComponent<Renderer>().bounds.size.x;
m_roadTileHeight = m_roadTile.GetComponent<Renderer>().bounds.size.y;
m_allTiles = new List<GameObject>();
}
// Start is called before the first frame update
void Start()
{
SetupMap();
}
void SetupMap()
{
//starting at the beginning, just put a few tiles in straight before any turns occur
for (int i = 0; i < 6; ++i)
{
GameObject newTempTile = Instantiate(m_roadTile, new Vector2(0, m_roadTileHeight * i), Quaternion.identity);
m_lastTilePlaced.m_tileType = MapTileType.NORMAL;
m_lastTilePlaced.m_position.x = newTempTile.transform.position.x;
m_lastTilePlaced.m_position.y = newTempTile.transform.position.y;
m_allTiles.Add(newTempTile);
}
//now lets create a starter map of 100 road tiles (including turns and straigt-aways)
for (int i = 0; i < 100; ++i)
{
//first check if its time to create a turn. Maybe I'll randomly choose to either create a turn or not here
//draw either turn or straight road, if the tile was a turn decide which direction we are now going (N, W, E, S).
//this helps us determine which turns we can take next
//repeat this process.
}
}
void GenerateMoreMap()
{
//this will generate more map onto the already existing road and then will delete some of the others
}
// Update is called once per frame
void Update()
{
}
private void OnDrawGizmos()
{
}
}
Thanks!
Have you tried splines? They let you make curvy paths like race tracks easily. If not, here is a video that might help: https://www.youtube.com/watch?v=7j_BNf9s0jM.

Avoid raycast hitting player without layermask

I'm making a FPS game, and the player can shoot himself it he aims down. If I add a layermask, it's fixed, but since I plan on making this game multiplayer, every player would have that same layermask. I'd rather not add yet another layermask to other players, if that's possible. Is there some other way to avoid the player shooting himself, withot using layermasks? Or is there an actual way to make other players have a seperate layermask?
Or is there an actual way to make other players have a seperate layermask?
As Layers need to be defined beforehand and are limited to 32 layers (8 already predefined by Unity) this solution would be feasible to implement, yes, but not be very scalable and depending to the complexity of the rest of your app very limited.
You could use RaycastAll, filter out if(hit != player) e.g. using Linq Where, order by the distance e.g. using Linq OrderBy and then use the first hit from the results.
Somewhat like
// Wherever you get these from
Ray ray; // the ray with origin amd direction for the cast
float distance; // if needed a maximum distance
LayerMask layers; // the general raycast layer - not different ones for each player ;)
GameObject player; // your player object
var hits = Physics.RaycastAll(ray, distance, layers);
if(hits.Length > 0)
{
// Filter out e.g. using Linq
hits = hits.Where(hit => hit.gameObject != player).ToArray();
if(hits.Length > 1)
{
// Sort by distance from ray origin
hits = hits.OrderBy(hit => hit.distance).ToArray();
}
// Finally get first hit
var hit = hits[0];
// ...
}

How can i turn the camera to left and right in unity for a sphere?

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.

Unity - Walk around a cube

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.

visual lag of the moving picture in Unity3D. How to make it smoother?

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);
}
}