I have a character rotation, it is based on this. There is a joystick. If you put your finger first on the rotation of the character, and then on the joystick - everything is fine. But if at first on the joystick, and after trying to turn, nothing will happen! Help. A few days can not decide
void Start()
{
mContr = GameObject.FindGameObjectWithTag("Joystick").GetComponent<MobileController>();
}
void Update()
{
if(xp > 0)
{
deadStatus = false;
ch_animator.SetBool("dead", false);
}
if(xp <= 0)
{ if(deadStatus == false)
{
menu.gameObject.SetActive(false);
ch_animator.SetBool("Run", false);
ch_animator.SetBool("Walk", false);
ch_animator.SetBool("right", false);
ch_animator.SetBool("left", false);
ch_animator.SetBool("dead", true);
dead.gameObject.SetActive(true);
if(GameObject.Find("selectLvl"))
{
GameObject.Find("selectLvl").SetActive(false);
}
if(GameObject.Find("settings"))
{
GameObject.Find("settings").SetActive(false);
}
deadStatus = true;
}
}
if(eat > 10)
{
if(xp>0&&xp!=100) {
xp += Time.deltaTime * 1f;
eat -= Time.deltaTime * 0.5f;
}
speedMove = 3;
} else {
speedMove = 1;
if(eat < 1 ) {
xp -= Time.deltaTime * 0.06f;
}
}
if(xp.ToString() != hpText.text) {
hpText.text = Math.Round(xp).ToString();
}
if(eat.ToString() != eatText.text)
{
eatText.text = Math.Round(eat).ToString();
}
if(star.ToString() != starText.text)
{
starText.text = star.ToString();
}
if(gun.ToString() != gunText.text)
{
gunText.text = gun.ToString();
}
int k = 1;
while(Input.touchCount > k)
{
Vector2 deltaposition = Vector2.zero;
if(Input.GetTouch(k).position.x > Screen.width / 2 - 100)
{
if(k == 0)
deltaposition = Input.GetTouch(k).deltaPosition;
deltaposition.x /= Screen.dpi;
if(deltaposition.x != 0)
{
float speedX = 3 * deltaposition.x;
player.transform.Rotate(Vector3.up * speedX);
}
}
k++;
}
CharacterMove();
GameGravity();
}
Jostic code
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class MobileController: MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image jostickBG;
[SerializeField]
private Image jostick;
public Vector2 inputVector;
private void Start()
{
jostickBG = GetComponent<Image>();
jostick = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnPointerDown(PointerEventData ped)
{
}
public virtual void OnPointerUp(PointerEventData ped)
{
inputVector = Vector2.zero;
jostick.rectTransform.anchoredPosition = Vector2.zero;
}
public virtual void OnDrag(PointerEventData ped)
{
Vector2 pos;
if(RectTransformUtility.ScreenPointToLocalPointInRectangle(jostickBG.rectTransform, ped.position, ped.pressEventCamera, out pos))
{
pos.x = (pos.x / jostickBG.rectTransform.sizeDelta.x);
pos.y = (pos.y / jostickBG.rectTransform.sizeDelta.y);
inputVector = new Vector2(pos.x * 2 - 0, pos.y * 2 - 0);
inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;
jostick.rectTransform.anchoredPosition = new Vector2(inputVector.x * (jostickBG.rectTransform.sizeDelta.x / 2), inputVector.y * (jostickBG.rectTransform.sizeDelta.y / 2));
}
}
public float Horizontal()
{
return inputVector.x;
}
public float Vertical()
{
return inputVector.y;
}
}
the problem is coming from the while loop:
your logic is only for k=0 on rotation player and k=1 for joy, and you begin to enter in the while loop with the value k=1, the test if is always false if for this value its the position of rotation player
if(Input.GetTouch(k).position.x > Screen.width / 2 - 100)
i suggest you to refactor your code like that:
when you have 2 touches k=0 and k=1, find the right action for each touches.
i dont understant why you dont enter in the while loop with k=0?
Related
I am using Sebastian Graves' Dark Souls in Unity series in order to make a game with souls-like mechanics and reached episode 4 but in comparison to his video, my player is tuck in place when using rolling or backstepping.
The problem seems to be coming from the AnimatorHandler script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Game
{
public class AnimatorHandler : MonoBehaviour
{
public Animator anim;
public InputHandler inputHandler;
public PlayerLocomotion playerLocomotion;
int vertical;
int horizontal;
public bool canRotate;
public void Initialize()
{
anim = GetComponent<Animator>();
inputHandler = GetComponentInParent<InputHandler>();
playerLocomotion = GetComponentInParent<PlayerLocomotion>();
vertical = Animator.StringToHash("Vertical");
horizontal = Animator.StringToHash("Horizontal");
}
public void UpdateAnimatorValues(float verticalMovement, float horizontalMovement)
{
float v = 0;
if (verticalMovement > 0 && verticalMovement < 0.55f)
{
v = 0.5f;
}
else if (verticalMovement > 0.55f)
{
v = 1;
}
else if (verticalMovement < 0 && verticalMovement > -0.55f)
{
v = -0.5f;
}
else if (verticalMovement < -0.55f)
{
v = -1;
}
else
{
v = 0;
}
float h = 0;
if (horizontalMovement > 0 && horizontalMovement < 0.55f)
{
h = 0.5f;
}
else if (horizontalMovement > 0.55f)
{
h = 1;
}
else if (horizontalMovement < 0 && horizontalMovement > -0.55f)
{
h = -0.5f;
}
else if (horizontalMovement < -0.55f)
{
h = -1;
}
else
{
h = 0;
}
anim.SetFloat(vertical, v, 0.1f, Time.deltaTime);
anim.SetFloat(horizontal, h, 0.1f, Time.deltaTime);
}
public void PlayTargetAnimation(string targetAnim, bool isInteracting)
{
anim.applyRootMotion = isInteracting;
anim.SetBool("isInteracting", isInteracting);
anim.CrossFade(targetAnim, 0.2f);
}
public void CanRotate()
{
canRotate = true;
}
public void StopRotation()
{
canRotate = false;
}
private void OnAnimatorMove()
{
if (inputHandler.isInteracting == false)
return;
float delta = Time.deltaTime;
playerLocomotion.rigidbody.drag = 0;
Vector3 deltaPosition = anim.deltaPosition;
deltaPosition.y = 0;
Vector3 velocity = deltaPosition / delta;
playerLocomotion.rigidbody.velocity = velocity;
// ???
}
}
}
The only method I found to make the player able to move was to delete playerLocomotion.rigidbody.velocity = velocity;
, but this generates another problem, as I am now able to change roll direction mid-animation.
How can I make this work?
So decided to give game dev a try, picked up unity,Now I decided to create a simple ping pong game.
My game has Bat.cs class, ball.cs, and GameHandler.cs.
The GameHandler.cs initializes the batRight, batLeft, ball using the Bat.cs, Ball.cs class and prefabs, it also keeps track of if someone scores then starts a serve by stopping the rally:
public class GameHandler : MonoBehaviour
{
public Bat bat;
public Ball ball;
public Score score;
public static Vector2 bottomLeft;
public static Vector2 topRight;
public static bool rallyOn = false;
public static bool isServingLeft = true;
public static bool isServingRight = false;
public static bool isTwoPlayers = true;
static Bat batRight;
static Bat batLeft;
public static Ball ball1;
static Score scoreLeft;
static Score scoreRight;
// Start is called before the first frame update
void Start()
{
//Convert screens pixels coordinate into games coordinate
bottomLeft = Camera.main.ScreenToWorldPoint(new Vector2(0, 0));
topRight = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
ball1 = Instantiate(ball) as Ball;
//Debug.Log("GameHandler.Start");
batRight = Instantiate(bat) as Bat;
batRight.Init(true);
batLeft = Instantiate(bat) as Bat;
batLeft.Init(false);
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
//Instatiate scores
scoreLeft = Instantiate(score, new Vector2(-2, -4), Quaternion.identity) as Score;
scoreRight = Instantiate(score, new Vector2(2, -4), Quaternion.identity) as Score;
}
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
if (GameHandler.rallyOn)
{
StopCoroutine(batRight.serveAi());
}
}
}
}
public static void increaseScoreByOne(bool isRight)
{
rallyOn = false;
if (isRight)
{
scoreRight.increaseScore();
isServingRight = true;
}
else
{
scoreLeft.increaseScore();
isServingLeft = true;
}
}
}
The ball.cs listens to the static GameHandler.rallyOn and starts moving the ball accordingly, it also changes direction of the ball if it hits a vertical wall or the bat:
public class Ball : MonoBehaviour
{
[SerializeField]
float speed;
float radius;
public Vector2 direction;
public Vector3 ballPosition;
// Start is called before the first frame update
void Start()
{
direction = Vector2.one.normalized; // direction is (1, 1) normalized
//Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
radius = transform.localScale.x / 2;
}
// Update is called once per frame
void Update()
{
ballPosition = transform.position;
if (GameHandler.rallyOn)
{
startRally();
}
}
void startRally()
{
transform.Translate(direction * speed * Time.deltaTime);
Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
if ((transform.position.y + radius) > GameHandler.topRight.y && direction.y > 0)
{
direction.y = -direction.y;
}
if ((transform.position.y + radius) < GameHandler.bottomLeft.y && direction.y < 0)
{
direction.y = -direction.y;
}
if ((transform.position.x + radius) > GameHandler.topRight.x && direction.x > 0)
{
// Left player scores
GameHandler.increaseScoreByOne(false);
//For no, just freeza the script
// Time.timeScale = 0;
//enabled = false;
}
if ((transform.position.x - radius) < GameHandler.bottomLeft.x && direction.x < 0)
{
// right player scores
GameHandler.increaseScoreByOne(true);
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Bat")
{
if (collision.GetComponent<Bat>().isRight && direction.x > 0)
{
direction.x = -direction.x;
}
if (!collision.GetComponent<Bat>().isRight && direction.x < 0)
{
direction.x = -direction.x;
}
}
}
public float getRadius()
{
return radius;
}
}
The bat.cs initiazes the two paddles, and either listens to user input if its 2 players or listens to player and use AI if it is player vs CPU.:
public class Bat : MonoBehaviour
{
float height;
[SerializeField] // this make this appear on editor without making this field public
float speed;
string input;
public bool isRight;
string PLAYER1_INPUT = "PaddleLeft";
string PLAYER2_INPUT = "PaddleRight";
// Start is called before the first frame update
void Start()
{
height = transform.localScale.y;
}
// Update is called once per frame
void Update()
{
if (GameHandler.isTwoPlayers)
{
if (isRight)
{
movePaddleonUserInput(PLAYER2_INPUT);
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
else
{
if (isRight)
{
movePaddleAi();
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
}
void movePaddleAi()
{
if (isRight && GameHandler.ball1.direction.x > 0 && GameHandler.ball1.ballPosition.x > 0)
{
//transform.Translate(direction * speed * Time.deltaTime);
if ((transform.position.y) > GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y < 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
if ((transform.position.y) < GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y > 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
}
}
void movePaddleonUserInput(string input)
{
// move = (-1 -> 1) * speed * timeDelta(this keep move framerate independent)
float move = Input.GetAxis(input) * speed * Time.deltaTime;
//Debug.Log((transform.position.y + height / 2) + " > "+ GameHandler.topRight.y+ "&&" + move +" > 0");
//Restrict paddle movement to to the screen
// (top edge of paddle > Screen top and we are moving up)
if ((transform.position.y + height / 2) > GameHandler.topRight.y && move > 0)
{
move = 0;
}
// (bottom edge of paddle < Screen top and we are moving down)
if ((transform.position.y - height / 2) < GameHandler.bottomLeft.y && move < 0)
{
move = 0;
}
transform.Translate(move * Vector2.up);
}
public void Init(bool isRightPaddle)
{
isRight = isRightPaddle;
Vector2 pos;
if (isRightPaddle)
{
isRight = isRightPaddle;
pos = new Vector2(GameHandler.topRight.x, 0);
// offset since center is the anchor
pos -= Vector2.right * transform.localScale.x;
input = "PaddleRight";
}
else
{
pos = new Vector2(GameHandler.bottomLeft.x, 0);
// offset since center is the anchor
pos += Vector2.right * transform.localScale.x;
input = "PaddleLeft";
}
transform.name = input;
transform.position = pos;
}
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
}
Now I also have score.cs and mainMenu scene , but no need to include that for this question, What I am struggling with now is the AI not stopping after it scores a point, I want the AI paddle to stop for a few seconds before it serves.
As you can see in the code, I added a yield return new WaitForSecondsRealtime(2f);
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
But this only cause the paddle to wait for the first time it scores , and then if it scores again in quick interval, it doesn't wait at all.
Not sure what I doing wrong here, thanks for your time.
The more plausible explanation to me would be that GameHandler.rallyOn and isServing* aren't all being reset to the correct values to prevent the serve from occurring before the coroutine even begins, or another check is needed somewhere to prevent a serve from occurring if all of the correct booleans aren't set. Try placing appropriate breakpoints and stepping through in a debugger.
You'd probably be better off using WaitForSeconds rather than WaitForSecondsRealtime, by the way, at least if there's a chance you might want to allow the game to be paused in the future.
Realized that the coroutine is called multiple times even before its finished due do it being called from update function in GameHandler.cs. Needed a way to check if the co-routine is already running and not start a new one from update if so, used the Game.isServing variable to do so:
public IEnumerator serveAi()
{
GameHandler.isServingRight = false; // coroutine started , no need to start new one
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
}
And my update in GameHandler is already checking for that variable before starting the coroutine:
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
}
}
}
I'm trying to programm my own little game in Unity, I'm not new to programming but new to Unity and C#. The problem is that I wrote my own classes to handle the game map and I am trying to connect these classes to the MonoBehaviour Scripts in Unity.
I have a script called InputManager, which is supposed to handle the input via mouse and keyboard etc. and in this script I want to create an object of the class MapManager which has access to my tiles and stuff. The problem I'm getting is that I can't seem to create an instance of MapManager in InputManager, not with the common new MapManager() anyway. When I use this a NullPointer of some sort is created, I guess?
I do not get a compiling error but an error once the game is launched which is:
NullReferenceException: Object reference not set to an instance of an object
InputManager.Update () (at Assets/Scripts/InputManager.cs:55)
Thank you for your help!
!UPDATE!:
I tried using a workaround so that it does not matter if Start() or Update() is called first, meaning that I just instantiate MapManager in the first Update() call. However, when I run the program the error is still the same. My conclusion is that somehow my constructor is not working or the Monobehaviour script somehow does not allow using the standard constructor... Any ideas?
Here is my code:
InputManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class InputManager : MonoBehaviour
{
public int mapRightBorder = 10;
public int mapLeftBorder = -10;
public int mapTopBorder = 8;
public int mapBottomBorder = -4;
public double camSpeed = 0.2;
public double mouseSensitivity = 0.3;
public double scrollSensitivity = 2;
public double maxZoomIn = -3;
public double maxZoomOut = -12;
public Tilemap ground, overlays, buildings;
public Tilemap selected;
public AnimatedTile animatedTile;
private double detectionBorder;
private double leftRightCorrection;
private MapManager mapManager;
// Start is called before the first frame update
void Start()
{
detectionBorder = 50;
leftRightCorrection = 1.2;
mapManager = new MapManager();
mapManager.ground = ground;
mapManager.overlays = overlays;
mapManager.buildings = buildings;
mapManager.selected = selected;
mapManager.animatedTile = animatedTile;
Cursor.lockState = CursorLockMode.Confined;
}
// Update is called once per frame
void Update()
{
moveCam();
checkMouse();
mapManager.updateTilemaps();
}
private void moveCam()
{
double moveX = Camera.main.transform.position.x;
double moveY = Camera.main.transform.position.y;
double moveZ = Camera.main.transform.position.z;
double xPos = Input.mousePosition.x;
double yPos = Input.mousePosition.y;
double zDelta = Input.GetAxis("Mouse ScrollWheel");
if (Input.GetKey(KeyCode.LeftArrow))
{
moveX -= camSpeed * leftRightCorrection;
}
else if (xPos >= 0 && xPos < detectionBorder)
{
moveX -= camSpeed * mouseSensitivity * leftRightCorrection;
}
else if (Input.GetKey(KeyCode.RightArrow))
{
moveX += camSpeed * leftRightCorrection;
}
else if (xPos <= Screen.width && xPos > Screen.width - detectionBorder)
{
moveX += camSpeed * mouseSensitivity * leftRightCorrection;
}
if(moveX > mapRightBorder || moveX < mapLeftBorder)
{
moveX = Camera.main.transform.position.x;
}
if (Input.GetKey(KeyCode.DownArrow))
{
moveY -= camSpeed;
}
else if (yPos >= 0 && yPos < detectionBorder)
{
moveY -= camSpeed * mouseSensitivity;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
moveY += camSpeed;
}
else if (yPos <= Screen.height && yPos > Screen.height - detectionBorder)
{
moveY += camSpeed * mouseSensitivity;
}
if(moveY > mapTopBorder || moveY < mapBottomBorder)
{
moveY = Camera.main.transform.position.y;
}
if (!(moveZ + zDelta * scrollSensitivity > maxZoomIn || moveZ + zDelta * scrollSensitivity < maxZoomOut))
{
moveZ += zDelta * scrollSensitivity;
}
Vector3 newPos = new Vector3((float)moveX, (float)moveY, (float) moveZ);
Camera.main.transform.position = newPos;
}
private void checkMouse()
{
if (Input.GetMouseButtonDown(0))
{
mapManager.selectTile(Input.mousePosition);
}
}
}
MapManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class MapManager
{
public int mapWidth = 16;
public int mapHeight = 16;
public Tilemap ground, overlays, buildings;
public Tilemap selected;
public AnimatedTile animatedTile;
private Vector3Int currentlySelected;
private OwnTilemap tilemap;
public MapManager()
{
tilemap = new OwnTilemap(mapWidth, mapHeight, ground, overlays, buildings);
currentlySelected = new Vector3Int(-1, -1, 0);
}
private Vector3Int mouseToTilemap(Vector3 mousePosition)
{
Ray ray = Camera.main.ScreenPointToRay(mousePosition);
// create a plane at 0,0,0 whose normal points to +Y:
Plane hPlane = new Plane(Vector3.forward, Vector3.zero);
// Plane.Raycast stores the distance from ray.origin to the hit point in this variable:
float enter = 0.0f;
if (hPlane.Raycast(ray, out enter))
{
//Get the point that is clicked
Vector3 hitPoint = ray.GetPoint(enter);
Vector3Int cell = ground.WorldToCell(hitPoint);
return cell;
}
return new Vector3Int(-1, -1, 0);
}
private bool isInBorders(Vector3Int p)
{
if (p.z != 0) return false;
if (p.x < 0 || p.x >= mapWidth) return false;
if (p.y < 0 || p.y >= mapHeight) return false;
return true;
}
public void updateTilemaps()
{
tilemap.updateTilemaps();
}
public void previewBuilding()
{
}
public void selectTile(Vector3 mousePosition)
{
if(currentlySelected != new Vector3Int(-1, -1, 0))
{
selected.SetTile(currentlySelected, null);
}
if (isInBorders(mouseToTilemap(mousePosition)))
{
selected.SetTile(mouseToTilemap(mousePosition), animatedTile);
currentlySelected = mouseToTilemap(mousePosition);
}
}
}
I would like to know how can I modify my code for my enemy to be able to move automatically in my grid ?
This is my code below :
[using System.Collections;
using UnityEngine;
class Enemy : MonoBehaviour {
private float moveSpeed = 50f;
private float gridSize = 18f;
private enum Orientation {
Horizontal,
Vertical
};
private Orientation gridOrientation = Orientation.Vertical;
private bool allowDiagonals = false;
private bool correctDiagonalSpeed = true;
private Vector2 input;
private bool isMoving = false;
private Vector3 startPosition;
private Vector3 endPosition;
private float t;
private float factor;
public void Update() {
if (!isMoving) {
input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (!allowDiagonals) {
if (Mathf.Abs(input.x) > Mathf.Abs(input.y)) {
input.y = 0;
} else {
input.x = 0;
}
}
if (input != Vector2.zero) {
StartCoroutine(move(transform));
}
}
}
public IEnumerator move (Transform transform)
{
isMoving = true;
startPosition = transform.position;
t = 0;
if (gridOrientation == Orientation.Horizontal) {
endPosition = new Vector3 (startPosition.x + System.Math.Sign (input.x) * gridSize,
startPosition.y, startPosition.z + System.Math.Sign (input.y) * gridSize);
} else {
endPosition = new Vector3 (startPosition.x + System.Math.Sign (input.x) * gridSize,
startPosition.y + System.Math.Sign (input.y) * gridSize, startPosition.z);
}
if (allowDiagonals && correctDiagonalSpeed && input.x != 0 && input.y != 0) {
factor = 0.7071f;
} else {
factor = 1f;
}
while (t < 1f) {
t += Time.deltaTime * (moveSpeed / gridSize) * factor;
transform.position = Vector3.Lerp (startPosition, endPosition, t);
yield return null;
}
isMoving = false;
yield return 0;
}
}
]
How can change width of Gizmos.DrawWireCube, based in child transforms (Gizmos.DrawWireSphere) transform.position or maybe the left/right limit of the transform?
My code so far:
position.cs
using UnityEngine;
using System.Collections;
public class Position : MonoBehaviour {
void OnDrawGizmos () {
Gizmos.DrawWireSphere(transform.position, 0.75f);
}
}
FormationController.cs
using UnityEngine;
using System.Collections;
public class FormationController : MonoBehaviour {
public GameObject enemyPrefab;
public float width = 10;
public float height = 5;
public float speed = 5;
public float padding = 1.5f;
public float SpawnDelaySeconds = 1;
private int direction = 1;
private float boundaryLeftEdge,boundaryRightEdge;
private PlayerController playerController;
// Use this for initialization
void Start () {
float distance = transform.position.z - Camera.main.transform.position.z;
Vector3 leftmost = Camera.main.ViewportToWorldPoint(new Vector3(0, 0, distance));
Vector3 rightmost = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, distance));
boundaryLeftEdge = leftmost.x + padding;
boundaryRightEdge = rightmost.x - padding;
SpawnUntilFull();
}
void OnDrawGizmos () {
Gizmos.DrawWireCube(transform.position, new Vector3 (width, height));
}
// Update is called once per frame
void Update () {
float formationRightEdge = transform.position.x + 0.5f * width;
float formationLeftEdge = transform.position.x - 0.5f * width;
if (formationRightEdge > boundaryRightEdge) {
direction = -1;
}
if (formationLeftEdge < boundaryLeftEdge) {
direction = 1;
}
transform.position += new Vector3(direction * speed * Time.deltaTime, 0, 0);
if (AllEnemiesAreDead()) {
SpawnUntilFull();
}
}
void SpawnUntilFull () {
Transform freePos = NextFreePosition();
GameObject enemy = Instantiate(enemyPrefab, freePos.position, Quaternion.identity) as GameObject;
enemy.transform.parent = freePos;
if (FreePositionExists()) {
Invoke ("SpawnUntilFull", SpawnDelaySeconds);
}
}
bool FreePositionExists () {
foreach( Transform position in transform) {
if (position.childCount <= 0) {
return true;
}
}
return false;
}
Transform NextFreePosition() {
foreach (Transform position in transform) {
if (position.childCount <= 0) {
return position;
}
}
return null;
}
bool AllEnemiesAreDead () {
foreach(Transform position in transform) {
if (position.childCount > 0) {
return false;
}
}
return true;
}
}
An example:
I'm making a game like "space invaders", but i can't figured out how when the most left invader die, the invaders formation changes to smaller formation... so the new most left invader "touches" the left boundary.
My scene:
Ignore the gizmo (the circle) at the most top
try this:
using UnityEngine;
using System.Collections;
public class FormationController : MonoBehaviour {
public GameObject enemyPrefab;
public float widthToLeft = 5;
public float widthToRight = 5;
public float height = 5;
public float speed = 5;
public float padding = 1.5f;
public float SpawnDelaySeconds = 1;
private int direction = 1;
private float boundaryLeftEdge,boundaryRightEdge;
private PlayerController playerController;
// Use this for initialization
void Start () {
float distance = transform.position.z - Camera.main.transform.position.z;
Vector3 leftmost = Camera.main.ViewportToWorldPoint(new Vector3(0, 0, distance));
Vector3 rightmost = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, distance));
boundaryLeftEdge = leftmost.x + padding;
boundaryRightEdge = rightmost.x - padding;
SpawnUntilFull();
}
void OnDrawGizmos () {
Gizmos.DrawWireCube(transform.position, new Vector3 (widthToLeft+widthToRight, height));
}
// Update is called once per frame
void Update () {
float formationRightEdge = transform.position.x + 0.5f * widthToRight;
float formationLeftEdge = transform.position.x - 0.5f * widthToLeft;
if (formationRightEdge > boundaryRightEdge) {
direction = -1;
}
if (formationLeftEdge < boundaryLeftEdge) {
direction = 1;
}
transform.position += new Vector3(direction * speed * Time.deltaTime, 0, 0);
if (AllEnemiesAreDead()) {
SpawnUntilFull();
}
}
void SpawnUntilFull () {
Transform freePos = NextFreePosition();
GameObject enemy = Instantiate(enemyPrefab, freePos.position, Quaternion.identity) as GameObject;
enemy.transform.parent = freePos;
if (FreePositionExists()) {
Invoke ("SpawnUntilFull", SpawnDelaySeconds);
}
}
bool FreePositionExists () {
foreach( Transform position in transform) {
if (position.childCount <= 0) {
return true;
}
}
return false;
}
Transform NextFreePosition() {
foreach (Transform position in transform) {
if (position.childCount <= 0) {
return position;
}
}
return null;
}
bool AllEnemiesAreDead () {
foreach(Transform position in transform) {
if (position.childCount > 0) {
return false;
}
}
return true;
}
}
i just changed width to widthToLeft and widthToRight
when the invader dies:
public void OnInvaderDeath() {
float mostLeft = 10000;
float mostRight = -10000;
foreach( Transform invaderTransform in invaderList ) {
if( invaderTransform.position.x < mostLeft )
mostLeft = invaderTransform.position.x;
if( invaderTransform.position.x > mostRight )
mostRight = invaderTransform.position.x;
}
widthToLeft = mostLeft + 0.75f;
widthToRight = mostRight + 0.75f;
}