I am making the Bouncing Ball using Processing. It works fine when I use the ball object once, but when I use it twice like ball1 & ball2, the balls appear on top of each other making the delusion that it is just one ball bouncing, although I'm setting their primary location and velocity a random number. So, where is the problem? (first argument is for velocity and the second is for x Coordinate)
Main class:
Ball ball1 = new Ball(int(random(0, 2)),int(random(width)));
Ball ball2 = new Ball(int(random(0, 2)),int(random(width)));
void setup() {
// Windows configurations
size(640, 360);
background(50);
}
void draw() {
// Draw the circle
ball1.display();
// Circle movements
ball1.movements();
// Movement limits
ball1.movementLimits();
// Draw the circle
ball2.display();
// Circle movements
ball2.movements();
// Movement limits
ball2.movementLimits();
}
Ball class:
float xCoordinates;
float yCoordinates;
float xVelocity;
float yVelocity;
final float gravity = 0.1;
class Ball {
Ball(int Velocity, int Coordinates) {
xCoordinates = Coordinates;
yCoordinates = height / 6;
if (Velocity == 0)
xVelocity = 2;
else
xVelocity = -2;
if (Velocity == 0)
yVelocity = 2;
else
yVelocity = -2;
}
void movementLimits() {
if (xCoordinates - 10 <= 0 || xCoordinates + 10 >= width)
xVelocity *= -1;
if (yCoordinates + 10 >= height)
yVelocity *= -0.9;
if (yCoordinates - 10 <= 0)
yVelocity *= -1;
}
void movements() {
xCoordinates += xVelocity;
yCoordinates += yVelocity;
yVelocity += gravity;
}
void display() {
background(50);
fill(255);
stroke(255);
circle(xCoordinates, yCoordinates, 20);
}
}
Problem 1:
Both of your objects are shaing the same cooridinates and velocity. They are stored globally so when one object changes it, the change is used by the other object as well. To fix this you should give your Ball class properties to hold the coordinates and velocities.
class Ball{
float x;
float y;
float dx;
float dy
public Ball(float x, float y, float dx, float dy){
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
}
Problem 2:
In the display function in Ball, you call background(50);. This will basicly cover the entire screan with the new background; over any previous balls which includes ball1. However, if you remove this line you'll get a kind of cool effect cause by all previous ball drawing sticking around. You should move the background(50); line to the beginning of the draw function. This way, you draw the two balls, draw over them with gray, then redraw the two balls in their new positions.
Related
I am working on a 3D project, in Unity.
I have an object moving in a confined space. The object have a fixed velocity, and it bounces back once they reach the space limit.
I want it to change direction once every n seconds.
The problem I am facing is: How to rotate a 3D vector by a given angle.
In 2D is pretty easy, while in 3D I am not sure how to handle it.
Can someone help me with that?
In 2D this is simple...
In three 3 as well.
You can e.g. simply rotate a Vector3 about any given Euler angles via
var newVector = Quaternion.Euler(x, y, z) * oldVector;
question remains where you get those angles from and whether those are random or you are rather looking for Reflect the vector once the objects reach your defined area constraints.
You can as well simply invert the individual components like e.g.
// Note for simplicity reasons this is not an actual "distance"
// but rather the maximum of each individual axis
public float maxDistance;
private Rigidbody _rigidbody;
private void Start ()
{
_rigidbody = GetComponent<Rigidbody>();
_rigidbody.velocity = Random.insideUnitSphere.normalized;
}
private void FixedUpdate()
{
var vel = _rigidbody.velocity;
var pos = _rigidbody.position;
if(Mathf.Abs(pos.x) >= maxDistance)
{
vel.x *= -1;
}
if(Mathf.Abs(pos.y) >= maxDistance)
{
vel.y *= -1;
}
if(Mathf.Abs(pos.z) >= maxDistance)
{
vel.z *= -1;
}
_rigidbody.velocity = vel;
}
You can change directions by a certain angle on a certain axis, making it similar to 2D.
If you are moving the object with its transform you can easily rotate an object with the Rotate method on the game object transform.
//in a script attached to the game object you want to rotate
transform.Rotate(Vector3.up, Random.Range(90,270), Space.self);
You can now use transform.forward to move the object.
If you want to go deeper into 3D rotation have a look at Quaternions
You can use the Quaternion.operator * to rotate one rotation by another, or to rotate a vector by a rotation.
Consider also looking at the Vector3 class methods such as Reflect and RotateTowards.
Tip: To keep a consistent speed across all directions, consider normalizing the direction vector, (0,1,1) will travel faster than (0,0,1).
You can normalize any vector as follows:
Vector3 direction = Vector3.up + Vector3.forward; //(0,1,1)
direction = direction.normalized; //(0,0.71,0.71)
I managed to do the thing I wanted. Firstly, I computed a Vector3 that was orthogonal to the current transform.forward; then I rotate that angle around itself of a random angle between 0 and 360 degrees, and finally I used that generated vector as axis for the rotation to apply to the velocity of my object.
Here is the code:
public static void ChangeObjectDirection(Rigidbody rb, int angle, float velocity)
{
// get the transform of rb
var t = rb.gameObject.transform;
// get the current velocity direction
var direction = t.forward;
// generate a normalized orthogonal vector wrt the current velocity direction
var orth = OrthogonalVector(direction);
// rotate the orthogonal vector around himself of a random angle between 0 and 360
orth = Quaternion.AngleAxis(Random.Range(0, 360), direction) * orth;
// generate random rotational angle in degrees
var randomAngle = Random.Range(-angle, angle);
// rotate the current velocity direction of randomAngle around the orth vector
direction = Quaternion.AngleAxis(randomAngle, orth) * direction;
// update the velocity direction
t.forward = direction;
rb.velocity = direction * velocity;
}
private static Vector3 OrthogonalVector(Vector3 u)
{
var a = u.x;
var b = u.y;
var c = u.z;
Vector3 v;
if (b == 0 && c == 0)
{
v = new Vector3(0f, 1f, 1f);
}
else if (a == 0 && c == 0)
{
v = new Vector3(1f, 0f, 1f);
}
else if (a == 0 && b == 0)
{
v = new Vector3(1f, 1f, 0f);
}
else
{
if (c != 0)
{
// ax + bx + cz == 0 with x == 1 and y == 1 => z = (-a - b) / c
v = new Vector3(1f, 1f, (-a - b) / c);
}
else
{
// ax + bx + cz == 0 with y == 1 and z == 1 => c = (-b - c) / a
v = new Vector3((-b - c) / a, 1f, 1f);
}
}
v = v.normalized;
return v;
}
I am trying to draw on a texture but I don't know the math to convert my mouse position to the texture position.
Currently, the code will draw on the texture but the coordinates are very off.
If someone can help me with this I would appreciate it.
var mousePosition = Input.mousePosition;
var drawPosition = new Vector2(mousePosition.x, mousePosition.y);
for (int x = 0; x < brushSize; x++)
{
for (int y = 0; y < brushSize; y++)
{
m_Texture.SetPixel(x + (int)drawPosition.x, y + (int)drawPosition.y, Color.clear);
}
}
m_Texture.Apply();
Try this:
Vector2 pos;
void Update(){
RectTransformUtility.ScreenPointToLocalPointInRectangle(
parentCanvas.transform as RectTransform, Input.mousePosition,
parentCanvas.worldCamera,
out pos);
}
Assign the parentCanvas and use the pos.x and pos.y inside your for loops
I am doing a Rubik cube generator with unity. Each of the pieces are basically a 1x1 cube which will be repeated in the shape of a bigger cube in my code as children of an empty object. The empty object is in the exact middle of the pieces, and all the pieces have their origins in the exact middle. However, when I put the empty to the center of the scene (0, 0, 0) It shows up in a different place.
Here are some pictures from the editor:
As you can see, the empty is in the center with coordinates set to 0, 0, 0
Now ,when it has children and the coordinates are all still 0, it shows in a different place
Edit:
#derHugo helped me out, but now my code that creates the cubes and sets the empty object to the middle of them does not work.
Here is the full code:
public GameObject PiecePrefab;
public int CubeSize;
Vector3 avg;
Vector3 ijk;
int cubeCount = 0;
// Start is called before the first frame update
void Start()
{
//Vector3 orgpos = gameObject.transform.position;
if (CubeSize <= 0)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
avg = new Vector3(0, 0, 0);
for (float k = 0; k < CubeSize; k++)
{
for (float j = 0; j < CubeSize; j++)
{
for (float i = 0; i < CubeSize; i++)
{
if (i == CubeSize - 1 || i == 0)
{
CreatePiece(i, j, k);
}
else if (j == CubeSize - 1 || j == 0)
{
CreatePiece(i, j, k);
}
else if (k == CubeSize - 1 || k == 0)
{
CreatePiece(i, j, k);
}
}
}
}
avg /= cubeCount;
gameObject.transform.position = avg;
var _Go = GameObject.FindGameObjectsWithTag("KuutionPala");
foreach (GameObject KuutionPala in _Go)
{
KuutionPala.transform.SetParent(transform);
}
//gameObject.transform.localPosition = orgpos;
void CreatePiece(float x, float y, float z)
{
ijk = new Vector3(x, y, z);
avg += ijk;
cubeCount++;
Vector3 offset3D;
offset3D = new Vector3(x / CubeSize, y / CubeSize, z / CubeSize);
var Piece = Instantiate(PiecePrefab, offset3D, transform.rotation);
Piece.transform.localScale /= CubeSize;
//Debug.LogFormat("x:" + x);
//Debug.LogFormat("y:" + y);
//Debug.LogFormat("z:" + z);
}
}
}
I think the error is on this row:
gameObject.transform.position = avg;
(Sorry if bad code)
As said there are two pivot modes in Unity (see Positioning GameObjects → Gizmo handle position toggles)
Pivot: positions the Gizmo at the actual pivot point of the GameObject, as defined by the Transform component.
Center: positions the Gizmo at a (geometrical) center position based on the selected GameObjects.
Yours is set to Center so in order to change that click on the button that says Center.
Then to your code
You are currently just hoping/assuming that your parent is correctly placed on 0,0,0.
Then you spawn all tiles in a range from 0 to (CubeSize - 1)/2 and then want to shift the center back.
I would rather go the other way round and calculate the correct local offset beforehand and directly spawn the tiles as children of the root with the correct offset. Into positive and negative direction.
Step 1: What is that local position?
For figuring the general maths out just look at two examples.
Let's say you have 3 cubes with indices 0,1,2. They have extends of 1/3 so actually there positions would need to look like
-0.5 0 0.5
| . | . | . |
Let's say you have 4 cubes with indices 0,1,2,3 and extends 1/4 then the positions would need to look like
-0.5 0 0.5
| . | . | . | . |
So as you can see the simplest way to go would be
start with the minimum position (e.g. -0.5f * Vector3.one)
always add half of the extends for the first offset (e.g. 1/CubeSize * 0.5f * Vector3.one)
add an offsets of the extends multiplied by the indices on top (e.g. 1/CubeSize * new Vector3(x,y,z))
so together something like
// be sure to cast to float here otherwise you get rounded ints
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
Step 2: Directly spawn as children with correct offset
void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
// This basically equals doing something like
//var Piece = Instantiate(PiecePrefab, transform.position, transform.rotation, transform);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}
Then you can reduce your code to
// Use a range so you directly clamp the value in the Inspector
[Range(1,30)]
public int CubeSize = 3;
// Start is called before the first frame update
void Start()
{
UpdateTiles();
}
// Using this you can already test the method without entering playmode
// via the context menu of the component
[ContextMenu(nameof(UpdateTiles)])
public void UpdateTiles()
{
// Destroy current children before spawning the new ones
foreach(var child in GetComponentsInChildren<Transform>().Where(child => child != transform)
{
if(!child) continue;
if(Application.isPlaying)
{
Destroy(child.gameObject);
}
else
{
DestroyImmediate(child.gameObject);
}
}
if (CubeSize < 1)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
// For making things easier to read I would use x,y,z here as well ;)
for (float x = 0; x < CubeSize; x++)
{
for (float y = 0; y < CubeSize; y++)
{
for (float z = 0; z < CubeSize; z++)
{
if (x == CubeSize - 1 || x == 0)
{
CreatePiece(x, y, z);
}
else if (y == CubeSize - 1 || y == 0)
{
CreatePiece(x, y, z);
}
else if (z == CubeSize - 1 || z == 0)
{
CreatePiece(x, y, z);
}
}
}
}
}
private void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}
so I'm trying to make a program that allows asteroids in a field to be attracted to each other like this:
https://www.youtube.com/watch?v=iAWZwTWJmhM
I have two programs to do this, one randomly generates asteroids, the other applies gravitational force to each object. the problem is that the asteroids will get faster as they get closer until they are bullet speed and the applied forces causes them to shoot away from each other and disappear. Is there a way to make them negate their forces on contact. I tried Rigidbody.isKinematic but that makes the asteroids still instead of rotating like they would in space. ill post the code below but here are the two projects I'm using the code from.
https://www.youtube.com/watch?v=Ouu3D_VHx9o
https://www.youtube.com/watch?v=6rTfZ2ox2_g
Code for asteroid spawner. I added in the random scale generator.:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AsteroidFieldGenerator : MonoBehaviour
{
public Transform AsteroidPrefab;
public int fieldRadius = 50;
public int asteroidCount = 60;
public float SizeMinPercent = 1;
public float SizeMaxPercent = 100;
// Start is called before the first frame update
void Start()
{
for (int loop = 0; loop < asteroidCount; loop++)
{
Instantiate(AsteroidPrefab, Random.insideUnitSphere * fieldRadius, Quaternion.identity);
AsteroidPrefab.transform.localScale = Vector3.one * (Random.Range(SizeMinPercent, SizeMaxPercent) / 100);
}
}
// Update is called once per frame
void Update()
{
}
}
Program for applying gravity:
'''
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Attractor : MonoBehaviour
{
const float G = 667.4f;
public static List<Attractor> Attractors;
public Rigidbody rb;
void FixedUpdate()
{
foreach (Attractor attractor in Attractors)
{
if (attractor != this)
Attract(attractor);
}
}
void OnEnable()
{
if (Attractors == null)
Attractors = new List<Attractor>();
Attractors.Add(this);
}
void OnDisable()
{
Attractors.Remove(this);
}
void Attract(Attractor objToAttract)
{
Rigidbody rbToAttract = objToAttract.rb;
Vector3 direction = rb.position - rbToAttract.position;
float distance = direction.magnitude;
if (distance == 0f)
return;
float forceMagnitude = G * (rb.mass * rbToAttract.mass) / Mathf.Pow(distance, 2);
Vector3 force = direction.normalized * forceMagnitude;
if (distance == 0)
force = force * 0;
rbToAttract.AddForce(force);
}
}
'''
You have to apply damping (resistance) forces, similar to say atmospheri resistance (air drag). Then the total energy of the system will decrease, which make it more likely that the particles cluster together. So basically, the equations of motion should be something like
F_grv[i,j,:] = G*mj*mi * (x[j,:] - x[i,:]) / norm(x[i,:] - x[j,:])^3
F_res[i,j,:] = - R( norm(x[i,:] - x[j,:]) ) * norm(v[i,:])^a * v[i,:]
R(u) = non-negative function that rapidly decreases when u goes away from 0,
and increasing rapidly when u gets very close to 0.
a is some positive number, say 1 or 2 or more.
dx[i,:]/dt = v[i,:]
dv[i,:]/dt = (1/mi) * sum(F_grv[i,j,:] + F_res[i,j] for j=1:n)
Here is a matlab code for the case of one particle orbiting a center of gravity with the standard Newtonian gravitational force acting on it plus a velocity dependent damping force:
function gravity_damping()
t = 0;
x0 = [5;1];
x_start = [-1; 10];
v_start = [0.15; 0.];
x = x_start;
v = v_start;
h = 0.3;
n = 700;
k0 = 7;
lambda = 2;
power1 = 10;
power2 = 2;
hold on
grid on
axis([-7 8 -3 12])
plot(x0(1), x0(2), 'ro');
for k = 1:n
t = t+h;
x = x + h*v/2;
v = v + h*F_grv(x-x0, 1, 1) + h*F_res(x-x0, v, k0, lambda, power1, power2);
x = x + h*v/2;
plot(x(1), x(2), 'bo');
pause(0.1)
end
end
function dvdt = F_grv(x_x0, mass, gr_const)
dvdt = - gr_const * mass * (x_x0) / norm(x_x0)^3;
end
function dvdt = F_res(x_x0, v, k0, a, power1, power2)
dvdt = - (k_res(norm(x_x0), k0, a, power1) * norm(v)^power2) * v;
end
function coeff = k_res(u, k0, a, power)
coeff = k0/(1 + (a*u)^(power));
end
I am working on adding a helicopter to my 2d game and I need it to move in circular motion whilst moving on the x axis as well. Below you can find the code that I am using which uses the mathematical circle equation.
angle += speed * Time.deltaTime; //if you want to switch direction, use -= instead of +=
float x = startPoint.x + Mathf.Cos(angle) * radius;
float y = startPoint.y + Mathf.Sin(angle) * radius;
transform.position = new Vector2(x + 2, y);
The helicopter is rotating correctly but I can't figure out how I can make it move along the x axis. Concept image of how it should work below:
1) Make an empty game object
2) Parent your box to the empty game object
3) rotate the box around the empty game object
4) move the empty game object to the side
If you want to avoid adding an empty parent, you can keep track of the center of rotation separately, rotate around it, and move it over time.
public class hello_rotate : MonoBehaviour
{
float angle = 0;
float radius = 1;
float speed = 10;
float linear_speed = 1;
Vector2 centerOfRotation;
// Start is called before the first frame update
void Start()
{
centerOfRotation = transform.position;
}
// Update is called once per frame
void Update()
{
centerOfRotation.x = centerOfRotation.x + linear_speed * Time.deltaTime;
angle += speed * Time.deltaTime; //if you want to switch direction, use -= instead of +=
float x = centerOfRotation.x + Mathf.Cos(angle) * radius;
float y = centerOfRotation.y + Mathf.Sin(angle) * radius;
transform.position = new Vector2(x + 2, y);
}
}