Calculate object position direction after collision - android

I am writing my own game engine (a very base one), I want to learn how physics work in game development and not using an already built game engine. I am writing my code in Java for Android devices (using SurfaceView).
The problem is that I don't know how to calculate the position for my object after a collision. I have created my own collision detection and it is working perfectly.
As you can see, the red rectangle is the area where my ball should move. The arrows is showing where the ball should move after a collision happens. The ball have different position, marked with 1 - 11 (note, while rendering the "world" you see only one ball!).
The balls are actually rectangles! But you can not see the edges.
I have created my own Game Object class, where I'm keeping data about the object position, velocity, origin, etc.:
public abstract class GameObject
{
public Vector2 dimension;
public Vector2 position;
public Vector2 velocity;
public Vector2 origin;
public Rectangle rectangle;
public GameObject(Resources resources)
{
this.dimension = new Vector2();
this.position = new Vector2();
this.velocity = new Vector2();
this.origin = new Vector2();
this.rectangle = new Rectangle();
}
public void update(float deltaTime)
{
position.x += velocity.x;
position.y += velocity.y;
rectangle.set(position.x, position.y, dimension.x, dimension.y);
origin.x = position.x + dimension.x / 2;
origin.y = position.y + dimension.y / 2;
}
}
This method is called if a ball collide with one of the red rectangle margins:
protected void onBallCollideWithLevelEdge(Ball ball)
{
// Calculate next position:
??????????
}
My ball have a velocity and a position. Should I save the previous position of the ball?

1) Why do you represents balls as rectangles? Circle is far more easy to handle, expecially if you want to extend collision to ball-ball.
2) If you are trying to make a physics engine you must have coordinates of all objects and the respective first and second derivatives, aka speed and acceleration. Moreover you need a mass for each object and maybe some other parameters, for example material (for friction) and elasticity, but this is not needed at the beginning.
3) When a collision with walls happens you have current ball position and velocity. Given this data you have to calculate normal force. Normal force is such that ball cannot pass through the wall, so I'd calculate it's magnitude using something like this:
Nx = DELTAx*k;
Ny = DELTAy*k;
where k is some elasticity constant that you can trim and x is the measure of how much the ball has penetrated in the wall. Note that this is good only for "slow" objects. If you deal with bullets you'd better using something like rays or.
Another way could be to calculate kinetic energy at the time of collision and transfer it to elastic energy. Once you have elastic energy you can release it in a direction normal to the wall, transforming it to a force.
Once you have the force, it becomes an acceleration by dividing it for the mass.
4) at each simulation iteration you add speed to position, and acceleration to speed, remembering of multiplying it for the integration time (dt). This time can be set arbitrarly and it's a constant. If you want a 100Hz simulation you set dt to 10ms. You also have to recalculate acceleration as the sum of forces divided by the mass.
5) As you note I never talked about direction because you don't need it if you are reasoning decomposing coordinates in each axis (x,y in a 2D engine). If the normal force is "right", as in your example, the Ny component will be set to zero, while Nx will be tranformed into acceleration and will change the horizontal speed. This also will change the ball's direction.
These are only advices, actually you should start by studying kinematics and later something of rational mechanics.

I had an function that looked something like this:
Position calculateValidPosition(Position start, Position end)
Position middlePoint = (start + end) /2
if (middlePoint == start || middlePoint == end)
return start
if( isColliding(middlePont) )
return calculateValidPosition(start, middlePoint)
else
return calculate(middlePoint, end)
I just made this code on the fly, so there would be a lot of room for improvements... starting by not making it recursive.
This function would be called when a collision is detected, passing as a parameter the last valid position of the object, and the current invalid position. On each iteration, the first parameter is always valid (no collition), and the second one is invalid (there is collition).
But I think this can give you an idea of a possible solution, so you can adapt it to your needs.

Related

Drawing line of sight between two actors

