Moving object 2d with viewmatrix - c#

I'm working on a small game based on the movements of the military in ww2. I first started to make a camera to look around and then I wrote a programm to slowly move a platoon towarts where i clicked and then stop if it was there. UNtil there everything works totally fine, but then I tried to get it to work while having moved the camera so the matrix wasn't the standard matrix. I haven't got the mooving of the platoon to the right location to work.
I'd greatly appreciate it if someone could tell me what I have to do to get it working
moving Code:
public void Update(MouseState mouse, GameTime gameTime,Matrix matrix)
{
if (mouse.LeftButton == ButtonState.Pressed)
{
mousePos = new Vector2(mouse.X, mouse.Y);
Vector2.Transform(mousePos, matrix);
oldPos = testObjPos;
Vector2.Transform(oldPos, matrix);
Difference = mousePos - oldPos;
Difference.Normalize();
}
testObjPos += Difference * (float)gameTime.ElapsedGameTime.TotalSeconds * 20;
if (testObjPos.X > mousePos.X - 1 && testObjPos.X < mousePos.X + 1 &&
testObjPos.Y > mousePos.Y - 1 && testObjPos.Y < mousePos.Y + 1)
Difference = new Vector2(0, 0);
}
and maybe my camera class is the problem
Camera COde
float moveSpeed = 300;
Vector2 position;
Matrix viewMatrix;
int screenwidth, screenheight;
public void Update(KeyboardState keyState, GameTime gameTime)
{
if (keyState.IsKeyDown(Keys.W))
position.Y -= moveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.S))
position.Y += moveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.A))
position.X -= moveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (keyState.IsKeyDown(Keys.D))
position.X += moveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
if (position.X < -1000)
position.X = -1000;
if (position.Y < -1000)
position.Y = -1000;
if (position.X > 1000)
position.X = 1000;
if (position.Y > 1000)
position.Y = 1000;
viewMatrix = Matrix.CreateTranslation(new Vector3(-position, 0));
}
Thanks for taking the time to look at it already.

