How to stop camera from moving further than the map? - c#

So i have a 2D world in Unity which has a sprite (Some hills). That is the map. I also have a camera that moves left - right when the mouse reaches the borders of the game's window using the following script (I hope it's not too messy, i'm lazy today :/ , i will add some comments to help).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCam : MonoBehaviour
{
public Camera Camera; //idk why i did this the component is parented to maincam
public float Divider; //This is to reduce the move amount to reasonable numbers.
void Start()
{
}
void FixedUpdate()
{
Vector3 mousePos = Input.mousePosition; //The simple stuff. Getting the mouse position
Debug.Log(mousePos.x); //Some debug stuff
Debug.Log(mousePos.y);
Debug.Log(Screen.width / 14);
Debug.Log(Screen.width - (Screen.width / 14));
if (mousePos.x < Screen.width / 14) //The if statement to trigger the movement only when the mouse is in the calculated border radius. I use the example 49 < 700 / 14 = 49 < 50
{
Camera.transform.Translate((mousePos.x - Screen.width / 14) / Divider, 0, 0); //Move the camera to the left by the calculated strength which is the distance between the mouse and the border radius end reduced to reasonable amounts by the Divider variable. It is set to 50 in the engine currently. The example is (49 - 700 / 14) / 50 = (49 - 50) / 50 = -1 / 50 = -0.02
Debug.Log((mousePos.x - Screen.width / 14) / Divider); //Debug stuff
} else if (mousePos.x > Screen.width - (Screen.width / 14)) //If not, we'll check if the mouse is in the right. We calculate the right border radius by subtracting the full width of the game window by the calculated radius. 651 > 700 - (700 / 14) = 651 > 700 - 50 = 651 > 650
{
Camera.transform.Translate((mousePos.x - (Screen.width - (Screen.width / 14))) / Divider, 0, 0); //The same, but we replace the left with right using the algorithm that's explained above.
Debug.Log((mousePos.x - (Screen.width - (Screen.width / 14))) / Divider); //DEBUGGGG
}
}
}
So that's the code. Now i want to add the logic for stopping the camera from extending further than the map. The problem is that i want the game to be responsive, so the set limitations are not an option. I had an idea that could possibly work exactly how i wanted, but it didn't work for some reason. When searching on the internet i found a solution, but it was confusing and unexplained, so i decided to make this post, I will be really thankful if you help!
This is an image of the scene if needed.

I solved it by using Camera.ViewportToWorldPoint() and spriteRenderer.bounds.

Related

How to control an object with a finger in Unity3D?

I'm new to programming. I am writing a simple game (I think many people know it under the name "Ping Pong") for smartphones. A game for two people. I need the screen to be divided into two areas. Everyone within their area should be able to control the object with their finger along the x axis. Accordingly, the object changes its position only along the x axis.
here's my game :)
I was able to write this script myself:
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition) * new Vector2(1, 0);
Vector2 mousePosition2 = mousePosition + new Vector2(1, -4.74f);
transformPosition1.transform.position = mousePosition2;
This script changes the position of the object relative to the x-axis of the mouse. But I do not know how to limit its area and divide it into two players. Thank you in advance for your help. I apologize for my English. Please do not use complex language constructions in the response.
One way would be putting one image to top half of the screen and other to bottom half and assign EventSystem to handle dragging.
Other way is to calculate the mouse position to see if it is within the top half or bottom half.
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
float y = mousePosition .y;
if (y > Screen.height / 2 && y < Screen.height)// top half {
// move the top side player
}
if (y > 0 && y < Screen.height / 2)// bottom half {
// move the bottom side player
}

Smooth velocity scroll

I'm trying to implement a smooth slow down scroll based on the velocity of the user gesture.
I'm using MR.Gestures to handle the pan gesture and obtain the velocity, then I'm running an animation loop to perform the deceleration but it's very jerky and I'm not sure what I can do to make it smooth.
_velocityX = (velocityX / (1000 / SCROLL_INTERVAL));
_velocityY = (velocityY / (1000 / SCROLL_INTERVAL));
I have SCROLL_INTERVAL set to 16 to scroll at roughly 60fps. My _friction variable is currently 0.98f.
In my animation loop I have the following:
var distance = new Point
{
X = 0,
Y = 0
};
if (Math.Abs(_velocityX) > 0)
{
distance.X += _velocityX;
_velocityX *= _friction;
}
if (Math.Abs(_velocityY) > 0)
{
distance.Y += _velocityY;
_velocityY *= _friction;
}
<snip>code here moves the camera by the values in distance.X and distance.Y</snip>
Now, this works but is very jerky and the issue appears to be that it may be moving by 10+ pixels at the start of the animation.
I believe based on this that my approach is incorrect but I can't find anything to help me change the approach.
Is there a better way to do this? Or a way to make this more smooth?

