Sorry if the question seems vague but I am creating a turn based, 2D roguelike game for coding practice and want the player to be able to move twice while the enemy moves once when the user clicks a button. I have tried using multiple booleans but to no avail.
The players turn is an integer which once it reaches 0, it becomes the enemies turn. The code for when the user clicks the button:
public void ButtonClicked()
{
GameManager.instance.playersTurn = 2;
}
the movement code inside my player manager(this is where the error lies)
void Update () {
if (0 > GameManager.instance.playersTurn)
return;
horizontal = (int)Input.GetAxisRaw ("Horizontal");
vertical = (int)Input.GetAxisRaw ("Vertical");
//dont allow vertical movement
if (horizontal != 0)
vertical = 0;
//if a key is pressed:
if (vertical != 0 || horizontal != 0)
AttemptMove<Wall> (horizontal, vertical);
}
protected override void AttemptMove <T>(int xDir, int yDir)
{
food--;
foodText.text = "Food: " + food;
base.AttemptMove<T> (xDir, yDir);
CheckIfGameOver ();
GameManager.instance.playersTurn--;
}
the GameManager.instance.playersTurn--; decrements until zero even if I have only moved once. How can I decrement it once per movement? I think the problem is that this is being called in update. Any pointers will be a great help, thanks guys.
Here is the other code from my parent class in case the error might lie here:
protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
{
Vector2 start = transform.position;
Vector2 end = start + new Vector2 (xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast (start, end, blockingLayer);
boxCollider.enabled= true;
if (hit.transform == null) {
StartCoroutine (SmoothMovement (end));
return true;
}
return false;
}
protected virtual void AttemptMove<T> (int xDir, int yDir)
where T: Component
{
RaycastHit2D hit;
bool canMove= Move (xDir, yDir, out hit);
if (hit.transform == null)
return;
T hitComponent = hit.transform.GetComponent<T> ();
if (!canMove && hitComponent != null)
OnCantMove (hitComponent);
}
protected IEnumerator SmoothMovement(Vector3 end)
{
float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
while (sqrRemainingDistance > float.Epsilon) {
Vector3 newPosition = Vector3.MoveTowards (rb2d.position, end, inverseMoveTime * Time.deltaTime);
rb2d.MovePosition (newPosition);
sqrRemainingDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
Related
so I made a script for multitouch using raycast. when dragged faster, the gameobject will be released, but when moving the gameobject slowly it follows the touch. here the codes
Vector2[] startPos = new Vector2[5];
Touch[] touch = new Touch[5];// Update is called once per frame
void FixedUpdate()
{
Debug.Log(Input.touchCount);
if (Input.touchCount > 0)
{
touch[Input.touchCount-1] = Input.GetTouch(Input.touchCount-1);
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(touch[Input.touchCount-1].position);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero, Mathf.Infinity);
if (hit.transform != null)
{
if (touch[Input.touchCount - 1].phase == TouchPhase.Moved)
{
hit.transform.position = worldPoint;]
}
else if (touch[Input.touchCount-1].phase == TouchPhase.Began)
{
startPos[touch[Input.touchCount-1].fingerId] = worldPoint;
}
else if (touch[Input.touchCount-1].phase == TouchPhase.Ended)
{
hit.transform.position = startPos[touch[Input.touchCount-1].fingerId];
}
}
}
}
what can i do for drag faster without gameobject will released? sorry for my bad english
one solution is to play with a bool variable and tag,
you keep in memory the gameobject you are dragging, you set a bool variable to true.. this is the idea , you try to use bool variable instead touchphase.ended/began...
this post could help you
i have just adapted to game2D
GameObject objet = null;
Plane plane;
float rayDistance;
Vector3 Offset;
bool mouseOver = false;
bool mousePressed = false;
void FixedUpdate()
{
if (Input.touchCount > 0)
{
mousePressed = true;
}
else
{
mousePressed = false;
objet = null;
}
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(touch[Input.touchCount - 1].position);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero, Mathf.Infinity);
if (hit.transform != null && hit.collider.tag == "Draggable")
{
mouseOver = true;
if (Input.GetTouch(0).phase != TouchPhase.Moved)
objet = hit.collider.gameObject;
}
else
{
if (mousePressed == false)
mouseOver = false;
}
if (mouseOver)
{
if (mousePressed)
{
//to adapt following your game configuration
plane = new Plane(Camera.main.transform.forward * -1, objet.transform.position);
plane.Raycast(ray, out rayDistance);
objet.transform.position = ray.GetPoint(rayDistance);// + Offset; to see if offset is needed
}
}
} // end update
I have two objects. The point is that I need to move the object up and down (hold and drag), and at the same time I need to move the other object up and down (hold and drag) independently. Something like this:
Example
After searching the Internet, I found a small script, but it only works for one touch at a time, and dragging only one object. Plus, if I touch with second finger the object changes his position to second finger position:
public class Move : MonoBehaviour {
private Vector3 offset;
void OnMouseDown() {
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(-2.527f, Input.mousePosition.y));
}
void OnMouseDrag() {
Vector3 curScreenPoint = new Vector3(-2.527f, Input.mousePosition.y);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
transform.position = curPosition;
}
}
I just can’t understand how I can make two objects drag and drop at the same time. I am new to unity and honestly i have problems with controllers
For touch screens I suggest you use Touch instead of mouse events. Touch class supports multiple touches at the same time and some useful information such as Touch.phase (Began, moving, stationary etc). I've written a script which you can attach to multiple objects with tag "Draggable", that makes objects move independently. Drag and drop the other object that should move when you use one finger to field otherObj and it should work. It only works for 2 obj in this version.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
public class PlayerActionHandler : MonoBehaviour
{
private Camera _cam;
public bool beingDragged;
public Vector3 offset;
public Vector3 currPos;
public int fingerIndex;
public GameObject otherObj;
// Start is called before the first frame update
void Start()
{
_cam = Camera.main;
}
// Update is called once per frame
void Update()
{
//ONLY WORKS FOR 2 OBJECTS
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(0).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = 0;
}
}
}
}else if (Input.touchCount == 1 && beingDragged)
{
otherObj.transform.SetParent(transform);
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}
//ONLY WORKS FOR 2 OBJECTS_END
else if (beingDragged && Input.touchCount > 1)
{
//We tie each finger to an object so the object only moves when tied finger moves
if (Input.GetTouch(fingerIndex).phase == TouchPhase.Moved ){
Vector3 pos = _cam.ScreenToWorldPoint(Input.GetTouch(fingerIndex).position);
currPos = new Vector3(pos.x, pos.y,0) + offset;
transform.position = currPos;
}
}else if (Input.touchCount > 0)
{
for (var i = 0; i < Input.touchCount; i++)
{
//We find the fingers which just touched the screen
if(Input.GetTouch(i).phase == TouchPhase.Began)
{
var raycast = _cam.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hit;
if (Physics.Raycast(raycast, out hit))
{
//use this tag if you want only chosen objects to be draggable
if (hit.transform.CompareTag("Draggable"))
{
if(hit.transform.name == name)
{
//set being dragged and finger index so we can move the object
beingDragged = true;
offset = gameObject.transform.position - _cam.ScreenToWorldPoint(Input.GetTouch(i).position);
offset = new Vector3(offset.x, offset.y, 0);
fingerIndex = i;
}
}
}
}
}
}else if (Input.touchCount == 0)
{
//if all fingers are lifted no object is being dragged
beingDragged = false;
}
}
}
I lost a lot of time trying to find what is the problem in code but I can not find the solution why my code is not triggered.
In my previous game when I implemented this code it worked perfectly, now when i implement into new game this same code for touch movement it doesn't work.
I tried to debug the code and put Debug.Log into Update method and when i swipe over screen it doesn't even get trigger.
This is the code:
int left = 0;
int right = 0;
int maxLeftCycles = 5;
int maxRightCycles = 5;
void Start()
{
//touch
left = maxLeftCycles;
right = maxRightCycles;
}
private void Update()
{
timer += Time.deltaTime;
if (Input.GetKeyUp(KeyCode.RightArrow) ||
Swipe.swipe == Swipe.SwipeDirection.right)
{
Swipe.ResetSwipe();
right = 0;
}
if (Input.GetKeyUp(KeyCode.LeftArrow) ||
Swipe.swipe == Swipe.SwipeDirection.left)
{
Swipe.ResetSwipe();
left = 0;
}
}
void FixedUpdate()
{
if (left < maxLeftCycles && !isMoving)
{
desiredPos = transform.position + Vector3.left * 1.52f;
isMoving = true;
left++;
}
if (right < maxRightCycles && !isMoving)
{
desiredPos = transform.position - Vector3.right * 1.52f;
isMoving = true;
right++;
}
if (isMoving)
{
transform.position = Vector3.MoveTowards(transform.position, desiredPos, moveSpeed * Time.deltaTime);
// this == is true if the difference between both
// vectors is smaller than 0.00001
if (transform.position == desiredPos)
{
isMoving = false;
transform.position = desiredPos;
}
}
}
I put Debug.Log in this code and in vector3.right and left but it never get triggered.
if (Input.GetKeyUp(KeyCode.RightArrow) ||
Swipe.swipe == Swipe.SwipeDirection.right)
{
Debug.Log("This is traacked");
Swipe.ResetSwipe();
right = 0;
}
if (Input.GetKeyUp(KeyCode.LeftArrow) ||
Swipe.swipe == Swipe.SwipeDirection.left)
{
Debug.Log("This is traacked");
Swipe.ResetSwipe();
left = 0;
}
This is the code for Swipe script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Swipe : MonoBehaviour
{
private float fingerStartTime = 0.0f;
private Vector2 fingerStartPos = Vector2.zero;
private bool isSwipe = false;
private float minSwipeDist = 50.0f;
private float maxSwipeTime = 0.5f;
public enum SwipeDirection
{
none,
up,
down,
right,
left
}
public static SwipeDirection swipe;
void Start()
{
swipe = SwipeDirection.none;
}
public static void ResetSwipe()
{
swipe = SwipeDirection.none;
}
// Update is called once per frame
void Update()
{
if (Input.touchCount > 0)
{
foreach (Touch touch in Input.touches)
{
switch (touch.phase)
{
case TouchPhase.Began:
/* this is a new touch */
isSwipe = true;
fingerStartTime = Time.time;
fingerStartPos = touch.position;
break;
case TouchPhase.Canceled:
/* The touch is being canceled */
isSwipe = false;
break;
case TouchPhase.Ended:
float gestureTime = Time.time - fingerStartTime;
float gestureDist = (touch.position - fingerStartPos).magnitude;
if (isSwipe && gestureTime < maxSwipeTime && gestureDist > minSwipeDist)
{
Vector2 direction = touch.position - fingerStartPos;
Vector2 swipeType = Vector2.zero;
if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
{
// the swipe is horizontal:
swipeType = Vector2.right * Mathf.Sign(direction.x);
}
else
{
// the swipe is vertical:
swipeType = Vector2.up * Mathf.Sign(direction.y);
}
if (swipeType.x != 0.0f)
{
if (swipeType.x > 0.0f)
{
// MOVE RIGHT
swipe = SwipeDirection.right;
}
else
{
// MOVE LEFT
swipe = SwipeDirection.left;
}
}
if (swipeType.y != 0.0f)
{
if (swipeType.y > 0.0f)
{
// MOVE UP
swipe = SwipeDirection.up;
}
else
{
// MOVE DOWN
swipe = SwipeDirection.down;
}
}
}
break;
}
}
}
}
}
The code in Update method for swipe input which I debug never get called or never work for me.I can not understand what i am doing wrong because the same code actually works in my previous game.
Thank you so much for reading my question I hope there will be some guy who can help me to solve this issue.
If it worked as is before hand in another project I would make sure that you are attaching the script to a game object. If it is attached to a game object make sure that it is not marked as inactive and that you aren't turning the object to inactive somewhere else in your scripts.
If neither of these are the case I would also try removing the script from the object and then reattaching it, and if that still doesn't work try deleting the object the script is attached to (if possible) and then recreate it and reattach the script.
I am working on football penalty game i am using a image target for ground i have a plane put grass texture on it i have models for goal post etc for football i add a sphere and add a RigidBody to it then i add a script to it for swiping the ball the problem is that if the Grivity is checked i am unable to see my football on the ground and if gravity is unchecked i am able to see my football but without grivity when i kicked the ball i am unable to put the ball into the net ball move to sky etc.please help me to solve my problem thanks.
Here's my script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SwipeControl : MonoBehaviour
{
//variables for swipe input detection
private Vector3 fp; //First finger position
private Vector3 lp; //Last finger position
private float dragDistance; //Distance needed for a swipe to register
//variables for determining the shot power and position
public float power; //power at which the ball is shot
private Vector3 footballPos;
//initial football position for replacing the ball at the same posiiton
private float factor = 34f;
// keep this factor constant, also used to determine force of shot
public bool canShoot = true; //flag to check if shot can be taken
public int scorePlayer = 0; //score of player
public int scoreOpponent = 0; //score of oponent
public int turn = 0; //0 for striker, 1 for goalie
public bool isGameOver = false; //flag for game over detection
Vector3 oppKickDir; //direction at which the ball is kicked by opponent
public int shotsTaken = 0; //number of rounds of penalties taken
private bool returned = true; //flag to check if the ball is returned to its initial position
public bool isKickedPlayer = false; //flag to check if the player has kicked the ball
public bool isKickedOpponent = false; //flag to check if the opponent has kicked the ball
void Start()
{
Time.timeScale = 1; //set it to 1 on start so as to overcome the effects of restarting the game by script
dragDistance = Screen.height * 20 / 100; //20% of the screen should be swiped to shoot
Physics.gravity = new Vector3(0, -20, 0); //reset the gravity of the ball to 20
footballPos = transform.position; //store the initial position of the football
}
// Update is called once per frame
void Update()
{
if (returned)
{ //check if the football is in its initial position
if (turn == 0 && !isGameOver)
{ //if its users turn to shoot and if the game is not over
playerLogic(); //call the playerLogic fucntion
}
else if (turn == 1 && !isGameOver)
{ //if its opponent's turn to shoot
opponentLogic(); //call the respective function
}
}
}
void playerLogic()
{
//Examine the touch inputs
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fp = touch.position;
lp = touch.position;
}
if (touch.phase == TouchPhase.Ended)
{
lp = touch.position;
//First check if it's actually a drag
if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
{ //It's a drag
//x and y repesent force to be added in the x, y axes.
float x = (lp.x - fp.x) / Screen.height * factor;
float y = (lp.y - fp.y) / Screen.height * factor;
//Now check what direction the drag was
//First check which axis
if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y))
{ //If the horizontal movement is greater than the vertical movement...
if ((lp.x > fp.x) && canShoot) //If the movement was to the right)
{ //Right move
GetComponent<Rigidbody>().AddForce((new Vector3(x, 10, 15)) * power);
}
else
{ //Left move
GetComponent<Rigidbody>().AddForce((new Vector3(x, 10, 15)) * power);
}
}
else
{ //the vertical movement is greater than the horizontal movement
if (lp.y > fp.y) //If the movement was up
{ //Up move
GetComponent<Rigidbody>().AddForce((new Vector3(x, y, 15)) * power);
}
else
{ //Down move
}
}
}
canShoot = false;
returned = false;
isKickedPlayer = true;
StartCoroutine(ReturnBall());
}
else
{ //It's a tap
}
}
}
IEnumerator ReturnBall()
{
yield return new WaitForSeconds(5.0f); //set a delay of 5 seconds before the ball is returned
GetComponent<Rigidbody>().velocity = Vector3.zero; //set the velocity of the ball to zero
GetComponent<Rigidbody>().angularVelocity = Vector3.zero; //set its angular vel to zero
transform.position = footballPos; //re positon it to initial position
//take turns in shooting
if (turn == 1)
turn = 0;
else if (turn == 0)
turn = 1;
canShoot = true; //set the canshoot flag to true
returned = true; //set football returned flag to true as well
}
void opponentLogic()
{
//check for screen tap
int fingerCount = 0;
foreach (Touch touch in Input.touches)
{
if (touch.phase != TouchPhase.Ended && touch.phase != TouchPhase.Canceled)
fingerCount++;
}
//if tapped, the opponent will shoot the football after some time delay as mentioned below
if (fingerCount > 0)
{
StartCoroutine(DelayAdd()); //add delay before the ball is shot
isKickedOpponent = true; //set opponent kicked to true
shotsTaken++; //increase set of penalty taken
returned = false;
StartCoroutine(ReturnBall()); //return the ball back to its initial position
}
}
IEnumerator DelayAdd()
{
yield return new WaitForSeconds(0.2f); //I have added a delay of 0.2 seconds
oppKickDir = new Vector3(Random.Range(-4f, 4f), Random.Range(5f, 10f), Random.Range(6f, 12f)); //generate a random x and y value in the range mentioned
GetComponent<Rigidbody>().AddForce(oppKickDir, ForceMode.Impulse); //add the force
}
}
So heres my problem. I have a box that I want my character to move around. But I want to be able to move around it while holding multiple move commands, for instance..
when moving right (towards the left of the obstacle) I want to be able to hold move right and up or down at the same time without the character sticking to the box. The funny part is, it works fine for the left and right side of the obstacle, yet it sticks when i try it on the top and bottom side of the obstacle.
Heres the Player Class (object im moving)
<!-- language: c# -->
public class Player
{
public Texture2D texture;
public Vector2 position;
public int speed;
public Vector2 offset;
public bool left, right, up, down;
public Rectangle collisionRect
{
get
{
return new Rectangle((int)position.X , (int)position.Y, texture.Width, texture.Height);
}
}
public Vector2 direction;
public Player(Texture2D texture, Vector2 position, int speed)
{
this.texture = texture;
this.position = position;
this.speed = speed;
offset.X = speed;
offset.Y = speed;
left = false;
right = false;
up = false;
down = false;
}
public virtual void Update(GameTime gameTime, Rectangle clientBounds)
{
direction = Vector2.Zero;
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
direction.X -= 1;
left = true;
}
else
left = false;
if (Keyboard.GetState().IsKeyDown(Keys.D))
{
direction.X += 1;
right = true;
}
else
right = false;
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
direction.Y -= 1;
up = true;
}
else
up = false;
if (Keyboard.GetState().IsKeyDown(Keys.S))
{
direction.Y += 1;
down = true;
}
else
down = false;
position += (direction * speed);
}
public virtual void Draw(GameTime gameTime, SpriteBatch spritebatch)
{
spritebatch.Draw(texture, collisionRect, Color.White);
}
}
Heres the Update Method in my maingame
<!-- language: c# -->
public override void Update(GameTime gameTime)
{
// TODO: Add your update code here
player.Update(gameTime, Game.Window.ClientBounds);
if (player.right && HitWall(player))
{
player.position.X -= player.offset.X;
}
else if (player.left && HitWall(player))
{
player.position.X += player.offset.X;
}
if (player.down && HitWall(player))
{
player.position.Y -= player.offset.Y;
}
else if (player.up && HitWall(player))
{
player.position.Y += player.offset.Y;
}
base.Update(gameTime);
}
And the HitWall function
<!-- language: c# -->
public bool HitWall(Player player)
{
for (int i = player.collisionRect.Top; i < player.collisionRect.Bottom; i++)
for (int j = player.collisionRect.Left; j < player.collisionRect.Right; j++)
if (TextureData[i * gameMap.map.Width + j] != Color.White)
return true;
return false;
}
I'm not sure where offset is defined, but I'm assuming it's the movement you've just made that frame.
Your problem is that because you check left & right before up and down, if you're moving diagonally down onto the top edge of the box, then you'll register a hit in the Y direction — HitWall doesn't check which direction you're going, it just checks for a collision. Therefore, the collision in the Y axis stil counts on the line if (player.right && HitWall(player)) and stops your lateral movement.
Best bet is to apply your sideways movement, check for a hit, move back if there is one — then apply your downwards movement, check for a hit, and move back if there is one. Correcting the position like this should mean you slide along the sides as you want.