I assume that matrix is your view matrix. This matrix is used to transform positions from world space to camera space.
Your mouse position is in view space and you want to transform it to world space, hence in the other way. Therefore, you need the inverse of matrix. Furthermore, the Vector2.Transform() method returns the transformed vector. It does not change the original one. So right now, you don't use any transformed positions:
var invMatrix = Matrix.Invert(matrix);
mousePos = Vector2.Transform(mousePos, invMatrix);
You probably do not want to transform oldPos because it already is in world space (probably, I can't tell definitely from the code snippet).
By the way, there is an easier way to check if testObjPos is near mousePos. Just check the length of the difference vector:
if((testObjPos - mousePos).Length() < 1)
//stop

Related

Bounding the camera to the map

I have a 2D game in unity, and I have a camera that follow my main character.
Currently, when I, for example, move the character to the left, I can see what's beyond the map, like so:
Say the map size is 15X15. I have a script generating 15X15 blocks of size 1X1, meaning the map bounds are (-1, -1) -> (15, 15).
There are two things I want to accomplish:
1) Have the camera not go out of the map bounds
2) When the map size is SMALLER than the camera, have the camera change its size.
Example for point 2)
The map is 5 columns and 15 rows, thus it's very narrow compared to the camera, like so:
or even 10 columns and 3 rows, like so:
I would want the size of the camera to change so it won't be neither wider or taller than the map.
How do I do those two things?
This is the github to the current scripts in the game. The CameraController script is where the additions are supposed to be
The orthographic size defines half of the vertical size, the horizontal size is based on aspect ratio.
From there you can define what should be the biggest value when centered.
The script below should get you going. As long as your level are rectangle (that obviously includes square), it will go fine:
public float speed = 2f;
public Transform min;
public Transform max;
private float aspect;
private float maxSize;
private void Start ()
{
this.aspect = Camera.main.aspect;
this.maxSize = max.position.x <= max.position.y ? max.position.x /2f / this.aspect :max.position.y / 2f;
}
private void Update ()
{
float size = Input.GetAxis ("Mouse ScrollWheel");
Camera.main.orthographicSize += size;
if (Camera.main.orthographicSize > maxSize)
{
Camera.main.orthographicSize = maxSize;
}
float x = Input.GetAxis ("Horizontal");
float y = Input.GetAxis ("Vertical");
Vector3 position = this.transform.position;
position.x += x * Time.deltaTime * this.speed;
position.y += y * Time.deltaTime * this.speed;
float orthSize = Camera.main.orthographicSize;
if (position.x < (this.min.position.x + orthSize * this.aspect))
{
position.x = this.min.position.x + orthSize * this.aspect;
}
else if (position.x > (this.max.position.x - orthSize * this.aspect))
{
position.x = this.max.position.x - orthSize * this.aspect;
}
if (position.y < (this.min.position.y + orthSize))
{
position.y = this.min.position.y + orthSize;
}
else if(position.y > (this.max.position.y - orthSize))
{
position.y = this.max.position.y - orthSize;
}
this.transform.position = position;
}
the idea is that you have two empty game objects place at bottom left and upper right. Bottom left is dragged into min and upper right goes int max. The speed variable is just how fast the camera translates. This is attached to the camera object. There is no limit for min size of camera, but you can do it.
The point is just that you get this going for your own project as this is more generic.
The rest is just considering the camera position, current size and aspect ratio (you cannot change that at runtime or you'd have to modify the code).
EDIT:
If you wish to bound the camera zoom to the movement,remove the first lines about size and add the following after you get the horizontal/vertical movement:
if (x != 0f || y != 0f) {
Camera.main.orthographicSize = Mathf.MoveTowards (Camera.main.orthographicSize, largeSize, Time.deltaTime);
} else {
Camera.main.orthographicSize = Mathf.MoveTowards (Camera.main.orthographicSize, size, Time.deltaTime);
}
Think of declaring the size, largeSize variables and set them to your need.

Unity avoiding obstacles with pathfinding c#

I have a simple project which includes pathfinding with obstacle avoidance. Now, I have void Steer which steers the object around since the path is not straight. then I have void AvoidObstacles which has raycast and the obstacle avoidance part basically.
Whenever the object steers, it calls the AvoidObstacles function. The problem now is, at the start, whenever it hasn't call in the Steer function yet, because it is a straigh line, it passes through the object not avoiding it.
Here are some of the codes used:
public Vector3 Steer(Vector3 target, bool bFinalPoint = false)
{
//Calculate the directional vector from the current position towards the target point
Vector3 desiredVelocity = (target - transform.position);
float dist = desiredVelocity.magnitude;
AvoidObstacles(ref desiredVelocity);
//Normalise the desired Velocity
desiredVelocity.Normalize();
//Calculate the velocity according to the speed
if (bFinalPoint && dist < 10.0f)
desiredVelocity *= (curSpeed * (dist / 10.0f));
else
desiredVelocity *= curSpeed;
//Calculate the force Vector
Vector3 steeringForce = desiredVelocity - velocity;
Vector3 acceleration = steeringForce / mass;
return acceleration;
}
here is the other one
public void AvoidObstacles(ref Vector3 desiredVelocity)
{
RaycastHit hit;
Vector3 leftRay = transform.position;
Vector3 rightRay = transform.position;
//leftRay.x -= 2;
//rightRay.x += 2;
Debug.DrawLine(transform.position,(transform.forward * 5) + transform.position,Color.green);
if(Physics.Raycast(transform.position, transform.forward,out hit, minimumDistToAvoid))
{
Debug.DrawLine(transform.position,(transform.forward * 10) + transform.position,Color.red);
if(hit.transform != transform)
{
//dir += hit.normal * 50;
//Get the normal of the hit point to calculate the new direction
Vector3 hitNormal = hit.normal;
hitNormal.y = 0.0f; //Don't want to move in Y-Space
//Get the new directional vector by adding force to vehicle's current forward vector
desiredVelocity = transform.forward + hitNormal * force;
}
}
}
and here is my update
void Update ()
{
//Unify the speed
curSpeed = speed * Time.deltaTime;
targetPoint = path.GetPoint(curPathIndex);
//If reach the radius within the path then move to next point in the path
if(Vector3.Distance(transform.position, targetPoint) < path.Radius)
{
//Don't move the vehicle if path is finished
if (curPathIndex < pathLength - 1)
curPathIndex ++;
else if (isLooping)
curPathIndex = 0;
else
return;
}
//Move the vehicle until the end point is reached in the path
if (curPathIndex >= pathLength )
return;
//Calculate the next Velocity towards the path
if(curPathIndex >= pathLength - 1 && !isLooping)
velocity += Steer(targetPoint, true);
else
velocity += Steer(targetPoint);
transform.position += velocity; //Move the vehicle according to the velocity
transform.rotation = Quaternion.LookRotation(velocity); //Rotate the vehicle towards the desired Velocity
//AvoidObstacles(ref Vector3 desiredVelocity);
dir.Normalize();
}
Maybe someone can help me out buy letting me know how can I call the avoidobstacle function outside of steer? Maybe in update or start perhaps.
I can't really use other algorithms, just this one right here. TIA

Keeping my object from rolling out of the screen

I am using the tilt function on a phone to control an object to roll left and right. I do not want it roll anything beyond the screen width.
As in the simple illustration below, the dotted lines represent the width of the screen. The 'O' is the object and the Max signs indicate the maximum point the object is allowed to roll to.
Max--------O--------Max
But currently using my code, the object still rolls out of the screen. Also tried testing both height n width and ended up the same result where the object rolls out of the screen. Please advice what I am doing wrong. Thank you.
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
if (!(Mathf.Round(dir.x) > Mathf.Round(Screen.width/2)) || !(Mathf.Round(dir.x) < -Mathf.Round(Screen.width/2)))
{
transform.Translate(dir * speed);
}
}
**Updated
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
//transform.Translate(dir * speed);
if (transform.position.x < 0)
{
transform.position = new Vector3(0, this.transform.position.y, this.transform.position.z);
}
else if (transform.position.x > Screen.width)
{
transform.position = new Vector3(Screen.width, this.transform.position.y, this.transform.position.z);
}
else
{
transform.Translate(dir * speed);
}
}
I think thereare several ways you can go about checking the transfomrs position.
first off if you were using a 2d camera you could use a method like
leftBounds = Camera.x - (Camera.pixelWidth/2);
however because ortho camera angles are not set at any particulare size at x distace from camera they are hard to calculate.
i have seen some instances were coliders on the camera just outside the render rand were placed as camera children
adding a colision mask to only affect the appropriate game object would be best.