Monogame - how to automatically move rectangle up and down and repeat?

So I'm working on my menu's background and I Draw() a texture there with a rectangle. How would I have the rectangle wait, move up and then down, wait and repeat? I tried the following:
// Update()
if (Rectangle.Y = -16) // My texture is positioned to -16 initially
Rectangle.Y++;
else if (Rectangle.Y = 0)
Rectangle.Y--;
So my game resolution is 1366x768. To have the background texture move up and down I had to make it have a height > 768. I made it 1366x800. Every time the above code is called it should wait 1-2seconds (not yet implemented), move 16 pixels down, wait again and go back 16 pixels up... But that code doesn't work... Could you guide me as to how this is done?
You can do it with Math.Sin, which will give you a smooth transition from -1 to 1. You will have to keep a copy of your rectangle's center Y position.
double time = gameTime.TotalGameTime.TotalSeconds;
Rectangle.Y = centerY + (int)(Math.Sin(time * transitionSpeed) * maxOffset);
You can play with double transitionSpeed to get the best visual effect. int maxOffset is the max amount of offset from centerY.
If you don't want smooth movements, then just do
int speed = 1; // speed of movement
Then in update
if (Rectangle.Y <= -16 || Rectangle.Y >= 0)
speed *= -1; // reverse move direction
Rectangle.Y += speed;

Get an object to wobble in Unity3D with C#

I am trying to simulate a boat in Unity3D. What I need it to be able to do is wobble like a real boat would while in water whenever it hits something. I have the boat colliding already, and all of its axes are unlocked. However, this means the boat will rotate, and then keep driving at an odd angle (like facing to the sky).
Is there a way to make the boat try to return to its original rotaions, without snapping to the exact values, but simply "rocking" back and forth, and then slowing down to eventually stop at the correct rotations again?
Here is the code am attempting to use:
void FixedUpdate ()
{
wobble();
}
void wobble()
{
if (this.transform.eulerAngles.x < 270)
{
this.rigidbody.AddTorque((float)19, (float)0, (float)0, ForceMode.Force);
}
else if (this.transform.eulerAngles.x > 270)
{
this.rigidbody.AddTorque((float)-19, (float)0, (float)0, ForceMode.Force);
}
else{}
if (this.transform.eulerAngles.z < 0)
{
this.rigidbody.AddTorque((float)19, (float)0, (float)0, ForceMode.Force);
}
else if (this.transform.eulerAngles.z > 0)
{
this.rigidbody.AddTorque((float)-19, (float)0, (float)0, ForceMode.Force);
}
else{}
}
However, now when my object hits something, it just starts spinning out of control. Any ideas?
You can use tweening. A wonderful technique to change values smoothly be-tween two values. In this case you can tween from your awkward bouncing angles to your boats sitting rotation by tweening between the two. There are good plugins to use like iTween which is fantastic but I will show you some half pseudo - half super-cereal code to get you started on the concept for "rotation correction"
Lets say I have my boat hit a nice big wave and its pointing my boat upwards to a 20deg angle.
My euler angle on X is 20 and I can return this to 0 by increasing the decreasing the value at a constant rate. I'm just showing X here but you can repeat the process for Z-axis. I would exclude Y as you will use your direction of your boat on Y and you don't want to screw up your boats navigation.
Update()
float angleDelta;
// check if value not 0 and tease the rotation towards it using angleDelta
if(transform.rotation.X > 0 ){
angleDelta = -0.2f;
} elseif (transform.rotation.X < 0){
angleDelta = 0.2f;
}
transform.rotation.X += angleDelta;
}
This incredibly simple implementation does the job but has the wonderful perk of being incredibly "snappy" and "jittery". So we want to add some smoothing to make it a more lifelike boat.
We do this by adding in a variable to the angleDelta:
Vector3 previousAngle;
float accelerationBuffer = 0.3f;
float decelerationBuffer = 0.1f;
Update()
Vector3 angleDelta;
//assuming that x=0 is our resting rotation
if(previousAngle.X > transform.rotation.X && transform.rotation.X > 0){
//speed up rotation correction - like gravity acting on boat
angleDelta.X += (previousAngle.X - transform.rotation.X) * accelerationBuffer;
} elseif(previousAngle.X < transform.rotation.X && transform.rotation.X > 0
//angle returning to resting place: slow down the rotation due to water resistatnce
angleDelta.X -= (previousAngle.X - transform.rotation.X) * deccelerationBuffer;
}
//If boat pointing to sky - reduce X
if(transform.rotation.X > 0 ){
transform.rotation.X -= angleDelta.X * Time.deltaTime;
//If boat diving into ocean - increase X
} elseif (transform.rotation.X < 0){
transform.rotation.X += angleDelta.X * Time.deltaTime; //Must not forget to use deltaTime!
}
//record rotation for next update
previousAngle = transform.rotation;
}
This is an incredibly rough draft but it gets across the theory that I'm trying to explain - you will need to adjust your own code accordingly as you haven't included any of your own (pastebin a snippet to us and maybe we can elaborate more!)