I am fresh learner of LibGDX. I am trying to learn LibGDX by developing a demo game. In the game when an army and enemy are visible to each other I want to draw a line of sight between them to prove that they see each other. The line of sight should increase gradually, say something like when we transfer file in windows 7 the green portion increases gradually. I am working with scene2D and have implemented Screen interface of scene2D.
You may want to look into a physics library. Either use it explicitly in your app (like Box2d or libgdx's BulletPhysics). Both of these have a concept of raycasting and some form of ray cast callback. This allows you to pick a "starting point" for your "line of sight" and see what the raycast hits/collides with.
If you don't want to use the physics library in your app, you could at least look at the source code for both, and roll your own, slimmed down functionality to achieve your line of sight goals.
So you are looking for something visually for the player and for calculations? I have no clue what you mean by the windows 7 file transfer thing.
It all depends on how accurate you want to have things but you need some kind of ray casting like Peter R is saying. You have libraries for this but depending on what you want this can be easy to implement yourself.
You take the Vector of a unit or army and the Vector of the enemy. Then check for obstructions between those Vectors. You should have a floatfor the distance each step of the line, the higher this is the more efficient but also less accurate since it could step over a small object.
Some crude untested pseudo code for 2D:
RayCast(Vector v1, Vector v2)
{
Vector2 p = v1;
Vector2 direction = (v2 - v1).normalize;
float distance = 0.5f;
float totalDistance = 200;
while (Distance(p & v2) > distance && Distance(p & v1) < totalDistance)
{
p += direction * distance;
if (some obstruction is at p)
{
//no line of sight
}
}
}
I have developed the game using AndEngine and i have used AndEngine box2D physics and i update the position between two players continuously as follows:
I have two players one player and other enemy. I have drawn the line and the end position of the line is given by player and enemy positions. I have done by getting their coordinates
//line of sight
final Line e1line = new Line(player.getX(), player.getY(), enemy.getX(), enemy.getY())
And finally i have used update handler to continusely move the line as the player moves as follows:
IUpdateHandler updatehand = new IUpdateHandler(){
#Override
public void onUpdate(float pSecondsElapsed) {
// line of sight and notifier update
e1line.setPosition(player.getX(), player.getY(), enemy1.getX(), enemy1.getY());
}
#Override
public void reset() {}
};

Panning the view of a gameObject instead of the camera in Unity3d?

I'm having a hard time to pan a view of a gameObject in Unity3d. I'm new to scripting and I'm trying to develop an AR (Augmented Reality) application for Android.
I need to have a gameObject (e.g. a model of a floor), from the normal top down view, rendered to a "pseudo" iso view, inclined to 45 degrees. As the gameObject is inclined, I need to have a panning function on its view, utilizing four (4) buttons (for left, right, forward(or up), backward(or down)).
The problem is that, I cannot use any of the known panning script snippets around the forum, as the AR camera has to be static in the scene.
Need to mention that, I need the panning function to be active only at the isometric view, (which I already compute with another script), not on top down view. So there must be no problem with the inclination of the axes of the gameObject, right?
Following, are two mockup images of the states, the gameObject (model floor) is rendered and the script code (from Unity reference), that I'm currently using, which is not very much functional for my needs.
Here is the code snippet, for left movement of the gameObject. I use the same with a change in -, +speed values, for the other movements, but I get it only move up, down, not forth, backwards:
#pragma strict
// The target gameObject.
var target: Transform;
// Speed in units per sec.
var speedLeft: float = -10;
private static var isPanLeft = false;
function FixedUpdate()
{
if(isPanLeft == true)
{
// The step size is equal to speed times frame time.
var step = speedLeft * Time.deltaTime;
// Move model position a step closer to the target.
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
}
static function doPanLeft()
{
isPanLeft = !isPanLeft;
}
It would be great, if someone be kind enough to take a look at this post, and make a suggestion on how this functionality can be coded the easiest way, as I'm a newbie?
Furthermore, if a sample code or a tutorial can be provided, it will be appreciated, as I can learn from this, a lot. Thank you all in advance for your time and answers.
If i understand correctly you have a camera with some fixed rotation and position and you have a object you want to move up/down/left/right from the cameras perspective
To rotated an object to a set of angles you simply do
transform.rotation = Quaternion.Euler(45, 45, 45);
Then to move it you use the cameras up/right/forward in worldspace like this to move it up and left
transform.position += camera.transform.up;
transform.position -= camera.transform.right;
If you only have one camera in your scene you can access its transform by Camera.main.transform
An example of how to move it when someone presses the left arrow
if(Input.GetKeyDown(KeyCode.LeftArrow))
{
transform.position -= camera.transform.right;
}

Moving object to touch position acting unexpectedly

Good evening, quick question.
Im developing a top-down 2D platformer game in Unity3D. Here is a picture of the game.
I have pretty much everything worked out on a desktop, but when attempting to set up the controls for mobile, I can't seem to get it to work the way it should. All I need is to get the player to move in the direction of wherever the user touches the screen. With the current code im using, the player just rotates in 4 directions, up, down, left and right. He also moves a little, but never goes far from his spawn point.
Please take a look at my revised code:
public Camera camera;
public float movespeed = 0;
// Use this for initialization
void Start () {
movespeed = 2.75F;
}
// Update is called once per frame
void Update () {
if (Input.touchCount > 0) {
// The screen has been touched so store the touch
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved) {
// If the finger is on the screen, move the object smoothly to the touch position
Vector3 touchPosition = camera.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, -13));
Quaternion rot = Quaternion.LookRotation(transform.position - touchPosition, Vector3.back);
transform.rotation = rot;
transform.eulerAngles = new Vector3 (0, 0, transform.eulerAngles.z);
rigidbody2D.angularVelocity = 0;
//float input = Input.GetAxis ("Vertical");
transform.position = Vector3.Lerp(transform.position, touchPosition, Time.deltaTime);
}
}
}
}
Any ideas on how I can get my player to move to the touched are of the screen? Any help would be much appreciated. Thanks in advance.
If I have understood correctly, you want your player game object to move towards the point on the screen that is being touched. I think it's probably best to describe the behavior of your code so that you can hopefully better understand what might be happening.
From the code posted, I can see one possible issue. Look again at this line:
Quaternion rot = Quaternion.LookRotation(transform.position - touchPosition, Vector3.back);
Here, you are asking Unity to calculate the unit quaternion that represents a rotation from the direction of Vector3.forward to the direction from of the player game object from the touch position. This probably isn't what you want. From the description of the problem, you want the game object to rotate to face the point on the screen being touched (rather than the opposite direction). You can either change the order of the subtraction operands or, preferably, use instead the Transform.LookAt method.
After this, you update the transform's rotation:
transform.rotation = rot;
That's fine, but note that you wouldn't need to do this when using Transform.LookAt.
You then set the transform's rotation again using in this line:
transform.eulerAngles = new Vector3 (0, 0, transform.eulerAngles.z);
I'm not entirely sure why you are doing this. If you only want one axis of rotation, you can use, for example:
transform.LookAt(new Vector3(touchPosition.x, touchPosition.y, transform.position.z))
This should rotate the player's transform around the z-axis to look in the direction of the point being touched.
Finally, you linearly interpolate the transform's position from its current position to the point being touched:
transform.position = Vector3.Lerp(transform.position, touchPosition, Time.deltaTime);
This isn't necessary. Instead, you should just move the player's transform forward. The player should be looking in the direction of the touched screen point. Hence, translating the player forward will move the player towards said screen point:
transform.position += transform.forward * speed * Time.deltaTime;
When the player is very close to the touched screen point it will overshoot and immediately rotate to look in the opposite direction. This will occur repeatedly. You should include some distance that specifies when the player is assumed to have reached the target point.

