I can already make the movement grid via pathfinding and avoid obstacles for the player. Now I want to make the AI move itself based on the movement grid and available action points (just like the player does), but I don't know how to do it. Right now, I am only able to make the character move to the position (but it is not follow the pathfinding, this character suppose to be the AI). I am stuck trying to solve this problem, but couldn't. Could you guys help me out? Thanks.
Here is the code I've got so far (it makes the character which is suppose to be AI to move to the position, but it not follow the pathfinding):
using UnityEngine;
using System.Collections;
public class AIPlayer : Player
{
void Awake()
{
moveDestination = transform.position;
}
// Use this for initialization
void Start()
{
ColorChanger();
}
// Update is called once per frame
void Update()
{
}
public override void TurnUpdate()
{
if (GameManager.instance.currentPlayerIndex == 5)
{
if (Vector3.Distance(moveDestination, transform.position) > 0.1f)
{
transform.position += (moveDestination - transform.position).normalized * moveSpeed * Time.deltaTime;
if (Vector3.Distance(moveDestination, transform.position) <= 0.1f)
{
transform.position = moveDestination;
actionPoints--;
}
}
else
{
moveDestination = new Vector3(2 - Mathf.Floor(GameManager.instance.mapSize / 2), 1.5f, -2 + Mathf.Floor(GameManager.instance.mapSize / 2));
GameManager.instance.NextTurn();
}
}
base.TurnUpdate();
}
public override void TurnOnGUI()
{
}
public override void ColorChanger()
{
base.ColorChanger();
}
}
Here is the link video for the game:
http://www.youtube.com/watch?v=eo7DzbBPQBs&feature=youtu.be
There's no code for pathfinding there. It's just an overly complicated lerp. As well, moving directly to the position will cause major headaches with graphical obstacle avoidance.
Your best bet is to implement a grid-based navmesh and use something like an A* search to find the path. The movement would be limited to adjacent squares, so graphical obstacle avoidance wouldn't happen.
Have a look at this tutorial. It'll give you everything you need except for animating player movement and the game logic for the target position.
Related
I am using the Unity Engine with C#.
I have a 1x1 cube which moves forward on a grid of 49, 1x1 cubes (screenshot below) - when I press the start button on the controller.
The movement code for the cube is below.
void MovePlayerCube()
{
transform.Translate(direction * moveSpeed * Time.deltaTime);
}
When this cube passes over a cube with an arrow on it, the cube will change direction to where the arrow is pointing (staying on the same Y axis).
I need to detect the exact point at which the cube is directly over the cube with the arrow on it, and run the 'change direction' code at that point.
I'm currently using Vector3.Distance to check if the X and Z coordinates of the 2 cubes are close enough together (if they are less than 0.03f in distance), I can't check if they are equal due to floating point imprecision.
However this is really ineffective as half the time this code doesn't register for probably the same reason, and if I increase the 0.03f to a point where it never misses it becomes really noticeable that the cube isn't aligned with the grid anymore.
There has to be a proper solution to this and hopefully I've clarified the situation enough?
Any advice is appreciated.
You are moving your cube via
transform.Translate(direction * moveSpeed * Time.deltaTime);
which will never be exact an might overshoot your positions.
=> I would rather implement a coroutine for moving the cube exactly one field at a time, ensuring that after each iteration it fully aligns with the grid and run your checks once in that moment.
It doesn't even have to match exactly then, you only need to check if you are somewhere hitting a cube below you.
So something like e.g.
private Vector3Int direction = Vector3Int.left;
private IEnumerator MoveRoutine()
{
// depends on your needs if this runs just forever or certain steps
// or has some exit condition
while(true)
{
// calculate the next position
// optional round it to int => 1x1 grid ensured on arrival
// again depends a bit on your needs
var nextPosition = Vector3Int.RoundToInt(transform.position) + direction;
// move until reaching the target position
// Vector3 == Vector3 uses a precision of 1e-5
while(transform.position != nextPosition)
{
transform.position = Vector3.MoveTowards(transform.position, nextPosition, moveSpeed * Time.deltaTime);
yield return null;
}
// set target position in one frame just to be sure
transform.position = nextPosition;
// run your check here ONCE and adjust direction
}
}
start this routine only ONCE via
StartCoroutine(MoveRoutine());
or if you have certain exit conditions at least only run one routine at a time.
A Corouine is basically just a temporary Update routine with a little bit different writing => of course you could implement the same in Update as well if you prefer that
private Vector3Int direction = Vector3Int.left;
private Vector3 nextPosition;
private void Start()
{
nextPosition = transform.position;
}
private void Update()
{
if(transform.position != nextPosition)
{
transform.position = Vector3.MoveTowards(transform.position, nextPosition, moveSpeed * Time.deltaTime);
}
else
{
transform.position = nextPosition;
// run your check here ONCE and adjust direction
// then set next position
nextPosition = Vector3Int.RoundToInt(transform.position) + direction;
}
}
Then regarding the check you can have a simple raycast since you only run it in a specific moment:
if(Physics.Raycast(transform.position, Vector3.down, out var hit))
{
direction = Vector3Int.RountToInt(hit.transform.forward);
}
assuming of course your targets have colliders attached, your moved cube position (pivot) is above those colliders (assumed it from your image) and your targets forward actually points int the desired new diretcion
I would do it this way. First I would split the ability of certain objects to be "moving with certain speed" and "moving in a certain direction", this can be done with C# interfaces. Why? Because then your "arrow" cube could affect not only your current moving cube, but anything that implements the interfaces (maybe in the future you'll have some enemy cube, and it will also be affected by the arrow modifier).
IMovingSpeed.cs
public interface IMovementSpeed
{
float MovementSpeed{ get; set; }
}
IMovementDirection3D.cs
public interface IMovementDirection3D
{
Vector3 MovementDirection { get; set; }
}
Then you implement the logic of your cube that moves automatically in a certain direction. Put this component on your player cube.
public class MovingStraight: MonoBehaviour, IMovementSpeed, IMovementDirection3D
{
private float _movementSpeed;
Vector3 MovementSpeed
{
get { return _movementSpeed; }
set { _movementSpeed = value; }
}
private Vector3 _movementDirection;
Vector3 MovementDirection
{
get { return _movementDirection; }
set { _movementDirection= value; }
}
void Update()
{
// use MovementSpeed and MovementDirection to advance the object position
}
}
Now to implement how the arrow cube modifies other objects, I would attach a collision (trigger) component for both moving cube and the arrow cube.
In the component of the arrow cube, you can implement an action when something enters this trigger zone, in our case we check if this object "has direction that we can change", and if so, we change the direction, and make sure that the object will be aligned, by forcing the arrow cube's position and the other object's position to be the same on the grid.
public class DirectionModifier: MonoBehaviour
{
private Vector3 _newDirection;
private void OnTriggerEnter(Collider collider)
{
IMovementDirection3D objectWithDirection = collider as IMovementDirection3D ;
if (objectWithDirection !=null)
{
objectWithDirection.MovementDirection = _newDirection;
// to make sure the object will continue moving exactly
// from where the arrow cube is
collider.transform.position.x = transform.position.x;
collider.transform.position.y = transform.position.y;
}
}
}
If you made your trigger zones too large, however, then the moving cube will "jump" abruptly when it enters the arrow cube's trigger zone. You can fix it by either starting a coroutine as other answers suggested, or you could make the trigger zones pretty small, so that the jump is not noticeable (just make sure not to make them too small, or they may not intersect each other)
You could then similarly create many other modifying blocks, that would change speed or something
I think that it is enough for you to check if the X and Z coordinates are equal, since the movement occurs only along them
Example
if(_player.transfom.position.x == _gameSquare.transfom.position.x && _player.transfom.position.z == _gameSquare.transfom.position.z)
{
Debag.Log("Rotate!")
}
I am developing a VR game.
Is a fighting game, the player will be able the punch the enemies (on his fist will be a collider and a disabled object with the damage script).
I need a script that will activate another object (the one with damage script) - (placed on his fist) but just on certain speed or force (you know, like in real life- if the enemy will be touched with the hand he should not be damaged, just on high force or speed)
What is the best solution?
thank you!
Since your player's fist is not being controlled by the physics system, it will not be possible to read the velocity of the player's hand like you would a normal Rigidbody. That being said, you can still calculate the speed and handle all of what you wish to do in one script.
Here's an example:
[RequireComponent(typeof(DamageScript))]
public class HandSpeedMonitor : Monobehaviour
{
public float threshold;
DamageScript damageScript;
Vector3 lastPos;
public void Awake()
{
damageScript = this.GetComponent<DamageScript>();
}
public void Start()
{
lastPos = this.transform.position;
}
public void Update()
{
float velocity = (lastPos - this.transform.position).magnitude / Time.deltaTime;
if(!damageScript.enabled && velocity > threshold)
damageScript.enabled = true;
else if(damageScript.enabled)
damageScript.enabled = false;
}
}
However, since .magnitude is an expensive call, you may want to consider storing your "threshold" as a squared speed "sqrThreshold" and use .sqrMagnitude, since it removes the square root component of vector math (saving on processing).
I'm working on a small game project for school in UNITY, specifically a clone of a snake game called Rattler Race. I'm pretty much a complete beginner with the engine, hence why I'm struggling a bit. The game we're suppose to make has to have 30 unique levels that have ascending complexity, something like this: Final level
My main problem at the moment is spawning food for the snake so it doesn't overlap with any inner walls or the borders.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnFood : MonoBehaviour
{
public GameObject FoodPrefab;
public Transform BorderTop;
public Transform BorderBottom;
public Transform BorderLeft;
public Transform BorderRight;
public Transform Obstacle;
Vector2 pos;
// Use this for initialization
void Start ()
{
for (int i = 0; i < 10; i++) {
Spawn();
}
}
void Spawn()
{
pos.x = Random.Range(BorderLeft.position.x + 5,BorderRight.position.x - 5);
pos.y = Random.Range(BorderBottom.position.y + 5, BorderTop.position.y - 5);
Instantiate(FoodPrefab, pos, Quaternion.identity);
}
// Update is called once per frame
void Update ()
{
}
}
The code is very simple ofcourse because at the moment the game field is empty with no obstacles:
Current state
However my problem is if I was to scale up that tiny red obstacle, like so:
Big Obstacle
The food would spawn behind it(every level has 10 food objects) and be impossible to get. My idea was to build levels off of one object(the "Obstacle") and its copies, I don't really know if that idea is sound yet but I wanted to try.
If theres any way or any method to spawn food objects in locations so they don't overlap with the obstacle, like to check if the space is already occupied or a method that checks if a would be food object intersects with an existing obstacle, I would be very grateful if someone teaches me, because I'm really lost at the moment.
Assuming your food is exactly one unit long, you could have a coroutine which would check if there is something around that food gameObject, if there isn't anything, you can spawn it.
public LayerMask layerMask; //Additional variable so you can control which layer you don't want to be detected in raycast
void Spawn(){
StartCoroutine(GameObjectExists());
}
IEnumerator GameObjectExists(){
do{
yield return null;
pos.x = Random.Range(BorderLeft.position.x + 5,BorderRight.position.x - 5);
pos.y = Random.Range(BorderBottom.position.y + 5, BorderTop.position.y - 5);
}while(Physics2D.OverlapCircle(new Vector2(pos), 1f, layerMask); //1f is the radius of your food gameObject.
Instantiate(FoodPrefab, pos, Quaternion.identity);
yield return null;
}
I'm making a billiard game and I have two questions:
How do I find the velocity of two balls when they collide with each other and how do I apply it to both balls ?
I already know the angles that they're gonna move, I just need to find the velocity that they'll move in those directions.
I was never good at physics/physics programming so I would appreciate any help given! Btw, my game is in 3D.
Thank you for your time!
Edit: What I'm trying to do is make the movement direction match the direction that I'm calculating using this script:
if (Physics.Raycast(ray, out hit, Mathf.Infinity, lmm))
{
location = new Vector3(hit.point.x, 1.64516f, hit.point.z);
}
if (Physics.SphereCast(transform.position, 0.77f, location - transform.position, out hitz, Mathf.Infinity, lmm2))
{
if (hitz.collider.tag == "Ball")
{
Vector3 start = hitz.point;
end = start + (-hitz.normal * 4);
lineRenderer2.SetPosition(1, end);
}
}
You can calculate the new velocities by applying an impulse to each ball. We can apply Newton's Third law to do so. PseudoCode:
RelativeVelocity = ball1.velocity - ball2.velocity;
Normal = ball1.position - ball2.position;
float dot = relativeVelocity*Normal;
dot*= ball1.mass + ball2.mass;
Normal*=dot;
ball1.velocity += Normal/ball1.mass;
ball2.velocity -= Normal/ball2.mass;
This however does not take into account friction between the two balls nor their angular momentum.
If I understand correctly, what you are trying to do is to apply the speed of "Ball A" as a force to "Ball B", and vice versa as well. If that is the case I would suggest something like this:
Attach this script to all the balls:
public class BallCollisionScript : MonoBehaviour
{
public Rigidbody Rigid_Body;
void Start()
{
Rigid_Body = this.GetComponent<Rigidbody>();
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag.Equals("Ball"))
{
BallScript otherBall = collision.gameObject.GetComponent<BallScript>();
Rigid_Body.AddForce(otherBall.Rigid_Body.velocity);
}
}
}
Make sure that all balls are tagged with "Ball".
Can somebody tell me how to do head based steering? I know how to do it while mooving only camera, but i want to moove object by head and camera to follow the object.
I need this because i want to implement game logic to the object(it will aleso work for me if i can treat camera as an normal object).
I found this code for steering only camera:
public float speed = /* some number */;
private CardboardHead head;
void Start()
{
head = // find the CardboardHead
// example:
// head = Camera.main.GetComponent<StereoController>().Head;
// or, make the variable public and use drag-and-drop in the Editor
}
void Update()
{
transform.position += speed * head.Gaze.direction;
}
I'm starting to make games for unity so if I made some mistakes please correct me.
Are you using cardboard plugin for Unity from here?
https://developers.google.com/cardboard/unity/download
if you do, then there is a prefab called cardboard main, put it in the scene, then if you see there is a game object called Head inside it and it contains CardboardHead script. So here is in your script:
public GameObject head; // drag the Head gameobject to here or you can just get it from the start
void Start()
{
if (!head) // if you didn't drag the gameobject
{
head = FindObjectOfType<CardboardHead>().gameObject;
}
}
void Update()
{
transform.position += speed * head.transform.forward; // it is better to multiply by Time.deltaTime
}
also btw why it is tagged as Java?
New questions:
So here is what I did. I split the 'visual' and 'mechanic'. I removed the Mesh Renderer from the player, freeze its rotation for the rigidbody. I made a new child for the 'visual' it has a Script called Rotate.cs and removed its collider.
Changes to script:
in Forward.cs use the rb.AddForce(transform.forward * speed); back, and in Rotate.cs just use
void Update () {
transform.Rotate(Vector3.right * 5);
}
That is the quickest solution I can think of, I'm sure there are other solutions which you can try