I am currently learning C# and XNA and I am having some troubles with getting my collision detection to work properly. I wish for my player to disappear when the Enemy object intersects.
Below shows my code within the Obj class
class Obj
{
public Vector2 position;
public float rotation = 0.0f;
public Texture2D spriteIndex;
public string spriteName;
public float speed = 0.0f;
public float scale = 1.0f;
public bool alive = true;
public Rectangle area;
public bool solid = false;
public Obj(Vector2 pos)
{
position = pos;
}
private Obj()
{
}
public virtual void Update()
{
if (!alive) return;
UpdateArea();
pushTo(speed, rotation);
}
public virtual void LoadContent(ContentManager content)
{
spriteIndex = content.Load<Texture2D>("sprites\\" + spriteName);
area = new Rectangle(0, 0, spriteIndex.Width, spriteIndex.Height);
}
public virtual void Draw(SpriteBatch spriteBatch)
{
if (!alive) return;
Rectangle Size;
Vector2 center = new Vector2(spriteIndex.Width / 2, spriteIndex.Height / 2);
spriteBatch.Draw(spriteIndex, position, null, Color.White, MathHelper.ToRadians(rotation), center, scale, SpriteEffects.None, 0);
}
public bool Collision(Vector2 pos, Obj obj)
{
Rectangle newArea = new Rectangle(area.X, area.Y, area.Width, area.Height);
newArea.X += (int)pos.X;
newArea.Y += (int)pos.Y;
foreach (Obj o in Items.objList)
{
if (o.GetType() == obj.GetType() && o.solid)
if (o.area.Intersects(newArea))
return true;
}
return false;
}
public Obj Collision(Obj obj)
{
foreach (Obj o in Items.objList)
{
if (o.GetType() == obj.GetType())
if (o.area.Intersects(area))
return o;
}
return new Obj();
}
public void UpdateArea()
{
area.X = (int)position.X - (spriteIndex.Width / 2);
area.Y = (int)position.Y - (spriteIndex.Height / 2);
}
public T CheckCollisionAgainst<T>() where T : Obj
{
// If collision detected, returns the colliding object; otherwise null.
return Items.objList
.OfType<T>()
.FirstOrDefault(o => o.solid && o.area.Intersects(area));
}
public virtual void pushTo(float pix, float dir)
{
float newX = (float)Math.Cos(MathHelper.ToRadians(dir));
float newY = (float)Math.Sin(MathHelper.ToRadians(dir));
position.X += pix * (float)newX;
position.Y += pix * (float)newY;
}
}
I am cycling through each Item in my objList to see if they intersect with each other, in this case, I want my Player to disappear if the Enemy intersects with them but this is not happening.
This code is from my Player class
class Player : Obj
{
KeyboardState keyboard;
KeyboardState prevKeyboard;
float spd;
public static Player player;
public Player(Vector2 pos)
: base(pos)
{
position = pos;
spd = 4;
spriteName = "WhiteBall";
solid = false;
player = this;
}
public override void Update()
{
player = this;
//If the player is NOT alive, end.
if (!alive) return;
keyboard = Keyboard.GetState();
//Keyboard controls for game
if(keyboard.IsKeyDown(Keys.W) && !Collision(new Vector2(0, -spd), new Enemy(new Vector2(0, 0))))
{
position.Y -= spd;
}
if (keyboard.IsKeyDown(Keys.A) && !Collision(new Vector2(-spd, 0), new Enemy(new Vector2(0, 0))))
{
position.X -= spd;
}
if (keyboard.IsKeyDown(Keys.S) && !Collision(new Vector2(0, spd), new Enemy(new Vector2(0, 0))))
{
position.Y += spd;
}
if (keyboard.IsKeyDown(Keys.D) && !Collision(new Vector2(spd, 0), new Enemy(new Vector2(0, 0))))
{
position.X += spd;
}
prevKeyboard = keyboard;
//Collision with enemy
Enemy enemy = CheckCollisionAgainst<Enemy>();
if (enemy != null)
{
alive = false;
}
base.Update();
}
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.DrawString(Game1.font, "Pick Up The Crew", new Vector2(350, 0), Color.White);
base.Draw(spriteBatch);
}
}
If it intersects with the Enemy, it should disappear but this doesnt seem to be happening.
Based on the comments you provided, I'm taking a shot here and providing a possible solution (ensure UpdateArea is called before calling this):
public T CheckCollisionAgainst<T>() where T : Obj
{
// If collision detected, returns the colliding object; otherwise null.
return Items.objList
.OfType<T>()
.FirstOrDefault(o => o.area.Intersects(area));
}
Enemy enemy = CheckCollisionAgainst<Enemy>();
if (enemy != null)
{
alive = false;
}
Related
I was following a tutorial for creating an enemy in Unity, but they didn't teach how to flip the enemy in case the Player goes to the other side of the map, oppose to where the enemy is.
So I tried to increase the raycast area, so when the Player collides with it from behind, the enemy will know that it has to flip. But something isn't working, cause it goes fine to the Player when it's facing the left side of the map, but once it flips, it totally stops working, and I can't figure it out why.
Anyone have any idea what should I do?
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Skeleton : MonoBehaviour
{
#region Public Variables
public Transform rayCast;
public LayerMask raycastMask;
public GameObject target;
public float rayCastLength;
public float attackDistance; //Mininum distance to attack
public float moveSpeed;
public float timer; // Cooldown b/w attacks
public bool inRange; //check if the player is near
#endregion
#region Private Variables
private RaycastHit2D hit;
private Animator anim;
private float distance; //Distance b/w enemy and player
public bool attackMode;
private float intTimer;
#endregion
void Awake() {
intTimer = timer;
anim = GetComponent<Animator>();
}
void Update() {
if (inRange)
{
hit = Physics2D.Raycast(rayCast.position, Vector2.left, rayCastLength, raycastMask);
}
//When the player is detected
if(hit.collider != null)
{
EnemyLogic();
}
// If it's not inside the raycast
else if(hit.collider == null)
{
inRange = false;
}
// If the player leaves the range
if (inRange == false)
{
anim.SetBool("canWalk", false);
StopAttack();
anim.SetInteger("Idle", 0);
}
}
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Player")
{
target = col.gameObject;
inRange = true;
Flip();
}
}
void EnemyLogic()
{
distance = Vector2.Distance(transform.position, target.transform.position);
if(distance > attackDistance)
{
Move();
StopAttack();
}
else if(attackDistance >= distance)
{
Attack();
}
}
void Move()
{
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", true);
if (!anim.GetCurrentAnimatorStateInfo(0).IsName("attack"))
{
Vector2 targetPosition = new Vector2(target.transform.position.x, transform.position.y);
transform.position = Vector2.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
void Attack()
{
timer = intTimer; //reset timer
attackMode = true;
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", false);
anim.SetBool("Attack", true);
}
void StopAttack()
{
attackMode = false;
anim.SetBool("Attack", false);
}
// Detects if the player is on the other side
void Flip()
{
Vector3 rotation = transform.eulerAngles;
if(target.transform.position.x < transform.position.x)
{
rotation.y = 180f;
}
else
{
rotation.y = 0f;
}
transform.eulerAngles = rotation;
}
}
You can flip the enemy using localScale. Do this:
if (Player.transform.position.x < this.transform.position.x)
{
transform.localScale = new Vector3(-1, 1, 1);
}else
{
transform.localScale = new Vector3(1, 1, 1);
}
This detects whenever the player's x position is greater or lower than the enemy and flips the whole object.
I want to change between 2 materials, depending on the platforms (gameobject) rotation.
Here is what I've done so far:
public class PlatformSpawner : MonoBehaviour
{
public GameObject platform;
public Material[] platformMaterial;
Material currentMaterial;
Renderer _renderer;
}
void Start()
{
_renderer = this.GetComponent<Renderer>();
}
I also wrote this, but I don't want to change materials by buttons:
public void LeftTurn()
{
_renderer.material = platformMaterial[0];
currentMaterial = _renderer.material;
}
public void RightTurn()
{
_renderer.material = platformMaterial[1];
currentMaterial = _renderer.material;
}
}
And this is where the platform rotates randomly 90 degrees to the left or to the right:
public struct SpawnPoint
{
public Vector3 position;
public Quaternion orientation;
public void Step(float distance)
{
if (Random.value < 0.5)
{
position.x += distance;
orientation = Quaternion.Euler(0, 90, 0); //change to one of the materials
}
else
{
position.z += distance;
orientation = Quaternion.Euler(0, 0, 0); //change to the other of the materials.
//This is where I want to material to switch.
//When the objects position changes, the material changes too.
}
}
}
There is a picture of the gameplay. I want to change the material of all the corner platforms to have a nice curve line view.
Can anyone help me what and how to do in this case? I am a bit lost there.
Every help is highly appreciated!
EDIT: new code looks like that. The only issue is that Unity gives me 15 errors (see on the picture below), even if Visual Studio says no issue has been found. The errors refer to the switch.
public class PlatformSpawner : MonoBehaviour
{
public GameObject platform;
public Transform lastPlatform;
SpawnPoint _spawn;
bool stop;
public Material straightMaterial;
public Material turnLeftMaterial;
public Material turnRightMaterial;
public Renderer roadPrefab;
[System.Serializable]
public struct SpawnPoint
{
public Vector3 position;
public Quaternion orientation;
public RoadType type;
public enum RoadType
{
Straight,
LeftTurn,
RightTurn
}
private enum Direction
{
Z,
X,
}
private Direction lastDirection;
public void Step(float distance)
{
type = RoadType.Straight;
if (Random.value < 0.5f)
{
position.x += distance;
orientation = Quaternion.Euler(0, 90, 0);
if (lastDirection == Direction.Z)
{
type = RoadType.RightTurn;
}
}
else
{
position.z += distance;
orientation = Quaternion.Euler(0, 0, 0);
if (lastDirection == Direction.X)
{
type = RoadType.LeftTurn;
}
lastDirection = Direction.Z;
}
}
}
void Start()
{
_spawn.position = lastPlatform.position;
_spawn.orientation = transform.rotation;
StartCoroutine(SpawnPlatforms());
}
IEnumerator SpawnPlatforms()
{
while (!stop)
{
var _spawn = new SpawnPoint();
for (var i = 0; i < 20; i++)
{
var newPlatform = Instantiate(roadPrefab, _spawn.position, _spawn.orientation);
_spawn.Step(1.5f);
var roadMaterial = _spawn.type switch
{
SpawnPoint.RoadType.LeftTurn => turnLeftMaterial,
SpawnPoint.RoadType.RightTurn => turnRightMaterial,
_ => straightMaterial
};
newPlatform.GetComponent<Renderer>().material = roadMaterial;
yield return new WaitForSeconds(0.1f);
}
}
}
}
So it sounds like you basically have a working system for switching the materials and spawning you road parts and materials already look correctly according to your rotations - now you only need to identify the curves.
Actually this is pretty simple:
is the current part in X direction and the next will be in Z -> Left Turn
is the current part in Z direction and the next will be in X -> RightTurn
any other case is straight
So you could probably do something like
public struct SpawnPoint
{
public Vector3 position;
public Quaternion orientation;
public RoadType type;
public enum RoadType
{
Straight,
LeftTurn,
RightTurn
}
private enum Direction
{
// since your orientation by default equals the Z direction use that as default value for the first tile
Z,
X,
}
private Direction lastDirection;
public void Step(float distance)
{
type = RoadType.Straight;
if (Random.value < 0.5f)
{
position.x += distance;
orientation = Quaternion.Euler(0, 90, 0);
if(lastDirection == Direction.Z)
{
type = RoadType.RightTurn;
}
lastDirection = Direction.X;
}
else
{
position.z += distance;
orientation = Quaternion.Euler(0, 0, 0);
if(lastDirection == Direction.X)
{
type = RoadType.LeftTurn;
}
lastDirection = Direction.Z;
}
}
}
And you didn't show your spawn code but I would assume something like
public class Example : MonoBehaviour
{
public Material straightMaterial;
public Material turnLeftMaterial;
public Material turnRightMaterial;
public Renderer roadPrefab;
private void Awake()
{
var spawnPoint = new SpawnPoint();
for(var i = 0; i < 20; i++)
{
var roadTile = Instantiate(roadPrefab, spawnPoint.position, spawnPoint.orientation);
// do the Step after spawning the current tile but before assigning the material
// -> we want/need to know already where the next tile is going to be
spawnPoint.Step(1f);
var roadMaterial = spawnPoint.type switch
{
SpawnPoint.RoadType.LeftTurn => turnLeftMaterial,
SpawnPoint.RoadType.RightTurn => turnRightMaterial,
_ => straightMaterial
};
roadTile.GetComponent<Renderer>().material = roadMaterial;
}
}
}
Behold my Paint skills ;)
This will get you started using Quaternion.Dot.
using UnityEngine;
[RequireComponent(typeof(Renderer))]
public class NewBehaviourScript : MonoBehaviour
{
public Material Material1;
public Material Material2;
public Vector3 Euler = new(90, 0, 0);
private Renderer _renderer;
private void Start()
{
_renderer = GetComponent<Renderer>();
_renderer.material = Material1;
}
private void Update()
{
var dot = Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler));
if (Mathf.Approximately(dot, 1.0f))
{
_renderer.material = Material2;
}
else
{
_renderer.material = Material1;
}
}
}
Using different materials for N, E, S, W corners:
using UnityEngine;
[RequireComponent(typeof(Renderer))]
public class NewBehaviourScript : MonoBehaviour
{
public Material Material1;
public Material Material2;
public Material Material3;
public Material Material4;
public Vector3 Euler1 = new(0, 0, 0);
public Vector3 Euler2 = new(0, 90, 0);
public Vector3 Euler3 = new(0, 180, 0);
public Vector3 Euler4 = new(0, 270, 0);
private Renderer _renderer;
private void Start()
{
_renderer = GetComponent<Renderer>();
_renderer.material = Material1;
}
private void Update()
{
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler1)), 1.0f))
{
_renderer.material = Material1;
}
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler2)), 1.0f))
{
_renderer.material = Material2;
}
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler3)), 1.0f))
{
_renderer.material = Material3;
}
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler4)), 1.0f))
{
_renderer.material = Material4;
}
}
}
Make sure to wrap the rotation past 360 degrees, else it'll always look yellow (4th material).
I am finding it hard to figure out why my transform is wrong. Can anyone help me on this problem. I am trying to make a FSM for my enemy so it either goes for the player or go for food. But when I try to test it I get a compiler error.
using UnityEngine;
using System.Collections;
public class Enemy : MovingObject
{
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipMove;
private Transform Player;
public AudioClip enemyAttack1;
public AudioClip enemyAttack2;
protected override void Start ()
{
GameManager.instance.AddEnemeyToList(this);
animator = GetComponent<Animator> ();
target = GameObject.FindGameObjectWithTag ("Food").transform;
base.Start ();
AIEnemy();
Player = GameObject.FindWithTag("Player").transform;
}
protected override void AttemptMove<T> (int xDir, int yDir)
{
if (skipMove)
{
skipMove = false;
return;
}
base.AttemptMove <T> (xDir, yDir);
skipMove = true;
}
public void MoveEnemy()
{
int xDir = 0;
int yDir = 0;
if (Mathf.Abs (target.position.x - transform.position.x) < float.Epsilon)
yDir = target.position.y > transform.position.y ? 1 : -1;
else
xDir = target.position.x > transform.position.x ? 1 : -1;
AttemptMove<Player> (xDir, yDir);
}
protected override void OnCantMove <T> (T component)
{
Player hitPlayer = component as Player;
hitPlayer.LoseFood (playerDamage);
animator.SetTrigger("enemyAttack");
SoundManager.instance.RandomizeSfx (enemyAttack1, enemyAttack2);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Food")
{
other.gameObject.SetActive(false);
}
else if (other.tag == "Soda")
{
other.gameObject.SetActive(false);
}
}
void AIEnemy()
{
int State = 0;
if (State == 0)
{
transform.LookAt(Player);
State++;
}
if (State == 1)
transform.LookAt(target);
Debug.Log("State 1");
State++;
if (State == 2)
{
Debug.Log("State 2");
}
}
}
public Transform FindClosetFood()
{
float minDistance = float.PositiveInfinity;
Transform closetFood = null;
GameObject[] foods = GameObject.FindGameObjectsWithTag("Food");
for(int i = 0; i<foods.Length; i++)
{
float distance = Vector2.Distance(transform.position, foods[i].transform.position);
if (distance < minDistance)
{
minDistance = distance;
closetFood = foods[i].transform;
}
}
return closetFood;
}
}
I added a private Transform Player. So my enemy knows what to look at but I still dont get anything in console. And I tried calling it in start. But now I ended up with this compiler error.
The error comes in this line
float distance = Vector2.Distance("transform".position, foods[i].transform.position);
MovingObject script:
using UnityEngine;
using System.Collections;
public abstract class MovingObject : MonoBehaviour
{
public float moveTime = 0.1f;
public LayerMask blockingLayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
// Use this for initialization
protected virtual void Start ()
{
boxCollider = GetComponent<BoxCollider2D> ();
rb2D = GetComponent<Rigidbody2D> ();
inverseMoveTime = 1f / moveTime;
}
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 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;
}
}
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 abstract void OnCantMove <T> (T component) where T : Component;
}
It can't find transform.position because transform is a variable undeclared under Component. MonoBehaviour drives from Behaviour and Behaviour derives from Component. To get access to the transform variable, your script must derive from one of these. Although MonoBehaviour is what the script should derive from.
In code, your Enemy script already derive from MovingObject script which derives from MonoBehaviour so that should give you access to the transform variable but there is a problem. There is an extra } at the end of the AIEnemy() function in your Enemy script. That extra } at the end of the AIEnemy() function closes or marks the end of the Enemy script therefore making the transform variable unavailable to you. Remove the extra } at the end of the AIEnemy() function and your problem should be fixed.
If you can't find it, use the new Enemy script below:
public class Enemy : MovingObject
{
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipMove;
private Transform Player;
public AudioClip enemyAttack1;
public AudioClip enemyAttack2;
protected override void Start()
{
GameManager.instance.AddEnemeyToList(this);
animator = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Food").transform;
base.Start();
AIEnemy();
Player = GameObject.FindWithTag("Player").transform;
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
if (skipMove)
{
skipMove = false;
return;
}
base.AttemptMove<T>(xDir, yDir);
skipMove = true;
}
public void MoveEnemy()
{
int xDir = 0;
int yDir = 0;
if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
yDir = target.position.y > transform.position.y ? 1 : -1;
else
xDir = target.position.x > transform.position.x ? 1 : -1;
AttemptMove<Player>(xDir, yDir);
}
protected override void OnCantMove<T>(T component)
{
Player hitPlayer = component as Player;
hitPlayer.LoseFood(playerDamage);
animator.SetTrigger("enemyAttack");
SoundManager.instance.RandomizeSfx(enemyAttack1, enemyAttack2);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Food")
{
other.gameObject.SetActive(false);
}
else if (other.tag == "Soda")
{
other.gameObject.SetActive(false);
}
}
void AIEnemy()
{
int State = 0;
if (State == 0)
{
transform.LookAt(Player);
State++;
}
if (State == 1)
transform.LookAt(target);
Debug.Log("State 1");
State++;
if (State == 2)
{
Debug.Log("State 2");
}
}
public Transform FindClosetFood()
{
float minDistance = float.PositiveInfinity;
Transform closetFood = null;
GameObject[] foods = GameObject.FindGameObjectsWithTag("Food");
for (int i = 0; i < foods.Length; i++)
{
float distance = Vector2.Distance(transform.position, foods[i].transform.position);
if (distance < minDistance)
{
minDistance = distance;
closetFood = foods[i].transform;
}
}
return closetFood;
}
}
I have a problem with collision. Sometimes it works right, but when I move with blue object inside red object, collision changes side and works bad. For example I add ZIP file: here
Generator script:
public class Generator : MonoBehaviour
{
public GameObject obstaclePrefab;
Dictionary<string, GameObject> obstacles;
Dictionary<string, Quaternion> rotations; // default rotation = open to the left
void Start()
{
rotations = new Dictionary<string, Quaternion>()
{
{ "left", Quaternion.Euler(0,0,0) },
{ "down", Quaternion.Euler(0,0,90) },
{ "right", Quaternion.Euler(0,180,0) },
{ "up", Quaternion.Euler(0,0,270) }
};
obstacles = new Dictionary<string, GameObject>();
SpawnObstacle(new Vector2(3,0),"left");
}
void SpawnObstacle(Vector2 position, string openSide)
{
//TODO
print("SpawnObstacle()");
GameObject go = (GameObject)Instantiate(obstaclePrefab, position, rotations[openSide]);
go.GetComponent<Obstacle>().openSide = openSide;
string pos = position.x + "_" + position.y;
obstacles.Add(pos, go);
}
public GameObject GetObjectAt(Vector3 position)
{
string pos = position.x + "_" + position.y;
if (obstacles.ContainsKey(pos) == true)
{
print(obstacles[pos]);
return obstacles[pos];
}
else return null;
}
}
PlayerMove script:
public class PlayerMove : MonoBehaviour
{
public Generator generator;
Vector3 pos;
public float speed;
void Start()
{
pos = transform.position;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
GameObject go = generator.GetObjectAt(transform.position - new Vector3(speed, 0, 0));
if (go == null || go.GetComponent<Obstacle>().canEnterFromSide("left"))
{
print(go);
pos.x -= speed;
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
GameObject go = generator.GetObjectAt(transform.position + new Vector3(speed, 0, 0));
if (go == null || go.GetComponent<Obstacle>().canEnterFromSide("right"))
{
print(go);
pos.x += speed;
}
}
else if (Input.GetKeyDown(KeyCode.UpArrow))
{
GameObject go = generator.GetObjectAt(transform.position + new Vector3(0, speed, 0));
if (go == null || go.GetComponent<Obstacle>().canEnterFromSide("up"))
{
print(go);
pos.y += speed;
}
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
GameObject go = generator.GetObjectAt(transform.position - new Vector3(0, speed, 0));
if (go == null || go.GetComponent<Obstacle>().canEnterFromSide("down"))
{
print(go);
pos.y -= speed;
}
}
transform.position = Vector2.MoveTowards(transform.position, pos, speed);
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("obstacle"))
{
col.gameObject.GetComponent<Obstacle>().Move(true);
print("obstacle");
}
/* else if (col.transform.root.GetComponent<Obstacle>().openSide == "left")
{
}*/
}
}
Obstacle script:
public class Obstacle : MonoBehaviour {
Vector3 pos;
GameObject player;
bool move = false;
public string openSide;
void Start () {
player = GameObject.FindWithTag("Player");
pos = transform.position;
}
public bool Move(bool mo)
{
if(mo)
move = true;
return move;
}
void Update () {
if (openSide == "left" && Input.GetKeyDown(KeyCode.LeftArrow))
move = false;
if (openSide == "right" && Input.GetKeyDown(KeyCode.RightArrow))
move = false;
if (openSide == "up" && Input.GetKeyDown(KeyCode.UpArrow))
move = false;
if (openSide == "down" && Input.GetKeyDown(KeyCode.DownArrow))
move = false;
if (move)
transform.position = player.transform.position;
}
public bool canEnterFromSide(string side)
{
return side == openSide;
}
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I am right now trying to display a vector holding an X and Y value, for a sprite, from one class Game Object.cs to Game1.cs. I move a protected value (protected Vector2 velocity;) to a public Vector2 velocity when I move it over the draw method (so that it will show how fast the sprite on screen is moving) it comes up with Error 1 An object reference is required for the non-static field, method, or property. So I add static, now it's public static Vector2 velocitys, and play the game. When I look at the X and Y value, they'er there but will not change when I move. I have had this problem on anything with a static.
Is there a way to get rid of the static, or fix this so I can see the X and Y update while I am playing? I have the velocitys Vector take velocity's X and Y in the update in GameObject.cs so that it will constantly take from velocity.
Why does it need a static? Can I change that? Can I update it on the screen?
This is the code:
GameObject.cs:
(Holdes the Vectors velocitys and velocity)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Tile_Engine;
namespace **
{
public class GameObject
{
#region Declarations
protected Vector2 worldLocation;
protected Vector2 velocity;
protected int frameWidth;
protected int frameHeight;
protected bool enabled;
protected bool flipped = false;
protected bool onGround;
protected Rectangle collisionRectangle;
protected int collideWidth;
protected int collideHeight;
protected bool codeBasedBlocks = true;
protected float drawDepth = 0.85f;
protected Dictionary<string, AnimationStrip> animations =
new Dictionary<string, AnimationStrip>();
protected string currentAnimation;
public Vector2 velocitys;
#endregion
#region Properties
public bool Enabled
{
get { return enabled; }
set { enabled = value; }
}
public Vector2 WorldLocation
{
get { return worldLocation; }
set { worldLocation = value; }
}
public Vector2 WorldCenter
{
get
{
return new Vector2(
(int)worldLocation.X + (int)(frameWidth / 2),
(int)worldLocation.Y + (int)(frameHeight / 2));
}
}
public Rectangle WorldRectangle
{
get
{
return new Rectangle(
(int)worldLocation.X,
(int)worldLocation.Y,
frameWidth,
frameHeight);
}
}
public Rectangle CollisionRectangle
{
get
{
return new Rectangle(
(int)worldLocation.X + collisionRectangle.X,
(int)worldLocation.Y + collisionRectangle.Y,
collisionRectangle.Width,
collisionRectangle.Height);
}
set { collisionRectangle = value; }
}
#endregion
#region Helper Methods
private void updateAnimation(GameTime gameTime)
{
if (animations.ContainsKey(currentAnimation))
{
if (animations[currentAnimation].FinishedPlaying)
{
PlayAnimation(animations[currentAnimation].NextAnimation);
}
else
{
animations[currentAnimation].Update(gameTime);
}
}
}
#endregion
#region Public Methods
public void PlayAnimation(string name)
{
if (!(name == null) && animations.ContainsKey(name))
{
currentAnimation = name;
animations[name].Play();
}
}
public virtual void Update(GameTime gameTime)
{
if (!enabled)
return;
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
updateAnimation(gameTime);
if (velocity.Y != 0)
{
velocitys = velocity;
onGround = false;
}
Vector2 moveAmount = velocity * elapsed;
moveAmount = horizontalCollisionTest(moveAmount);
moveAmount = verticalCollisionTest(moveAmount);
Vector2 newPosition = worldLocation + moveAmount;
newPosition = new Vector2(
MathHelper.Clamp(newPosition.X, 0,
Camera.WorldRectangle.Width - frameWidth),
MathHelper.Clamp(newPosition.Y, 2 * (-TileMap.TileHeight),
Camera.WorldRectangle.Height - frameHeight));
worldLocation = newPosition;
}
public virtual void Draw(SpriteBatch spriteBatch)
{
if (!enabled)
return;
if (animations.ContainsKey(currentAnimation))
{
SpriteEffects effect = SpriteEffects.None;
if (flipped)
{
effect = SpriteEffects.FlipHorizontally;
}
spriteBatch.Draw(
animations[currentAnimation].Texture,
Camera.WorldToScreen(WorldRectangle),
animations[currentAnimation].FrameRectangle,
Color.White, 0.0f, Vector2.Zero, effect, drawDepth);
}
}
#endregion
#region Map-Based Collision Detecting Methods
private Vector2 horizontalCollisionTest(Vector2 moveAmount)
{
if (moveAmount.X == 0)
return moveAmount;
Rectangle afterMoveRect = CollisionRectangle;
afterMoveRect.Offset((int)moveAmount.X, 0);
Vector2 corner1, corner2;
if (moveAmount.X < 0)
{
corner1 = new Vector2(afterMoveRect.Left,
afterMoveRect.Top + 1);
corner2 = new Vector2(afterMoveRect.Left,
afterMoveRect.Bottom - 1);
}
else
{
corner1 = new Vector2(afterMoveRect.Right,
afterMoveRect.Top + 1);
corner2 = new Vector2(afterMoveRect.Right,
afterMoveRect.Bottom - 1);
}
Vector2 mapCell1 = TileMap.GetCellByPixel(corner1);
Vector2 mapCell2 = TileMap.GetCellByPixel(corner2);
if (!TileMap.CellIsPassable(mapCell1) ||
!TileMap.CellIsPassable(mapCell2))
{
moveAmount.X = 0;
velocity.X = 0;
}
if (codeBasedBlocks)
{
if (TileMap.CellCodeValue(mapCell1) == "BLOCK" ||
TileMap.CellCodeValue(mapCell2) == "BLOCK")
{
moveAmount.X = 0;
velocity.X = 0;
}
}
return moveAmount;
}
private Vector2 verticalCollisionTest(Vector2 moveAmount)
{
if (moveAmount.Y == 0)
return moveAmount;
Rectangle afterMoveRect = CollisionRectangle;
afterMoveRect.Offset((int)moveAmount.X, (int)moveAmount.Y);
Vector2 corner1, corner2;
if (moveAmount.Y < 0)
{
corner1 = new Vector2(afterMoveRect.Left + 1,
afterMoveRect.Top);
corner2 = new Vector2(afterMoveRect.Right - 1,
afterMoveRect.Top);
}
else
{
corner1 = new Vector2(afterMoveRect.Left + 1,
afterMoveRect.Bottom);
corner2 = new Vector2(afterMoveRect.Right - 1,
afterMoveRect.Bottom);
}
Vector2 mapCell1 = TileMap.GetCellByPixel(corner1);
Vector2 mapCell2 = TileMap.GetCellByPixel(corner2);
if (!TileMap.CellIsPassable(mapCell1) ||
!TileMap.CellIsPassable(mapCell2))
{
if (moveAmount.Y > 0)
onGround = true;
moveAmount.Y = 0;
velocity.Y = 0;
}
if (codeBasedBlocks)
{
if (TileMap.CellCodeValue(mapCell1) == "BLOCK" ||
TileMap.CellCodeValue(mapCell2) == "BLOCK")
{
if (moveAmount.Y > 0)
onGround = true;
moveAmount.Y = 0;
velocity.Y = 0;
}
}
return moveAmount;
}
#endregion
}
}
Game1.cs:
(Draws the Vector2 velocity)
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Tile_Engine;
namespace **
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Player player;
SpriteFont pericles8;
Vector2 scorePosition = new Vector2(20, 580);
enum GameState { TitleScreen, Playing, PlayerDead, GameOver };
GameState gameState = GameState.TitleScreen;
Vector2 gameOverPosition = new Vector2(350, 300);
Vector2 livesPosition = new Vector2(600, 580);
Vector2 Velocitys = new Vector2(100, 580);
Texture2D titleScreen;
float deathTimer = 0.0f;
float deathDelay = 5.0f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
this.graphics.PreferredBackBufferWidth = 800;
this.graphics.PreferredBackBufferHeight = 600;
this.graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
TileMap.Initialize(
Content.Load<Texture2D>(#"Textures\PlatformTiles"));
TileMap.spriteFont =
Content.Load<SpriteFont>(#"Fonts\Pericles8");
pericles8 = Content.Load<SpriteFont>(#"Fonts\Pericles8");
titleScreen = Content.Load<Texture2D>(#"Textures\TitleScreen");
Camera.WorldRectangle = new Rectangle(0, 0, 160 * 48, 12 * 48);
Camera.Position = Vector2.Zero;
Camera.ViewPortWidth = 800;
Camera.ViewPortHeight = 600;
player = new Player(Content);
LevelManager.Initialize(Content, player);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
KeyboardState keyState = Keyboard.GetState();
GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
if (gameState == GameState.TitleScreen)
{
if (keyState.IsKeyDown(Keys.Space) ||
gamepadState.Buttons.A == ButtonState.Pressed)
{
StartNewGame();
gameState = GameState.Playing;
}
}
if (gameState == GameState.Playing)
{
player.Update(gameTime);
LevelManager.Update(gameTime);
if (player.Dead)
{
if (player.LivesRemaining > 0)
{
gameState = GameState.PlayerDead;
deathTimer = 0.0f;
}
else{
gameState = GameState.GameOver;
deathTimer = 0.0f;
}
}
}
if (gameState == GameState.PlayerDead)
{
player.Update(gameTime);
LevelManager.Update(gameTime);
deathTimer = elapsed;
if (deathTimer > deathDelay)
{
player.WorldLocation = Vector2.Zero;
LevelManager.ReloadLevel();
player.Revive();
gameState = GameState.Playing;
}
}
if (gameState == GameState.GameOver)
{
deathTimer += elapsed;
if (deathTimer > deathDelay)
{
gameState = GameState.TitleScreen;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
// TODO: Add your drawing code here
spriteBatch.Begin(
SpriteSortMode.BackToFront,
BlendState.AlphaBlend);
if (gameState == GameState.TitleScreen)
{
spriteBatch.Draw(titleScreen, Vector2.Zero, Color.White);
}
if ((gameState == GameState.Playing) ||
(gameState == GameState.PlayerDead) ||
(gameState == GameState.GameOver))
{
TileMap.Draw(spriteBatch);
player.Draw(spriteBatch);
LevelManager.Draw(spriteBatch);
spriteBatch.DrawString(
pericles8,
"Score: " + player.Score.ToString(),
scorePosition,
Color.White);
spriteBatch.DrawString(
pericles8,
"Lives Remaining: " + player.LivesRemaining.ToString(),
livesPosition,
Color.White);
spriteBatch.DrawString(
pericles8,
"Velocity: " + GameObject.velocitys.ToString(),
Velocitys,
Color.White);
}
if (gameState == GameState.PlayerDead)
{
}
if (gameState == GameState.GameOver)
{
spriteBatch.DrawString(
pericles8,
"G A M E O V E R !",
gameOverPosition,
Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
private void StartNewGame()
{
player.Revive();
player.LivesRemaining = 3;
player.WorldLocation = Vector2.Zero;
LevelManager.LoadLevel(0);
}
}
}
Player.cs:
(A part of the velocity)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Tile_Engine;
namespace **
{
public class Player : GameObject
{
#region Declarations
private Vector2 fallSpeed = new Vector2(0, 20);
private float moveScale = 180.0f;
private bool dead = false;
public int score = 0;
private int livesRemaining = 3;
#endregion
public bool Dead
{
get { return dead; }
}
public int Score
{
get { return score; }
set { score = value; }
}
public int LivesRemaining
{
get { return livesRemaining; }
set { livesRemaining = value; }
}
public void Kill()
{
PlayAnimation("die");
LivesRemaining--;
velocity.X = 0;
dead = true;
}
public void Revive()
{
PlayAnimation("idle");
dead = false;
}
#region Constructor
public Player(ContentManager content)
{
animations.Add("idle",
new AnimationStrip(
content.Load<Texture2D>(#"Textures\Sprites\Player\Idle"),
48,
"idle"));
animations["idle"].LoopAnimation = true;
animations.Add("run",
new AnimationStrip(
content.Load<Texture2D>(#"Textures\Sprites\Player\Run"),
48,
"run"));
animations["run"].LoopAnimation = true;
animations.Add("jump",
new AnimationStrip(
content.Load<Texture2D>(#"Textures\Sprites\Player\Jump"),
48,
"jump"));
animations["jump"].LoopAnimation = false;
animations["jump"].FrameLength = 0.08f;
animations["jump"].NextAnimation = "idle";
animations.Add("die",
new AnimationStrip(
content.Load<Texture2D>(#"Textures\Sprites\Player\Die"),
48,
"die"));
animations["die"].LoopAnimation = false;
frameWidth = 48;
frameHeight = 48;
CollisionRectangle = new Rectangle(9, 1, 30, 46);
drawDepth = 0.825f;
enabled = true;
codeBasedBlocks = false;
PlayAnimation("idle");
}
#endregion
#region Public Methods
public override void Update(GameTime gameTime)
{
if (!Dead)
{
string newAnimation = "idle";
velocity = new Vector2(0, velocity.Y);
GamePadState gamePad = GamePad.GetState(PlayerIndex.One);
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Left) ||
(gamePad.ThumbSticks.Left.X < -0.3f))
{
flipped = false;
newAnimation = "run";
velocity = new Vector2(-moveScale, velocity.Y);
}
if (keyState.IsKeyDown(Keys.Right) ||
(gamePad.ThumbSticks.Left.X > 0.3f))
{
flipped = true;
newAnimation = "run";
velocity = new Vector2(moveScale, velocity.Y);
}
if (newAnimation != currentAnimation)
{
PlayAnimation(newAnimation);
}
if (keyState.IsKeyDown(Keys.Space) ||
(gamePad.Buttons.A == ButtonState.Pressed))
{
if (onGround)
{
Jump();
newAnimation = "jump";
}
}
if (currentAnimation == "jump")
newAnimation = "jump";
if (keyState.IsKeyDown(Keys.Up) ||
gamePad.ThumbSticks.Left.Y > 0.3f)
{
checkLevelTransition();
}
}
velocity += fallSpeed;
repositionCamera();
base.Update(gameTime);
}
public void Jump()
{
velocity.Y = -500;
}
#endregion
#region Helper Methods
private void repositionCamera()
{
int screenLocX = (int)Camera.WorldToScreen(worldLocation).X;
if (screenLocX > 500)
{
Camera.Move(new Vector2(screenLocX - 500, 0));
}
if (screenLocX < 200)
{
Camera.Move(new Vector2(screenLocX - 200, 0));
}
}
private void checkLevelTransition()
{
Vector2 centerCell = TileMap.GetCellByPixel(WorldCenter);
if (TileMap.CellCodeValue(centerCell).StartsWith("T_"))
{
string[] code = TileMap.CellCodeValue(centerCell).Split('_');
if (code.Length != 4)
return;
LevelManager.LoadLevel(int.Parse(code[1]));
WorldLocation = new Vector2(
int.Parse(code[2]) * TileMap.TileWidth,
int.Parse(code[3]) * TileMap.TileHeight);
LevelManager.RespawnLocation = WorldLocation;
velocity = Vector2.Zero;
}
}
#endregion
}
}
I have figured out for my self, I mostly wanted a quick answer. Just making a public vector does not help, I needed a method to transfer over the Vector:
public Vector2 Velocitys
{
get { return velocity; }
set { velocity = value; }
}
Then just like the public int Score method I draw it:
spriteBatch.DrawString(
pericles8,
"Velocity: " + player.Velocitys.ToString(),
Velocitys,
Color.White);
It works like a charm.
(Its pretty Ironic that the one thing that I asked why I would use it (get and set) would be the answer)