Box2d: Maximum possible linear velocity?

I think I've configured Box2d to have some sort of maximum velocity for any body, but I'm not sure. I apply an impulse like (100000000, 100000000), and the body moves just as fast as (100, 100) - which is not that fast at all.
I'm using the Box2d XNA C# port.
My game is a top-down 2d.
Here is some code that may be relevant:
private readonly Vector2 GRAVITY = new Vector2(0, 0);
public void initializePhysics(ContactReporter contactReporter)
{
world = new World(GRAVITY, true);
IContactListener contactListener = contactReporter;
world.ContactListener = contactListener;
}
public void Update(GameTime gameTime)
{
// ...
worldState.PhysicsWorld.Step((float)gameTime.ElapsedGameTime.TotalSeconds, 10, 10);
//...
}
Here is some example code that applies the impulse:
private void ApplyImpulseFromInput()
{
Vector2 movementImpulse = new Vector2();
if (inputReader.ControlActivation(ActionInputType.MOVE_LEFT) == 1f)
{
movementImpulse.X = -Constants.PLAYER_IMPULSE_CONSTANT;
} else if (inputReader.ControlActivation(ActionInputType.MOVE_RIGHT) == 1f)
{
movementImpulse.X = Constants.PLAYER_IMPULSE_CONSTANT; ;
}
if (inputReader.ControlActivation(ActionInputType.MOVE_UP) == 1f)
{
movementImpulse.Y = -Constants.PLAYER_IMPULSE_CONSTANT; ;
} else if (inputReader.ControlActivation(ActionInputType.MOVE_DOWN) == 1f)
{
movementImpulse.Y = Constants.PLAYER_IMPULSE_CONSTANT; ;
}
model.Body.ApplyImpulse(movementImpulse, model.Position);
}
If Constants.PLAYER_IMPULSE_CONSTANT is anywhere from 1000f to 1000000000f, the player can move at most (-120, -120) to (120, 120). If the constant is less, like 1f, the player will move more slowly.
This code is used to set up physics for everything in the game world:
controller.Model.BodyDef = new BodyDef();
controller.Model.BodyDef.type = controller.Model.Mobile ? BodyType.Dynamic : BodyType.Static;
controller.Model.Body = worldState.PhysicsWorld.CreateBody(controller.Model.BodyDef);
controller.Model.Body.SetLinearDamping(10.0f);
Could it possibly be the linear damping? I changed it from 10.0f to 0, with no effect.
UPDATE: Weirdness with linear damping: I have made these observations on the body that is moved with the apply impulse method above:
Linear Damping Max Speed
0f 120
10f 120
50f 120
55f 90
60f 0
70f 0
100f 0
100000f 0
Why is there a range of sensitivity in linear damping between 50f and 60f?
That's not the way to fix that problem. You are supposed to scale down your objects when creating them in the box2D world. Then you can just scale the information that box2D gives you back to the size of your world.
Let's say for example that a box in my world is 120 pixels long. If I scaled the object down by 30 times so that it can be simulated by box2d properly then the length of my box in the box2D world would be 4 "pixels" long (120 / 30 or size of your object / scale). Now, let's say that box2D calculates that my box moved 3 "pixels" in the box2d world. I could then grab that information and scale it back up to my world's size which would mean that the box just moved 90 pixels (3 * 30). I hope that didn't sound too confusing. I usually find it hard to explain myself.
I have the same problem with version 2.1a
i found out that changing line 128 in b2Settings.as can help.
Change static public const b2_maxTranslation:Number = 2.0 to a higher number.
sure that this isn't the right way, but right now dont really know how to do it correctly.

Categories

Resources