Unity2D Android Touch misbehaving

I am attempting to translate an object depending on the touch position of the user.
The problem with it is, when I test it out, the object disappears as soon as I drag my finger on my phone screen. I am not entirely sure what's going on with it?
If somebody can guide me that would be great :)
Thanks
This is the Code:
#pragma strict
function Update () {
for (var touch : Touch in Input.touches)
{
if (touch.phase == TouchPhase.Moved) {
transform.Translate(0, touch.position.y, 0);
}
}
}
The problem is that you're moving the object by touch.position.y. This isn't a point inworld, it's a point on the touch screen. What you'll want to do is probably Camera.main.ScreenToWorldPoint(touch.position).y which will give you the position inworld for wherever you've touched.
Of course, Translate takes a vector indicating distance, not final destination, so simply sticking the above in it still won't work as you're intending.
Instead maybe try this:
Vector3 EndPos = Camera.main.ScreenToWorldPoint(touch.position);
float speed = 1f;
transform.position = Vector3.Lerp(transform.position, EndPos, speed * Time.deltaTime);
which should move the object towards your finger while at the same time keeping its movements smooth looking.
You'll want to ask this question at Unity's dedicated Questions/Answers site: http://answers.unity3d.com/index.html
There are very few people that come to stackoverflow for Unity specific question, unless they relate to Android/iOS specific features.
As for the cause of your problem, touch.position.y is define in screen space (pixels) where as transform.Translate is expecting world units (meters). You can convert between the two using the Camera.ScreenToWorldPoint() method, then creating a vector out of the camera position and screen world point. With this vector you can then either intersect some geometry in the scene or simply use it as a point in front of the camera.
http://docs.unity3d.com/Documentation/ScriptReference/Camera.ScreenToWorldPoint.html