C# XNA: How to get asteroid bouncing off all sides of the screen

I am trying to make an asteroids game and have managed to get the asteroid to move in a straight line from one side to the screen to the other however, it runs in an infinite straight line instead of bouncing off all the sides of the screen like i want it to.
Code that moves the asteroid:
public void Update(GameTime gameTime)
{
position.X = position.X + speed;
position.Y = position.Y + speed;
if (position.X <= 0)
{
position.X = 0;
speed = random.Next(-3,3);
}
// Right Boundary
if (position.X >= 1280 - texture.Width)
{
position.X = 1280 - texture.Width;
speed = random.Next(-3,3);
}
// Top Boundary
if (position.Y <= 0)
{
position.Y = 0;
speed = random.Next(-3,3);
}
//Bottom Boundary
if (position.Y >= 1024 - texture.Height)
{
position.Y = 1024 - texture.Height;
speed = random.Next(-3,3);
}
}
How would I go about amending this code so that it stops moving in a straight line and bounces off all the sides of the screen.
(position and speed are declared within a superclass and the value of speed is declared within the asteroids class constructor)
Any suggestions would be appreciated. Cheers
Since I can't comment yet, im going to try my best to understand your question.
from my understanding what happens to you is that the astroids go straight up and down instead of bouncing all around the screen?
I would suggest you to use matrices, and to create a rotation like that. you can read more about it here treating the astroid like a rocket, and implamenting in your own code:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Angle_to_Direction.php
first create your asteroids at random places, and add them radnom velocity.vector2. so on your update function you update like this:
position += velocity
then use this function to reverse velocity if bounce.
private void CheckCollision()
{
if (position.X < 0){
position.X = 0;
velocity.X *= -1;
}
if (position.X + texture.Width > screenBounds.Width){
position.X = screenBounds.Width - texture.Width;
velocity.X *= -1;
}
if (position.Y < 0){
position.Y = 0;
velocity.Y *= -1;
}
}

How to stop movement, when mouse is off screen