Calibrating 3d Accelerometer for 2d Game

I am making a 2d game. The phone is held horizontally and a character moves up/down & left/right to avoid obstacles. The character is controlled by the accelerometer on the phone. Everything works fine if the player doesn't mind (0,0) (the point where the character stands still) being when the phone is held perfectly flat. In this scenario it's possible to just read the Y and X values directly and use them to control the character. The accelerometer values are between -10 and 10 (they get multiplied by an acceleration constant to decide the movement speed of the character), libgdx is the framework used.
The problem is that having (0,0) isn't very comfortable, so the idea is to calibrate it so that 0,0 will be set to the phones position at a specific point in time.
Which brings me to my question, how would I do this? I tried just reading the current X and Y values then subtracting it. The problem with that is that when the phone is held at a 90 degree angle then the X offset value is 10 (which is the max value) so it ends up becoming impossible to move because the value will never go over 10 (10-10 = 0). The Z axis has to come into play here somehow, I'm just not sure how.
Thanks for the help, I tried explaining as best as I can, I did try searching for the solution, but I don't even know what the proper term is for what I'm looking for.
An old question, but I am providing the answer here as I couldn't find a good answer for Android or LibGDX anywhere. The code below is based on a solution someone posted for iOS (sorry, I have lost the reference).
You can do this in three parts:
Capture a vector representing the neutral direction:
Vector3 tiltCalibration = new Vector3(
Gdx.input.getAccelerometerX(),
Gdx.input.getAccelerometerY(),
Gdx.input.getAccelerometerZ() );
Transform this vector into a rotation matrix:
public void initTiltControls( Vector3 tiltCalibration ) {
Vector3.tmp.set( 0, 0, 1 );
Vector3.tmp2.set( tiltCalibration ).nor();
Quaternion rotateQuaternion = new Quaternion().setFromCross( Vector3.tmp, Vector3.tmp2 );
Matrix4 m = new Matrix4( Vector3.Zero, rotateQuaternion, new Vector3( 1f, 1f, 1f ) );
this.calibrationMatrix = m.inv();
}
Whenever you need inputs from the accelerometer, first run them through the rotation matrix:
public void handleAccelerometerInputs( float x, float y, float z ) {
Vector3.tmp.set( x, y, z );
Vector3.tmp.mul( this.calibrationMatrix );
x = Vector3.tmp.x;
y = Vector3.tmp.y;
z = Vector3.tmp.z;
[use x, y and z here]
...
}
For a simple solution you can look at the methods:
Gdx.input.getAzimuth(), Gdx.input.getPitch(), Gdx.input.getRoll()
The downside is that those somehow use the internal compass to give your devices rotation compared to North/South/East/West. I did only test that very shortly so I'm not 100% sure about it though. Might be worth a look.
The more complex method involves some trigonometry, basically you have to calculate the angle the phone is held at from Gdx.input.getAccelerometerX/Y/Z(). Must be something like (for rotation along the longer side of the phone):
Math.atan(Gdx.input.getAccelerometerX() / Gdx.input.getAccelerometerZ());
For both approaches you then store the initial angle and subtract it later on again. You have to watch out for the ranges though, I think Math.atan(...) is within -Pi and Pi.
Hopefully that'll get you started somehow. You might search for "Accelerometer to pitch/roll/rotation" and similar, too.

Categories

Resources