I'm hoping there's someone out there that can help me with a small problem.
Currently I have an Input Manager attached to the main camera to allow the user to pan around the map by moving the mouse to the edges of the window, but I've encountered a slight problem which I've tried to fix myself to no avail.
If the mouse goes outside of the window, the panning still happens, which I find irritating when I'm debugging or using other applications. So I am hoping that someone can help me to stop the movement happening when the mouse is outside the game window.
Here is the code for my Input Manager.
using UnityEngine;
using System.Collections;
public class InputManager : MonoBehaviour {
public Vector3 position = new Vector3(0,0, -10);
public int boundary = 50;
public int speed = 4;
private int screenBoundsWidth;
private int screenBoundsHeight;
// Use this for initialization
void Start()
{
screenBoundsWidth = Screen.width;
screenBoundsHeight = Screen.height;
}
// Update is called once per frame
void Update()
{
if (Input.mousePosition.x > screenBoundsWidth - boundary) {
position.x += speed * Time.deltaTime;
}
if (Input.mousePosition.x < 0 + boundary) {
position.x -= speed * Time.deltaTime;
}
if (Input.mousePosition.y > screenBoundsHeight - 10) {
position.y += speed * Time.deltaTime;
}
if (Input.mousePosition.y < 0 + boundary) {
position.y -= speed * Time.deltaTime;
}
Camera.mainCamera.transform.position = position;
}
}
Thank you for your time.
EDIT
I have come up with a hacky work around, but it still causes the movement to happen in certain locations around the outside of the window. I am hoping someone can come up with a better solution.
if (Input.mousePosition.x < screenBoundsWidth && Input.mousePosition.y < screenBoundsHeight) {
if (Input.mousePosition.x > screenBoundsWidth - boundary) {
position.x += speed * Time.deltaTime;
}
}
if (Input.mousePosition.x > 0 && Input.mousePosition.y > 0) {
if (Input.mousePosition.x < 0 + boundary) {
position.x -= speed * Time.deltaTime;
}
}
if (Input.mousePosition.y < screenBoundsHeight && Input.mousePosition.x < screenBoundsWidth) {
if (Input.mousePosition.y > screenBoundsHeight - 22) {
position.y += speed * Time.deltaTime;
}
}
if (Input.mousePosition.y > 0 && Input.mousePosition.x > 0) {
if (Input.mousePosition.y < 0 + boundary) {
position.y -= speed * Time.deltaTime;
}
}
3 Ideas:
Rect screenRect = new Rect(0,0, Screen.width, Screen.height);
if (!screenRect.Contains(Input.mousePosition))
return;
The same can be written more verbously as:
float mouseX = Input.MousePosition.x;
float mouseY = Input.MousePosition.y;
float screenX = Screen.width;
float screenY = Screen.height;
if (mouseX < 0 || mouseX > screenX || mouseY < 0 || mouseY > screenY)
return;
// your Update body
...which is pretty much the same as your "hacky" solution (which is completely valid imho).
Another option is to create 4 Rect objects for each screen border, then check if mouse is inside those rects. Example:
public float boundary = 50;
public float speed = 4;
private Rect bottomBorder;
private Rect topBorder;
private Transform cameraTransform;
private void Start()
{
cameraTransform = Camera.mainCamera.transform
bottomBorder = new Rect(0, 0, Screen.width, boundary);
topBorder = new Rect(0, Screen.height - boundary, Screen.width, boundary);
}
private void Update()
{
if (topBorder.Contains(Input.mousePosition))
{
position.y += speed * Time.deltaTime;
}
if (bottomBorder.Contains(Input.mousePosition))
{
position.y -= speed * Time.deltaTime;
}
cameraTransform.position = position;
}
The tricky part here is that Rect coordinates have Y axis pointing down and Input.mousePosition has Y pointing up... so bottomBorder Rect has to be on the top, and topBorder has to be at the bottom. Left and right borders are not affected.
Due to the way Unity and the various host operating systems interact, you have limited control of the mouse cursor. (in short the OS controls the mouse Unity just reads it) That being said you do have some options. Screen.lockCursor jumps to mind.
http://docs.unity3d.com/Documentation/ScriptReference/Screen-lockCursor.html
It won't do exactly what you are looking for but it might be a good starting point
Time.speed = 0;
is this what you want?

Categories

Resources